summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase')
-rw-r--r--storage/innobase/dict/dict0dict.cc33
-rw-r--r--storage/innobase/dict/dict0mem.cc76
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
-rw-r--r--storage/innobase/include/dict0dict.h21
-rw-r--r--storage/innobase/include/dict0mem.h5
-rw-r--r--storage/innobase/include/trx0trx.h8
-rw-r--r--storage/innobase/row/row0uins.cc37
-rw-r--r--storage/innobase/row/row0umod.cc14
-rw-r--r--storage/innobase/trx/trx0trx.cc43
9 files changed, 90 insertions, 149 deletions
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 553463755f6..25a3a4b8dfb 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1435,7 +1435,7 @@ dict_make_room_in_cache(
ut_ad(0);
}
};);
- dict_table_remove_from_cache_low(table, TRUE);
+ dict_table_remove_from_cache(table, true);
++n_evicted;
}
@@ -1969,14 +1969,11 @@ dict_table_change_id_in_cache(
ut_fold_ull(table->id), table);
}
-/**********************************************************************//**
-Removes a table object from the dictionary cache. */
-void
-dict_table_remove_from_cache_low(
-/*=============================*/
- dict_table_t* table, /*!< in, own: table */
- ibool lru_evict) /*!< in: TRUE if table being evicted
- to make room in the table LRU list */
+/** Evict a table definition from the InnoDB data dictionary cache.
+@param[in,out] table cached table definition to be evicted
+@param[in] lru whether this is part of least-recently-used eviction
+@param[in] keep whether to keep (not free) the object */
+void dict_table_remove_from_cache(dict_table_t* table, bool lru, bool keep)
{
dict_foreign_t* foreign;
dict_index_t* index;
@@ -2009,7 +2006,7 @@ dict_table_remove_from_cache_low(
index != NULL;
index = UT_LIST_GET_LAST(table->indexes)) {
- dict_index_remove_from_cache_low(table, index, lru_evict);
+ dict_index_remove_from_cache_low(table, index, lru);
}
/* Remove table from the hash tables of tables */
@@ -2031,7 +2028,7 @@ dict_table_remove_from_cache_low(
ut_ad(dict_lru_validate());
- if (lru_evict && table->drop_aborted) {
+ if (lru && table->drop_aborted) {
/* When evicting the table definition,
drop the orphan indexes from the data dictionary
and free the index pages. */
@@ -2056,17 +2053,9 @@ dict_table_remove_from_cache_low(
UT_DELETE(table->vc_templ);
}
- dict_mem_table_free(table);
-}
-
-/**********************************************************************//**
-Removes a table object from the dictionary cache. */
-void
-dict_table_remove_from_cache(
-/*=========================*/
- dict_table_t* table) /*!< in, own: table */
-{
- dict_table_remove_from_cache_low(table, FALSE);
+ if (!keep) {
+ dict_mem_table_free(table);
+ }
}
/****************************************************************//**
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index e6c5050d949..a26354657f7 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -1346,6 +1346,7 @@ dict_table_t::rollback_instant(
DBUG_ASSERT(n_cols >= old_n_cols);
DBUG_ASSERT(n_cols == n_def);
DBUG_ASSERT(index->n_def == index->n_fields);
+ DBUG_ASSERT(index->n_core_fields <= index->n_fields);
const unsigned n_remove = n_cols - old_n_cols;
@@ -1405,81 +1406,6 @@ dict_table_t::rollback_instant(
} while ((index = dict_table_get_next_index(index)) != NULL);
}
-/** Trim the instantly added columns when an insert into SYS_COLUMNS
-is rolled back during ALTER TABLE or recovery.
-@param[in] n number of surviving non-system columns */
-void dict_table_t::rollback_instant(unsigned n)
-{
- ut_ad(mutex_own(&dict_sys->mutex));
- dict_index_t* index = indexes.start;
- DBUG_ASSERT(index->is_instant());
- DBUG_ASSERT(index->n_def == index->n_fields);
- DBUG_ASSERT(n_cols == n_def);
- DBUG_ASSERT(n >= index->n_uniq);
- DBUG_ASSERT(n_cols > n + DATA_N_SYS_COLS);
- const unsigned n_remove = n_cols - n - DATA_N_SYS_COLS;
-
- char* names = const_cast<char*>(dict_table_get_col_name(this, n));
- const char* sys = names;
- for (unsigned i = n_remove; i--; ) {
- sys += strlen(sys) + 1;
- }
- static const char system[] = "DB_ROW_ID\0DB_TRX_ID\0DB_ROLL_PTR";
- DBUG_ASSERT(!memcmp(sys, system, sizeof system));
- for (unsigned i = index->n_fields - n_remove; i < index->n_fields;
- i++) {
- if (index->fields[i].col->is_nullable()) {
- index->n_nullable--;
- }
- }
- index->n_fields -= n_remove;
- index->n_def = index->n_fields;
- memmove(names, sys, sizeof system);
- memmove(cols + n, cols + n_cols - DATA_N_SYS_COLS,
- DATA_N_SYS_COLS * sizeof *cols);
- n_cols -= n_remove;
- n_def = n_cols;
- n_t_cols -= n_remove;
- n_t_def -= n_remove;
-
- for (unsigned i = DATA_N_SYS_COLS; i--; ) {
- cols[n_cols - i].ind--;
- }
-
- if (dict_index_is_auto_gen_clust(index)) {
- DBUG_ASSERT(index->n_uniq == 1);
- dict_field_t* field = index->fields;
- field->name = sys;
- field->col = dict_table_get_sys_col(this, DATA_ROW_ID);
- field++;
- field->name = sys + sizeof "DB_ROW_ID";
- field->col = dict_table_get_sys_col(this, DATA_TRX_ID);
- field++;
- field->name = sys + sizeof "DB_ROW_ID\0DB_TRX_ID";
- field->col = dict_table_get_sys_col(this, DATA_ROLL_PTR);
-
- /* Replace the DB_ROW_ID column in secondary indexes. */
- while ((index = dict_table_get_next_index(index)) != NULL) {
- field = &index->fields[index->n_fields - 1];
- DBUG_ASSERT(field->col->mtype == DATA_SYS);
- DBUG_ASSERT(field->col->prtype
- == DATA_NOT_NULL + DATA_TRX_ID);
- field->col--;
- field->name = sys;
- }
-
- return;
- }
-
- dict_field_t* field = &index->fields[index->n_uniq];
- field->name = sys + sizeof "DB_ROW_ID";
- field->col = dict_table_get_sys_col(this, DATA_TRX_ID);
- field++;
- field->name = sys + sizeof "DB_ROW_ID\0DB_TRX_ID";
- field->col = dict_table_get_sys_col(this, DATA_ROLL_PTR);
-}
-
-
/** Check if record in clustered index is historical row.
@param[in] rec clustered row
@param[in] offsets offsets
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 8964aad2809..b2df3983831 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -17212,7 +17212,7 @@ innodb_internal_table_validate(
DBUG_EXECUTE_IF("innodb_evict_autoinc_table",
mutex_enter(&dict_sys->mutex);
- dict_table_remove_from_cache_low(user_table, TRUE);
+ dict_table_remove_from_cache(user_table, true);
mutex_exit(&dict_sys->mutex);
);
}
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 0da785a4e5c..6a098591256 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -374,21 +374,12 @@ dict_table_add_system_columns(
dict_table_t* table, /*!< in/out: table */
mem_heap_t* heap) /*!< in: temporary heap */
MY_ATTRIBUTE((nonnull));
-/**********************************************************************//**
-Removes a table object from the dictionary cache. */
-void
-dict_table_remove_from_cache(
-/*=========================*/
- dict_table_t* table) /*!< in, own: table */
- MY_ATTRIBUTE((nonnull));
-/**********************************************************************//**
-Removes a table object from the dictionary cache. */
-void
-dict_table_remove_from_cache_low(
-/*=============================*/
- dict_table_t* table, /*!< in, own: table */
- ibool lru_evict) /*!< in: TRUE if table being evicted
- to make room in the table LRU list */
+/** Evict a table definition from the InnoDB data dictionary cache.
+@param[in,out] table cached table definition to be evicted
+@param[in] lru whether this is part of least-recently-used evictiono
+@param[in] keep whether to keep (not free) the object */
+void dict_table_remove_from_cache(dict_table_t* table, bool lru = false,
+ bool keep = false)
MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Renames a table object.
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 62741c8baaa..7637a387b8f 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1551,11 +1551,6 @@ struct dict_table_t {
dict_col_t* old_cols,
const char* old_col_names);
- /** Trim the instantly added columns when an insert into SYS_COLUMNS
- is rolled back during ALTER TABLE or recovery.
- @param[in] n number of surviving non-system columns */
- void rollback_instant(unsigned n);
-
/** Add the table definition to the data dictionary cache */
void add_to_cache();
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index d6a8b8c771b..cb878fa5b19 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -482,6 +482,7 @@ Check transaction state */
ut_ad(!(t)->read_view.is_open()); \
ut_ad((t)->lock.wait_thr == NULL); \
ut_ad(UT_LIST_GET_LEN((t)->lock.trx_locks) == 0); \
+ ut_ad(UT_LIST_GET_LEN((t)->lock.evicted_tables) == 0); \
ut_ad((t)->dict_operation == TRX_DICT_OP_NONE); \
} while(0)
@@ -606,6 +607,9 @@ struct trx_lock_t {
lock_list table_locks; /*!< All table locks requested by this
transaction, including AUTOINC locks */
+ /** List of pending trx_t::evict_table() */
+ UT_LIST_BASE_NODE_T(dict_table_t) evicted_tables;
+
bool cancel; /*!< true if the transaction is being
rolled back either via deadlock
detection or due to lock timeout. The
@@ -1112,6 +1116,10 @@ public:
return(assign_temp_rseg());
}
+ /** Evict a table definition due to the rollback of ALTER TABLE.
+ @param[in] table_id table identifier */
+ void evict_table(table_id_t table_id);
+
bool is_referenced()
{
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index d610e45edbc..3a1690782ff 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -140,10 +140,11 @@ row_undo_ins_remove_clust_rec(
break;
case DICT_COLUMNS_ID:
/* This is rolling back an INSERT into SYS_COLUMNS.
- If it was part of an instant ADD COLUMN operation, we
- must modify the table definition. At this point, any
- corresponding operation to the metadata record will have
- been rolled back. */
+ If it was part of an instant ALTER TABLE operation, we
+ must evict the table definition, so that it can be
+ reloaded after the dictionary operation has been
+ completed. At this point, any corresponding operation
+ to the metadata record will have been rolled back. */
ut_ad(!online);
ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
ut_ad(node->rec_type == TRX_UNDO_INSERT_REC);
@@ -158,33 +159,7 @@ row_undo_ins_remove_clust_rec(
if (len != 8) {
break;
}
- const table_id_t table_id = mach_read_from_8(data);
- data = rec_get_nth_field_old(rec, DICT_FLD__SYS_COLUMNS__POS,
- &len);
- if (len != 4) {
- break;
- }
- const unsigned pos = mach_read_from_4(data);
- if (pos == 0 || pos >= (1U << 16)) {
- break;
- }
- dict_table_t* table = dict_table_open_on_id(
- table_id, true, DICT_TABLE_OP_OPEN_ONLY_IF_CACHED);
- if (!table) {
- break;
- }
-
- dict_index_t* index = dict_table_get_first_index(table);
-
- if (index && index->is_instant()
- && DATA_N_SYS_COLS + 1 + pos == table->n_cols) {
- /* This is the rollback of an instant ADD COLUMN.
- Remove the column from the dictionary cache,
- but keep the system columns. */
- table->rollback_instant(pos);
- }
-
- dict_table_close(table, true, false);
+ node->trx->evict_table(mach_read_from_8(data));
}
if (btr_cur_optimistic_delete(btr_cur, 0, &mtr)) {
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index 0ab186aac5e..63cf63b2614 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -147,6 +147,20 @@ row_undo_mod_clust_low(
ut_a(!dummy_big_rec);
}
+ if (err == DB_SUCCESS
+ && btr_cur_get_index(btr_cur)->table->id == DICT_COLUMNS_ID) {
+ /* This is rolling back an UPDATE or DELETE on SYS_COLUMNS.
+ If it was part of an instant ALTER TABLE operation, we
+ must evict the table definition, so that it can be
+ reloaded after the dictionary operation has been
+ completed. At this point, any corresponding operation
+ to the metadata record will have been rolled back. */
+ const dfield_t& table_id = *dtuple_get_nth_field(node->row, 0);
+ ut_ad(dfield_get_len(&table_id) == 8);
+ node->trx->evict_table(mach_read_from_8(static_cast<byte*>(
+ table_id.data)));
+ }
+
return(err);
}
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);