Skip to content

Commit

Permalink
Bug#35410528 : INSTANT DDL crashes 8.0.32 after upgrading from 5.7.41
Browse files Browse the repository at this point in the history
Background:
 When tables are loaded in mem cache (dict_table_t) they go through
 fill_dict_table() which makes sure all in mem metadata is updated
 for the tables correctly.

 But in case of upgrade from 5.7, tables are loaded in dict_table_t
 cache from dict_load_table(). And then it remains in cache to be used.

Issue:
 During upgrade, when the table is loaded from dict_load_table(), it
 doesn't set the initial/current/total/_column_count metadata of
 dict_table_t. Which causes issues when table is used after INSTANT
 ADD/DROP DDL.

 Note this is done only once and next server restarts, the table is
 loaded from fill_dict_table() function. And this is why if there is a
 restart after upgrade, the issue is not seen.

Fix:
 Made sure when the table is loaded from dict_load_table() during
 upgrade, the column count metadata is also set correctly.

Change-Id: I7729a9e03683737bfe8b3025203f31551b710f70
  • Loading branch information
Mayank Prasad authored and dahlerlend committed May 31, 2023
1 parent e9b5041 commit bbcb9bc
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 28 deletions.
48 changes: 25 additions & 23 deletions storage/innobase/dict/dict0load.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1621,56 +1621,48 @@ static inline space_id_t dict_check_sys_tables(bool validate) {
return max_space_id;
}

/** Loads definitions for table columns. */
static void dict_load_columns(dict_table_t *table, /*!< in/out: table */
mem_heap_t *heap) /*!< in/out: memory heap
for temporary storage */
{
dict_table_t *sys_columns;
dict_index_t *sys_index;
btr_pcur_t pcur;
dtuple_t *tuple;
dfield_t *dfield;
const rec_t *rec;
byte *buf;
ulint i;
mtr_t mtr;
ulint n_skipped = 0;

/** Load columns in an innodb cached table object from SYS_COLUMNS table.
@param[in, out] table Table cache object
@param[in, out] heap memory heap for temporary storage */
static void dict_load_columns(dict_table_t *table, mem_heap_t *heap) {
ut_ad(dict_sys_mutex_own());

mtr_t mtr;
mtr_start(&mtr);

sys_columns = dict_table_get_low("SYS_COLUMNS");
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
dict_table_t *sys_columns = dict_table_get_low("SYS_COLUMNS");
dict_index_t *sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
ut_ad(!dict_table_is_comp(sys_columns));

ut_ad(name_of_col_is(sys_columns, sys_index, DICT_FLD__SYS_COLUMNS__NAME,
"NAME"));
ut_ad(name_of_col_is(sys_columns, sys_index, DICT_FLD__SYS_COLUMNS__PREC,
"PREC"));

tuple = dtuple_create(heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
dtuple_t *tuple = dtuple_create(heap, 1);
dfield_t *dfield = dtuple_get_nth_field(tuple, 0);

buf = static_cast<byte *>(mem_heap_alloc(heap, 8));
byte *buf = static_cast<byte *>(mem_heap_alloc(heap, 8));
mach_write_to_8(buf, table->id);

dfield_set_data(dfield, buf, 8);
dict_index_copy_types(tuple, sys_index, 1);

btr_pcur_t pcur;
pcur.open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &mtr,
UT_LOCATION_HERE);

ut_ad(table->n_t_cols == static_cast<ulint>(table->n_cols) +
static_cast<ulint>(table->n_v_cols));

for (i = 0; i + DATA_N_SYS_COLS < table->n_t_cols + n_skipped; i++) {
size_t non_v_cols = 0;
size_t n_skipped = 0;
for (size_t i = 0; i + DATA_N_SYS_COLS < table->n_t_cols + n_skipped; i++) {
const char *err_msg;
const char *name = nullptr;
ulint nth_v_col = ULINT_UNDEFINED;

rec = pcur.get_rec();
const rec_t *rec = pcur.get_rec();

ut_a(pcur.is_on_user_rec());

Expand All @@ -1684,6 +1676,11 @@ static void dict_load_columns(dict_table_t *table, /*!< in/out: table */
ib::fatal(UT_LOCATION_HERE, ER_IB_MSG_195) << err_msg;
}

if (nth_v_col == ULINT_UNDEFINED) {
/* Not a virtual column */
non_v_cols++;
}

/* Note: Currently we have one DOC_ID column that is
shared by all FTS indexes on a table. And only non-virtual
column can be used for FULLTEXT index */
Expand Down Expand Up @@ -1727,6 +1724,11 @@ static void dict_load_columns(dict_table_t *table, /*!< in/out: table */

pcur.close();
mtr_commit(&mtr);

/* The table is getting upgraded from 5.7 where there was no row version */
table->initial_col_count = table->current_col_count = table->total_col_count =
non_v_cols;
table->current_row_version = 0;
}

/** Loads definitions for index fields.
Expand Down
8 changes: 3 additions & 5 deletions storage/innobase/include/dict0mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,7 @@ struct dict_table_t {
uint32_t total_col_count{0};

/** Set if table is upgraded instant table */
unsigned m_upgraded_instant : 1;
bool m_upgraded_instant{false};

/** table dynamic metadata status, protected by dict_persist->mutex */
std::atomic<table_dirty_status> dirty_status;
Expand Down Expand Up @@ -2531,13 +2531,11 @@ detect this and will eventually quit sooner. */
bool has_instant_drop_cols() const { return (get_n_instant_drop_cols() > 0); }

/** Set table to be upgraded table with INSTANT ADD columns in V1. */
void set_upgraded_instant() { m_upgraded_instant = 1; }
void set_upgraded_instant() { m_upgraded_instant = true; }

/** Checks if table is upgraded table with INSTANT ADD columns in V1.
@return true if it is, false otherwise */
bool is_upgraded_instant() const {
return (m_upgraded_instant == 1) ? true : false;
}
bool is_upgraded_instant() const { return m_upgraded_instant; }

/** Check whether the table is corrupted.
@return true if the table is corrupted, otherwise false */
Expand Down

0 comments on commit bbcb9bc

Please sign in to comment.