diff options
Diffstat (limited to 'storage/xtradb/btr/btr0btr.c')
-rw-r--r-- | storage/xtradb/btr/btr0btr.c | 651 |
1 files changed, 344 insertions, 307 deletions
diff --git a/storage/xtradb/btr/btr0btr.c b/storage/xtradb/btr/btr0btr.c index 2029a95cc19..6ba9b36207b 100644 --- a/storage/xtradb/btr/btr0btr.c +++ b/storage/xtradb/btr/btr0btr.c @@ -16,7 +16,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ -/****************************************************** +/**************************************************//** +@file btr/btr0btr.c The B-tree Created 6/2/1994 Heikki Tuuri @@ -31,6 +32,8 @@ Created 6/2/1994 Heikki Tuuri #include "fsp0fsp.h" #include "page0page.h" #include "page0zip.h" + +#ifndef UNIV_HOTBACKUP #include "btr0cur.h" #include "btr0sea.h" #include "btr0pcur.h" @@ -95,15 +98,15 @@ we allocate pages for the non-leaf levels of the tree. */ #ifdef UNIV_BTR_DEBUG -/****************************************************************** -Checks a file segment header within a B-tree root page. */ +/**************************************************************//** +Checks a file segment header within a B-tree root page. +@return TRUE if valid */ static ibool btr_root_fseg_validate( /*===================*/ - /* out: TRUE if valid */ - const fseg_header_t* seg_header, /* in: segment header */ - ulint space) /* in: tablespace identifier */ + const fseg_header_t* seg_header, /*!< in: segment header */ + ulint space) /*!< in: tablespace identifier */ { ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET); @@ -114,15 +117,15 @@ btr_root_fseg_validate( } #endif /* UNIV_BTR_DEBUG */ -/****************************************************************** -Gets the root node of a tree and x-latches it. */ +/**************************************************************//** +Gets the root node of a tree and x-latches it. +@return root page, x-latched */ static buf_block_t* btr_root_block_get( /*===============*/ - /* out: root page, x-latched */ - dict_index_t* index, /* in: index tree */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + mtr_t* mtr) /*!< in: mtr */ { ulint space; ulint zip_size; @@ -150,29 +153,29 @@ btr_root_block_get( return(block); } -/****************************************************************** -Gets the root node of a tree and x-latches it. */ +/**************************************************************//** +Gets the root node of a tree and x-latches it. +@return root page, x-latched */ UNIV_INTERN page_t* btr_root_get( /*=========*/ - /* out: root page, x-latched */ - dict_index_t* index, /* in: index tree */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + mtr_t* mtr) /*!< in: mtr */ { return(buf_block_get_frame(btr_root_block_get(index, mtr))); } -/***************************************************************** +/*************************************************************//** Gets pointer to the previous user record in the tree. It is assumed that -the caller has appropriate latches on the page and its neighbor. */ +the caller has appropriate latches on the page and its neighbor. +@return previous user record, NULL if there is none */ UNIV_INTERN rec_t* btr_get_prev_user_rec( /*==================*/ - /* out: previous user record, NULL if there is none */ - rec_t* rec, /* in: record on leaf level */ - mtr_t* mtr) /* in: mtr holding a latch on the page, and if + rec_t* rec, /*!< in: record on leaf level */ + mtr_t* mtr) /*!< in: mtr holding a latch on the page, and if needed, also to the previous page */ { page_t* page; @@ -221,16 +224,16 @@ btr_get_prev_user_rec( return(NULL); } -/***************************************************************** +/*************************************************************//** Gets pointer to the next user record in the tree. It is assumed that the -caller has appropriate latches on the page and its neighbor. */ +caller has appropriate latches on the page and its neighbor. +@return next user record, NULL if there is none */ UNIV_INTERN rec_t* btr_get_next_user_rec( /*==================*/ - /* out: next user record, NULL if there is none */ - rec_t* rec, /* in: record on leaf level */ - mtr_t* mtr) /* in: mtr holding a latch on the page, and if + rec_t* rec, /*!< in: record on leaf level */ + mtr_t* mtr) /*!< in: mtr holding a latch on the page, and if needed, also to the next page */ { page_t* page; @@ -277,18 +280,18 @@ btr_get_next_user_rec( return(NULL); } -/****************************************************************** +/**************************************************************//** Creates a new index page (not the root, and also not used in page reorganization). @see btr_page_empty(). */ static void btr_page_create( /*============*/ - buf_block_t* block, /* in/out: page to be created */ - page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */ - dict_index_t* index, /* in: index */ - ulint level, /* in: the B-tree level of the page */ - mtr_t* mtr) /* in: mtr */ + buf_block_t* block, /*!< in/out: page to be created */ + page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ + dict_index_t* index, /*!< in: index */ + ulint level, /*!< in: the B-tree level of the page */ + mtr_t* mtr) /*!< in: mtr */ { page_t* page = buf_block_get_frame(block); @@ -307,16 +310,16 @@ btr_page_create( btr_page_set_index_id(page, page_zip, index->id, mtr); } -/****************************************************************** +/**************************************************************//** Allocates a new file page to be used in an ibuf tree. Takes the page from -the free list of the tree, which must contain pages! */ +the free list of the tree, which must contain pages! +@return new allocated block, x-latched */ static buf_block_t* btr_page_alloc_for_ibuf( /*====================*/ - /* out: new allocated block, x-latched */ - dict_index_t* index, /* in: index tree */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + mtr_t* mtr) /*!< in: mtr */ { fil_addr_t node_addr; page_t* root; @@ -344,22 +347,21 @@ btr_page_alloc_for_ibuf( return(new_block); } -/****************************************************************** +/**************************************************************//** Allocates a new file page to be used in an index tree. NOTE: we assume -that the caller has made the reservation for free extents! */ +that the caller has made the reservation for free extents! +@return new allocated block, x-latched; NULL if out of space */ UNIV_INTERN buf_block_t* btr_page_alloc( /*===========*/ - /* out: new allocated block, x-latched; - NULL if out of space */ - dict_index_t* index, /* in: index */ - ulint hint_page_no, /* in: hint of a good page */ - byte file_direction, /* in: direction where a possible + dict_index_t* index, /*!< in: index */ + ulint hint_page_no, /*!< in: hint of a good page */ + byte file_direction, /*!< in: direction where a possible page split is made */ - ulint level, /* in: level where the page is placed + ulint level, /*!< in: level where the page is placed in the tree */ - mtr_t* mtr) /* in: mtr */ + mtr_t* mtr) /*!< in: mtr */ { fseg_header_t* seg_header; page_t* root; @@ -398,15 +400,15 @@ btr_page_alloc( return(new_block); } -/****************************************************************** -Gets the number of pages in a B-tree. */ +/**************************************************************//** +Gets the number of pages in a B-tree. +@return number of pages */ UNIV_INTERN ulint btr_get_size( /*=========*/ - /* out: number of pages */ - dict_index_t* index, /* in: index */ - ulint flag) /* in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ + dict_index_t* index, /*!< in: index */ + ulint flag) /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */ { fseg_header_t* seg_header; page_t* root; @@ -442,16 +444,16 @@ btr_get_size( return(n); } -/****************************************************************** +/**************************************************************//** Frees a page used in an ibuf tree. Puts the page to the free list of the ibuf tree. */ static void btr_page_free_for_ibuf( /*===================*/ - dict_index_t* index, /* in: index tree */ - buf_block_t* block, /* in: block to be freed, x-latched */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + buf_block_t* block, /*!< in: block to be freed, x-latched */ + mtr_t* mtr) /*!< in: mtr */ { page_t* root; @@ -466,7 +468,7 @@ btr_page_free_for_ibuf( mtr)); } -/****************************************************************** +/**************************************************************//** Frees a file page used in an index tree. Can be used also to (BLOB) external storage pages, because the page level 0 can be given as an argument. */ @@ -474,10 +476,10 @@ UNIV_INTERN void btr_page_free_low( /*==============*/ - dict_index_t* index, /* in: index tree */ - buf_block_t* block, /* in: block to be freed, x-latched */ - ulint level, /* in: page level */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + buf_block_t* block, /*!< in: block to be freed, x-latched */ + ulint level, /*!< in: page level */ + mtr_t* mtr) /*!< in: mtr */ { fseg_header_t* seg_header; page_t* root; @@ -508,16 +510,16 @@ btr_page_free_low( buf_block_get_page_no(block), mtr); } -/****************************************************************** +/**************************************************************//** Frees a file page used in an index tree. NOTE: cannot free field external storage pages because the page must contain info on its level. */ UNIV_INTERN void btr_page_free( /*==========*/ - dict_index_t* index, /* in: index tree */ - buf_block_t* block, /* in: block to be freed, x-latched */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + buf_block_t* block, /*!< in: block to be freed, x-latched */ + mtr_t* mtr) /*!< in: mtr */ { ulint level; @@ -526,18 +528,18 @@ btr_page_free( btr_page_free_low(index, block, level, mtr); } -/****************************************************************** +/**************************************************************//** Sets the child node file address in a node pointer. */ UNIV_INLINE void btr_node_ptr_set_child_page_no( /*===========================*/ - rec_t* rec, /* in: node pointer record */ - page_zip_des_t* page_zip,/* in/out: compressed page whose uncompressed + rec_t* rec, /*!< in: node pointer record */ + page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed part will be updated, or NULL */ - const ulint* offsets,/* in: array returned by rec_get_offsets() */ - ulint page_no,/* in: child node address */ - mtr_t* mtr) /* in: mtr */ + const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ + ulint page_no,/*!< in: child node address */ + mtr_t* mtr) /*!< in: mtr */ { byte* field; ulint len; @@ -561,17 +563,17 @@ btr_node_ptr_set_child_page_no( } } -/**************************************************************** -Returns the child page of a node pointer and x-latches it. */ +/************************************************************//** +Returns the child page of a node pointer and x-latches it. +@return child page, x-latched */ static buf_block_t* btr_node_ptr_get_child( /*===================*/ - /* out: child page, x-latched */ - const rec_t* node_ptr,/* in: node pointer */ - dict_index_t* index, /* in: index */ - const ulint* offsets,/* in: array returned by rec_get_offsets() */ - mtr_t* mtr) /* in: mtr */ + const rec_t* node_ptr,/*!< in: node pointer */ + dict_index_t* index, /*!< in: index */ + const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ + mtr_t* mtr) /*!< in: mtr */ { ulint page_no; ulint space; @@ -584,21 +586,20 @@ btr_node_ptr_get_child( page_no, RW_X_LATCH, mtr)); } -/**************************************************************** +/************************************************************//** Returns the upper level node pointer to a page. It is assumed that mtr holds -an x-latch on the tree. */ +an x-latch on the tree. +@return rec_get_offsets() of the node pointer record */ static ulint* btr_page_get_father_node_ptr( /*=========================*/ - /* out: rec_get_offsets() of the - node pointer record */ - ulint* offsets,/* in: work area for the return value */ - mem_heap_t* heap, /* in: memory heap to use */ - btr_cur_t* cursor, /* in: cursor pointing to user record, + ulint* offsets,/*!< in: work area for the return value */ + mem_heap_t* heap, /*!< in: memory heap to use */ + btr_cur_t* cursor, /*!< in: cursor pointing to user record, out: cursor on node pointer record, its page x-latched */ - mtr_t* mtr) /* in: mtr */ + mtr_t* mtr) /*!< in: mtr */ { dtuple_t* tuple; rec_t* user_rec; @@ -659,8 +660,7 @@ btr_page_get_father_node_ptr( " to fix the\n" "InnoDB: corruption. If the crash happens at " "the database startup, see\n" - "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/" - "forcing-recovery.html about\n" + "InnoDB: " REFMAN "forcing-recovery.html about\n" "InnoDB: forcing recovery. " "Then dump + drop + reimport.\n", stderr); @@ -670,21 +670,20 @@ btr_page_get_father_node_ptr( return(offsets); } -/**************************************************************** +/************************************************************//** Returns the upper level node pointer to a page. It is assumed that mtr holds -an x-latch on the tree. */ +an x-latch on the tree. +@return rec_get_offsets() of the node pointer record */ static ulint* btr_page_get_father_block( /*======================*/ - /* out: rec_get_offsets() of the - node pointer record */ - ulint* 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* cursor) /* out: cursor on node pointer record, + ulint* 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* cursor) /*!< out: cursor on node pointer record, its page x-latched */ { rec_t* rec @@ -694,17 +693,17 @@ 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, + 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 */ { mem_heap_t* heap; @@ -718,21 +717,20 @@ btr_page_get_father( mem_heap_free(heap); } -/**************************************************************** -Creates the root node for a new index tree. */ +/************************************************************//** +Creates the root node for a new index tree. +@return page number of the created root, FIL_NULL if did not succeed */ UNIV_INTERN ulint btr_create( /*=======*/ - /* out: page number of the created root, - FIL_NULL if did not succeed */ - ulint type, /* in: type of the index */ - ulint space, /* in: space where created */ - ulint zip_size,/* in: compressed page size in bytes + ulint type, /*!< in: type of the index */ + ulint space, /*!< in: space where created */ + ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - dulint index_id,/* in: index id */ - dict_index_t* index, /* in: index */ - mtr_t* mtr) /* in: mini-transaction handle */ + dulint index_id,/*!< in: index id */ + dict_index_t* index, /*!< in: index */ + mtr_t* mtr) /*!< in: mini-transaction handle */ { ulint page_no; buf_block_t* block; @@ -837,17 +835,17 @@ btr_create( return(page_no); } -/**************************************************************** +/************************************************************//** Frees a B-tree except the root page, which MUST be freed after this by calling btr_free_root. */ UNIV_INTERN void btr_free_but_not_root( /*==================*/ - ulint space, /* in: space where created */ - ulint zip_size, /* in: compressed page size in bytes + ulint space, /*!< in: space where created */ + ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ - ulint root_page_no) /* in: root page number */ + ulint root_page_no) /*!< in: root page number */ { ibool finished; page_t* root; @@ -894,17 +892,17 @@ top_loop: } } -/**************************************************************** +/************************************************************//** Frees the B-tree root page. Other tree MUST already have been freed. */ UNIV_INTERN void btr_free_root( /*==========*/ - ulint space, /* in: space where created */ - ulint zip_size, /* in: compressed page size in bytes + ulint space, /*!< in: space where created */ + ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ - ulint root_page_no, /* in: root page number */ - mtr_t* mtr) /* in: a mini-transaction which has already + ulint root_page_no, /*!< in: root page number */ + mtr_t* mtr) /*!< in: a mini-transaction which has already been started */ { buf_block_t* block; @@ -921,21 +919,22 @@ btr_free_root( while (!fseg_free_step(header, mtr)); } +#endif /* !UNIV_HOTBACKUP */ -/***************************************************************** +/*************************************************************//** Reorganizes an index page. */ static ibool btr_page_reorganize_low( /*====================*/ - ibool recovery,/* in: TRUE if called in recovery: + ibool recovery,/*!< in: TRUE if called in recovery: locks should not be updated, i.e., there cannot exist locks on the page, and a hash index should not be dropped: it cannot exist */ - buf_block_t* block, /* in: page to be reorganized */ - dict_index_t* index, /* in: record descriptor */ - mtr_t* mtr) /* in: mtr */ + buf_block_t* block, /*!< in: page to be reorganized */ + dict_index_t* index, /*!< in: record descriptor */ + mtr_t* mtr) /*!< in: mtr */ { page_t* page = buf_block_get_frame(block); page_zip_des_t* page_zip = buf_block_get_page_zip(block); @@ -956,29 +955,39 @@ btr_page_reorganize_low( data_size1 = page_get_data_size(page); max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1); +#ifndef UNIV_HOTBACKUP /* Write the log record */ mlog_open_and_write_index(mtr, page, index, page_is_comp(page) ? MLOG_COMP_PAGE_REORGANIZE : MLOG_PAGE_REORGANIZE, 0); +#endif /* !UNIV_HOTBACKUP */ /* Turn logging off */ log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); +#ifndef UNIV_HOTBACKUP temp_block = buf_block_alloc(0); +#else /* !UNIV_HOTBACKUP */ + ut_ad(block == back_block1); + temp_block = back_block2; +#endif /* !UNIV_HOTBACKUP */ temp_page = temp_block->frame; /* Copy the old page to temporary space */ buf_frame_copy(temp_page, page); +#ifndef UNIV_HOTBACKUP if (UNIV_LIKELY(!recovery)) { btr_search_drop_page_hash_index(block); } + block->check_index_page_at_flush = TRUE; +#endif /* !UNIV_HOTBACKUP */ + /* Recreate the page: note that global data on page (possible segment headers, next page-field, etc.) is preserved intact */ page_create(block, mtr, dict_table_is_comp(index->table)); - block->check_index_page_at_flush = TRUE; /* Copy the records from the temporary space to the recreated page; do not copy the lock bits yet */ @@ -986,8 +995,16 @@ btr_page_reorganize_low( page_copy_rec_list_end_no_locks(block, temp_block, page_get_infimum_rec(temp_page), index, mtr); - /* Copy max trx id to recreated page */ - page_set_max_trx_id(block, NULL, page_get_max_trx_id(temp_page)); + + if (dict_index_is_sec_or_ibuf(index) && page_is_leaf(page)) { + /* Copy max trx id to recreated page */ + trx_id_t max_trx_id = page_get_max_trx_id(temp_page); + page_set_max_trx_id(block, NULL, max_trx_id, mtr); + /* In crash recovery, dict_index_is_sec_or_ibuf() always + returns TRUE, even for clustered indexes. max_trx_id is + unused in clustered index pages. */ + ut_ad(!ut_dulint_is_zero(max_trx_id) || recovery); + } if (UNIV_LIKELY_NULL(page_zip) && UNIV_UNLIKELY @@ -999,10 +1016,12 @@ btr_page_reorganize_low( goto func_exit; } +#ifndef UNIV_HOTBACKUP if (UNIV_LIKELY(!recovery)) { /* Update the record lock bitmaps */ lock_move_reorganize_page(block, temp_block); } +#endif /* !UNIV_HOTBACKUP */ data_size2 = page_get_data_size(page); max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1); @@ -1029,7 +1048,9 @@ func_exit: #ifdef UNIV_ZIP_DEBUG ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ +#ifndef UNIV_HOTBACKUP buf_block_free(temp_block); +#endif /* !UNIV_HOTBACKUP */ /* Restore logging mode */ mtr_set_log_mode(mtr, log_mode); @@ -1037,37 +1058,39 @@ func_exit: return(success); } -/***************************************************************** +#ifndef UNIV_HOTBACKUP +/*************************************************************//** Reorganizes an index page. IMPORTANT: if btr_page_reorganize() is invoked on a compressed leaf page of a non-clustered index, the caller must update the insert buffer free bits in the same mini-transaction in such a way that the -modification will be redo-logged. */ +modification will be redo-logged. +@return TRUE on success, FALSE on failure */ UNIV_INTERN ibool btr_page_reorganize( /*================*/ - /* out: TRUE on success, FALSE on failure */ - buf_block_t* block, /* in: page to be reorganized */ - dict_index_t* index, /* in: record descriptor */ - mtr_t* mtr) /* in: mtr */ + buf_block_t* block, /*!< in: page to be reorganized */ + dict_index_t* index, /*!< in: record descriptor */ + mtr_t* mtr) /*!< in: mtr */ { return(btr_page_reorganize_low(FALSE, block, index, mtr)); } +#endif /* !UNIV_HOTBACKUP */ -/*************************************************************** -Parses a redo log record of reorganizing a page. */ +/***********************************************************//** +Parses a redo log record of reorganizing a page. +@return end of log record or NULL */ UNIV_INTERN byte* btr_parse_page_reorganize( /*======================*/ - /* out: end of log record or NULL */ - byte* ptr, /* in: buffer */ + byte* ptr, /*!< in: buffer */ byte* end_ptr __attribute__((unused)), - /* in: buffer end */ - dict_index_t* index, /* in: record descriptor */ - buf_block_t* block, /* in: page to be reorganized, or NULL */ - mtr_t* mtr) /* in: mtr or NULL */ + /*!< in: buffer end */ + dict_index_t* index, /*!< in: record descriptor */ + buf_block_t* block, /*!< in: page to be reorganized, or NULL */ + mtr_t* mtr) /*!< in: mtr or NULL */ { ut_ad(ptr && end_ptr); @@ -1080,17 +1103,18 @@ btr_parse_page_reorganize( return(ptr); } -/***************************************************************** -Empties an index page. @see btr_page_create().*/ +#ifndef UNIV_HOTBACKUP +/*************************************************************//** +Empties an index page. @see btr_page_create(). */ static void btr_page_empty( /*===========*/ - buf_block_t* block, /* in: page to be emptied */ - page_zip_des_t* page_zip,/* out: compressed page, or NULL */ - dict_index_t* index, /* in: index of the page */ - ulint level, /* in: the B-tree level of the page */ - mtr_t* mtr) /* in: mtr */ + buf_block_t* block, /*!< in: page to be emptied */ + page_zip_des_t* page_zip,/*!< out: compressed page, or NULL */ + dict_index_t* index, /*!< in: index of the page */ + ulint level, /*!< in: the B-tree level of the page */ + mtr_t* mtr) /*!< in: mtr */ { page_t* page = buf_block_get_frame(block); @@ -1115,24 +1139,24 @@ btr_page_empty( block->check_index_page_at_flush = TRUE; } -/***************************************************************** +/*************************************************************//** Makes tree one level higher by splitting the root, and inserts the tuple. It is assumed that mtr contains an x-latch on the tree. NOTE that the operation of this function must always succeed, we cannot reverse it: therefore enough free disk space must be -guaranteed to be available before this function is called. */ +guaranteed to be available before this function is called. +@return inserted record */ UNIV_INTERN rec_t* btr_root_raise_and_insert( /*======================*/ - /* out: inserted record */ - btr_cur_t* cursor, /* in: cursor at which to insert: must be + btr_cur_t* cursor, /*!< in: cursor at which to insert: must be on the root page; when the function returns, the cursor is positioned on the predecessor of the inserted record */ - const dtuple_t* tuple, /* in: tuple to insert */ - ulint n_ext, /* in: number of externally stored columns */ - mtr_t* mtr) /* in: mtr */ + const dtuple_t* tuple, /*!< in: tuple to insert */ + ulint n_ext, /*!< in: number of externally stored columns */ + mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; page_t* root; @@ -1287,16 +1311,16 @@ btr_root_raise_and_insert( return(btr_page_split_and_insert(cursor, tuple, n_ext, mtr)); } -/***************************************************************** +/*************************************************************//** Decides if the page should be split at the convergence point of inserts -converging to the left. */ +converging to the left. +@return TRUE if split recommended */ UNIV_INTERN ibool btr_page_get_split_rec_to_left( /*===========================*/ - /* out: TRUE if split recommended */ - btr_cur_t* cursor, /* in: cursor at which to insert */ - rec_t** split_rec) /* out: if split recommended, + btr_cur_t* cursor, /*!< in: cursor at which to insert */ + rec_t** split_rec) /*!< out: if split recommended, the first record on upper half page, or NULL if tuple to be inserted should be first */ @@ -1332,16 +1356,16 @@ btr_page_get_split_rec_to_left( return(FALSE); } -/***************************************************************** +/*************************************************************//** Decides if the page should be split at the convergence point of inserts -converging to the right. */ +converging to the right. +@return TRUE if split recommended */ UNIV_INTERN ibool btr_page_get_split_rec_to_right( /*============================*/ - /* out: TRUE if split recommended */ - btr_cur_t* cursor, /* in: cursor at which to insert */ - rec_t** split_rec) /* out: if split recommended, + btr_cur_t* cursor, /*!< in: cursor at which to insert */ + rec_t** split_rec) /*!< out: if split recommended, the first record on upper half page, or NULL if tuple to be inserted should be first */ @@ -1390,19 +1414,19 @@ split_at_new: return(FALSE); } -/***************************************************************** +/*************************************************************//** Calculates a split record such that the tuple will certainly fit on its half-page when the split is performed. We assume in this function -only that the cursor page has at least one user record. */ +only that the cursor page has at least one user record. +@return split record, or NULL if tuple will be the first record on +upper half-page */ static rec_t* btr_page_get_sure_split_rec( /*========================*/ - /* out: split record, or NULL if tuple - will be the first record on upper half-page */ - btr_cur_t* cursor, /* in: cursor at which insert should be made */ - const dtuple_t* tuple, /* in: tuple to insert */ - ulint n_ext) /* in: number of externally stored columns */ + btr_cur_t* cursor, /*!< in: cursor at which insert should be made */ + const dtuple_t* tuple, /*!< in: tuple to insert */ + ulint n_ext) /*!< in: number of externally stored columns */ { page_t* page; page_zip_des_t* page_zip; @@ -1510,24 +1534,24 @@ func_exit: return(rec); } -/***************************************************************** +/*************************************************************//** Returns TRUE if the insert fits on the appropriate half-page with the -chosen split_rec. */ +chosen split_rec. +@return TRUE if fits */ static ibool btr_page_insert_fits( /*=================*/ - /* out: TRUE if fits */ - btr_cur_t* cursor, /* in: cursor at which insert + btr_cur_t* cursor, /*!< in: cursor at which insert should be made */ - const rec_t* split_rec,/* in: suggestion for first record + const rec_t* split_rec,/*!< in: suggestion for first record on upper half-page, or NULL if tuple to be inserted should be first */ - const ulint* offsets,/* in: rec_get_offsets( + const ulint* offsets,/*!< in: rec_get_offsets( split_rec, cursor->index) */ - const dtuple_t* tuple, /* in: tuple to insert */ - ulint n_ext, /* in: number of externally stored columns */ - mem_heap_t* heap) /* in: temporary memory heap */ + const dtuple_t* tuple, /*!< in: tuple to insert */ + ulint n_ext, /*!< in: number of externally stored columns */ + mem_heap_t* heap) /*!< in: temporary memory heap */ { page_t* page; ulint insert_size; @@ -1607,17 +1631,17 @@ btr_page_insert_fits( return(FALSE); } -/*********************************************************** +/*******************************************************//** Inserts a data tuple to a tree on a non-leaf level. It is assumed that mtr holds an x-latch on the tree. */ UNIV_INTERN void btr_insert_on_non_leaf_level( /*=========================*/ - dict_index_t* index, /* in: index */ - ulint level, /* in: level, must be > 0 */ - dtuple_t* tuple, /* in: the record to be inserted */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index */ + ulint level, /*!< in: level, must be > 0 */ + dtuple_t* tuple, /*!< in: the record to be inserted */ + mtr_t* mtr) /*!< in: mtr */ { big_rec_t* dummy_big_rec; btr_cur_t cursor; @@ -1638,20 +1662,20 @@ btr_insert_on_non_leaf_level( ut_a(err == DB_SUCCESS); } -/****************************************************************** +/**************************************************************//** Attaches the halves of an index page on the appropriate level in an index tree. */ static void btr_attach_half_pages( /*==================*/ - dict_index_t* index, /* in: the index tree */ - buf_block_t* block, /* in/out: page to be split */ - rec_t* split_rec, /* in: first record on upper + dict_index_t* index, /*!< in: the index tree */ + buf_block_t* block, /*!< in/out: page to be split */ + rec_t* split_rec, /*!< in: first record on upper half page */ - buf_block_t* new_block, /* in/out: the new half page */ - ulint direction, /* in: FSP_UP or FSP_DOWN */ - mtr_t* mtr) /* in: mtr */ + buf_block_t* new_block, /*!< in/out: the new half page */ + ulint direction, /*!< in: FSP_UP or FSP_DOWN */ + mtr_t* mtr) /*!< in: mtr */ { ulint space; ulint zip_size; @@ -1773,26 +1797,25 @@ btr_attach_half_pages( btr_page_set_next(upper_page, upper_page_zip, next_page_no, mtr); } -/***************************************************************** +/*************************************************************//** Splits an index page to halves and inserts the tuple. It is assumed -that mtr holds an x-latch to the index tree. NOTE: the tree x-latch -is released within this function! NOTE that the operation of this -function must always succeed, we cannot reverse it: therefore -enough free disk space must be guaranteed to be available before -this function is called. */ +that mtr holds an x-latch to the index tree. NOTE: the tree x-latch is +released within this function! NOTE that the operation of this +function must always succeed, we cannot reverse it: therefore enough +free disk space (2 pages) must be guaranteed to be available before +this function is called. + +@return inserted record */ UNIV_INTERN rec_t* btr_page_split_and_insert( /*======================*/ - /* out: inserted record; NOTE: the tree - x-latch is released! NOTE: 2 free disk - pages must be available! */ - btr_cur_t* cursor, /* in: cursor at which to insert; when the + btr_cur_t* cursor, /*!< in: cursor at which to insert; when the function returns, the cursor is positioned on the predecessor of the inserted record */ - const dtuple_t* tuple, /* in: tuple to insert */ - ulint n_ext, /* in: number of externally stored columns */ - mtr_t* mtr) /* in: mtr */ + const dtuple_t* tuple, /*!< in: tuple to insert */ + ulint n_ext, /*!< in: number of externally stored columns */ + mtr_t* mtr) /*!< in: mtr */ { buf_block_t* block; page_t* page; @@ -2144,17 +2167,17 @@ func_exit: return(rec); } -/***************************************************************** +/*************************************************************//** Removes a page from the level list of pages. */ static void btr_level_list_remove( /*==================*/ - ulint space, /* in: space where removed */ - ulint zip_size,/* in: compressed page size in bytes + ulint space, /*!< in: space where removed */ + ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - page_t* page, /* in: page to remove */ - mtr_t* mtr) /* in: mtr */ + page_t* page, /*!< in: page to remove */ + mtr_t* mtr) /*!< in: mtr */ { ulint prev_page_no; ulint next_page_no; @@ -2204,36 +2227,39 @@ btr_level_list_remove( } } -/******************************************************************** +/****************************************************************//** Writes the redo log record for setting an index record as the predefined minimum record. */ UNIV_INLINE void btr_set_min_rec_mark_log( /*=====================*/ - rec_t* rec, /* in: record */ - byte type, /* in: MLOG_COMP_REC_MIN_MARK or MLOG_REC_MIN_MARK */ - mtr_t* mtr) /* in: mtr */ + rec_t* rec, /*!< in: record */ + byte type, /*!< in: MLOG_COMP_REC_MIN_MARK or MLOG_REC_MIN_MARK */ + mtr_t* mtr) /*!< in: mtr */ { mlog_write_initial_log_record(rec, type, mtr); /* Write rec offset as a 2-byte ulint */ mlog_catenate_ulint(mtr, page_offset(rec), MLOG_2BYTES); } +#else /* !UNIV_HOTBACKUP */ +# define btr_set_min_rec_mark_log(rec,comp,mtr) ((void) 0) +#endif /* !UNIV_HOTBACKUP */ -/******************************************************************** +/****************************************************************//** Parses the redo log record for setting an index record as the predefined -minimum record. */ +minimum record. +@return end of log record or NULL */ UNIV_INTERN byte* btr_parse_set_min_rec_mark( /*=======================*/ - /* out: end of log record or NULL */ - byte* ptr, /* in: buffer */ - byte* end_ptr,/* in: buffer end */ - ulint comp, /* in: nonzero=compact page format */ - page_t* page, /* in: page or NULL */ - mtr_t* mtr) /* in: mtr or NULL */ + byte* ptr, /*!< in: buffer */ + byte* end_ptr,/*!< in: buffer end */ + ulint comp, /*!< in: nonzero=compact page format */ + page_t* page, /*!< in: page or NULL */ + mtr_t* mtr) /*!< in: mtr or NULL */ { rec_t* rec; @@ -2253,14 +2279,14 @@ btr_parse_set_min_rec_mark( return(ptr + 2); } -/******************************************************************** +/****************************************************************//** Sets a record as the predefined minimum record. */ UNIV_INTERN void btr_set_min_rec_mark( /*=================*/ - rec_t* rec, /* in: record */ - mtr_t* mtr) /* in: mtr */ + rec_t* rec, /*!< in: record */ + mtr_t* mtr) /*!< in: mtr */ { ulint info_bits; @@ -2279,15 +2305,16 @@ btr_set_min_rec_mark( } } -/***************************************************************** +#ifndef UNIV_HOTBACKUP +/*************************************************************//** Deletes on the upper level the node pointer to a page. */ UNIV_INTERN 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 */ + 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; @@ -2307,19 +2334,19 @@ btr_node_ptr_delete( } } -/***************************************************************** +/*************************************************************//** If page is the only on its level, this function moves its records to the father page, thus reducing the tree height. */ static void btr_lift_page_up( /*=============*/ - dict_index_t* index, /* in: index tree */ - buf_block_t* block, /* in: page which is the only on its level; + dict_index_t* index, /*!< in: index tree */ + buf_block_t* block, /*!< in: page which is the only on its level; must not be empty: use btr_discard_only_page_on_level if the last record from the page should be removed */ - mtr_t* mtr) /* in: mtr */ + mtr_t* mtr) /*!< in: mtr */ { buf_block_t* father_block; page_t* father_page; @@ -2328,7 +2355,7 @@ btr_lift_page_up( page_t* page = buf_block_get_frame(block); ulint root_page_no; buf_block_t* blocks[BTR_MAX_LEVELS]; - ulint n_blocks; /* last used index in blocks[] */ + ulint n_blocks; /*!< last used index in blocks[] */ ulint i; ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL); @@ -2429,7 +2456,7 @@ btr_lift_page_up( ut_ad(btr_check_node_ptr(index, father_block, mtr)); } -/***************************************************************** +/*************************************************************//** Tries to merge the page first to the left immediate brother if such a brother exists, and the node pointers to the current page and to the brother reside on the same page. If the left brother does not satisfy these @@ -2437,17 +2464,17 @@ conditions, looks at the right brother. If the page is the only one on that level lifts the records of the page to the father page, thus reducing the tree height. It is assumed that mtr holds an x-latch on the tree and on the page. If cursor is on the leaf level, mtr must also hold x-latches to the -brothers, if they exist. */ +brothers, if they exist. +@return TRUE on success */ UNIV_INTERN ibool btr_compress( /*=========*/ - /* out: TRUE on success */ - btr_cur_t* cursor, /* in: cursor on the page to merge or lift; + btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift; the page must not be empty: in record delete use btr_discard_page if the page would become empty */ - mtr_t* mtr) /* in: mtr */ + mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; ulint space; @@ -2721,7 +2748,7 @@ err_exit: return(TRUE); } -/***************************************************************** +/*************************************************************//** 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 @@ -2730,11 +2757,15 @@ static void btr_discard_only_page_on_level( /*===========================*/ - dict_index_t* index, /* in: index tree */ - buf_block_t* block, /* in: page which is the only on its level */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + buf_block_t* block, /*!< in: page which is the only on its level */ + mtr_t* mtr) /*!< in: mtr */ { - ulint page_level = 0; + ulint page_level = 0; + trx_id_t max_trx_id; + + /* Save the PAGE_MAX_TRX_ID from the leaf page. */ + max_trx_id = page_get_max_trx_id(buf_block_get_frame(block)); while (buf_block_get_page_no(block) != dict_index_get_page(index)) { btr_cur_t cursor; @@ -2777,13 +2808,20 @@ btr_discard_only_page_on_level( btr_page_empty(block, buf_block_get_page_zip(block), index, 0, mtr); - /* We play it safe and reset the free bits for the root */ if (!dict_index_is_clust(index)) { + /* We play it safe and reset the free bits for the root */ ibuf_reset_free_bits(block); + + if (page_is_leaf(buf_block_get_frame(block))) { + ut_a(!ut_dulint_is_zero(max_trx_id)); + page_set_max_trx_id(block, + buf_block_get_page_zip(block), + max_trx_id, mtr); + } } } -/***************************************************************** +/*************************************************************//** Discards a page from a B-tree. This is used to remove the last record from a B-tree page: the whole page must be removed at the same time. This cannot be used for the root page, which is allowed to be empty. */ @@ -2791,9 +2829,9 @@ UNIV_INTERN void btr_discard_page( /*=============*/ - btr_cur_t* cursor, /* in: cursor on the page to discard: not on + btr_cur_t* cursor, /*!< in: cursor on the page to discard: not on the root page */ - mtr_t* mtr) /* in: mtr */ + mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; ulint space; @@ -2892,13 +2930,13 @@ btr_discard_page( } #ifdef UNIV_BTR_PRINT -/***************************************************************** +/*************************************************************//** Prints size info of a B-tree. */ UNIV_INTERN void btr_print_size( /*===========*/ - dict_index_t* index) /* in: index tree */ + dict_index_t* index) /*!< in: index tree */ { page_t* root; fseg_header_t* seg; @@ -2931,19 +2969,19 @@ btr_print_size( mtr_commit(&mtr); } -/**************************************************************** +/************************************************************//** Prints recursively index tree pages. */ static void btr_print_recursive( /*================*/ - dict_index_t* index, /* in: index tree */ - buf_block_t* block, /* in: index page */ - ulint width, /* in: print this many entries from start + dict_index_t* index, /*!< in: index tree */ + buf_block_t* block, /*!< in: index page */ + ulint width, /*!< in: print this many entries from start and end */ - mem_heap_t** heap, /* in/out: heap for rec_get_offsets() */ - ulint** offsets,/* in/out: buffer for rec_get_offsets() */ - mtr_t* mtr) /* in: mtr */ + mem_heap_t** heap, /*!< in/out: heap for rec_get_offsets() */ + ulint** offsets,/*!< in/out: buffer for rec_get_offsets() */ + mtr_t* mtr) /*!< in: mtr */ { const page_t* page = buf_block_get_frame(block); page_cur_t cursor; @@ -2993,14 +3031,14 @@ btr_print_recursive( } } -/****************************************************************** +/**************************************************************//** Prints directories and other info of all nodes in the tree. */ UNIV_INTERN void btr_print_index( /*============*/ - dict_index_t* index, /* in: index */ - ulint width) /* in: print this many entries from start + dict_index_t* index, /*!< in: index */ + ulint width) /*!< in: print this many entries from start and end */ { mtr_t mtr; @@ -3029,16 +3067,16 @@ btr_print_index( #endif /* UNIV_BTR_PRINT */ #ifdef UNIV_DEBUG -/**************************************************************** -Checks that the node pointer to a page is appropriate. */ +/************************************************************//** +Checks that the node pointer to a page is appropriate. +@return TRUE */ UNIV_INTERN ibool btr_check_node_ptr( /*===============*/ - /* out: TRUE */ - dict_index_t* index, /* in: index tree */ - buf_block_t* block, /* in: index page */ - mtr_t* mtr) /* in: mtr */ + dict_index_t* index, /*!< in: index tree */ + buf_block_t* block, /*!< in: index page */ + mtr_t* mtr) /*!< in: mtr */ { mem_heap_t* heap; dtuple_t* tuple; @@ -3073,15 +3111,15 @@ func_exit: } #endif /* UNIV_DEBUG */ -/**************************************************************** +/************************************************************//** Display identification information for a record. */ static void btr_index_rec_validate_report( /*==========================*/ - const page_t* page, /* in: index page */ - const rec_t* rec, /* in: index record */ - const dict_index_t* index) /* in: index */ + const page_t* page, /*!< in: index page */ + const rec_t* rec, /*!< in: index record */ + const dict_index_t* index) /*!< in: index */ { fputs("InnoDB: Record in ", stderr); dict_index_name_print(stderr, NULL, index); @@ -3089,17 +3127,17 @@ btr_index_rec_validate_report( page_get_page_no(page), (ulint) page_offset(rec)); } -/**************************************************************** +/************************************************************//** Checks the size and number of fields in a record based on the definition of -the index. */ +the index. +@return TRUE if ok */ UNIV_INTERN ibool btr_index_rec_validate( /*===================*/ - /* out: TRUE if ok */ - const rec_t* rec, /* in: index record */ - const dict_index_t* index, /* in: index */ - ibool dump_on_error) /* in: TRUE if the function + const rec_t* rec, /*!< in: index record */ + const dict_index_t* index, /*!< in: index */ + ibool dump_on_error) /*!< in: TRUE if the function should print hex dump of record and page on error */ { @@ -3154,7 +3192,7 @@ btr_index_rec_validate( for (i = 0; i < n; i++) { ulint fixed_size = dict_col_get_fixed_size( - dict_index_get_nth_col(index, i)); + dict_index_get_nth_col(index, i), page_is_comp(page)); rec_get_nth_field_offs(offsets, i, &len); @@ -3198,16 +3236,16 @@ btr_index_rec_validate( return(TRUE); } -/**************************************************************** +/************************************************************//** Checks the size and number of fields in records based on the definition of -the index. */ +the index. +@return TRUE if ok */ static ibool btr_index_page_validate( /*====================*/ - /* out: TRUE if ok */ - buf_block_t* block, /* in: index page */ - dict_index_t* index) /* in: index */ + buf_block_t* block, /*!< in: index page */ + dict_index_t* index) /*!< in: index */ { page_cur_t cur; ibool ret = TRUE; @@ -3232,16 +3270,15 @@ btr_index_page_validate( return(ret); } -/**************************************************************** +/************************************************************//** Report an error on one page of an index tree. */ static void btr_validate_report1( /*=================*/ - /* out: TRUE if ok */ - dict_index_t* index, /* in: index */ - ulint level, /* in: B-tree level */ - const buf_block_t* block) /* in: index page */ + dict_index_t* index, /*!< in: index */ + ulint level, /*!< in: B-tree level */ + const buf_block_t* block) /*!< in: index page */ { fprintf(stderr, "InnoDB: Error in page %lu of ", buf_block_get_page_no(block)); @@ -3252,17 +3289,16 @@ btr_validate_report1( putc('\n', stderr); } -/**************************************************************** +/************************************************************//** Report an error on two pages of an index tree. */ static void btr_validate_report2( /*=================*/ - /* out: TRUE if ok */ - const dict_index_t* index, /* in: index */ - ulint level, /* in: B-tree level */ - const buf_block_t* block1, /* in: first index page */ - const buf_block_t* block2) /* in: second index page */ + const dict_index_t* index, /*!< in: index */ + ulint level, /*!< in: B-tree level */ + const buf_block_t* block1, /*!< in: first index page */ + const buf_block_t* block2) /*!< in: second index page */ { fprintf(stderr, "InnoDB: Error in pages %lu and %lu of ", buf_block_get_page_no(block1), @@ -3274,16 +3310,16 @@ btr_validate_report2( putc('\n', stderr); } -/**************************************************************** -Validates index tree level. */ +/************************************************************//** +Validates index tree level. +@return TRUE if ok */ static ibool btr_validate_level( /*===============*/ - /* out: TRUE if ok */ - dict_index_t* index, /* in: index tree */ - trx_t* trx, /* in: transaction or NULL */ - ulint level) /* in: level number */ + dict_index_t* index, /*!< in: index tree */ + trx_t* trx, /*!< in: transaction or NULL */ + ulint level) /*!< in: level number */ { ulint space; ulint zip_size; @@ -3620,15 +3656,15 @@ node_ptr_fails: return(ret); } -/****************************************************************** -Checks the consistency of an index tree. */ +/**************************************************************//** +Checks the consistency of an index tree. +@return TRUE if ok */ UNIV_INTERN ibool btr_validate_index( /*===============*/ - /* out: TRUE if ok */ - dict_index_t* index, /* in: index */ - trx_t* trx) /* in: transaction or NULL */ + dict_index_t* index, /*!< in: index */ + trx_t* trx) /*!< in: transaction or NULL */ { mtr_t mtr; page_t* root; @@ -3654,3 +3690,4 @@ btr_validate_index( return(TRUE); } +#endif /* !UNIV_HOTBACKUP */ |