diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-11-17 09:19:32 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-11-17 09:19:32 +0200 |
commit | d5332086d7aa1eaef9da5850d38dd1489fad7032 (patch) | |
tree | bd65941f8399f6f215d3bfb930d2fc2a44416cea /storage/innobase/include | |
parent | 0e6f2757d11502d74d21e4a75fa5247fc3334024 (diff) | |
parent | 9aea7d83c8d006519bdf1f3269136b3756ed7548 (diff) | |
download | mariadb-git-d5332086d7aa1eaef9da5850d38dd1489fad7032.tar.gz |
Merge 10.6 into 10.7
Diffstat (limited to 'storage/innobase/include')
-rw-r--r-- | storage/innobase/include/btr0btr.h | 136 | ||||
-rw-r--r-- | storage/innobase/include/btr0btr.inl | 40 | ||||
-rw-r--r-- | storage/innobase/include/btr0cur.h | 74 | ||||
-rw-r--r-- | storage/innobase/include/btr0cur.inl | 12 | ||||
-rw-r--r-- | storage/innobase/include/btr0pcur.h | 249 | ||||
-rw-r--r-- | storage/innobase/include/btr0pcur.inl | 107 | ||||
-rw-r--r-- | storage/innobase/include/btr0types.h | 96 | ||||
-rw-r--r-- | storage/innobase/include/dyn0buf.h | 56 | ||||
-rw-r--r-- | storage/innobase/include/gis0rtree.h | 22 | ||||
-rw-r--r-- | storage/innobase/include/ibuf0ibuf.h | 38 | ||||
-rw-r--r-- | storage/innobase/include/ibuf0ibuf.inl | 31 | ||||
-rw-r--r-- | storage/innobase/include/ibuf0types.h | 31 | ||||
-rw-r--r-- | storage/innobase/include/log0log.h | 7 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.h | 264 | ||||
-rw-r--r-- | storage/innobase/include/mtr0mtr.inl | 185 | ||||
-rw-r--r-- | storage/innobase/include/page0cur.h | 22 | ||||
-rw-r--r-- | storage/innobase/include/page0cur.inl | 19 | ||||
-rw-r--r-- | storage/innobase/include/row0ins.h | 8 | ||||
-rw-r--r-- | storage/innobase/include/row0row.h | 13 |
19 files changed, 502 insertions, 908 deletions
diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index a4bf42adcfb..a2aa46b62da 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -55,103 +55,8 @@ not acceptable for it to lead to mysterious memory corruption, but it is acceptable for the program to die with a clear assert failure. */ #define BTR_MAX_LEVELS 100 -/** Latching modes for btr_cur_search_to_nth_level(). */ -enum btr_latch_mode { - /** Search a record on a leaf page and S-latch it. */ - BTR_SEARCH_LEAF = RW_S_LATCH, - /** (Prepare to) modify a record on a leaf page and X-latch it. */ - BTR_MODIFY_LEAF = RW_X_LATCH, - /** Obtain no latches. */ - BTR_NO_LATCHES = RW_NO_LATCH, - /** Search the previous record. */ - BTR_SEARCH_PREV = 4 | BTR_SEARCH_LEAF, - /** Modify the previous record. */ - BTR_MODIFY_PREV = 4 | BTR_MODIFY_LEAF, - /** Start searching the entire B-tree. */ - BTR_SEARCH_TREE = 8 | BTR_SEARCH_LEAF, - /** Start modifying1 the entire B-tree. */ - BTR_MODIFY_TREE = 8 | BTR_MODIFY_LEAF, - /** Continue searching the entire B-tree. */ - BTR_CONT_SEARCH_TREE = 4 | BTR_SEARCH_TREE, - /** Continue modifying the entire B-tree. */ - BTR_CONT_MODIFY_TREE = 4 | BTR_MODIFY_TREE, - - /* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually - exclusive. */ - /** The search tuple will be inserted to the secondary index - at the searched position. When the leaf page is not in the - buffer pool, try to use the change buffer. */ - BTR_INSERT = 64, - - /** Try to delete mark a secondary index leaf page record at - the searched position using the change buffer when the page is - not in the buffer pool. */ - BTR_DELETE_MARK = 128, - - /** Try to purge the record using the change buffer when the - secondary index leaf page is not in the buffer pool. */ - BTR_DELETE = BTR_INSERT | BTR_DELETE_MARK, - - /** The caller is already holding dict_index_t::lock S-latch. */ - BTR_ALREADY_S_LATCHED = 256, - /** Search and S-latch a leaf page, assuming that the - dict_index_t::lock S-latch is being held. */ - BTR_SEARCH_LEAF_ALREADY_S_LATCHED = BTR_SEARCH_LEAF - | BTR_ALREADY_S_LATCHED, - /** Search the entire index tree, assuming that the - dict_index_t::lock S-latch is being held. */ - BTR_SEARCH_TREE_ALREADY_S_LATCHED = BTR_SEARCH_TREE - | BTR_ALREADY_S_LATCHED, - /** Search and X-latch a leaf page, assuming that the - dict_index_t::lock S-latch is being held. */ - BTR_MODIFY_LEAF_ALREADY_S_LATCHED = BTR_MODIFY_LEAF - | BTR_ALREADY_S_LATCHED, - - /** Attempt to delete-mark a secondary index record. */ - BTR_DELETE_MARK_LEAF = BTR_MODIFY_LEAF | BTR_DELETE_MARK, - /** Attempt to delete-mark a secondary index record - while holding the dict_index_t::lock S-latch. */ - BTR_DELETE_MARK_LEAF_ALREADY_S_LATCHED = BTR_DELETE_MARK_LEAF - | BTR_ALREADY_S_LATCHED, - /** Attempt to purge a secondary index record. */ - BTR_PURGE_LEAF = BTR_MODIFY_LEAF | BTR_DELETE, - /** Attempt to purge a secondary index record - while holding the dict_index_t::lock S-latch. */ - BTR_PURGE_LEAF_ALREADY_S_LATCHED = BTR_PURGE_LEAF - | BTR_ALREADY_S_LATCHED, - - /** In the case of BTR_MODIFY_TREE, the caller specifies - the intention to delete record only. It is used to optimize - block->lock range.*/ - BTR_LATCH_FOR_DELETE = 512, - - /** Attempt to purge a secondary index record in the tree. */ - BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE -}; - -/** This flag ORed to BTR_INSERT says that we can ignore possible -UNIQUE definition on secondary indexes when we decide if we can use -the insert buffer to speed up inserts */ -#define BTR_IGNORE_SEC_UNIQUE 2048U - -/** In the case of BTR_MODIFY_TREE, the caller specifies the intention -to insert record only. It is used to optimize block->lock range.*/ -#define BTR_LATCH_FOR_INSERT 4096U - -/** This flag is for undo insert of rtree. For rtree, we need this flag -to find proper rec to undo insert.*/ -#define BTR_RTREE_UNDO_INS 8192U - -/** In the case of BTR_MODIFY_LEAF, the caller intends to allocate or -free the pages of externally stored fields. */ -#define BTR_MODIFY_EXTERNAL 16384U - -/** Try to delete mark the record at the searched position when the -record is in spatial index */ -#define BTR_RTREE_DELETE_MARK 32768U - #define BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode) \ - ((latch_mode) & ulint(~(BTR_INSERT \ + btr_latch_mode((latch_mode) & ~(BTR_INSERT \ | BTR_DELETE_MARK \ | BTR_RTREE_UNDO_INS \ | BTR_RTREE_DELETE_MARK \ @@ -159,13 +64,11 @@ record is in spatial index */ | BTR_IGNORE_SEC_UNIQUE \ | BTR_ALREADY_S_LATCHED \ | BTR_LATCH_FOR_INSERT \ - | BTR_LATCH_FOR_DELETE \ - | BTR_MODIFY_EXTERNAL))) + | BTR_LATCH_FOR_DELETE)) -#define BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode) \ - ((latch_mode) & ulint(~(BTR_LATCH_FOR_INSERT \ - | BTR_LATCH_FOR_DELETE \ - | BTR_MODIFY_EXTERNAL))) +#define BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode) \ + btr_latch_mode((latch_mode) \ + & ~(BTR_LATCH_FOR_INSERT | BTR_LATCH_FOR_DELETE)) /**************************************************************//** Checks and adjusts the root node of a tree during IMPORT TABLESPACE. @@ -229,17 +132,6 @@ inline uint32_t btr_page_get_prev(const page_t* page) } /**************************************************************//** -Releases the latch on a leaf page and bufferunfixes it. */ -UNIV_INLINE -void -btr_leaf_page_release( -/*==================*/ - buf_block_t* block, /*!< in: buffer block */ - ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or - BTR_MODIFY_LEAF */ - mtr_t* mtr) /*!< in: mtr */ - MY_ATTRIBUTE((nonnull)); -/**************************************************************//** Gets the child node file address in a node pointer. NOTE: the offsets array must contain all offsets for the record since we read the last field according to offsets and assume that it contains @@ -359,15 +251,12 @@ be done either within the same mini-transaction, or by invoking ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages, IBUF_BITMAP_FREE is unaffected by reorganization. +@param cursor page cursor +@param mtr mini-transaction @return error code @retval DB_FAIL if reorganizing a ROW_FORMAT=COMPRESSED page failed */ -dberr_t -btr_page_reorganize( -/*================*/ - page_cur_t* cursor, /*!< in/out: page cursor */ - dict_index_t* index, /*!< in: the index tree of the page */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); +dberr_t btr_page_reorganize(page_cur_t *cursor, mtr_t *mtr) + MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Decide if the page should be split at the convergence point of inserts converging to the left. @param[in] cursor insert position @@ -445,13 +334,10 @@ inline void btr_set_min_rec_mark(rec_t *rec, const buf_block_t &block, } /** 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 +@param[in,out] cursor cursor pointing to the x-latched parent page @return whether the cursor was successfully positioned */ -bool btr_page_get_father(dict_index_t* index, buf_block_t* block, mtr_t* mtr, - btr_cur_t* cursor) +bool btr_page_get_father(mtr_t* mtr, btr_cur_t* cursor) MY_ATTRIBUTE((nonnull,warn_unused_result)); #ifdef UNIV_DEBUG /************************************************************//** diff --git a/storage/innobase/include/btr0btr.inl b/storage/innobase/include/btr0btr.inl index f92622cc400..9a9e39b6b4c 100644 --- a/storage/innobase/include/btr0btr.inl +++ b/storage/innobase/include/btr0btr.inl @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2021, MariaDB Corporation. +Copyright (c) 2015, 2022, 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 @@ -24,10 +24,7 @@ The B-tree Created 6/2/1994 Heikki Tuuri *******************************************************/ -#include "mach0data.h" -#include "mtr0mtr.h" #include "mtr0log.h" -#include "page0zip.h" /**************************************************************//** Gets the index id field of a page. @@ -112,38 +109,3 @@ btr_node_ptr_get_child_page_no( return(page_no); } - -/**************************************************************//** -Releases the latches on a leaf page and bufferunfixes it. */ -UNIV_INLINE -void -btr_leaf_page_release( -/*==================*/ - buf_block_t* block, /*!< in: buffer block */ - ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or - BTR_MODIFY_LEAF */ - mtr_t* mtr) /*!< in: mtr */ -{ - ut_ad(latch_mode == BTR_SEARCH_LEAF - || latch_mode == BTR_MODIFY_LEAF - || latch_mode == BTR_NO_LATCHES); - - ut_ad(!mtr->memo_contains_flagged(block, MTR_MEMO_MODIFY)); - - mtr_memo_type_t mode; - switch (latch_mode) { - case BTR_SEARCH_LEAF: - mode = MTR_MEMO_PAGE_S_FIX; - break; - case BTR_MODIFY_LEAF: - mode = MTR_MEMO_PAGE_X_FIX; - break; - case BTR_NO_LATCHES: - mode = MTR_MEMO_BUF_FIX; - break; - default: - ut_a(0); - } - - mtr->memo_release(block, mode); -} diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 6626b2e948a..aa890be9936 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -96,7 +96,7 @@ btr_cur_get_page( Returns the index of a cursor. @param cursor b-tree cursor @return index */ -#define btr_cur_get_index(cursor) ((cursor)->index) +#define btr_cur_get_index(cursor) ((cursor)->index()) /*********************************************************//** Positions a tree cursor at a given record. */ UNIV_INLINE @@ -137,7 +137,7 @@ bool btr_cur_optimistic_latch_leaves( buf_block_t* block, ib_uint64_t modify_clock, - ulint* latch_mode, + btr_latch_mode* latch_mode, btr_cur_t* cursor, mtr_t* mtr); @@ -148,7 +148,6 @@ to node pointer page number fields on the upper levels of the tree! Note that if mode is PAGE_CUR_LE, which is used in inserts, then cursor->up_match and cursor->low_match both will have sensible values. If mode is PAGE_CUR_GE, then up_match will a have a sensible value. -@param index index @param level the tree level of search @param tuple data tuple; NOTE: n_fields_cmp in tuple must be set so that it cannot get compared to the node ptr page number field! @@ -166,27 +165,13 @@ If mode is PAGE_CUR_GE, then up_match will a have a sensible value. @param mtr mini-transaction @param autoinc PAGE_ROOT_AUTO_INC to be written (0 if none) @return DB_SUCCESS on success or error code otherwise */ -dberr_t btr_cur_search_to_nth_level(dict_index_t *index, ulint level, +dberr_t btr_cur_search_to_nth_level(ulint level, const dtuple_t *tuple, - page_cur_mode_t mode, ulint latch_mode, + page_cur_mode_t mode, + btr_latch_mode latch_mode, btr_cur_t *cursor, mtr_t *mtr, ib_uint64_t autoinc= 0); -/*****************************************************************//** -Opens a cursor at either end of an index. -@return DB_SUCCESS or error code */ -dberr_t -btr_cur_open_at_index_side( - bool from_left, /*!< in: true if open to the low end, - false if to the high end */ - dict_index_t* index, /*!< in: index */ - ulint latch_mode, /*!< in: latch mode */ - btr_cur_t* cursor, /*!< in/out: cursor */ - ulint level, /*!< in: level to search for - (0=leaf) */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); - /**********************************************************************//** Positions a cursor at a randomly chosen position within a B-tree. @return true if the index is available and we have put the cursor, false @@ -194,7 +179,7 @@ if the index is unavailable */ bool btr_cur_open_at_rnd_pos( dict_index_t* index, /*!< in: index */ - ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ + btr_latch_mode latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ btr_cur_t* cursor, /*!< in/out: B-tree cursor */ mtr_t* mtr) /*!< in: mtr */ MY_ATTRIBUTE((nonnull,warn_unused_result)); @@ -281,7 +266,6 @@ btr_cur_update_alloc_zip_func( /*==========================*/ page_zip_des_t* page_zip,/*!< in/out: compressed page */ page_cur_t* cursor, /*!< in/out: B-tree page cursor */ - dict_index_t* index, /*!< in: the index corresponding to cursor */ #ifdef UNIV_DEBUG rec_offs* offsets,/*!< in/out: offsets of the cursor record */ #endif /* UNIV_DEBUG */ @@ -291,11 +275,11 @@ btr_cur_update_alloc_zip_func( mtr_t* mtr) /*!< in/out: mini-transaction */ MY_ATTRIBUTE((nonnull, warn_unused_result)); #ifdef UNIV_DEBUG -# define btr_cur_update_alloc_zip(page_zip,cursor,index,offsets,len,cr,mtr) \ - btr_cur_update_alloc_zip_func(page_zip,cursor,index,offsets,len,cr,mtr) +# define btr_cur_update_alloc_zip(page_zip,cursor,offsets,len,cr,mtr) \ + btr_cur_update_alloc_zip_func(page_zip,cursor,offsets,len,cr,mtr) #else /* UNIV_DEBUG */ -# define btr_cur_update_alloc_zip(page_zip,cursor,index,offsets,len,cr,mtr) \ - btr_cur_update_alloc_zip_func(page_zip,cursor,index,len,cr,mtr) +# define btr_cur_update_alloc_zip(page_zip,cursor,offsets,len,cr,mtr) \ + btr_cur_update_alloc_zip_func(page_zip,cursor,len,cr,mtr) #endif /* UNIV_DEBUG */ /** Apply an update vector to a record. No field size changes are allowed. @@ -689,7 +673,7 @@ btr_rec_copy_externally_stored_field( void btr_cur_latch_leaves( buf_block_t* block, - ulint latch_mode, + btr_latch_mode latch_mode, btr_cur_t* cursor, mtr_t* mtr, btr_latch_leaves_t* latch_leaves = nullptr); @@ -752,7 +736,6 @@ enum btr_cur_method { /** The tree cursor: the definition appears here only for the compiler to know struct size! */ struct btr_cur_t { - dict_index_t* index; /*!< index where positioned */ page_cur_t page_cur; /*!< page cursor */ purge_node_t* purge_node; /*!< purge node, for BTR_DELETE */ buf_block_t* left_block; /*!< this field is used to store @@ -817,28 +800,19 @@ struct btr_cur_t { information of the path through the tree */ rtr_info_t* rtr_info; /*!< rtree search info */ - btr_cur_t():thr(NULL), rtr_info(NULL) {} - /* default values */ - /** Zero-initialize all fields */ - void init() - { - index = NULL; - memset(&page_cur, 0, sizeof page_cur); - purge_node = NULL; - left_block = NULL; - thr = NULL; - flag = btr_cur_method(0); - tree_height = 0; - up_match = 0; - up_bytes = 0; - low_match = 0; - low_bytes = 0; - n_fields = 0; - n_bytes = 0; - fold = 0; - path_arr = NULL; - rtr_info = NULL; - } + btr_cur_t() { memset((void*) this, 0, sizeof *this); } + + dict_index_t *index() const { return page_cur.index; } + buf_block_t *block() const { return page_cur.block; } + + /** Open the cursor on the first or last record. + @param first true=first record, false=last record + @param index B-tree + @param latch_mode which latches to acquire + @param mtr mini-transaction + @return error code */ + dberr_t open_leaf(bool first, dict_index_t *index, btr_latch_mode latch_mode, + mtr_t *mtr); }; /** Modify the delete-mark flag of a record. diff --git a/storage/innobase/include/btr0cur.inl b/storage/innobase/include/btr0cur.inl index 76a2d3be49c..955cf34288e 100644 --- a/storage/innobase/include/btr0cur.inl +++ b/storage/innobase/include/btr0cur.inl @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2021, MariaDB Corporation. +Copyright (c) 2018, 2022, 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 @@ -72,7 +72,7 @@ btr_cur_position( btr_cur_t* cursor) /*!< out: cursor */ { page_cur_position(rec, block, btr_cur_get_page_cur(cursor)); - cursor->index = index; + cursor->page_cur.index = index; } /*********************************************************************//** @@ -98,14 +98,14 @@ btr_cur_compress_recommendation( if (!page_has_siblings(page) || page_get_data_size(page) - < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)) { + < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index())) { /* The page fillfactor has dropped below a predefined minimum value OR the level in the B-tree contains just one page: we recommend compression if this is not the root page. */ - return cursor->index->page + return cursor->index()->page != btr_cur_get_block(cursor)->page.id().page_no(); } @@ -133,14 +133,14 @@ btr_cur_can_delete_without_compress( if (!page_has_siblings(page) || page_get_n_recs(page) < 2 || page_get_data_size(page) - rec_size - < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index)) { + < BTR_CUR_PAGE_COMPRESS_LIMIT(cursor->index())) { /* The page fillfactor will drop below a predefined minimum value, OR the level in the B-tree contains just one page, OR the page will become empty: we recommend compression if this is not the root page. */ - return cursor->index->page + return cursor->index()->page == btr_cur_get_block(cursor)->page.id().page_no(); } diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index 5103484da29..cd8eacdc212 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -46,13 +46,6 @@ of a scroll cursor easier */ }; /**************************************************************//** -Allocates memory for a persistent cursor object and initializes the cursor. -@return own: persistent cursor */ -btr_pcur_t* -btr_pcur_create_for_mysql(void); -/*============================*/ - -/**************************************************************//** Resets a persistent cursor object, freeing ::old_rec_buf if it is allocated and resetting the other members to their initial values. */ void @@ -61,12 +54,6 @@ btr_pcur_reset( btr_pcur_t* cursor);/*!< in, out: persistent cursor */ /**************************************************************//** -Frees the memory for a persistent cursor object. */ -void -btr_pcur_free_for_mysql( -/*====================*/ - btr_pcur_t* cursor); /*!< in, own: persistent cursor */ -/**************************************************************//** Copies the stored position of a pcur to another pcur. */ void btr_pcur_copy_stored_position( @@ -83,21 +70,11 @@ btr_pcur_init( /*==========*/ btr_pcur_t* pcur); /*!< in: persistent cursor */ -/** Free old_rec_buf. -@param[in] pcur Persistent cursor holding old_rec to be freed. */ -UNIV_INLINE -void -btr_pcur_free( - btr_pcur_t* pcur); - /**************************************************************//** Initializes and opens a persistent cursor to an index tree. */ inline dberr_t -btr_pcur_open_low( -/*==============*/ - dict_index_t* index, /*!< in: index */ - ulint level, /*!< in: level in the btree */ +btr_pcur_open( const dtuple_t* tuple, /*!< in: tuple on which search done */ page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...; NOTE that if the search is made using a unique @@ -105,17 +82,14 @@ btr_pcur_open_low( PAGE_CUR_LE, not PAGE_CUR_GE, as the latter may end up on the previous page from the record! */ - ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ + btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written (0 if none) */ mtr_t* mtr) /*!< in: mtr */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -#define btr_pcur_open(i,t,md,l,c,m) \ - btr_pcur_open_low(i,0,t,md,l,c,0,m) /** Opens an persistent cursor to an index tree without initializing the cursor. -@param index index @param tuple tuple on which search done @param mode PAGE_CUR_L, ...; NOTE that if the search is made using a unique prefix of a record, mode should be PAGE_CUR_LE, not @@ -126,26 +100,11 @@ cursor. @param mtr mini-transaction @return DB_SUCCESS on success or error code otherwise. */ inline -dberr_t btr_pcur_open_with_no_init(dict_index_t *index, const dtuple_t *tuple, - page_cur_mode_t mode, ulint latch_mode, +dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple, + page_cur_mode_t mode, + btr_latch_mode latch_mode, btr_pcur_t *cursor, mtr_t *mtr); -/*****************************************************************//** -Opens a persistent cursor at either end of an index. */ -UNIV_INLINE -dberr_t -btr_pcur_open_at_index_side( -/*========================*/ - bool from_left, /*!< in: true if open to the low end, - false if to the high end */ - dict_index_t* index, /*!< in: index */ - ulint latch_mode, /*!< in: latch mode */ - btr_pcur_t* pcur, /*!< in/out: cursor */ - bool init_pcur, /*!< in: whether to initialize pcur */ - ulint level, /*!< in: level to search for - (0=leaf) */ - mtr_t* mtr) /*!< in/out: mini-transaction */ - MY_ATTRIBUTE((nonnull,warn_unused_result)); /**************************************************************//** Gets the up_match value for a pcur after a search. @return number of matched fields at the cursor or to the right if @@ -356,102 +315,103 @@ enum pcur_pos_t { /* The persistent B-tree cursor structure. This is used mainly for SQL selects, updates, and deletes. */ -struct btr_pcur_t{ - /** Return value of restore_position() */ - enum restore_status { - /** cursor position on user rec and points on the record with - the same field values as in the stored record */ - SAME_ALL, - /** cursor position is on user rec and points on the record with - the same unique field values as in the stored record */ - SAME_UNIQ, - /** cursor position is not on user rec or points on the record - with not the same uniq field values as in the stored record */ - NOT_SAME, - /** the index tree is corrupted */ - CORRUPTED - }; - /** a B-tree cursor */ - btr_cur_t btr_cur; - /** see TODO note below! - BTR_SEARCH_LEAF, BTR_MODIFY_LEAF, BTR_MODIFY_TREE or BTR_NO_LATCHES, - depending on the latching state of the page and tree where the cursor - is positioned; BTR_NO_LATCHES means that the cursor is not currently - positioned: - we say then that the cursor is detached; it can be restored to - attached if the old position was stored in old_rec */ - ulint latch_mode; - /** true if old_rec is stored */ - bool old_stored; - /** if cursor position is stored, contains an initial segment of the - latest record cursor was positioned either on, before or after */ - rec_t* old_rec; - /** btr_cur.index->n_core_fields when old_rec was copied */ - uint16 old_n_core_fields; - /** number of fields in old_rec */ - uint16 old_n_fields; - /** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on - whether cursor was on, before, or after the old_rec record */ - enum btr_pcur_pos_t rel_pos; - /** buffer block when the position was stored */ - buf::Block_hint block_when_stored; - /** the modify clock value of the buffer block when the cursor position - was stored */ - ib_uint64_t modify_clock; - /** btr_pcur_store_position() and btr_pcur_restore_position() state. */ - enum pcur_pos_t pos_state; - /** PAGE_CUR_G, ... */ - page_cur_mode_t search_mode; - /** the transaction, if we know it; otherwise this field is not defined; - can ONLY BE USED in error prints in fatal assertion failures! */ - trx_t* trx_if_known; - /*-----------------------------*/ - /* NOTE that the following fields may possess dynamically allocated - memory which should be freed if not needed anymore! */ - - /** NULL, or a dynamically allocated buffer for old_rec */ - byte* old_rec_buf; - /** old_rec_buf size if old_rec_buf is not NULL */ - ulint buf_size; - - btr_pcur_t() : - btr_cur(), latch_mode(RW_NO_LATCH), - old_stored(false), old_rec(NULL), - old_n_fields(0), rel_pos(btr_pcur_pos_t(0)), - block_when_stored(), - modify_clock(0), pos_state(BTR_PCUR_NOT_POSITIONED), - search_mode(PAGE_CUR_UNSUPP), trx_if_known(NULL), - old_rec_buf(NULL), buf_size(0) - { - btr_cur.init(); - } - - /** Return the index of this persistent cursor */ - dict_index_t* index() const { return(btr_cur.index); } - MY_ATTRIBUTE((nonnull, warn_unused_result)) - /** Restores the stored position of a persistent cursor bufferfixing - the page and obtaining the specified latches. If the cursor position - was saved when the - (1) cursor was positioned on a user record: this function restores the - position to the last record LESS OR EQUAL to the stored record; - (2) cursor was positioned on a page infimum record: restores the - position to the last record LESS than the user record which was the - successor of the page infimum; - (3) cursor was positioned on the page supremum: restores to the first - record GREATER than the user record which was the predecessor of the - supremum. - (4) cursor was positioned before the first or after the last in an - empty tree: restores to before first or after the last in the tree. - @param restore_latch_mode BTR_SEARCH_LEAF, ... - @param mtr mtr - @retval SAME_ALL cursor position on user rec and points on - the record with the same field values as in the stored record, - @retval SAME_UNIQ cursor position is on user rec and points on the - record with the same unique field values as in the stored record, - @retval NOT_SAME cursor position is not on user rec or points on - the record with not the same uniq field values as in the stored - @retval CORRUPTED if the index is corrupted */ - restore_status restore_position(ulint latch_mode, mtr_t *mtr); +struct btr_pcur_t +{ + /** Return value of restore_position() */ + enum restore_status { + /** cursor position on user rec and points on the record with + the same field values as in the stored record */ + SAME_ALL, + /** cursor position is on user rec and points on the record with + the same unique field values as in the stored record */ + SAME_UNIQ, + /** cursor position is not on user rec or points on the record + with not the same uniq field values as in the stored record */ + NOT_SAME, + /** the index tree is corrupted */ + CORRUPTED + }; + /** a B-tree cursor */ + btr_cur_t btr_cur; + /** @see BTR_PCUR_WAS_POSITIONED + BTR_SEARCH_LEAF, BTR_MODIFY_LEAF, BTR_MODIFY_TREE or BTR_NO_LATCHES, + depending on the latching state of the page and tree where the cursor + is positioned; BTR_NO_LATCHES means that the cursor is not currently + positioned: + we say then that the cursor is detached; it can be restored to + attached if the old position was stored in old_rec */ + btr_latch_mode latch_mode= BTR_NO_LATCHES; + /** if cursor position is stored, contains an initial segment of the + latest record cursor was positioned either on, before or after */ + rec_t *old_rec= nullptr; + /** btr_cur.index()->n_core_fields when old_rec was copied */ + uint16 old_n_core_fields= 0; + /** number of fields in old_rec */ + uint16 old_n_fields= 0; + /** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on + whether cursor was on, before, or after the old_rec record */ + btr_pcur_pos_t rel_pos= btr_pcur_pos_t(0); + /** buffer block when the position was stored */ + buf::Block_hint block_when_stored; + /** the modify clock value of the buffer block when the cursor position + was stored */ + ib_uint64_t modify_clock= 0; + /** btr_pcur_store_position() and btr_pcur_restore_position() state. */ + enum pcur_pos_t pos_state= BTR_PCUR_NOT_POSITIONED; + page_cur_mode_t search_mode= PAGE_CUR_UNSUPP; + /** the transaction, if we know it; otherwise this field is not defined; + can ONLY BE USED in error prints in fatal assertion failures! */ + trx_t *trx_if_known= nullptr; + /** a dynamically allocated buffer for old_rec */ + byte *old_rec_buf= nullptr; + /** old_rec_buf size if old_rec_buf is not NULL */ + ulint buf_size= 0; + + /** Return the index of this persistent cursor */ + dict_index_t *index() const { return(btr_cur.index()); } + MY_ATTRIBUTE((nonnull, warn_unused_result)) + /** Restores the stored position of a persistent cursor bufferfixing + the page and obtaining the specified latches. If the cursor position + was saved when the + (1) cursor was positioned on a user record: this function restores the + position to the last record LESS OR EQUAL to the stored record; + (2) cursor was positioned on a page infimum record: restores the + position to the last record LESS than the user record which was the + successor of the page infimum; + (3) cursor was positioned on the page supremum: restores to the first + record GREATER than the user record which was the predecessor of the + supremum. + (4) cursor was positioned before the first or after the last in an + empty tree: restores to before first or after the last in the tree. + @param restore_latch_mode BTR_SEARCH_LEAF, ... + @param mtr mtr + @retval SAME_ALL cursor position on user rec and points on + the record with the same field values as in the stored record, + @retval SAME_UNIQ cursor position is on user rec and points on the + record with the same unique field values as in the stored record, + @retval NOT_SAME cursor position is not on user rec or points on + the record with not the same uniq field values as in the stored + @retval CORRUPTED if the index is corrupted */ + restore_status restore_position(btr_latch_mode latch_mode, mtr_t *mtr); + + /** Open the cursor on the first or last record. + @param first true=first record, false=last record + @param index B-tree + @param latch_mode which latches to acquire + @param mtr mini-transaction + @return error code */ + dberr_t open_leaf(bool first, dict_index_t *index, btr_latch_mode latch_mode, + mtr_t *mtr) + + { + this->latch_mode= BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode); + search_mode= first ? PAGE_CUR_G : PAGE_CUR_L; + pos_state= BTR_PCUR_IS_POSITIONED; + old_rec= nullptr; + + return btr_cur.open_leaf(first, index, + BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode), mtr); + } }; inline buf_block_t *btr_pcur_get_block(btr_pcur_t *cursor) @@ -479,10 +439,9 @@ MY_ATTRIBUTE((nonnull, warn_unused_result)) inline dberr_t btr_pcur_open_on_user_rec( - dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ... */ - ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or + btr_latch_mode latch_mode, /*!< in: BTR_SEARCH_LEAF or BTR_MODIFY_LEAF */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ @@ -490,7 +449,7 @@ btr_pcur_open_on_user_rec( { ut_ad(mode == PAGE_CUR_GE || mode == PAGE_CUR_G); ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF); - if (dberr_t err= btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr)) + if (dberr_t err= btr_pcur_open(tuple, mode, latch_mode, cursor, 0, mtr)) return err; if (!btr_pcur_is_after_last_on_page(cursor) || btr_pcur_is_after_last_in_tree(cursor)) diff --git a/storage/innobase/include/btr0pcur.inl b/storage/innobase/include/btr0pcur.inl index 82801f4426d..551f8f20fca 100644 --- a/storage/innobase/include/btr0pcur.inl +++ b/storage/innobase/include/btr0pcur.inl @@ -36,7 +36,6 @@ btr_pcur_get_rel_pos( { ut_ad(cursor); ut_ad(cursor->old_rec); - ut_ad(cursor->old_stored); ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED || cursor->pos_state == BTR_PCUR_IS_POSITIONED); @@ -163,7 +162,7 @@ btr_pcur_move_to_next_on_page( ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - cursor->old_stored = false; + cursor->old_rec = nullptr; return page_cur_move_to_next(btr_pcur_get_page_cur(cursor)); } @@ -177,7 +176,7 @@ btr_pcur_move_to_prev_on_page( { ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - cursor->old_stored = false; + cursor->old_rec = nullptr; return page_cur_move_to_prev(btr_pcur_get_page_cur(cursor)); } @@ -196,7 +195,7 @@ btr_pcur_move_to_next_user_rec( { ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - cursor->old_stored = false; + cursor->old_rec = nullptr; loop: if (btr_pcur_is_after_last_on_page(cursor)) { if (btr_pcur_is_after_last_in_tree(cursor) @@ -230,7 +229,7 @@ btr_pcur_move_to_next( ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); - cursor->old_stored= false; + cursor->old_rec= nullptr; if (btr_pcur_is_after_last_on_page(cursor)) return !btr_pcur_is_after_last_in_tree(cursor) && @@ -294,31 +293,17 @@ btr_pcur_init( /*==========*/ btr_pcur_t* pcur) /*!< in: persistent cursor */ { - pcur->old_stored = false; pcur->old_rec_buf = NULL; pcur->old_rec = NULL; pcur->btr_cur.rtr_info = NULL; } -/** Free old_rec_buf. -@param[in] pcur Persistent cursor holding old_rec to be freed. */ -UNIV_INLINE -void -btr_pcur_free( - btr_pcur_t* pcur) -{ - ut_free(pcur->old_rec_buf); -} - /**************************************************************//** Initializes and opens a persistent cursor to an index tree. */ inline dberr_t -btr_pcur_open_low( -/*==============*/ - dict_index_t* index, /*!< in: index */ - ulint level, /*!< in: level in the btree */ +btr_pcur_open( const dtuple_t* tuple, /*!< in: tuple on which search done */ page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...; NOTE that if the search is made using a unique @@ -326,26 +311,24 @@ btr_pcur_open_low( PAGE_CUR_LE, not PAGE_CUR_GE, as the latter may end up on the previous page from the record! */ - ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ + btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written (0 if none) */ mtr_t* mtr) /*!< in: mtr */ { - ut_ad(!index->is_spatial()); - btr_pcur_init(cursor); + ut_ad(!cursor->index()->is_spatial()); cursor->latch_mode= BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode); cursor->search_mode= mode; cursor->pos_state= BTR_PCUR_IS_POSITIONED; cursor->trx_if_known= nullptr; - return btr_cur_search_to_nth_level(index, level, tuple, mode, latch_mode, + return btr_cur_search_to_nth_level(0, tuple, mode, latch_mode, btr_pcur_get_btr_cur(cursor), mtr, autoinc); } /** Opens an persistent cursor to an index tree without initializing the cursor. -@param index index @param tuple tuple on which search done @param mode PAGE_CUR_L, ...; NOTE that if the search is made using a unique prefix of a record, mode should be PAGE_CUR_LE, not @@ -356,59 +339,21 @@ cursor. @param mtr mini-transaction @return DB_SUCCESS on success or error code otherwise. */ inline -dberr_t btr_pcur_open_with_no_init(dict_index_t *index, const dtuple_t *tuple, - page_cur_mode_t mode, ulint latch_mode, +dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple, + page_cur_mode_t mode, + btr_latch_mode latch_mode, btr_pcur_t *cursor, mtr_t *mtr) { cursor->latch_mode= BTR_LATCH_MODE_WITHOUT_INTENTION(latch_mode); cursor->search_mode= mode; cursor->pos_state= BTR_PCUR_IS_POSITIONED; - cursor->old_stored= false; cursor->trx_if_known= nullptr; /* Search with the tree cursor */ - return btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode, + return btr_cur_search_to_nth_level(0, tuple, mode, latch_mode, btr_pcur_get_btr_cur(cursor), mtr); } -/*****************************************************************//** -Opens a persistent cursor at either end of an index. */ -UNIV_INLINE -dberr_t -btr_pcur_open_at_index_side( -/*========================*/ - bool from_left, /*!< in: true if open to the low end, - false if to the high end */ - dict_index_t* index, /*!< in: index */ - ulint latch_mode, /*!< in: latch mode */ - btr_pcur_t* pcur, /*!< in/out: cursor */ - bool init_pcur, /*!< in: whether to initialize pcur */ - ulint level, /*!< in: level to search for - (0=leaf) */ - mtr_t* mtr) /*!< in/out: mini-transaction */ -{ - dberr_t err = DB_SUCCESS; - - pcur->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode); - - pcur->search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L; - - if (init_pcur) { - btr_pcur_init(pcur); - } - - err = btr_cur_open_at_index_side( - from_left, index, latch_mode, - btr_pcur_get_btr_cur(pcur), level, mtr); - pcur->pos_state = BTR_PCUR_IS_POSITIONED; - - pcur->old_stored = false; - - pcur->trx_if_known = NULL; - - return (err); -} - /**************************************************************//** Frees the possible memory heap of a persistent cursor and sets the latch mode of the persistent cursor to BTR_NO_LATCHES. @@ -425,25 +370,21 @@ btr_pcur_close( /*===========*/ btr_pcur_t* cursor) /*!< in: persistent cursor */ { - ut_free(cursor->old_rec_buf); - - if (cursor->btr_cur.rtr_info) { - rtr_clean_rtr_info(cursor->btr_cur.rtr_info, true); - cursor->btr_cur.rtr_info = NULL; - } + ut_free(cursor->old_rec_buf); - cursor->old_rec = NULL; - cursor->old_rec_buf = NULL; - cursor->btr_cur.page_cur.rec = NULL; - cursor->btr_cur.page_cur.block = NULL; + if (cursor->btr_cur.rtr_info) + rtr_clean_rtr_info(cursor->btr_cur.rtr_info, true); - cursor->old_rec = NULL; - cursor->old_stored = false; + cursor->btr_cur.rtr_info= nullptr; + cursor->old_rec = nullptr; + cursor->old_rec_buf = nullptr; + cursor->btr_cur.page_cur.rec = nullptr; + cursor->btr_cur.page_cur.block = nullptr; - cursor->latch_mode = BTR_NO_LATCHES; - cursor->pos_state = BTR_PCUR_NOT_POSITIONED; + cursor->latch_mode = BTR_NO_LATCHES; + cursor->pos_state = BTR_PCUR_NOT_POSITIONED; - cursor->trx_if_known = NULL; + cursor->trx_if_known = nullptr; } /*********************************************************//** @@ -459,5 +400,5 @@ btr_pcur_move_before_first_on_page( page_cur_set_before_first(btr_pcur_get_block(cursor), btr_pcur_get_page_cur(cursor)); - cursor->old_stored = false; + cursor->old_rec = nullptr; } diff --git a/storage/innobase/include/btr0types.h b/storage/innobase/include/btr0types.h index 83c374e2561..6118bfbc128 100644 --- a/storage/innobase/include/btr0types.h +++ b/storage/innobase/include/btr0types.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2019, MariaDB Corporation. +Copyright (c) 2018, 2022, 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 @@ -24,8 +24,7 @@ The index tree general types Created 2/17/1996 Heikki Tuuri *************************************************************************/ -#ifndef btr0types_h -#define btr0types_h +#pragma once #include "page0types.h" #include "rem0types.h" @@ -56,4 +55,93 @@ in the index record. */ #define BTR_EXTERN_LOCAL_STORED_MAX_SIZE \ (BTR_EXTERN_FIELD_REF_SIZE * 2) -#endif +/** Latching modes for btr_cur_search_to_nth_level(). */ +enum btr_latch_mode { + /** Search a record on a leaf page and S-latch it. */ + BTR_SEARCH_LEAF = RW_S_LATCH, + /** (Prepare to) modify a record on a leaf page and X-latch it. */ + BTR_MODIFY_LEAF = RW_X_LATCH, + /** Obtain no latches. */ + BTR_NO_LATCHES = RW_NO_LATCH, + /** Search the previous record. */ + BTR_SEARCH_PREV = 4 | BTR_SEARCH_LEAF, + /** Modify the previous record. */ + BTR_MODIFY_PREV = 4 | BTR_MODIFY_LEAF, + /** Start searching the entire B-tree. */ + BTR_SEARCH_TREE = 8 | BTR_SEARCH_LEAF, + /** Start modifying1 the entire B-tree. */ + BTR_MODIFY_TREE = 8 | BTR_MODIFY_LEAF, + /** Continue searching the entire B-tree. */ + BTR_CONT_SEARCH_TREE = 4 | BTR_SEARCH_TREE, + /** Continue modifying the entire B-tree. */ + BTR_CONT_MODIFY_TREE = 4 | BTR_MODIFY_TREE, + + /* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually + exclusive. */ + /** The search tuple will be inserted to the secondary index + at the searched position. When the leaf page is not in the + buffer pool, try to use the change buffer. */ + BTR_INSERT = 64, + + /** Try to delete mark a secondary index leaf page record at + the searched position using the change buffer when the page is + not in the buffer pool. */ + BTR_DELETE_MARK = 128, + + /** Try to purge the record using the change buffer when the + secondary index leaf page is not in the buffer pool. */ + BTR_DELETE = BTR_INSERT | BTR_DELETE_MARK, + + /** The caller is already holding dict_index_t::lock S-latch. */ + BTR_ALREADY_S_LATCHED = 256, + /** Search and S-latch a leaf page, assuming that the + dict_index_t::lock S-latch is being held. */ + BTR_SEARCH_LEAF_ALREADY_S_LATCHED = BTR_SEARCH_LEAF + | BTR_ALREADY_S_LATCHED, + /** Search the entire index tree, assuming that the + dict_index_t::lock S-latch is being held. */ + BTR_SEARCH_TREE_ALREADY_S_LATCHED = BTR_SEARCH_TREE + | BTR_ALREADY_S_LATCHED, + /** Search and X-latch a leaf page, assuming that the + dict_index_t::lock is being held in non-exclusive mode. */ + BTR_MODIFY_LEAF_ALREADY_LATCHED = BTR_MODIFY_LEAF + | BTR_ALREADY_S_LATCHED, + + /** Attempt to delete-mark a secondary index record. */ + BTR_DELETE_MARK_LEAF = BTR_MODIFY_LEAF | BTR_DELETE_MARK, + /** Attempt to delete-mark a secondary index record + while holding the dict_index_t::lock S-latch. */ + BTR_DELETE_MARK_LEAF_ALREADY_S_LATCHED = BTR_DELETE_MARK_LEAF + | BTR_ALREADY_S_LATCHED, + /** Attempt to purge a secondary index record. */ + BTR_PURGE_LEAF = BTR_MODIFY_LEAF | BTR_DELETE, + /** Attempt to purge a secondary index record + while holding the dict_index_t::lock S-latch. */ + BTR_PURGE_LEAF_ALREADY_S_LATCHED = BTR_PURGE_LEAF + | BTR_ALREADY_S_LATCHED, + + /** In the case of BTR_MODIFY_TREE, the caller specifies + the intention to delete record only. It is used to optimize + block->lock range.*/ + BTR_LATCH_FOR_DELETE = 512, + + /** In the case of BTR_MODIFY_TREE, the caller specifies + the intention to delete record only. It is used to optimize + block->lock range.*/ + BTR_LATCH_FOR_INSERT = 1024, + + /** Attempt to delete a record in the tree. */ + BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE, + + /** Attempt to insert a record into the tree. */ + BTR_INSERT_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_INSERT, + + /** This flag ORed to BTR_INSERT says that we can ignore possible + UNIQUE definition on secondary indexes when we decide if we can use + the insert buffer to speed up inserts */ + BTR_IGNORE_SEC_UNIQUE = 2048, + /** Rollback in spatial index */ + BTR_RTREE_UNDO_INS = 4096, + /** Try to delete mark a spatial index record */ + BTR_RTREE_DELETE_MARK = 8192 +}; diff --git a/storage/innobase/include/dyn0buf.h b/storage/innobase/include/dyn0buf.h index cb8b998f0ea..208e49c34a7 100644 --- a/storage/innobase/include/dyn0buf.h +++ b/storage/innobase/include/dyn0buf.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2020, MariaDB Corporation. +Copyright (c) 2018, 2022, 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 @@ -331,60 +331,6 @@ public: } /** - Iterate over each block and call the functor. - @return false if iteration was terminated. */ - template <typename Functor> - bool for_each_block(const Functor& functor) const - { - for (typename list_t::iterator it = m_list.begin(), - end = m_list.end(); - it != end; ++it) { - - if (!functor(&*it)) { - return false; - } - } - - return(true); - } - - /** - Iterate over all the blocks in reverse and call the iterator - @return false if iteration was terminated. */ - template <typename Functor> - bool for_each_block_in_reverse(Functor& functor) const - { - for (list_t::reverse_iterator it = m_list.rbegin(), - end = m_list.rend(); - it != end; ++it) { - - if (!functor(&*it)) { - return false; - } - } - - return(true); - } - - /** - Iterate over all the blocks in reverse and call the iterator - @return false if iteration was terminated. */ - template <typename Functor> - bool for_each_block_in_reverse(const Functor& functor) const - { - for (list_t::reverse_iterator it = m_list.rbegin(), - end = m_list.rend(); - it != end; ++it) { - - if (!functor(&*it)) { - return false; - } - } - - return(true); - } - - /** @return the first block */ block_t* front() MY_ATTRIBUTE((warn_unused_result)) diff --git a/storage/innobase/include/gis0rtree.h b/storage/innobase/include/gis0rtree.h index 8cd5e384530..777f2432c93 100644 --- a/storage/innobase/include/gis0rtree.h +++ b/storage/innobase/include/gis0rtree.h @@ -256,23 +256,14 @@ rtr_get_mbr_from_tuple( rtr_mbr* mbr); /*!< out: mbr to fill */ /* Get the rtree page father. -@param[in] offsets work area for the return value -@param[in] index rtree index -@param[in] block child page in the index @param[in,out] mtr mtr @param[in] sea_cur search cursor, contains information about parent nodes in search -@param[out] cursor cursor on node pointer record, +@param[in,out] cursor cursor on node pointer record, its page x-latched @return whether the cursor was successfully positioned */ -bool -rtr_page_get_father( - dict_index_t* index, - buf_block_t* block, - mtr_t* mtr, - btr_cur_t* sea_cur, - btr_cur_t* cursor) - MY_ATTRIBUTE((nonnull(1,2,3,5), warn_unused_result)); +bool rtr_page_get_father(mtr_t *mtr, btr_cur_t *sea_cur, btr_cur_t *cursor) + MY_ATTRIBUTE((nonnull(1,3), warn_unused_result)); /************************************************************//** Returns the father block to a page. It is assumed that mtr holds @@ -283,8 +274,6 @@ rtr_page_get_father_block( /*======================*/ rec_offs* offsets,/*!< in: work area for the return value */ mem_heap_t* heap, /*!< in: memory heap to use */ - 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* sea_cur,/*!< in: search cursor, contains information about parent nodes in search */ @@ -298,7 +287,7 @@ rtr_store_parent_path( /*==================*/ const buf_block_t* block, /*!< in: block of the page */ btr_cur_t* btr_cur,/*!< in/out: persistent cursor */ - ulint latch_mode, + btr_latch_mode latch_mode, /*!< in: latch_mode */ ulint level, /*!< in: index level */ mtr_t* mtr); /*!< in: mtr */ @@ -310,7 +299,7 @@ bool rtr_pcur_open( dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ - ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ + btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ mtr_t* mtr) /*!< in: mtr */ MY_ATTRIBUTE((warn_unused_result)); @@ -432,7 +421,6 @@ rtr_check_same_block( btr_cur_t* cur, /*!< in/out: position at the parent entry pointing to the child if successful */ buf_block_t* parentb,/*!< in: parent page to check */ - buf_block_t* childb, /*!< in: child Page */ mem_heap_t* heap); /*!< in: memory heap */ /*********************************************************************//** diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h index e6f72b05087..c246b2ef513 100644 --- a/storage/innobase/include/ibuf0ibuf.h +++ b/storage/innobase/include/ibuf0ibuf.h @@ -30,7 +30,6 @@ Created 7/19/1997 Heikki Tuuri #include "mtr0mtr.h" #include "dict0mem.h" #include "fsp0fsp.h" -#include "ibuf0types.h" /** Default value for maximum on-disk size of change buffer in terms of percentage of the buffer pool. */ @@ -61,6 +60,37 @@ enum ibuf_use_t { /** Operations that can currently be buffered. */ extern ulong innodb_change_buffering; +/** Insert buffer struct */ +struct ibuf_t{ + Atomic_relaxed<ulint> size; /*!< current size of the ibuf index + tree, in pages */ + Atomic_relaxed<ulint> max_size; /*!< recommended maximum size of the + ibuf index tree, in pages */ + ulint seg_size; /*!< allocated pages of the file + segment containing ibuf header and + tree */ + bool empty; /*!< Protected by the page + latch of the root page of the + insert buffer tree + (FSP_IBUF_TREE_ROOT_PAGE_NO). true + if and only if the insert + buffer tree is empty. */ + ulint free_list_len; /*!< length of the free list */ + ulint height; /*!< tree height */ + dict_index_t* index; /*!< insert buffer index */ + + /** number of pages merged */ + Atomic_counter<ulint> n_merges; + Atomic_counter<ulint> n_merged_ops[IBUF_OP_COUNT]; + /*!< number of operations of each type + merged to index pages */ + Atomic_counter<ulint> n_discarded_ops[IBUF_OP_COUNT]; + /*!< number of operations of each type + discarded without merging due to the + tablespace being deleted or the + index being dropped */ +}; + /** The insert buffer control structure */ extern ibuf_t ibuf; @@ -339,9 +369,9 @@ void ibuf_delete_for_discarded_space(uint32_t space); /** Contract the change buffer by reading pages to the buffer pool. @return a lower limit for the combined size in bytes of entries which -will be merged from ibuf trees to the pages read, 0 if ibuf is -empty */ -ulint ibuf_merge_all(); +will be merged from ibuf trees to the pages read +@retval 0 if ibuf.empty */ +ulint ibuf_contract(); /** Contracts insert buffer trees by reading pages referring to space_id to the buffer pool. diff --git a/storage/innobase/include/ibuf0ibuf.inl b/storage/innobase/include/ibuf0ibuf.inl index 2c2620511c7..9f4e937f31d 100644 --- a/storage/innobase/include/ibuf0ibuf.inl +++ b/storage/innobase/include/ibuf0ibuf.inl @@ -64,37 +64,6 @@ ibuf_mtr_commit( mtr_commit(mtr); } -/** Insert buffer struct */ -struct ibuf_t{ - ulint size; /*!< current size of the ibuf index - tree, in pages */ - ulint max_size; /*!< recommended maximum size of the - ibuf index tree, in pages */ - ulint seg_size; /*!< allocated pages of the file - segment containing ibuf header and - tree */ - bool empty; /*!< Protected by the page - latch of the root page of the - insert buffer tree - (FSP_IBUF_TREE_ROOT_PAGE_NO). true - if and only if the insert - buffer tree is empty. */ - ulint free_list_len; /*!< length of the free list */ - ulint height; /*!< tree height */ - dict_index_t* index; /*!< insert buffer index */ - - /** number of pages merged */ - Atomic_counter<ulint> n_merges; - Atomic_counter<ulint> n_merged_ops[IBUF_OP_COUNT]; - /*!< number of operations of each type - merged to index pages */ - Atomic_counter<ulint> n_discarded_ops[IBUF_OP_COUNT]; - /*!< number of operations of each type - discarded without merging due to the - tablespace being deleted or the - index being dropped */ -}; - /************************************************************************//** Sets the free bit of the page in the ibuf bitmap. This is done in a separate mini-transaction, hence this operation does not restrict further work to only diff --git a/storage/innobase/include/ibuf0types.h b/storage/innobase/include/ibuf0types.h deleted file mode 100644 index 6b7c47208a0..00000000000 --- a/storage/innobase/include/ibuf0types.h +++ /dev/null @@ -1,31 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1997, 2009, Oracle and/or its affiliates. All Rights Reserved. - -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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/ibuf0types.h -Insert buffer global types - -Created 7/29/1997 Heikki Tuuri -*******************************************************/ - -#ifndef ibuf0types_h -#define ibuf0types_h - -struct ibuf_t; - -#endif diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 629ddacdf1b..0f9a4da049b 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -2,7 +2,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2009, Google Inc. -Copyright (c) 2017, 2021, MariaDB Corporation. +Copyright (c) 2017, 2022, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -466,6 +466,11 @@ public: size_t buf_free; /** recommended maximum size of buf, after which the buffer is flushed */ size_t max_buf_free; + + /** Log sequence number when a log file overwrite (broken crash recovery) + was noticed. Protected by mutex. */ + lsn_t overwrite_warned; + /** mutex to serialize access to the flush list when we are putting dirty blocks in the list. The idea behind this mutex is to be able to release log_sys.mutex during mtr_commit and still ensure that diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 7f9bf27c6fb..ffc9b85193f 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -28,6 +28,8 @@ Created 11/26/1995 Heikki Tuuri #include "fil0fil.h" #include "dyn0buf.h" +#include "buf0buf.h" +#include <vector> /** Start a mini-transaction. */ #define mtr_start(m) (m)->start() @@ -48,11 +50,6 @@ savepoint. */ @return old mode */ #define mtr_set_log_mode(m, d) (m)->set_log_mode((d)) -/** Release an object in the memo stack. -@return true if released */ -#define mtr_memo_release(m, o, t) \ - (m)->memo_release((o), (t)) - #ifdef UNIV_PFS_RWLOCK # define mtr_s_lock_index(i,m) (m)->s_lock(__FILE__, __LINE__, &(i)->lock) # define mtr_x_lock_index(i,m) (m)->x_lock(__FILE__, __LINE__, &(i)->lock) @@ -66,19 +63,16 @@ savepoint. */ #define mtr_release_block_at_savepoint(m, s, b) \ (m)->release_block_at_savepoint((s), (b)) -#define mtr_block_sx_latch_at_savepoint(m, s, b) \ - (m)->sx_latch_at_savepoint((s), (b)) - -#define mtr_block_x_latch_at_savepoint(m, s, b) \ - (m)->x_latch_at_savepoint((s), (b)) - /** Mini-transaction memo stack slot. */ -struct mtr_memo_slot_t { - /** pointer to the object */ - void* object; - - /** type of the stored object */ - mtr_memo_type_t type; +struct mtr_memo_slot_t +{ + /** pointer to the object, or nullptr if released */ + void *object; + /** type of the stored object */ + mtr_memo_type_t type; + + /** Release the object */ + void release() const; }; /** Mini-transaction handle and buffer */ @@ -89,14 +83,19 @@ struct mtr_t { /** Commit the mini-transaction. */ void commit(); - /** Release latches till savepoint. To simplify the code only - MTR_MEMO_S_LOCK and MTR_MEMO_PAGE_S_FIX slot types are allowed to be - released, otherwise it would be neccesary to add one more argument in the - function to point out what slot types are allowed for rollback, and this - would be overengineering as currently the function is used only in one place - in the code. - @param savepoint savepoint, can be obtained with get_savepoint */ - void rollback_to_savepoint(ulint savepoint); + /** Release latches of unmodified buffer pages. + @param begin first slot to release + @param end last slot to release, or get_savepoint() */ + void rollback_to_savepoint(ulint begin, ulint end); + + /** Release latches of unmodified buffer pages. + @param begin first slot to release */ + void rollback_to_savepoint(ulint begin) + { rollback_to_savepoint(begin, m_memo->size()); } + + /** Release the last acquired buffer page latch. */ + void release_last_page() + { auto s= m_memo->size(); rollback_to_savepoint(s - 1, s); } /** Commit a mini-transaction that is shrinking a tablespace. @param space tablespace that is being shrunk */ @@ -117,26 +116,89 @@ struct mtr_t { void commit_files(lsn_t checkpoint_lsn= 0); /** @return mini-transaction savepoint (current size of m_memo) */ - ulint get_savepoint() const { ut_ad(is_active()); return m_memo.size(); } + ulint get_savepoint() const + { + ut_ad(is_active()); + return m_memo ? m_memo->size() : 0; + } - /** Release the (index tree) s-latch stored in an mtr memo after a - savepoint. - @param savepoint value returned by @see set_savepoint. - @param lock latch to release */ - inline void release_s_latch_at_savepoint( - ulint savepoint, - index_lock* lock); + /** Release the (index tree) s-latch stored in an mtr memo after a savepoint. + @param savepoint value returned by get_savepoint() + @param lock index latch to release */ + void release_s_latch_at_savepoint(ulint savepoint, index_lock *lock) + { + ut_ad(is_active()); + mtr_memo_slot_t &slot= m_memo->at(savepoint); + ut_ad(slot.object == lock); + ut_ad(slot.type == MTR_MEMO_S_LOCK); + slot.object= nullptr; + lock->s_unlock(); + } + /** Release the block in an mtr memo after a savepoint. */ + void release_block_at_savepoint(ulint savepoint, buf_block_t *block) + { + ut_ad(is_active()); + mtr_memo_slot_t &slot= m_memo->at(savepoint); + ut_ad(slot.object == block); + ut_ad(!(slot.type & MTR_MEMO_MODIFY)); + slot.object= nullptr; + block->page.unfix(); + + switch (slot.type) { + case MTR_MEMO_PAGE_S_FIX: + block->page.lock.s_unlock(); + break; + case MTR_MEMO_PAGE_SX_FIX: + case MTR_MEMO_PAGE_X_FIX: + block->page.lock.u_or_x_unlock(slot.type == MTR_MEMO_PAGE_SX_FIX); + break; + default: + break; + } + } - /** Release the block in an mtr memo after a savepoint. */ - inline void release_block_at_savepoint( - ulint savepoint, - buf_block_t* block); + /** @return if we are about to make a clean buffer block dirty */ + static bool is_block_dirtied(const buf_page_t &b) + { + ut_ad(b.in_file()); + ut_ad(b.frame); + ut_ad(b.buf_fix_count()); + return b.oldest_modification() <= 1 && b.id().space() < SRV_TMP_SPACE_ID; + } - /** SX-latch a not yet latched block after a savepoint. */ - inline void sx_latch_at_savepoint(ulint savepoint, buf_block_t* block); + /** X-latch a not yet latched block after a savepoint. */ + void x_latch_at_savepoint(ulint savepoint, buf_block_t *block) + { + ut_ad(is_active()); + ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX | + MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); + mtr_memo_slot_t &slot= m_memo->at(savepoint); + ut_ad(slot.object == block); + ut_ad(slot.type == MTR_MEMO_BUF_FIX); + slot.type= MTR_MEMO_PAGE_X_FIX; + block->page.lock.x_lock(); + ut_ad(!block->page.is_io_fixed()); + + if (!m_made_dirty) + m_made_dirty= is_block_dirtied(block->page); + } - /** X-latch a not yet latched block after a savepoint. */ - inline void x_latch_at_savepoint(ulint savepoint, buf_block_t* block); + /** U-latch a not yet latched block after a savepoint. */ + void sx_latch_at_savepoint(ulint savepoint, buf_block_t *block) + { + ut_ad(is_active()); + ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX | + MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)); + mtr_memo_slot_t &slot= m_memo->at(savepoint); + ut_ad(slot.object == block); + ut_ad(slot.type == MTR_MEMO_BUF_FIX); + slot.type= MTR_MEMO_PAGE_SX_FIX; + block->page.lock.u_lock(); + ut_ad(!block->page.is_io_fixed()); + + if (!m_made_dirty) + m_made_dirty= is_block_dirtied(block->page); + } /** @return the logging mode */ mtr_log_t get_log_mode() const @@ -290,19 +352,17 @@ struct mtr_t { /** Acquire an exclusive tablespace latch. @param space tablespace */ void x_lock_space(fil_space_t *space); - /** Release an object in the memo stack. - @param object object - @param type object type - @return bool if lock released */ - bool memo_release(const void *object, ulint type); - /** Release a page latch. - @param[in] ptr pointer to within a page frame - @param[in] type object type: MTR_MEMO_PAGE_X_FIX, ... */ - void release_page(const void *ptr, mtr_memo_type_t type); + + /** Release an index latch. */ + void release(const index_lock &lock) { release(&lock); } + /** Release a latch to an unmodified page. */ + void release(const buf_block_t &block) { release(&block); } /** Note that the mini-transaction will modify data. */ void flag_modified() { m_modifications = true; } private: + /** Release an unmodified object. */ + void release(const void *object); /** Mark the given latched page as modified. @param block page that will be modified */ void modify(const buf_block_t& block); @@ -340,73 +400,93 @@ public: @param rw_latch RW_S_LATCH, RW_SX_LATCH, RW_X_LATCH, RW_NO_LATCH */ void page_lock(buf_block_t *block, ulint rw_latch); + /** Acquire a latch on a buffer-fixed buffer pool block. + @param savepoint savepoint location of the buffer-fixed block + @param rw_latch latch to acquire */ + void upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch); + /** Register a page latch on a buffer-fixed block was buffer-fixed. @param latch latch type */ void u_lock_register(ulint savepoint) { - mtr_memo_slot_t *slot= m_memo.at<mtr_memo_slot_t*>(savepoint); - ut_ad(slot->type == MTR_MEMO_BUF_FIX); - slot->type= MTR_MEMO_PAGE_SX_FIX; + mtr_memo_slot_t &slot= m_memo->at(savepoint); + ut_ad(slot.type == MTR_MEMO_BUF_FIX); + slot.type= MTR_MEMO_PAGE_SX_FIX; + } + + /** Register a page latch on a buffer-fixed block was buffer-fixed. + @param latch latch type */ + void s_lock_register(ulint savepoint) + { + mtr_memo_slot_t &slot= m_memo->at(savepoint); + ut_ad(slot.type == MTR_MEMO_BUF_FIX); + slot.type= MTR_MEMO_PAGE_S_FIX; } /** Upgrade U locks on a block to X */ void page_lock_upgrade(const buf_block_t &block); - /** Upgrade X lock to X */ + /** Upgrade U lock to X */ void lock_upgrade(const index_lock &lock); /** Check if we are holding tablespace latch @param space tablespace to search for @param shared whether to look for shared latch, instead of exclusive @return whether space.latch is being held */ - bool memo_contains(const fil_space_t& space, bool shared= false) + bool memo_contains(const fil_space_t& space, bool shared= false) const MY_ATTRIBUTE((warn_unused_result)); #ifdef UNIV_DEBUG /** Check if we are holding an rw-latch in this mini-transaction @param lock latch to search for @param type held latch type @return whether (lock,type) is contained */ - bool memo_contains(const index_lock &lock, mtr_memo_type_t type) + bool memo_contains(const index_lock &lock, mtr_memo_type_t type) const MY_ATTRIBUTE((warn_unused_result)); - /** Check if memo contains the given item. - @param object object to search - @param flags specify types of object (can be ORred) of - MTR_MEMO_PAGE_S_FIX ... values - @return true if contains */ - bool memo_contains_flagged(const void* ptr, ulint flags) const; - - /** Check if memo contains the given page. - @param[in] ptr pointer to within buffer frame - @param[in] flags specify types of object with OR of - MTR_MEMO_PAGE_S_FIX... values - @return the block - @retval NULL if not found */ - buf_block_t* memo_contains_page_flagged( - const byte* ptr, - ulint flags) const; - - /** @return true if mini-transaction contains modifications. */ - bool has_modifications() const { return m_modifications; } + /** Check if memo contains an index or buffer block latch. + @param object object to search + @param flags specify types of object latches + @return true if contains */ + bool memo_contains_flagged(const void *object, ulint flags) const + MY_ATTRIBUTE((warn_unused_result, nonnull)); + + /** Check if memo contains the given page. + @param ptr pointer to within page frame + @param flags types latch to look for + @return the block + @retval nullptr if not found */ + buf_block_t *memo_contains_page_flagged(const byte *ptr, ulint flags) const; + + /** @return true if mini-transaction contains modifications. */ + bool has_modifications() const { return m_modifications; } #endif /* UNIV_DEBUG */ - /** @return true if a record was added to the mini-transaction */ - bool is_dirty() const { return m_made_dirty; } - - /** Push an object to an mtr memo stack. - @param object object - @param type object type: MTR_MEMO_S_LOCK, ... */ - inline void memo_push(void* object, mtr_memo_type_t type); - - /** Check if this mini-transaction is dirtying a clean page. - @param block block being x-fixed - @return true if the mtr is dirtying a clean page. */ - static inline bool is_block_dirtied(const buf_block_t* block) - MY_ATTRIBUTE((warn_unused_result)); + /** Push an object to an mtr memo stack. + @param object object + @param type object type: MTR_MEMO_S_LOCK, ... */ + void memo_push(void *object, mtr_memo_type_t type) __attribute__((nonnull)) + { + ut_ad(is_active()); + /* If this mtr has U or X latched a clean page then we set + the m_made_dirty flag. This tells us if we need to + grab log_sys.flush_order_mutex at mtr_t::commit() so that we + can insert the dirtied page into the buf_pool.flush_list. + + FIXME: Do this only when the MTR_MEMO_MODIFY flag is set! */ + if (!m_made_dirty && + (type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))) + m_made_dirty= + is_block_dirtied(*static_cast<const buf_page_t*>(object)); + + if (!m_memo) + m_memo= new std::vector<mtr_memo_slot_t>(1, {object, type}); + else + m_memo->emplace_back(mtr_memo_slot_t{object, type}); + } /** @return the size of the log is empty */ size_t get_log_size() const { return m_log.size(); } /** @return whether the log and memo are empty */ - bool is_empty() const { return m_memo.size() == 0 && m_log.size() == 0; } + bool is_empty() const { return !get_savepoint() && !get_log_size(); } /** Write an OPT_PAGE_CHECKSUM record. */ inline void page_checksum(const buf_page_t &bpage); @@ -657,6 +737,8 @@ private: @return {start_lsn,flush_ahead} */ inline std::pair<lsn_t,page_flush_ahead> finish_write(ulint len); + /** Release all latches. */ + void release(); /** Release the resources */ inline void release_resources(); @@ -708,7 +790,7 @@ private: #endif /* UNIV_DEBUG */ /** acquired dict_index_t::lock, fil_space_t::latch, buf_block_t */ - mtr_buf_t m_memo; + std::vector<mtr_memo_slot_t> *m_memo= nullptr; /** mini-transaction log */ mtr_buf_t m_log; @@ -724,5 +806,3 @@ private: /** set of freed page ids */ range_set *m_freed_pages= nullptr; }; - -#include "mtr0mtr.inl" diff --git a/storage/innobase/include/mtr0mtr.inl b/storage/innobase/include/mtr0mtr.inl deleted file mode 100644 index 75be7adc6a5..00000000000 --- a/storage/innobase/include/mtr0mtr.inl +++ /dev/null @@ -1,185 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2022, 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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/mtr0mtr.ic -Mini-transaction buffer - -Created 11/26/1995 Heikki Tuuri -*******************************************************/ - -#include "buf0buf.h" - -/** Check if a mini-transaction is dirtying a clean page. -@return true if the mtr is dirtying a clean page. */ -inline bool mtr_t::is_block_dirtied(const buf_block_t *block) -{ - ut_ad(block->page.in_file()); - ut_ad(block->page.frame); - ut_ad(block->page.buf_fix_count()); - return block->page.oldest_modification() <= 1 && - block->page.id().space() < SRV_TMP_SPACE_ID; -} - -/** -Pushes an object to an mtr memo stack. */ -void -mtr_t::memo_push(void* object, mtr_memo_type_t type) -{ - ut_ad(is_active()); - ut_ad(object != NULL); - ut_ad(type >= MTR_MEMO_PAGE_S_FIX); - ut_ad(type <= MTR_MEMO_SPACE_S_LOCK); - ut_ad(type == MTR_MEMO_PAGE_X_MODIFY || ut_is_2pow(type)); - - /* If this mtr has U or X latched a clean page then we set - the m_made_dirty flag. This tells us if we need to - grab log_sys.flush_order_mutex at mtr_t::commit() so that we - can insert the dirtied page into the buf_pool.flush_list. */ - - if (!m_made_dirty - && (type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))) { - - m_made_dirty = is_block_dirtied( - reinterpret_cast<const buf_block_t*>(object)); - } - - mtr_memo_slot_t* slot = m_memo.push<mtr_memo_slot_t*>(sizeof(*slot)); - - slot->type = type; - slot->object = object; -} - -/** -Releases the (index tree) s-latch stored in an mtr memo after a -savepoint. */ -void -mtr_t::release_s_latch_at_savepoint( - ulint savepoint, - index_lock* lock) -{ - ut_ad(is_active()); - ut_ad(m_memo.size() > savepoint); - - mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); - - ut_ad(slot->object == lock); - ut_ad(slot->type == MTR_MEMO_S_LOCK); - - lock->s_unlock(); - - slot->object = NULL; -} - -/** -SX-latches the not yet latched block after a savepoint. */ - -void -mtr_t::sx_latch_at_savepoint( - ulint savepoint, - buf_block_t* block) -{ - ut_ad(is_active()); - ut_ad(m_memo.size() > savepoint); - - ut_ad(!memo_contains_flagged( - block, - MTR_MEMO_PAGE_S_FIX - | MTR_MEMO_PAGE_X_FIX - | MTR_MEMO_PAGE_SX_FIX)); - - mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); - - ut_ad(slot->object == block); - - /* == RW_NO_LATCH */ - ut_a(slot->type == MTR_MEMO_BUF_FIX); - - block->page.lock.u_lock(); - ut_ad(!block->page.is_io_fixed()); - - if (!m_made_dirty) { - m_made_dirty = is_block_dirtied(block); - } - - slot->type = MTR_MEMO_PAGE_SX_FIX; -} - -/** -X-latches the not yet latched block after a savepoint. */ - -void -mtr_t::x_latch_at_savepoint( - ulint savepoint, - buf_block_t* block) -{ - ut_ad(is_active()); - ut_ad(m_memo.size() > savepoint); - - ut_ad(!memo_contains_flagged( - block, - MTR_MEMO_PAGE_S_FIX - | MTR_MEMO_PAGE_X_FIX - | MTR_MEMO_PAGE_SX_FIX)); - - mtr_memo_slot_t* slot = m_memo.at<mtr_memo_slot_t*>(savepoint); - - ut_ad(slot->object == block); - - /* == RW_NO_LATCH */ - ut_a(slot->type == MTR_MEMO_BUF_FIX); - - block->page.lock.x_lock(); - ut_ad(!block->page.is_io_fixed()); - - if (!m_made_dirty) { - m_made_dirty = is_block_dirtied(block); - } - - slot->type = MTR_MEMO_PAGE_X_FIX; -} - -/** -Releases the block in an mtr memo after a savepoint. */ - -void -mtr_t::release_block_at_savepoint( - ulint savepoint, - buf_block_t* block) -{ - ut_ad(is_active()); - - mtr_memo_slot_t *slot = m_memo.at<mtr_memo_slot_t*>(savepoint); - - ut_a(slot->object == block); - slot->object= nullptr; - block->page.unfix(); - - switch (slot->type) { - case MTR_MEMO_PAGE_S_FIX: - block->page.lock.s_unlock(); - break; - case MTR_MEMO_PAGE_SX_FIX: - case MTR_MEMO_PAGE_X_FIX: - block->page.lock.u_or_x_unlock(slot->type == MTR_MEMO_PAGE_SX_FIX); - break; - default: - break; - } -} diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h index 80542299482..28aa30565e4 100644 --- a/storage/innobase/include/page0cur.h +++ b/storage/innobase/include/page0cur.h @@ -129,7 +129,6 @@ page_cur_tuple_insert( /*==================*/ page_cur_t* cursor, /*!< in/out: a page cursor */ const dtuple_t* tuple, /*!< in: pointer to a data tuple */ - dict_index_t* index, /*!< in: record descriptor */ rec_offs** offsets,/*!< out: offsets on *rec */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ ulint n_ext, /*!< in: number of externally stored columns */ @@ -143,7 +142,6 @@ rec_t* page_cur_insert_rec_low( /*====================*/ const page_cur_t*cur, /*!< in: page cursor */ - dict_index_t* index, /*!< in: record descriptor */ const rec_t* rec, /*!< in: record to insert after cur */ rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */ mtr_t* mtr) /*!< in/out: mini-transaction */ @@ -165,7 +163,6 @@ page_cur_insert_rec_zip( /*====================*/ page_cur_t* cursor, /*!< in/out: page cursor, logical position unchanged */ - dict_index_t* index, /*!< in: record descriptor */ const rec_t* rec, /*!< in: pointer to a physical record */ rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */ mtr_t* mtr) /*!< in/out: mini-transaction */ @@ -177,7 +174,6 @@ void page_cur_delete_rec( /*================*/ page_cur_t* cursor, /*!< in/out: a page cursor */ - const dict_index_t* index, /*!< in: record descriptor */ const rec_offs* offsets,/*!< in: rec_get_offsets( cursor->rec, index) */ mtr_t* mtr) /*!< in/out: mini-transaction */ @@ -239,8 +235,6 @@ Searches the right position for a page cursor. */ bool page_cur_search_with_match( /*=======================*/ - const buf_block_t* block, /*!< in: buffer block */ - const dict_index_t* index, /*!< in: record descriptor */ const dtuple_t* tuple, /*!< in: data tuple */ page_cur_mode_t mode, /*!< in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or @@ -251,13 +245,11 @@ page_cur_search_with_match( ulint* ilow_matched_fields, /*!< in/out: already matched fields in lower limit record */ - page_cur_t* cursor, /*!< out: page cursor */ + page_cur_t* cursor, /*!< in/out: page cursor */ rtr_info_t* rtr_info);/*!< in/out: rtree search stack */ #ifdef BTR_CUR_HASH_ADAPT MY_ATTRIBUTE((warn_unused_result)) /** Search the right position for a page cursor. -@param[in] block buffer block -@param[in] index index tree @param[in] tuple key to be searched for @param[in] mode search mode @param[in,out] iup_matched_fields already matched fields in the @@ -268,11 +260,9 @@ first partially matched field in the upper limit record lower limit record @param[in,out] ilow_matched_bytes already matched bytes in the first partially matched field in the lower limit record -@param[out] cursor page cursor */ +@param[in,out] cursor page cursor */ bool page_cur_search_with_match_bytes( - const buf_block_t* block, - const dict_index_t* index, const dtuple_t* tuple, page_cur_mode_t mode, ulint* iup_matched_fields, @@ -284,16 +274,12 @@ page_cur_search_with_match_bytes( /***********************************************************//** Positions a page cursor on a randomly chosen user record on a page. If there are no user records, sets the cursor on the infimum record. */ -void -page_cur_open_on_rnd_user_rec( -/*==========================*/ - buf_block_t* block, /*!< in: page */ - page_cur_t* cursor);/*!< out: page cursor */ +void page_cur_open_on_rnd_user_rec(page_cur_t *cursor); /** Index page cursor */ struct page_cur_t{ - const dict_index_t* index; + dict_index_t* index; rec_t* rec; /*!< pointer to a record on page */ rec_offs* offsets; buf_block_t* block; /*!< pointer to the block containing rec */ diff --git a/storage/innobase/include/page0cur.inl b/storage/innobase/include/page0cur.inl index 8f69dc22878..1638b5749ff 100644 --- a/storage/innobase/include/page0cur.inl +++ b/storage/innobase/include/page0cur.inl @@ -167,14 +167,12 @@ page_cur_tuple_insert( /*==================*/ page_cur_t* cursor, /*!< in/out: a page cursor */ const dtuple_t* tuple, /*!< in: pointer to a data tuple */ - dict_index_t* index, /*!< in: record descriptor */ rec_offs** offsets,/*!< out: offsets on *rec */ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */ ulint n_ext, /*!< in: number of externally stored columns */ mtr_t* mtr) /*!< in/out: mini-transaction */ { - rec_t* rec; - ulint size = rec_get_converted_size(index, tuple, n_ext); + ulint size = rec_get_converted_size(cursor->index, tuple, n_ext); if (!*heap) { *heap = mem_heap_create(size @@ -183,21 +181,20 @@ page_cur_tuple_insert( * sizeof **offsets); } - rec = rec_convert_dtuple_to_rec((byte*) mem_heap_alloc(*heap, size), - index, tuple, n_ext); + rec_t* rec = rec_convert_dtuple_to_rec( + static_cast<byte*>(mem_heap_alloc(*heap, size)), + cursor->index, tuple, n_ext); - *offsets = rec_get_offsets(rec, index, *offsets, + *offsets = rec_get_offsets(rec, cursor->index, *offsets, page_is_leaf(cursor->block->page.frame) - ? index->n_core_fields : 0, + ? cursor->index->n_core_fields : 0, ULINT_UNDEFINED, heap); ut_ad(size == rec_offs_size(*offsets)); if (is_buf_block_get_page_zip(cursor->block)) { - rec = page_cur_insert_rec_zip( - cursor, index, rec, *offsets, mtr); + rec = page_cur_insert_rec_zip(cursor, rec, *offsets, mtr); } else { - rec = page_cur_insert_rec_low(cursor, - index, rec, *offsets, mtr); + rec = page_cur_insert_rec_low(cursor, rec, *offsets, mtr); } ut_ad(!rec || !cmp_dtuple_rec(tuple, rec, *offsets)); diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h index 25c09258b3c..1f8af6030d1 100644 --- a/storage/innobase/include/row0ins.h +++ b/storage/innobase/include/row0ins.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2021, MariaDB Corporation. +Copyright (c) 2017, 2022, 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 @@ -78,7 +78,7 @@ dberr_t row_ins_clust_index_entry_low( /*==========================*/ ulint flags, /*!< in: undo logging and locking flags */ - ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, + btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, depending on whether we wish optimistic or pessimistic descent down the index tree */ dict_index_t* index, /*!< in: clustered index */ @@ -94,13 +94,13 @@ same fields is found, the other record is necessarily marked deleted. It is then unmarked. Otherwise, the entry is just inserted to the index. @retval DB_SUCCESS on success @retval DB_LOCK_WAIT on lock wait when !(flags & BTR_NO_LOCKING_FLAG) -@retval DB_FAIL if retry with BTR_MODIFY_TREE is needed +@retval DB_FAIL if retry with BTR_INSERT_TREE is needed @return error code */ dberr_t row_ins_sec_index_entry_low( /*========================*/ ulint flags, /*!< in: undo logging and locking flags */ - ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, + btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_INSERT_TREE, depending on whether we wish optimistic or pessimistic descent down the index tree */ dict_index_t* index, /*!< in: secondary index */ diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h index 1e0fdc65238..a1350740e2a 100644 --- a/storage/innobase/include/row0row.h +++ b/storage/innobase/include/row0row.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2020, MariaDB Corporation. +Copyright (c) 2016, 2022, 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 @@ -303,13 +303,13 @@ row_build_row_ref_fast( /***************************************************************//** Searches the clustered index record for a row, if we have the row reference. -@return TRUE if found */ -ibool +@return true if found */ +bool row_search_on_row_ref( /*==================*/ btr_pcur_t* pcur, /*!< out: persistent cursor, which must be closed by the caller */ - ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */ + btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */ const dict_table_t* table, /*!< in: table */ const dtuple_t* ref, /*!< in: row reference */ mtr_t* mtr) /*!< in/out: mtr */ @@ -321,7 +321,7 @@ on the secondary index record are preserved. rec_t* row_get_clust_rec( /*==============*/ - ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */ + btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */ const rec_t* rec, /*!< in: record in a secondary index */ dict_index_t* index, /*!< in: secondary index */ dict_index_t** clust_index,/*!< out: clustered index */ @@ -363,9 +363,8 @@ Searches an index record. enum row_search_result row_search_index_entry( /*===================*/ - dict_index_t* index, /*!< in: index */ const dtuple_t* entry, /*!< in: index entry */ - ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */ + btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF, ... */ btr_pcur_t* pcur, /*!< in/out: persistent cursor, which must be closed by the caller */ mtr_t* mtr) /*!< in: mtr */ |