Skip to content

Commit e369cc5

Browse files
ram1048dahlerlend
authored andcommitted
Bug#37292404 Update instant dropped extern blob
Thanks to mengchu shi (Alibaba) for the contribution. Background: Row update is done: 1. In-place, if the changes fit within the row 2. Optimistically, if the changes fit within the page and page re-organization is not required 3. Pessimistically otherwise: the old row is deleted and updated row is inserted The following steps are followed during pessimistic update: 1. Prepare in-memory copy (dtuple_t) from the physical record (rec_t) 2. Apply changes to the tuple as described by the update vector 3. Check if field(s) of the tuple must be stored externally 4. If yes, then modify update vector and tuple to indicate it; and create a big record (big_rec_t) 5. Perform undo logging 6. Delete the old physical record 7. Create the physical record (rec_t) back from the updated tuple 8. Insert the updated record Description: When performing undo logging, we log all the fields being modified by the update vector into the undo log. We must not encounter any field which is dropped instantly when logging to the undo log. That is, the update vector must not contain any field which is dropped instantly when we start performing undo logging. When a column is dropped with ALGORITHM=INSTANT, the existing rows are not touched. Thus, an in-memory tuple built from the such existing rows will contain the field(s) which are dropped instantly. Issue: Consider the following scenario: 1. Table is created with a blob column say c1 2. Row is inserted such that c1 is stored externally 3. ALTER TABLE .. DROP COLUMN c1, ALGORITHM=INSTANT; 4. Row is updated and the update is done pessimistically Observe the field c1 along the steps of the pessimistic update: 1. The in-memory copy will contain the dropped field c1 as the column was dropped with ALGORITHM=INSTANT 2. The changes to the tuple will propagate the dropped field as is to the updated tuple 3. The field c1 must be stored externally 4. The field c1 is stored externally and the update vector now includes c1 5. We reach an unexpected state here, causing the server to halt. The field c1 is being undo logged as it is part of the update vector. But the field c1 is already dropped instantly. This violates the prerequisite of undo logging (see Description). Fix: When applying the update on the tuple, ensure that any field which is dropped instantly is removed from the tuple. This ensures that dropped fields are not propagated and are not considered in later stages of the update. Note: When the update is performed pessimistically, the row is brought to the latest row version. This is done when inserting the updated row. Change-Id: I86695f34e88e70bd2fded2479fa90a75437eba28
1 parent 55ee19f commit e369cc5

File tree

1 file changed

+19
-22
lines changed

1 file changed

+19
-22
lines changed

storage/innobase/row/row0upd.cc

+19-22
Original file line numberDiff line numberDiff line change
@@ -1119,44 +1119,41 @@ void row_upd_index_replace_new_col_vals_index_pos(dtuple_t *entry,
11191119
bool order_only,
11201120
mem_heap_t *heap) {
11211121
DBUG_TRACE;
1122-
1123-
ulint i;
1124-
ulint n_fields;
1125-
const page_size_t &page_size = dict_table_page_size(index->table);
1126-
11271122
ut_ad(index);
11281123
ut_ad(!index->table->skip_alter_undo);
11291124

11301125
dtuple_set_info_bits(entry, update->info_bits);
11311126

1132-
if (order_only) {
1133-
n_fields = dict_index_get_n_unique(index);
1134-
} else {
1135-
n_fields = dict_index_get_n_fields(index);
1136-
}
1127+
const ulint n_fields = order_only ? dict_index_get_n_unique(index)
1128+
: dict_index_get_n_fields(index);
1129+
for (ulint field_index = 0; field_index < n_fields; field_index++) {
1130+
ulint field_no;
1131+
bool is_virtual{false};
11371132

1138-
for (i = 0; i < n_fields; i++) {
1139-
const dict_field_t *field;
1140-
const dict_col_t *col;
1141-
const upd_field_t *uf;
1133+
const dict_field_t *field = index->get_field(field_index);
1134+
const dict_col_t *col = field->col;
11421135

1143-
field = index->get_field(i);
1144-
col = field->col;
1145-
if (col->is_virtual()) {
1146-
const dict_v_col_t *vcol = reinterpret_cast<const dict_v_col_t *>(col);
1136+
if (col->is_instant_dropped()) {
1137+
dfield_t *field = dtuple_get_nth_field(entry, field_index);
1138+
field->reset();
1139+
continue;
1140+
}
11471141

1148-
uf = upd_get_field_by_field_no(update, vcol->v_pos, true);
1142+
if (col->is_virtual()) {
1143+
is_virtual = true;
1144+
field_no = reinterpret_cast<const dict_v_col_t *>(col)->v_pos;
11491145
} else {
1150-
uf = upd_get_field_by_field_no(update, i, false);
1146+
field_no = field_index;
11511147
}
11521148

1153-
if (uf) {
1149+
if (auto uf = upd_get_field_by_field_no(update, field_no, is_virtual); uf) {
11541150
upd_field_t *tmp = const_cast<upd_field_t *>(uf);
1155-
dfield_t *dfield = dtuple_get_nth_field(entry, i);
1151+
dfield_t *dfield = dtuple_get_nth_field(entry, field_index);
11561152
tmp->ext_in_old = dfield_is_ext(dfield);
11571153

11581154
dfield_copy(&tmp->old_val, dfield);
11591155

1156+
const auto &page_size = dict_table_page_size(index->table);
11601157
row_upd_index_replace_new_col_val(index, dfield, field, col, uf, heap,
11611158
dict_index_is_sdi(index), page_size);
11621159
}

0 commit comments

Comments
 (0)