diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-10-10 12:44:10 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-10-10 12:47:46 +0300 |
commit | f545e3cfa9fcc6b706a6e0ee6f2af2124e514e18 (patch) | |
tree | fb1edcbeb2db72dffe67d20e36d3b381edc9ccf2 /storage/innobase/trx | |
parent | f58a0b3afc4277f9ed077d939be135580f116352 (diff) | |
download | mariadb-git-f545e3cfa9fcc6b706a6e0ee6f2af2124e514e18.tar.gz |
MDEV-15562: Remove dict_table_t::rollback_instant(unsigned n)
On the rollback of changes to SYS_COLUMNS, MDEV-15562 will
break the assumption that the only instantaneous changes to columns
are the addition to the end of the column list.
The function dict_table_t::rollback_instant(unsigned n)
is inherently incompatible with instantly dropping or reordering
columns.
When a change to SYS_COLUMNS is rolled back, we must simply evict
the affected table definition, at the end of the rollback. We cannot
free the table object immediately, because the current transaction
that is being rolled back may be holding a lock on the table and
its metadata record.
dict_table_remove_from_cache_low(): Replaced
by dict_table_remove_from_cache().
dict_table_remove_from_cache(): Add a third parameter keep=false,
so that the table can be freed by the caller.
trx_lock_t::evicted_tables: List of tables on which trx_t::evict_table()
was invoked.
trx_t::evict_table(): Evict a table definition during rollback.
trx_commit_in_memory(): Empty the trx->lock.evicted_tables list
after the locks were released, by freeing the table objects.
row_undo_ins_remove_clust_rec(), row_undo_mod_clust_low():
Invoke trx_t::evict_table() on the affected table if a change to
SYS_COLUMNS is being rolled back.
Diffstat (limited to 'storage/innobase/trx')
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index d51e26aa771..600a6eb6229 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -214,6 +214,9 @@ struct TrxFactory { lock_trx_lock_list_init(&trx->lock.trx_locks); + UT_LIST_INIT(trx->lock.evicted_tables, + &dict_table_t::table_LRU); + UT_LIST_INIT( trx->trx_savepoints, &trx_named_savept_t::trx_savepoints); @@ -238,6 +241,7 @@ struct TrxFactory { } ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); + ut_ad(UT_LIST_GET_LEN(trx->lock.evicted_tables) == 0); UT_DELETE(trx->xid); ut_free(trx->detailed_error); @@ -390,6 +394,7 @@ trx_t *trx_create() ut_ad(trx->lock.n_rec_locks == 0); ut_ad(trx->lock.table_cached == 0); ut_ad(trx->lock.rec_cached == 0); + ut_ad(UT_LIST_GET_LEN(trx->lock.evicted_tables) == 0); #ifdef WITH_WSREP trx->wsrep_event = NULL; @@ -1250,6 +1255,37 @@ trx_update_mod_tables_timestamp( trx->mod_tables.clear(); } +/** Evict a table definition due to the rollback of ALTER TABLE. +@param[in] table_id table identifier */ +void trx_t::evict_table(table_id_t table_id) +{ + ut_ad(in_rollback); + + dict_table_t* table = dict_table_open_on_id( + table_id, true, DICT_TABLE_OP_OPEN_ONLY_IF_CACHED); + if (!table) { + return; + } + + if (!table->release()) { + /* This must be a DDL operation that is being rolled + back in an active connection. */ + ut_a(table->get_ref_count() == 1); + ut_ad(!is_recovered); + ut_ad(mysql_thd); + return; + } + + /* This table should only be locked by this transaction, if at all. */ + ut_ad(UT_LIST_GET_LEN(table->locks) <= 1); + const bool locked = UT_LIST_GET_LEN(table->locks); + ut_ad(!locked || UT_LIST_GET_FIRST(table->locks)->trx == this); + dict_table_remove_from_cache(table, true, locked); + if (locked) { + UT_LIST_ADD_FIRST(lock.evicted_tables, table); + } +} + /****************************************************************//** Commits a transaction in memory. */ static @@ -1315,9 +1351,16 @@ trx_commit_in_memory( trx_update_mod_tables_timestamp(trx); MONITOR_INC(MONITOR_TRX_RW_COMMIT); } + + while (dict_table_t* table = UT_LIST_GET_FIRST( + trx->lock.evicted_tables)) { + UT_LIST_REMOVE(trx->lock.evicted_tables, table); + dict_mem_table_free(table); + } } ut_ad(!trx->rsegs.m_redo.undo); + ut_ad(UT_LIST_GET_LEN(trx->lock.evicted_tables) == 0); if (trx_rseg_t* rseg = trx->rsegs.m_redo.rseg) { mutex_enter(&rseg->mutex); |