📄 btr0cur.c
字号:
/******************************************************The index tree cursorAll changes that row operations make to a B-tree or the recordsthere must go through this module! Undo log records are written hereof every modify or insert of a clustered index record. NOTE!!!To make sure we do not run out of disk space during a pessimisticinsert or update, we have to reserve 2 x the height of the index treemany pages in the tablespace before we start the operation, becauseif leaf splitting has been started, it is difficult to undo, exceptby crashing the database and doing a roll-forward.(c) 1994-2001 Innobase OyCreated 10/16/1994 Heikki Tuuri*******************************************************/#include "btr0cur.h"#ifdef UNIV_NONINL#include "btr0cur.ic"#endif#include "page0page.h"#include "rem0rec.h"#include "rem0cmp.h"#include "btr0btr.h"#include "btr0sea.h"#include "row0upd.h"#include "trx0rec.h"#include "que0que.h"#include "row0row.h"#include "srv0srv.h"#include "ibuf0ibuf.h"#include "lock0lock.h"#ifdef UNIV_DEBUG/* If the following is set to TRUE, this module prints a lot oftrace information of individual record operations */ibool btr_cur_print_record_ops = FALSE;#endif /* UNIV_DEBUG */ulint btr_cur_n_non_sea = 0;ulint btr_cur_n_sea = 0;ulint btr_cur_n_non_sea_old = 0;ulint btr_cur_n_sea_old = 0;/* In the optimistic insert, if the insert does not fit, but this much spacecan be released by page reorganize, then it is reorganized */#define BTR_CUR_PAGE_REORGANIZE_LIMIT (UNIV_PAGE_SIZE / 32)/* When estimating number of different kay values in an index samplethis many index pages */#define BTR_KEY_VAL_ESTIMATE_N_PAGES 8/* The structure of a BLOB part header *//*--------------------------------------*/#define BTR_BLOB_HDR_PART_LEN 0 /* BLOB part len on this page */#define BTR_BLOB_HDR_NEXT_PAGE_NO 4 /* next BLOB part page no, FIL_NULL if none *//*--------------------------------------*/#define BTR_BLOB_HDR_SIZE 8/***********************************************************************Marks all extern fields in a record as owned by the record. This functionshould be called if the delete mark of a record is removed: a not deletemarked record always owns all its extern fields. */staticvoidbtr_cur_unmark_extern_fields(/*=========================*/ rec_t* rec, /* in: record in a clustered index */ mtr_t* mtr, /* in: mtr */ const ulint* offsets);/* in: array returned by rec_get_offsets() *//***********************************************************************Adds path information to the cursor for the current page, for whichthe binary search has been performed. */staticvoidbtr_cur_add_path_info(/*==================*/ btr_cur_t* cursor, /* in: cursor positioned on a page */ ulint height, /* in: height of the page in tree; 0 means leaf node */ ulint root_height); /* in: root node height in tree *//***************************************************************Frees the externally stored fields for a record, if the field is mentionedin the update vector. */staticvoidbtr_rec_free_updated_extern_fields(/*===============================*/ dict_index_t* index, /* in: index of rec; the index tree MUST be X-latched */ rec_t* rec, /* in: record */ const ulint* offsets,/* in: rec_get_offsets(rec, index) */ upd_t* update, /* in: update vector */ ibool do_not_free_inherited,/* in: TRUE if called in a rollback and we do not want to free inherited fields */ mtr_t* mtr); /* in: mini-transaction handle which contains an X-latch to record page and to the tree *//***************************************************************Gets the externally stored size of a record, in units of a database page. */staticulintbtr_rec_get_externally_stored_len(/*==============================*/ /* out: externally stored part, in units of a database page */ rec_t* rec, /* in: record */ const ulint* offsets);/* in: array returned by rec_get_offsets() *//*==================== B-TREE SEARCH =========================*/ /************************************************************************Latches the leaf page or pages requested. */staticvoidbtr_cur_latch_leaves(/*=================*/ page_t* page, /* in: leaf page where the search converged */ ulint space, /* in: space id */ ulint page_no, /* in: page number of the leaf */ ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ btr_cur_t* cursor, /* in: cursor */ mtr_t* mtr) /* in: mtr */{ ulint left_page_no; ulint right_page_no; page_t* get_page; ut_ad(page && mtr); if (latch_mode == BTR_SEARCH_LEAF) { get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr); ut_a(page_is_comp(get_page) == page_is_comp(page)); buf_block_align(get_page)->check_index_page_at_flush = TRUE; } else if (latch_mode == BTR_MODIFY_LEAF) { get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr); ut_a(page_is_comp(get_page) == page_is_comp(page)); buf_block_align(get_page)->check_index_page_at_flush = TRUE; } else if (latch_mode == BTR_MODIFY_TREE) { /* x-latch also brothers from left to right */ left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { get_page = btr_page_get(space, left_page_no, RW_X_LATCH, mtr); ut_a(page_is_comp(get_page) == page_is_comp(page)); buf_block_align(get_page)->check_index_page_at_flush = TRUE; } get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr); ut_a(page_is_comp(get_page) == page_is_comp(page)); buf_block_align(get_page)->check_index_page_at_flush = TRUE; right_page_no = btr_page_get_next(page, mtr); if (right_page_no != FIL_NULL) { get_page = btr_page_get(space, right_page_no, RW_X_LATCH, mtr); buf_block_align(get_page)->check_index_page_at_flush = TRUE; } } else if (latch_mode == BTR_SEARCH_PREV) { /* s-latch also left brother */ left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { cursor->left_page = btr_page_get(space, left_page_no, RW_S_LATCH, mtr); ut_a(page_is_comp(cursor->left_page) == page_is_comp(page)); buf_block_align( cursor->left_page)->check_index_page_at_flush = TRUE; } get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr); ut_a(page_is_comp(get_page) == page_is_comp(page)); buf_block_align(get_page)->check_index_page_at_flush = TRUE; } else if (latch_mode == BTR_MODIFY_PREV) { /* x-latch also left brother */ left_page_no = btr_page_get_prev(page, mtr); if (left_page_no != FIL_NULL) { cursor->left_page = btr_page_get(space, left_page_no, RW_X_LATCH, mtr); ut_a(page_is_comp(cursor->left_page) == page_is_comp(page)); buf_block_align( cursor->left_page)->check_index_page_at_flush = TRUE; } get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr); ut_a(page_is_comp(get_page) == page_is_comp(page)); buf_block_align(get_page)->check_index_page_at_flush = TRUE; } else { ut_error; }}/************************************************************************Searches an index tree and positions a tree cursor on a given level.NOTE: n_fields_cmp in tuple must be set so that it cannot be comparedto 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, thencursor->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. */voidbtr_cur_search_to_nth_level(/*========================*/ dict_index_t* index, /* in: index */ ulint level, /* in: the tree level of search */ dtuple_t* tuple, /* in: data tuple; NOTE: n_fields_cmp in tuple must be set so that it cannot get compared to the node ptr page number field! */ ulint mode, /* in: PAGE_CUR_L, ...; Inserts should always be made using PAGE_CUR_LE to search the position! */ ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with BTR_INSERT and BTR_ESTIMATE; cursor->left_page is used to store a pointer to the left neighbor page, in the cases BTR_SEARCH_PREV and BTR_MODIFY_PREV; NOTE that if has_search_latch is != 0, we maybe do not have a latch set on the cursor page, we assume the caller uses his search latch to protect the record! */ btr_cur_t* cursor, /* in/out: tree cursor; the cursor page is s- or x-latched, but see also above! */ ulint has_search_latch,/* in: info on the latch mode the caller currently has on btr_search_latch: RW_S_LATCH, or 0 */ mtr_t* mtr) /* in: mtr */{ dict_tree_t* tree; page_cur_t* page_cursor; page_t* page; page_t* guess; rec_t* node_ptr; ulint page_no; ulint space; ulint up_match; ulint up_bytes; ulint low_match; ulint low_bytes; ulint height; ulint savepoint; ulint rw_latch; ulint page_mode; ulint insert_planned; ulint buf_mode; ulint estimate; ulint ignore_sec_unique; ulint root_height = 0; /* remove warning */#ifdef BTR_CUR_ADAPT btr_search_t* info;#endif mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; /* Currently, PAGE_CUR_LE is the only search mode used for searches ending to upper levels */ ut_ad(level == 0 || mode == PAGE_CUR_LE); ut_ad(dict_tree_check_search_tuple(index->tree, tuple)); ut_ad(!(index->type & DICT_IBUF) || ibuf_inside()); ut_ad(dtuple_check_typed(tuple));#ifdef UNIV_DEBUG cursor->up_match = ULINT_UNDEFINED; cursor->low_match = ULINT_UNDEFINED;#endif insert_planned = latch_mode & BTR_INSERT; estimate = latch_mode & BTR_ESTIMATE; ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE; latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE | BTR_IGNORE_SEC_UNIQUE); ut_ad(!insert_planned || (mode == PAGE_CUR_LE)); cursor->flag = BTR_CUR_BINARY; cursor->index = index;#ifndef BTR_CUR_ADAPT guess = NULL;#else info = btr_search_get_info(index); guess = info->root_guess;#ifdef BTR_CUR_HASH_ADAPT#ifdef UNIV_SEARCH_PERF_STAT info->n_searches++;#endif if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ && !estimate#ifdef PAGE_CUR_LE_OR_EXTENDS && mode != PAGE_CUR_LE_OR_EXTENDS#endif /* PAGE_CUR_LE_OR_EXTENDS */ && srv_use_adaptive_hash_indexes && btr_search_guess_on_hash(index, info, tuple, mode, latch_mode, cursor, has_search_latch, mtr)) { /* Search using the hash index succeeded */ ut_ad(cursor->up_match != ULINT_UNDEFINED || mode != PAGE_CUR_GE); ut_ad(cursor->up_match != ULINT_UNDEFINED || mode != PAGE_CUR_LE); ut_ad(cursor->low_match != ULINT_UNDEFINED || mode != PAGE_CUR_LE); btr_cur_n_sea++; return; }#endif#endif btr_cur_n_non_sea++; /* If the hash search did not succeed, do binary search down the tree */ if (has_search_latch) { /* Release possible search latch to obey latching order */ rw_lock_s_unlock(&btr_search_latch); } /* Store the position of the tree latch we push to mtr so that we know how to release it when we have latched leaf node(s) */ savepoint = mtr_set_savepoint(mtr); tree = index->tree; if (latch_mode == BTR_MODIFY_TREE) { mtr_x_lock(dict_tree_get_lock(tree), mtr); } else if (latch_mode == BTR_CONT_MODIFY_TREE) { /* Do nothing */ ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_X_LOCK)); } else { mtr_s_lock(dict_tree_get_lock(tree), mtr); } page_cursor = btr_cur_get_page_cur(cursor); space = dict_tree_get_space(tree); page_no = dict_tree_get_page(tree); up_match = 0; up_bytes = 0; low_match = 0; low_bytes = 0; height = ULINT_UNDEFINED; rw_latch = RW_NO_LATCH; buf_mode = BUF_GET; /* We use these modified search modes on non-leaf levels of the B-tree. These let us end up in the right B-tree leaf. In that leaf we use the original search mode. */ switch (mode) { case PAGE_CUR_GE: page_mode = PAGE_CUR_L; break; case PAGE_CUR_G: page_mode = PAGE_CUR_LE; break; default:#ifdef PAGE_CUR_LE_OR_EXTENDS ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE || mode == PAGE_CUR_LE_OR_EXTENDS);#else /* PAGE_CUR_LE_OR_EXTENDS */ ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE);#endif /* PAGE_CUR_LE_OR_EXTENDS */ page_mode = mode; break; } /* Loop and search until we arrive at the desired level */ for (;;) { if ((height == 0) && (latch_mode <= BTR_MODIFY_LEAF)) { rw_latch = latch_mode; if (insert_planned && ibuf_should_try(index, ignore_sec_unique)) { /* Try insert to the insert buffer if the page is not in the buffer pool */ buf_mode = BUF_GET_IF_IN_POOL; } }retry_page_get: page = buf_page_get_gen(space, page_no, rw_latch, guess, buf_mode, __FILE__, __LINE__, mtr); if (page == NULL) { /* This must be a search to perform an insert; try insert to the insert buffer */ ut_ad(buf_mode == BUF_GET_IF_IN_POOL); ut_ad(insert_planned); ut_ad(cursor->thr); if (ibuf_should_try(index, ignore_sec_unique) && ibuf_insert(tuple, index, space, page_no, cursor->thr)) { /* Insertion to the insert buffer succeeded */ cursor->flag = BTR_CUR_INSERT_TO_IBUF; if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } return; } /* Insert to the insert buffer did not succeed: retry page get */ buf_mode = BUF_GET; goto retry_page_get; } buf_block_align(page)->check_index_page_at_flush = TRUE; #ifdef UNIV_SYNC_DEBUG if (rw_latch != RW_NO_LATCH) { buf_page_dbg_add_level(page, SYNC_TREE_NODE); }#endif ut_ad(0 == ut_dulint_cmp(tree->id, btr_page_get_index_id(page))); if (height == ULINT_UNDEFINED) { /* We are in the root node */ height = btr_page_get_level(page, mtr); root_height = height; cursor->tree_height = root_height + 1;#ifdef BTR_CUR_ADAPT if (page != guess) { info->root_guess = page; } #endif } if (height == 0) { if (rw_latch == RW_NO_LATCH) { btr_cur_latch_leaves(page, space, page_no, latch_mode, cursor, mtr); } if ((latch_mode != BTR_MODIFY_TREE) && (latch_mode != BTR_CONT_MODIFY_TREE)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -