diff options
author | Marko Mäkelä <marko.makela@oracle.com> | 2012-09-19 22:35:38 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@oracle.com> | 2012-09-19 22:35:38 +0300 |
commit | 6bbe24e9a00d9190df72c353810ae909e5116994 (patch) | |
tree | 5438ffe1893dd8644e2de800622ecf26c4d584e0 /storage/innobase/ibuf | |
parent | a5f36f4c531a31e4f2f441ef8af78788692117ce (diff) | |
download | mariadb-git-6bbe24e9a00d9190df72c353810ae909e5116994.tar.gz |
Bug#14636528 INNODB CHANGE BUFFERING IS NOT ENTIRELY CRASH-SAFE
Delete-mark change buffer records when resorting to a pessimistic
delete from the change buffer B-tree. Skip delete-marked records in
the change buffer merge and when estimating whether an operation can
be buffered. Without this fix, we could try to apply the same buffered
changes multiple times if the server was killed at the right moment.
In MySQL 5.5 and later: ibuf_get_volume_buffered_count_func(): Ignore
delete-marked (already processed) records.
ibuf_delete_rec(): Add a crash point before optimistic delete. If the
optimistic delete fails, flag the record processed before
mtr_commit().
ibuf_merge_or_delete_for_page(): Ignore delete-marked (already
processed) records.
Backport to 5.1: Rename btr_cur_del_unmark_for_ibuf() to
btr_cur_set_deleted_flag_for_ibuf() and add a parameter.
rb:1307 approved by Jimmy Yang
Diffstat (limited to 'storage/innobase/ibuf')
-rw-r--r-- | storage/innobase/ibuf/ibuf0ibuf.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 476d78e79ba..e2b5bda44fd 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -2978,7 +2978,7 @@ dump: /* The records only differ in the delete-mark. Clear the delete-mark, like we did before Bug #56680 was fixed. */ - btr_cur_del_unmark_for_ibuf(rec, mtr); + btr_cur_set_deleted_flag_for_ibuf(rec, FALSE, mtr); updated_in_place: mem_heap_free(heap); return; @@ -3058,6 +3058,22 @@ ibuf_delete_rec( ut_ad(ibuf_inside()); +#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG + if (ibuf_debug == 2) { + /* Inject a fault (crash). We do this before trying + optimistic delete, because a pessimistic delete in the + change buffer would require a larger test case. */ + + /* Flag the buffered record as processed, to avoid + an assertion failure after crash recovery. */ + btr_cur_set_deleted_flag_for_ibuf( + btr_pcur_get_rec(pcur), TRUE, mtr); + mtr_commit(mtr); + log_make_checkpoint_at(ut_dulint_max, TRUE); + DBUG_SUICIDE(); + } +#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ + success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr); if (success) { @@ -3072,7 +3088,13 @@ ibuf_delete_rec( return(FALSE); } - /* We have to resort to a pessimistic delete from ibuf */ + /* We have to resort to a pessimistic delete from ibuf. + Delete-mark the record so that it will not be applied again, + in case the server crashes before the pessimistic delete is + made persistent. */ + btr_cur_set_deleted_flag_for_ibuf( + btr_pcur_get_rec(pcur), TRUE, mtr); + btr_pcur_store_position(pcur, mtr); btr_pcur_commit_specify_mtr(pcur, mtr); @@ -3343,7 +3365,7 @@ loop: fputs("InnoDB: Discarding record\n ", stderr); rec_print_old(stderr, ibuf_rec); fputs("\n from the insert buffer!\n\n", stderr); - } else if (page) { + } else if (page && !rec_get_deleted_flag(ibuf_rec, 0)) { /* Now we have at pcur a record which should be inserted to the index page; NOTE that the call below copies pointers to fields in ibuf_rec, and we must |