From 1bd98154791d77a44d2afc4bf6eb78f692fb7b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 25 Mar 2019 11:27:29 +0200 Subject: [PATCH 1/3] MDEV-14126: Fix type mismatch Backport some changes to B-tree page accessor functions from 10.3, including changing page_get_n_recs() to return uint16_t. --- storage/innobase/include/page0page.h | 22 ++++++------ storage/innobase/include/page0page.ic | 48 ++++++++++++--------------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 18c536c05e9..2b869dbe8c3 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -175,7 +175,7 @@ inline page_t* page_align(const void* ptr) { - return(static_cast(ut_align_down(ptr, UNIV_PAGE_SIZE))); + return(static_cast(ut_align_down(ptr, srv_page_size))); } /** Gets the byte offset within a page frame. @@ -186,7 +186,7 @@ inline ulint page_offset(const void* ptr) { - return(ut_align_offset(ptr, UNIV_PAGE_SIZE)); + return(ut_align_offset(ptr, srv_page_size)); } /** Determine whether an index page is not in ROW_FORMAT=REDUNDANT. @@ -286,7 +286,7 @@ page_rec_is_user_rec_low(ulint offset) compile_time_assert(PAGE_NEW_SUPREMUM < PAGE_OLD_SUPREMUM_END); compile_time_assert(PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM_END); ut_ad(offset >= PAGE_NEW_INFIMUM); - ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START); + ut_ad(offset <= srv_page_size - PAGE_EMPTY_DIR_START); return(offset != PAGE_NEW_SUPREMUM && offset != PAGE_NEW_INFIMUM @@ -302,7 +302,7 @@ bool page_rec_is_supremum_low(ulint offset) { ut_ad(offset >= PAGE_NEW_INFIMUM); - ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START); + ut_ad(offset <= srv_page_size - PAGE_EMPTY_DIR_START); return(offset == PAGE_NEW_SUPREMUM || offset == PAGE_OLD_SUPREMUM); } @@ -314,7 +314,7 @@ bool page_rec_is_infimum_low(ulint offset) { ut_ad(offset >= PAGE_NEW_INFIMUM); - ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START); + ut_ad(offset <= srv_page_size - PAGE_EMPTY_DIR_START); return(offset == PAGE_NEW_INFIMUM || offset == PAGE_OLD_INFIMUM); } @@ -455,7 +455,7 @@ page_header_set_field( Returns the offset stored in the given header field. @return offset from the start of the page, or 0 */ UNIV_INLINE -ulint +uint16_t page_header_get_offs( /*=================*/ const page_t* page, /*!< in: page */ @@ -549,7 +549,7 @@ Gets the number of user records on page (the infimum and supremum records are not user records). @return number of user records */ UNIV_INLINE -ulint +uint16_t page_get_n_recs( /*============*/ const page_t* page); /*!< in: index page */ @@ -567,7 +567,7 @@ page_rec_get_n_recs_before( Gets the number of records in the heap. @return number of user records */ UNIV_INLINE -ulint +uint16_t page_dir_get_n_heap( /*================*/ const page_t* page); /*!< in: index page */ @@ -588,7 +588,7 @@ page_dir_set_n_heap( Gets the number of dir slots in directory. @return number of slots */ UNIV_INLINE -ulint +uint16_t page_dir_get_n_slots( /*=================*/ const page_t* page); /*!< in: index page */ @@ -614,7 +614,7 @@ page_dir_get_nth_slot( ulint n); /*!< in: position */ #else /* UNIV_DEBUG */ # define page_dir_get_nth_slot(page, n) \ - ((page) + (UNIV_PAGE_SIZE - PAGE_DIR \ + ((page) + (srv_page_size - PAGE_DIR \ - (n + 1) * PAGE_DIR_SLOT_SIZE)) #endif /* UNIV_DEBUG */ /**************************************************************//** @@ -868,7 +868,7 @@ Returns the sum of the sizes of the records in the record list excluding the infimum and supremum records. @return data in bytes */ UNIV_INLINE -ulint +uint16_t page_get_data_size( /*===============*/ const page_t* page); /*!< in: index page */ diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index 11d5e2d1854..d6fded4f178 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -188,19 +188,17 @@ page_header_set_field( Returns the offset stored in the given header field. @return offset from the start of the page, or 0 */ UNIV_INLINE -ulint +uint16_t page_header_get_offs( /*=================*/ const page_t* page, /*!< in: page */ ulint field) /*!< in: PAGE_FREE, ... */ { - ulint offs; - ut_ad((field == PAGE_FREE) || (field == PAGE_LAST_INSERT) || (field == PAGE_HEAP_TOP)); - offs = page_header_get_field(page, field); + uint16_t offs = page_header_get_field(page, field); ut_ad((field != PAGE_HEAP_TOP) || offs); @@ -400,7 +398,8 @@ page_get_middle_rec( /*================*/ page_t* page) /*!< in: page */ { - ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2; + ulint middle = (ulint(page_get_n_recs(page)) + + PAGE_HEAP_NO_USER_LOW) / 2; return(page_rec_get_nth(page, middle)); } @@ -441,7 +440,7 @@ Gets the number of user records on page (infimum and supremum records are not user records). @return number of user records */ UNIV_INLINE -ulint +uint16_t page_get_n_recs( /*============*/ const page_t* page) /*!< in: index page */ @@ -454,7 +453,7 @@ page_get_n_recs( Gets the number of dir slots in directory. @return number of slots */ UNIV_INLINE -ulint +uint16_t page_dir_get_n_slots( /*=================*/ const page_t* page) /*!< in: index page */ @@ -479,7 +478,7 @@ page_dir_set_n_slots( Gets the number of records in the heap. @return number of user records */ UNIV_INLINE -ulint +uint16_t page_dir_get_n_heap( /*================*/ const page_t* page) /*!< in: index page */ @@ -524,7 +523,7 @@ page_dir_get_nth_slot( ut_ad(page_dir_get_n_slots(page) > n); return((page_dir_slot_t*) - page + UNIV_PAGE_SIZE - PAGE_DIR + page + srv_page_size - PAGE_DIR - (n + 1) * PAGE_DIR_SLOT_SIZE); } #endif /* UNIV_DEBUG */ @@ -643,7 +642,7 @@ page_rec_get_next_low( offs = rec_get_next_offs(rec, comp); - if (offs >= UNIV_PAGE_SIZE) { + if (offs >= srv_page_size) { fprintf(stderr, "InnoDB: Next record offset is nonsensical %lu" " in record at offset %lu\n" @@ -832,9 +831,8 @@ page_rec_get_base_extra_size( /*=========================*/ const rec_t* rec) /*!< in: physical record */ { -#if REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES -# error "REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES" -#endif + compile_time_assert(REC_N_NEW_EXTRA_BYTES + 1 + == REC_N_OLD_EXTRA_BYTES); return(REC_N_NEW_EXTRA_BYTES + (ulint) !page_rec_is_comp(rec)); } @@ -845,21 +843,17 @@ Returns the sum of the sizes of the records in the record list, excluding the infimum and supremum records. @return data in bytes */ UNIV_INLINE -ulint +uint16_t page_get_data_size( /*===============*/ const page_t* page) /*!< in: index page */ { - ulint ret; - - ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP) - - (page_is_comp(page) - ? PAGE_NEW_SUPREMUM_END - : PAGE_OLD_SUPREMUM_END) - - page_header_get_field(page, PAGE_GARBAGE)); - - ut_ad(ret < UNIV_PAGE_SIZE); - + uint16_t ret = page_header_get_field(page, PAGE_HEAP_TOP) + - (page_is_comp(page) + ? PAGE_NEW_SUPREMUM_END + : PAGE_OLD_SUPREMUM_END) + - page_header_get_field(page, PAGE_GARBAGE); + ut_ad(ret < srv_page_size); return(ret); } @@ -907,13 +901,13 @@ page_get_free_space_of_empty( ulint comp) /*!< in: nonzero=compact page layout */ { if (comp) { - return((ulint)(UNIV_PAGE_SIZE + return((ulint)(srv_page_size - PAGE_NEW_SUPREMUM_END - PAGE_DIR - 2 * PAGE_DIR_SLOT_SIZE)); } - return((ulint)(UNIV_PAGE_SIZE + return((ulint)(srv_page_size - PAGE_OLD_SUPREMUM_END - PAGE_DIR - 2 * PAGE_DIR_SLOT_SIZE)); @@ -1051,7 +1045,7 @@ page_mem_free( page_zip_dir_delete(page_zip, rec, index, offsets, free); } else { page_header_set_field(page, page_zip, PAGE_N_RECS, - page_get_n_recs(page) - 1); + ulint(page_get_n_recs(page)) - 1); } } From ade0a0e9d57906e6a32c145c7201dbf216392f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 25 Mar 2019 15:55:00 +0200 Subject: [PATCH 2/3] Avoid sign mismatch in comparisons This is follow-up to commit 1bd98154791d77a44d2afc4bf6eb78f692fb7b5b. --- storage/innobase/btr/btr0sea.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index b494565b288..a4f0f9e5b88 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -2,7 +2,7 @@ Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -80,7 +80,7 @@ btr_search_sys_t* btr_search_sys; /** If the number of records on the page divided by this parameter would have been successfully accessed using a hash index, the index is then built on the page, assuming the global limit has been reached */ -#define BTR_SEARCH_PAGE_BUILD_LIMIT 16 +#define BTR_SEARCH_PAGE_BUILD_LIMIT 16U /** The global limit for consecutive potentially successful hash searches, before hash index building is started */ @@ -570,7 +570,7 @@ btr_search_update_block_hash_info( if ((!block->index) || (block->n_hash_helps - > 2 * page_get_n_recs(block->frame)) + > 2U * page_get_n_recs(block->frame)) || (block->n_fields != block->curr_n_fields) || (block->n_bytes != block->curr_n_bytes) || (block->left_side != block->curr_left_side)) { From 525e79b057ce1256aac9f8248b89d8d507ab22c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 25 Mar 2019 16:03:24 +0200 Subject: [PATCH 3/3] MDEV-19022: InnoDB fails to cleanup useless B-tree pages The test case for reproducing MDEV-14126 demonstrates that InnoDB can end up with an index tree where a non-leaf page has only one child page. The test case innodb.innodb_bug14676111 demonstrates that such pages are sometimes unavoidable, because InnoDB does not implement any sort of B-tree rotation. But, there is no reason to allow a root page with only one child page. btr_cur_node_ptr_delete(): Replaces btr_node_ptr_delete(). btr_page_get_father(): Declare globally. btr_discard_only_page_on_level(): Declare with ATTRIBUTE_COLD. It turns out that this function is not covered by the innodb.innodb_bug14676111 test case after all. btr_discard_page(): If the root page ends up having only one child page, shrink the tree by invoking btr_lift_page_up(). --- .../suite/innodb/r/innodb_bug14676111.result | 20 ++--- storage/innobase/btr/btr0btr.cc | 74 +++++-------------- storage/innobase/btr/btr0cur.cc | 23 +++++- storage/innobase/btr/btr0defragment.cc | 8 +- storage/innobase/include/btr0btr.h | 17 ++--- storage/innobase/include/btr0cur.h | 7 +- 6 files changed, 70 insertions(+), 79 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_bug14676111.result b/mysql-test/suite/innodb/r/innodb_bug14676111.result index d1e21c92d95..49d099263de 100644 --- a/mysql-test/suite/innodb/r/innodb_bug14676111.result +++ b/mysql-test/suite/innodb/r/innodb_bug14676111.result @@ -39,7 +39,7 @@ Table Op Msg_type Msg_text test.t1 analyze status OK select CLUST_INDEX_SIZE from information_schema.INNODB_SYS_TABLESTATS where NAME = 'test/t1'; CLUST_INDEX_SIZE -5 +4 set global innodb_limit_optimistic_insert_debug = 10000; connection con2; rollback; @@ -50,15 +50,6 @@ Table Op Msg_type Msg_text test.t1 analyze status OK select CLUST_INDEX_SIZE from information_schema.INNODB_SYS_TABLESTATS where NAME = 'test/t1'; CLUST_INDEX_SIZE -3 -begin; -insert into t1 values (2); -rollback; -analyze table t1; -Table Op Msg_type Msg_text -test.t1 analyze status OK -select CLUST_INDEX_SIZE from information_schema.INNODB_SYS_TABLESTATS where NAME = 'test/t1'; -CLUST_INDEX_SIZE 2 begin; insert into t1 values (2); @@ -69,5 +60,14 @@ test.t1 analyze status OK select CLUST_INDEX_SIZE from information_schema.INNODB_SYS_TABLESTATS where NAME = 'test/t1'; CLUST_INDEX_SIZE 1 +begin; +insert into t1 values (2); +rollback; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select CLUST_INDEX_SIZE from information_schema.INNODB_SYS_TABLESTATS where NAME = 'test/t1'; +CLUST_INDEX_SIZE +1 drop table t1; set global innodb_limit_optimistic_insert_debug = @old_innodb_limit_optimistic_insert_debug; diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 5b1e7e1b853..a40e39624e2 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1062,18 +1062,13 @@ btr_page_get_father_block( return(btr_page_get_father_node_ptr(offsets, heap, cursor, mtr)); } -/************************************************************//** -Seeks to the upper level node pointer to a page. -It is assumed that mtr holds an x-latch on the tree. */ -static -void -btr_page_get_father( -/*================*/ - dict_index_t* index, /*!< in: b-tree index */ - buf_block_t* block, /*!< in: child page in the index */ - mtr_t* mtr, /*!< in: mtr */ - btr_cur_t* cursor) /*!< out: cursor on node pointer record, - its page x-latched */ +/** Seek to the parent page of a B-tree page. +@param[in,out] index b-tree +@param[in] block child page +@param[in,out] mtr mini-transaction +@param[out] cursor cursor pointing to the x-latched parent page */ +void btr_page_get_father(dict_index_t* index, buf_block_t* block, mtr_t* mtr, + btr_cur_t* cursor) { mem_heap_t* heap; rec_t* rec @@ -3463,33 +3458,6 @@ btr_set_min_rec_mark( } } -/*************************************************************//** -Deletes on the upper level the node pointer to a page. */ -void -btr_node_ptr_delete( -/*================*/ - dict_index_t* index, /*!< in: index tree */ - buf_block_t* block, /*!< in: page whose node pointer is deleted */ - mtr_t* mtr) /*!< in: mtr */ -{ - btr_cur_t cursor; - ibool compressed; - dberr_t err; - - ut_ad(mtr_is_block_fix(mtr, block, MTR_MEMO_PAGE_X_FIX, index->table)); - - /* Delete node pointer on father page */ - btr_page_get_father(index, block, mtr, &cursor); - - compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, - BTR_CREATE_FLAG, false, mtr); - ut_a(err == DB_SUCCESS); - - if (!compressed) { - btr_cur_compress_if_useful(&cursor, FALSE, mtr); - } -} - /*************************************************************//** If page is the only on its level, this function moves its records to the father page, thus reducing the tree height. @@ -3939,7 +3907,7 @@ retry: lock_rec_free_all_from_discard_page(block); lock_mutex_exit(); } else { - btr_node_ptr_delete(index, block, mtr); + btr_cur_node_ptr_delete(&father_cursor, mtr); if (!dict_table_is_locking_disabled(index->table)) { lock_update_merge_left( merge_block, orig_pred, block); @@ -4217,8 +4185,9 @@ err_exit: /*************************************************************//** Discards a page that is the only page on its level. This will empty the whole B-tree, leaving just an empty root page. This function -should never be reached, because btr_compress(), which is invoked in +should almost never be reached, because btr_compress(), which is invoked in delete operations, calls btr_lift_page_up() to flatten the B-tree. */ +ATTRIBUTE_COLD static void btr_discard_only_page_on_level( @@ -4318,10 +4287,7 @@ btr_discard_page( buf_block_t* block; page_t* page; rec_t* node_ptr; -#ifdef UNIV_DEBUG btr_cur_t parent_cursor; - bool parent_is_different = false; -#endif block = btr_cur_get_block(cursor); index = btr_cur_get_index(cursor); @@ -4337,13 +4303,11 @@ btr_discard_page( MONITOR_INC(MONITOR_INDEX_DISCARD); -#ifdef UNIV_DEBUG if (dict_index_is_spatial(index)) { rtr_page_get_father(index, block, mtr, cursor, &parent_cursor); } else { btr_page_get_father(index, block, mtr, &parent_cursor); } -#endif /* Decide the page which will inherit the locks */ @@ -4351,7 +4315,7 @@ btr_discard_page( right_page_no = btr_page_get_next(buf_block_get_frame(block), mtr); const page_size_t page_size(dict_table_page_size(index->table)); - + ut_d(bool parent_is_different = false); if (left_page_no != FIL_NULL) { merge_block = btr_block_get( page_id_t(space, left_page_no), page_size, @@ -4407,15 +4371,9 @@ btr_discard_page( } if (dict_index_is_spatial(index)) { - btr_cur_t father_cursor; - - /* Since rtr_node_ptr_delete doesn't contain get father - node ptr, so, we need to get father node ptr first and then - delete it. */ - rtr_page_get_father(index, block, mtr, cursor, &father_cursor); - rtr_node_ptr_delete(index, &father_cursor, block, mtr); + rtr_node_ptr_delete(index, &parent_cursor, block, mtr); } else { - btr_node_ptr_delete(index, block, mtr); + btr_cur_node_ptr_delete(&parent_cursor, mtr); } /* Remove the page from the level list */ @@ -4453,6 +4411,12 @@ btr_discard_page( we cannot use btr_check_node_ptr() */ ut_ad(parent_is_different || btr_check_node_ptr(index, merge_block, mtr)); + + if (btr_cur_get_block(&parent_cursor)->page.id.page_no() == index->page + && !page_has_siblings(btr_cur_get_page(&parent_cursor)) + && page_get_n_recs(btr_cur_get_page(&parent_cursor)) == 1) { + btr_lift_page_up(index, merge_block, mtr); + } } #ifdef UNIV_BTR_PRINT diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 37372af4b44..8f26ac9e0e5 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -5358,8 +5358,10 @@ btr_cur_pessimistic_delete( on the page */ ulint level = btr_page_get_level(page, mtr); - btr_node_ptr_delete(index, block, mtr); - + btr_cur_t cursor; + btr_page_get_father(index, block, mtr, &cursor); + btr_cur_node_ptr_delete(&cursor, mtr); + // FIXME: reuse the node_ptr from above dtuple_t* node_ptr = dict_index_build_node_ptr( index, next_rec, block->page.id.page_no(), heap, level); @@ -5428,6 +5430,23 @@ return_after_reservations: return(ret); } +/** Delete the node pointer in a parent page. +@param[in,out] parent cursor pointing to parent record +@param[in,out] mtr mini-transaction */ +void btr_cur_node_ptr_delete(btr_cur_t* parent, mtr_t* mtr) +{ + ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(parent), + MTR_MEMO_PAGE_X_FIX)); + dberr_t err; + ibool compressed = btr_cur_pessimistic_delete(&err, TRUE, parent, + BTR_CREATE_FLAG, false, + mtr); + ut_a(err == DB_SUCCESS); + if (!compressed) { + btr_cur_compress_if_useful(parent, FALSE, mtr); + } +} + /*******************************************************************//** Adds path information to the cursor for the current page, for which the binary search has been performed. */ diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index 077cf8a1c73..2bb2e84ee05 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -484,6 +484,7 @@ btr_defragment_merge_pages( ULINT_UNDEFINED); } } + btr_cur_t parent; if (n_recs_to_move == n_recs) { /* The whole page is merged with the previous page, free it. */ @@ -491,7 +492,8 @@ btr_defragment_merge_pages( from_block); btr_search_drop_page_hash_index(from_block); btr_level_list_remove(space, page_size, (page_t*)from_page, index, mtr); - btr_node_ptr_delete(index, from_block, mtr); + btr_page_get_father(index, from_block, mtr, &parent); + btr_cur_node_ptr_delete(&parent, mtr); /* btr_blob_dbg_remove(from_page, index, "btr_defragment_n_pages"); */ btr_page_free(index, from_block, mtr); @@ -509,7 +511,9 @@ btr_defragment_merge_pages( lock_update_split_and_merge(to_block, orig_pred, from_block); - btr_node_ptr_delete(index, from_block, mtr); + // FIXME: reuse the node_ptr! + btr_page_get_father(index, from_block, mtr, &parent); + btr_cur_node_ptr_delete(&parent, mtr); rec = page_rec_get_next( page_get_infimum_rec(from_page)); node_ptr = dict_index_build_node_ptr( diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index 967f738f4e3..23e445e2d5f 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -2,7 +2,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2014, 2018, MariaDB Corporation. +Copyright (c) 2014, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -545,14 +545,13 @@ btr_set_min_rec_mark( rec_t* rec, /*!< in/out: record */ mtr_t* mtr) /*!< in: mtr */ MY_ATTRIBUTE((nonnull)); -/*************************************************************//** -Deletes on the upper level the node pointer to a page. */ -void -btr_node_ptr_delete( -/*================*/ - dict_index_t* index, /*!< in: index tree */ - buf_block_t* block, /*!< in: page whose node pointer is deleted */ - mtr_t* mtr) /*!< in: mtr */ +/** Seek to the parent page of a B-tree page. +@param[in,out] index b-tree +@param[in] block child page +@param[in,out] mtr mini-transaction +@param[out] cursor cursor pointing to the x-latched parent page */ +void btr_page_get_father(dict_index_t* index, buf_block_t* block, mtr_t* mtr, + btr_cur_t* cursor) MY_ATTRIBUTE((nonnull)); #ifdef UNIV_DEBUG /************************************************************//** diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 0f027536525..769d9e82542 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -529,6 +529,11 @@ btr_cur_pessimistic_delete( bool rollback,/*!< in: performing rollback? */ mtr_t* mtr) /*!< in: mtr */ MY_ATTRIBUTE((nonnull)); +/** Delete the node pointer in a parent page. +@param[in,out] parent cursor pointing to parent record +@param[in,out] mtr mini-transaction */ +void btr_cur_node_ptr_delete(btr_cur_t* parent, mtr_t* mtr) + MY_ATTRIBUTE((nonnull)); /***********************************************************//** Parses a redo log record of updating a record in-place. @return end of log record or NULL */