diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-05-03 15:17:16 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-05-03 15:17:16 +0300 |
commit | 6c43068d6342bd1a7c1dbb24079ac4da4ba9b4ff (patch) | |
tree | ba126c01ece73aaa499dcd592c0144b227b1d6f0 /storage/innobase/rem | |
parent | 01843d191094d524428c786d4fd6310d4b6f9224 (diff) | |
download | mariadb-git-6c43068d6342bd1a7c1dbb24079ac4da4ba9b4ff.tar.gz |
MDEV-15060 Assertion in row_log_table_apply_op after instant ADD when the table is emptied during subsequent ALTER TABLE
During an online table rebuild, a table could be emptied and converted
from 'instant ADD' format to plain (pre-10.3) format. All online_log
records for rebuilding the table must be written and parsed in the
format of the table that existed at the start of the operation.
row_log_t::n_core_fields: A new field for recording index->n_core_fields
when online ALTER is initiated in row_log_allocate().
row_log_t::is_instant(): Determine if the log is in the instant format.
Only invoked by the row_log_table_ family of functions.
dict_index_t::get_n_nullable(): Remove is_instant() debug assertions.
Because a table can be converted to non-instant format during a
table-rebuilding ALTER TABLE, these assertions would be bogus when
executing row_log_table_apply().
rec_init_offsets_temp(): Add the parameter n_core for passing the
original index->n_core_fields.
rec_init_offsets_temp(): Add a 3-parameter variant.
rec_init_offsets_comp_ordinary(): Add the parameter n_core for
passing the index->n_core_fields.
Diffstat (limited to 'storage/innobase/rem')
-rw-r--r-- | storage/innobase/rem/rem0rec.cc | 48 |
1 files changed, 36 insertions, 12 deletions
diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index 6da2866b0c1..7d1a35d82e4 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -298,6 +298,7 @@ in ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED. This is a special case of rec_init_offsets() and rec_get_offsets_func(). @param[in] rec leaf-page record @param[in] index the index that the record belongs in +@param[in] n_core number of core fields (index->n_core_fields) @param[in,out] offsets offsets, with valid rec_offs_n_fields(offsets) @param[in] format record format */ static inline @@ -306,17 +307,19 @@ rec_init_offsets_comp_ordinary( const rec_t* rec, const dict_index_t* index, ulint* offsets, + ulint n_core, rec_leaf_format format) { ulint offs = 0; ulint any = 0; const byte* nulls = rec; const byte* lens = NULL; - ulint n_fields = index->n_core_fields; + ulint n_fields = n_core; ulint null_mask = 1; - ut_ad(index->n_core_fields > 0); - ut_ad(index->n_fields >= index->n_core_fields); + ut_ad(index->n_core_fields >= n_core); + ut_ad(n_core > 0); + ut_ad(index->n_fields >= n_core); ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable)); ut_ad(format == REC_LEAF_TEMP || format == REC_LEAF_TEMP_COLUMNS_ADDED || dict_table_is_comp(index->table)); @@ -344,17 +347,17 @@ ordinary: /* We would have !index->is_instant() when rolling back an instant ADD COLUMN operation. */ nulls -= REC_N_NEW_EXTRA_BYTES; + ut_ad(index->is_instant()); /* fall through */ case REC_LEAF_TEMP_COLUMNS_ADDED: - ut_ad(index->is_instant()); - n_fields = unsigned(index->n_core_fields) + 1 - + rec_get_n_add_field(nulls); + n_fields = n_core + 1 + rec_get_n_add_field(nulls); ut_ad(n_fields <= index->n_fields); const ulint n_nullable = index->get_n_nullable(n_fields); const ulint n_null_bytes = UT_BITS_IN_BYTES(n_nullable); ut_d(n_null = n_nullable); ut_ad(n_null <= index->n_nullable); - ut_ad(n_null_bytes >= index->n_core_null_bytes); + ut_ad(n_null_bytes >= index->n_core_null_bytes + || n_core < index->n_core_fields); lens = --nulls - n_null_bytes; } @@ -614,11 +617,13 @@ rec_init_offsets( case REC_STATUS_COLUMNS_ADDED: ut_ad(leaf); rec_init_offsets_comp_ordinary(rec, index, offsets, + index->n_core_fields, REC_LEAF_COLUMNS_ADDED); return; case REC_STATUS_ORDINARY: ut_ad(leaf); rec_init_offsets_comp_ordinary(rec, index, offsets, + index->n_core_fields, REC_LEAF_ORDINARY); return; } @@ -1689,25 +1694,44 @@ rec_get_converted_size_temp( @param[in] rec temporary file record @param[in] index index of that the record belongs to @param[in,out] offsets offsets to the fields; in: rec_offs_n_fields(offsets) -@param[in] status REC_STATUS_ORDINARY or REC_STATUS_COLUMNS_ADDED -*/ +@param[in] n_core number of core fields (index->n_core_fields) +@param[in] status REC_STATUS_ORDINARY or REC_STATUS_COLUMNS_ADDED */ void rec_init_offsets_temp( const rec_t* rec, const dict_index_t* index, ulint* offsets, + ulint n_core, rec_comp_status_t status) { ut_ad(status == REC_STATUS_ORDINARY || status == REC_STATUS_COLUMNS_ADDED); - ut_ad(status == REC_STATUS_ORDINARY || index->is_instant()); - - rec_init_offsets_comp_ordinary(rec, index, offsets, + /* The table may have been converted to plain format + if it was emptied during an ALTER TABLE operation. */ + ut_ad(index->n_core_fields == n_core || !index->is_instant()); + ut_ad(index->n_core_fields >= n_core); + rec_init_offsets_comp_ordinary(rec, index, offsets, n_core, status == REC_STATUS_COLUMNS_ADDED ? REC_LEAF_TEMP_COLUMNS_ADDED : REC_LEAF_TEMP); } +/** Determine the offset to each field in temporary file. +@param[in] rec temporary file record +@param[in] index index of that the record belongs to +@param[in,out] offsets offsets to the fields; in: rec_offs_n_fields(offsets) +*/ +void +rec_init_offsets_temp( + const rec_t* rec, + const dict_index_t* index, + ulint* offsets) +{ + ut_ad(!index->is_instant()); + rec_init_offsets_comp_ordinary(rec, index, offsets, + index->n_core_fields, REC_LEAF_TEMP); +} + /** Convert a data tuple prefix to the temporary file format. @param[out] rec record in temporary file format @param[in] index clustered or secondary index |