📄 btr0cur.c
字号:
/* Release the tree s-latch */ mtr_release_s_latch_at_savepoint( mtr, savepoint, dict_tree_get_lock(tree)); } page_mode = mode; } page_cur_search_with_match(page, index, tuple, page_mode, &up_match, &up_bytes, &low_match, &low_bytes, page_cursor); if (estimate) { btr_cur_add_path_info(cursor, height, root_height); } /* If this is the desired level, leave the loop */ ut_ad(height == btr_page_get_level(page_cur_get_page(page_cursor), mtr)); if (level == height) { if (level > 0) { /* x-latch the page */ page = btr_page_get(space, page_no, RW_X_LATCH, mtr); ut_a((ibool)!!page_is_comp(page) == index->table->comp); } break; } ut_ad(height > 0); height--; guess = NULL; node_ptr = page_cur_get_rec(page_cursor); offsets = rec_get_offsets(node_ptr, cursor->index, offsets, ULINT_UNDEFINED, &heap); /* Go to the child node */ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } if (level == 0) { cursor->low_match = low_match; cursor->low_bytes = low_bytes; cursor->up_match = up_match; cursor->up_bytes = up_bytes;#ifdef BTR_CUR_ADAPT if (srv_use_adaptive_hash_indexes) { btr_search_info_update(index, cursor); }#endif 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); } if (has_search_latch) { rw_lock_s_lock(&btr_search_latch); }}/*********************************************************************Opens a cursor at either end of an index. */voidbtr_cur_open_at_index_side(/*=======================*/ ibool 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: cursor */ mtr_t* mtr) /* in: mtr */{ page_cur_t* page_cursor; dict_tree_t* tree; page_t* page; ulint page_no; ulint space; ulint height; ulint root_height = 0; /* remove warning */ rec_t* node_ptr; ulint estimate; ulint savepoint; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; estimate = latch_mode & BTR_ESTIMATE; latch_mode = latch_mode & ~BTR_ESTIMATE; tree = index->tree; /* Store the position of the tree latch we push to mtr so that we know how to release it when we have latched the leaf node */ savepoint = mtr_set_savepoint(mtr); if (latch_mode == BTR_MODIFY_TREE) { mtr_x_lock(dict_tree_get_lock(tree), mtr); } else { mtr_s_lock(dict_tree_get_lock(tree), mtr); } page_cursor = btr_cur_get_page_cur(cursor); cursor->index = index; space = dict_tree_get_space(tree); page_no = dict_tree_get_page(tree); height = ULINT_UNDEFINED; for (;;) { page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL, BUF_GET, __FILE__, __LINE__, mtr); ut_ad(0 == ut_dulint_cmp(tree->id, btr_page_get_index_id(page))); buf_block_align(page)->check_index_page_at_flush = TRUE; if (height == ULINT_UNDEFINED) { /* We are in the root node */ height = btr_page_get_level(page, mtr); root_height = height; } if (height == 0) { btr_cur_latch_leaves(page, space, page_no, latch_mode, cursor, mtr); /* In versions <= 3.23.52 we had forgotten to release the tree latch here. If in an index scan we had to scan far to find a record visible to the current transaction, that could starve others waiting for the tree latch. */ if ((latch_mode != BTR_MODIFY_TREE) && (latch_mode != BTR_CONT_MODIFY_TREE)) { /* Release the tree s-latch */ mtr_release_s_latch_at_savepoint( mtr, savepoint, dict_tree_get_lock(tree)); } } if (from_left) { page_cur_set_before_first(page, page_cursor); } else { page_cur_set_after_last(page, page_cursor); } if (height == 0) { if (estimate) { btr_cur_add_path_info(cursor, height, root_height); } break; } ut_ad(height > 0); if (from_left) { page_cur_move_to_next(page_cursor); } else { page_cur_move_to_prev(page_cursor); } if (estimate) { btr_cur_add_path_info(cursor, height, root_height); } height--; node_ptr = page_cur_get_rec(page_cursor); offsets = rec_get_offsets(node_ptr, cursor->index, offsets, ULINT_UNDEFINED, &heap); /* Go to the child node */ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); }} /**************************************************************************Positions a cursor at a randomly chosen position within a B-tree. */voidbtr_cur_open_at_rnd_pos(/*====================*/ dict_index_t* index, /* in: index */ ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */ btr_cur_t* cursor, /* in/out: B-tree cursor */ mtr_t* mtr) /* in: mtr */{ page_cur_t* page_cursor; dict_tree_t* tree; page_t* page; ulint page_no; ulint space; ulint height; rec_t* node_ptr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; tree = index->tree; if (latch_mode == BTR_MODIFY_TREE) { mtr_x_lock(dict_tree_get_lock(tree), mtr); } else { mtr_s_lock(dict_tree_get_lock(tree), mtr); } page_cursor = btr_cur_get_page_cur(cursor); cursor->index = index; space = dict_tree_get_space(tree); page_no = dict_tree_get_page(tree); height = ULINT_UNDEFINED; for (;;) { page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL, BUF_GET, __FILE__, __LINE__, mtr); 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); } if (height == 0) { btr_cur_latch_leaves(page, space, page_no, latch_mode, cursor, mtr); } page_cur_open_on_rnd_user_rec(page, page_cursor); if (height == 0) { break; } ut_ad(height > 0); height--; node_ptr = page_cur_get_rec(page_cursor); offsets = rec_get_offsets(node_ptr, cursor->index, offsets, ULINT_UNDEFINED, &heap); /* Go to the child node */ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); }} /*==================== B-TREE INSERT =========================*//*****************************************************************Inserts a record if there is enough space, or if enough space canbe freed by reorganizing. Differs from _optimistic_insert becauseno heuristics is applied to whether it pays to use CPU time forreorganizing the page or not. */staticrec_t*btr_cur_insert_if_possible(/*=======================*/ /* out: pointer to inserted record if succeed, else NULL */ btr_cur_t* cursor, /* in: cursor on page after which to insert; cursor stays valid */ dtuple_t* tuple, /* in: tuple to insert; the size info need not have been stored to tuple */ ibool* reorg, /* out: TRUE if reorganization occurred */ mtr_t* mtr) /* in: mtr */{ page_cur_t* page_cursor; page_t* page; rec_t* rec; ut_ad(dtuple_check_typed(tuple)); *reorg = FALSE; page = btr_cur_get_page(cursor); ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); page_cursor = btr_cur_get_page_cur(cursor); /* Now, try the insert */ rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr); if (!rec) { /* If record did not fit, reorganize */ btr_page_reorganize(page, cursor->index, mtr); *reorg = TRUE; page_cur_search(page, cursor->index, tuple, PAGE_CUR_LE, page_cursor); rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr); } return(rec);}/*****************************************************************For an insert, checks the locks and does the undo logging if desired. */UNIV_INLINEulintbtr_cur_ins_lock_and_undo(/*======================*/ /* out: DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */ ulint flags, /* in: undo logging and locking flags: if not zero, the parameters index and thr should be specified */ btr_cur_t* cursor, /* in: cursor on page after which to insert */ dtuple_t* entry, /* in: entry to insert */ que_thr_t* thr, /* in: query thread or NULL */ ibool* inherit)/* out: TRUE if the inserted new record maybe should inherit LOCK_GAP type locks from the successor record */{ dict_index_t* index; ulint err; rec_t* rec; dulint roll_ptr; /* Check if we have to wait for a lock: enqueue an explicit lock request if yes */ rec = btr_cur_get_rec(cursor); index = cursor->index; err = lock_rec_insert_check_and_lock(flags, rec, index, thr, inherit); if (err != DB_SUCCESS) { return(err); } if ((index->type & DICT_CLUSTERED) && !(index->type & DICT_IBUF)) { err = trx_undo_report_row_operation(flags, TRX_UNDO_INSERT_OP, thr, index, entry, NULL, 0, NULL, &roll_ptr); if (err != DB_SUCCESS) { return(err); } /* Now we can fill in the roll ptr field in entry */ if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_index_entry_sys_field(entry, index, DATA_ROLL_PTR, roll_ptr); } } return(DB_SUCCESS);}#ifdef UNIV_DEBUG/*****************************************************************Report information about a transaction. */staticvoidbtr_cur_trx_report(/*===============*/ trx_t* trx, /* in: transaction */ const dict_index_t* index, /* in: index */ const char* op) /* in: operation */{ fprintf(stderr, "Trx with id %lu %lu going to ", ut_dulint_get_high(trx->id), ut_dulint_get_low(trx->id)); fputs(op, stderr); dict_index_name_print(stderr, trx, index); putc('\n', stderr);}#endif /* UNIV_DEBUG *//*****************************************************************Tries to perform an insert to a page in an index tree, next to cursor.It is assumed that mtr holds an x-latch on the page. The operation doesnot succeed if there is too little space on the page. If there is justone record on the page, the insert will always succeed; this is toprevent trying to split a page with just one record. */ulintbtr_cur_optimistic_insert(/*======================*/ /* out: DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */ ulint flags, /* in: undo logging and locking flags: if not zero, the parameters index and thr should be specified */ btr_cur_t* cursor, /* in: cursor on page after which to insert; cursor stays valid */ dtuple_t* entry, /* in: entry to insert */ rec_t** rec, /* out: pointer to inserted record if succeed */ big_rec_t** big_rec,/* out: big rec vector whose fields have to be stored externally by the caller, or NULL */ que_thr_t* thr, /* in: query thread or NULL */ mtr_t* mtr) /* in: mtr */{ big_rec_t* big_rec_vec = NULL; dict_index_t* index; page_cur_t* page_cursor; page_t* page; ulint max_size; rec_t* dummy_rec; ulint level; ibool reorg; ibool inherit; ulint rec_size; ulint type; ulint err; *big_rec = NULL; page = btr_cur_get_page(cursor); index = cursor->index; if (!dtuple_check_typed_no_assert(entry)) { fputs("InnoDB: Error in a tuple to insert into ", stderr); dict_index_name_print(stderr, thr_get_trx(thr), index); }#ifdef UNIV_DEBUG if (btr_cur_print_record_ops && thr) { btr_cur_trx_report(thr_get_trx(thr), index, "insert into "); dtuple_print(stderr, entry); }#endif /* UNIV_DEBUG */ ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); max_size = page_get_max_insert_size_after_reorganize(page, 1); level = btr_page_get_level(page, mtr);calculate_sizes_again: /* Calculate the record size when entry is converted to a record */ rec_size = rec_get_converted_size(index, entry); if (rec_size >=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -