Commit 2caade50 authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#53812: assert row/row0umod.c line 660 in txn rollback after crash recovery

row_undo_mod_upd_exist_sec(): Tolerate a failure to build the index entry
for a DYNAMIC or COMPRESSED table during crash recovery.
parent da0b6d61
...@@ -657,24 +657,55 @@ row_undo_mod_upd_exist_sec( ...@@ -657,24 +657,55 @@ row_undo_mod_upd_exist_sec(
/* Build the newest version of the index entry */ /* Build the newest version of the index entry */
entry = row_build_index_entry(node->row, node->ext, entry = row_build_index_entry(node->row, node->ext,
index, heap); index, heap);
ut_a(entry); if (UNIV_UNLIKELY(!entry)) {
/* NOTE that if we updated the fields of a /* The server must have crashed in
delete-marked secondary index record so that row_upd_clust_rec_by_insert(), in
alphabetically they stayed the same, e.g., row_ins_index_entry_low() before
'abc' -> 'aBc', we cannot return to the original btr_store_big_rec_extern_fields()
values because we do not know them. But this should has written the externally stored columns
not cause problems because in row0sel.c, in queries (BLOBs) of the new clustered index entry. */
we always retrieve the clustered index record or an
earlier version of it, if the secondary index record /* The table must be in DYNAMIC or COMPRESSED
through which we do the search is delete-marked. */ format. REDUNDANT and COMPACT formats
store a local 768-byte prefix of each
err = row_undo_mod_del_mark_or_remove_sec(node, thr, externally stored column. */
index, ut_a(dict_table_get_format(index->table)
entry); >= DICT_TF_FORMAT_ZIP);
if (err != DB_SUCCESS) {
mem_heap_free(heap); /* This is only legitimate when
rolling back an incomplete transaction
return(err); after crash recovery. */
ut_a(thr_get_trx(thr)->is_recovered);
/* The server must have crashed before
completing the insert of the new
clustered index entry and before
inserting to the secondary indexes.
Because node->row was not yet written
to this index, we can ignore it. But
we must restore node->undo_row. */
} else {
/* NOTE that if we updated the fields of a
delete-marked secondary index record so that
alphabetically they stayed the same, e.g.,
'abc' -> 'aBc', we cannot return to the
original values because we do not know them.
But this should not cause problems because
in row0sel.c, in queries we always retrieve
the clustered index record or an earlier
version of it, if the secondary index record
through which we do the search is
delete-marked. */
err = row_undo_mod_del_mark_or_remove_sec(
node, thr, index, entry);
if (err != DB_SUCCESS) {
mem_heap_free(heap);
return(err);
}
mem_heap_empty(heap);
} }
/* We may have to update the delete mark in the /* We may have to update the delete mark in the
...@@ -683,7 +714,6 @@ row_undo_mod_upd_exist_sec( ...@@ -683,7 +714,6 @@ row_undo_mod_upd_exist_sec(
the secondary index record if we updated its fields the secondary index record if we updated its fields
but alphabetically they stayed the same, e.g., but alphabetically they stayed the same, e.g.,
'abc' -> 'aBc'. */ 'abc' -> 'aBc'. */
mem_heap_empty(heap);
entry = row_build_index_entry(node->undo_row, entry = row_build_index_entry(node->undo_row,
node->undo_ext, node->undo_ext,
index, heap); index, heap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment