From 028d253dd7401fa564bcf817fe81c7034f2512d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 2 Oct 2017 10:22:42 +0300 Subject: [PATCH] MDEV-13980 InnoDB fails to discard record lock when discarding an index page btr_cur_pessimistic_delete(): Discard a possible record lock also in the case when the record was the only one in the page. Failure to do this would corrupt the record lock data structures in a partial rollback (ROLLBACK TO SAVEPOINT or rolling back a row operation due to some error, such as a duplicate key in a unique secondary index). --- storage/innobase/btr/btr0cur.c | 10 +++++----- storage/xtradb/btr/btr0cur.c | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 2c1ab4bffae..e8c467409b2 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -2,6 +2,7 @@ Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2017, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -3193,7 +3194,6 @@ btr_cur_pessimistic_delete( ulint n_reserved; ibool success; ibool ret = FALSE; - ulint level; mem_heap_t* heap; ulint* offsets; @@ -3240,6 +3240,8 @@ btr_cur_pessimistic_delete( #endif /* UNIV_ZIP_DEBUG */ } + lock_update_delete(block, rec); + if (UNIV_UNLIKELY(page_get_n_recs(page) < 2) && UNIV_UNLIKELY(dict_index_get_page(index) != buf_block_get_page_no(block))) { @@ -3255,10 +3257,7 @@ btr_cur_pessimistic_delete( goto return_after_reservations; } - lock_update_delete(block, rec); - level = btr_page_get_level(page, mtr); - - if (level > 0 + if (!page_is_leaf(page) && UNIV_UNLIKELY(rec == page_rec_get_next( page_get_infimum_rec(page)))) { @@ -3281,6 +3280,7 @@ btr_cur_pessimistic_delete( on a page, we have to change the father node pointer so that it is equal to the new leftmost node pointer on the page */ + ulint level = btr_page_get_level(page, mtr); btr_node_ptr_delete(index, block, mtr); diff --git a/storage/xtradb/btr/btr0cur.c b/storage/xtradb/btr/btr0cur.c index d9c1a2ef7a8..0d015111d81 100644 --- a/storage/xtradb/btr/btr0cur.c +++ b/storage/xtradb/btr/btr0cur.c @@ -2,6 +2,7 @@ Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2017, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -3376,7 +3377,6 @@ btr_cur_pessimistic_delete( ulint n_reserved; ibool success; ibool ret = FALSE; - ulint level; mem_heap_t* heap; ulint* offsets; @@ -3425,6 +3425,8 @@ btr_cur_pessimistic_delete( #endif /* UNIV_ZIP_DEBUG */ } + lock_update_delete(block, rec); + if (UNIV_UNLIKELY(page_get_n_recs(page) < 2) && UNIV_UNLIKELY(dict_index_get_page(index) != buf_block_get_page_no(block))) { @@ -3440,10 +3442,7 @@ btr_cur_pessimistic_delete( goto return_after_reservations; } - lock_update_delete(block, rec); - level = btr_page_get_level(page, mtr); - - if (level > 0 + if (!page_is_leaf(page) && UNIV_UNLIKELY(rec == page_rec_get_next( page_get_infimum_rec(page)))) { @@ -3466,6 +3465,7 @@ btr_cur_pessimistic_delete( on a page, we have to change the father node pointer so that it is equal to the new leftmost node pointer on the page */ + ulint level = btr_page_get_level(page, mtr); btr_node_ptr_delete(index, block, mtr);