📄 btr0cur.c
字号:
ut_min(page_get_free_space_of_empty(page_is_comp(page)) / 2, REC_MAX_DATA_SIZE)) { /* The record is so big that we have to store some fields externally on separate database pages */ big_rec_vec = dtuple_convert_big_rec(index, entry, NULL, 0); if (big_rec_vec == NULL) { return(DB_TOO_BIG_RECORD); } goto calculate_sizes_again; } /* If there have been many consecutive inserts, and we are on the leaf level, check if we have to split the page to reserve enough free space for future updates of records. */ type = index->type; if ((type & DICT_CLUSTERED) && (dict_tree_get_space_reserve(index->tree) + rec_size > max_size) && (page_get_n_recs(page) >= 2) && (0 == level) && (btr_page_get_split_rec_to_right(cursor, &dummy_rec) || btr_page_get_split_rec_to_left(cursor, &dummy_rec))) { if (big_rec_vec) { dtuple_convert_back_big_rec(index, entry, big_rec_vec); } return(DB_FAIL); } if (!(((max_size >= rec_size) && (max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT)) || (page_get_max_insert_size(page, 1) >= rec_size) || (page_get_n_recs(page) <= 1))) { if (big_rec_vec) { dtuple_convert_back_big_rec(index, entry, big_rec_vec); } return(DB_FAIL); } /* Check locks and write to the undo log, if specified */ err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &inherit); if (err != DB_SUCCESS) { if (big_rec_vec) { dtuple_convert_back_big_rec(index, entry, big_rec_vec); } return(err); } page_cursor = btr_cur_get_page_cur(cursor); reorg = FALSE; /* Now, try the insert */ *rec = page_cur_insert_rec_low(page_cursor, entry, index, NULL, NULL, mtr); if (UNIV_UNLIKELY(!(*rec))) { /* If the record did not fit, reorganize */ btr_page_reorganize(page, index, mtr); ut_ad(page_get_max_insert_size(page, 1) == max_size); reorg = TRUE; page_cur_search(page, index, entry, PAGE_CUR_LE, page_cursor); *rec = page_cur_tuple_insert(page_cursor, entry, index, mtr); if (UNIV_UNLIKELY(!*rec)) { fputs("InnoDB: Error: cannot insert tuple ", stderr); dtuple_print(stderr, entry); fputs(" into ", stderr); dict_index_name_print(stderr, thr_get_trx(thr), index); fprintf(stderr, "\nInnoDB: max insert size %lu\n", (ulong) max_size); ut_error; } }#ifdef BTR_CUR_HASH_ADAPT if (!reorg && (0 == level) && (cursor->flag == BTR_CUR_HASH)) { btr_search_update_hash_node_on_insert(cursor); } else { btr_search_update_hash_on_insert(cursor); }#endif if (!(flags & BTR_NO_LOCKING_FLAG) && inherit) { lock_update_insert(*rec); }/* fprintf(stderr, "Insert into page %lu, max ins size %lu," " rec %lu ind type %lu\n", buf_frame_get_page_no(page), max_size, rec_size + PAGE_DIR_SLOT_SIZE, type);*/ if (!(type & DICT_CLUSTERED)) { /* We have added a record to page: update its free bits */ ibuf_update_free_bits_if_full(cursor->index, page, max_size, rec_size + PAGE_DIR_SLOT_SIZE); } *big_rec = big_rec_vec; return(DB_SUCCESS);}/*****************************************************************Performs an insert on a page of an index tree. It is assumed that mtrholds an x-latch on the tree and on the cursor page. If the insert ismade on the leaf level, to avoid deadlocks, mtr must also own x-latchesto brothers of page, if those brothers exist. */ulintbtr_cur_pessimistic_insert(/*=======================*/ /* out: DB_SUCCESS or error number */ ulint flags, /* in: undo logging and locking flags: if not zero, the parameter thr should be specified; if no undo logging is specified, then the caller must have reserved enough free extents in the file space so that the insertion will certainly succeed */ btr_cur_t* cursor, /* in: cursor 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 */{ dict_index_t* index = cursor->index; big_rec_t* big_rec_vec = NULL; page_t* page; ulint err; ibool dummy_inh; ibool success; ulint n_extents = 0; ulint n_reserved; ut_ad(dtuple_check_typed(entry)); *big_rec = NULL; page = btr_cur_get_page(cursor); ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(btr_cur_get_tree(cursor)), MTR_MEMO_X_LOCK)); ut_ad(mtr_memo_contains(mtr, buf_block_align(page), MTR_MEMO_PAGE_X_FIX)); /* Try first an optimistic insert; reset the cursor flag: we do not assume anything of how it was positioned */ cursor->flag = BTR_CUR_BINARY; err = btr_cur_optimistic_insert(flags, cursor, entry, rec, big_rec, thr, mtr); if (err != DB_FAIL) { return(err); } /* Retry with a pessimistic insert. Check locks and write to undo log, if specified */ err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &dummy_inh); if (err != DB_SUCCESS) { return(err); } if (!(flags & BTR_NO_UNDO_LOG_FLAG)) { /* First reserve enough free space for the file segments of the index tree, so that the insert will not fail because of lack of space */ n_extents = cursor->tree_height / 16 + 3; success = fsp_reserve_free_extents(&n_reserved, index->space, n_extents, FSP_NORMAL, mtr); if (!success) { err = DB_OUT_OF_FILE_SPACE; return(err); } } if (rec_get_converted_size(index, entry) >= ut_min(page_get_free_space_of_empty(page_is_comp(page)) / 2, REC_MAX_DATA_SIZE)) { /* The record is so big that we have to store some fields externally on separate database pages */ big_rec_vec = dtuple_convert_big_rec(index, entry, NULL, 0); if (big_rec_vec == NULL) { if (n_extents > 0) { fil_space_release_free_extents(index->space, n_reserved); } return(DB_TOO_BIG_RECORD); } } if (dict_tree_get_page(index->tree) == buf_frame_get_page_no(page)) { /* The page is the root page */ *rec = btr_root_raise_and_insert(cursor, entry, mtr); } else { *rec = btr_page_split_and_insert(cursor, entry, mtr); } btr_cur_position(index, page_rec_get_prev(*rec), cursor); #ifdef BTR_CUR_ADAPT btr_search_update_hash_on_insert(cursor);#endif if (!(flags & BTR_NO_LOCKING_FLAG)) { lock_update_insert(*rec); } err = DB_SUCCESS; if (n_extents > 0) { fil_space_release_free_extents(index->space, n_reserved); } *big_rec = big_rec_vec; return(err);}/*==================== B-TREE UPDATE =========================*//*****************************************************************For an update, checks the locks and does the undo logging. */UNIV_INLINEulintbtr_cur_upd_lock_and_undo(/*======================*/ /* out: DB_SUCCESS, DB_WAIT_LOCK, or error number */ ulint flags, /* in: undo logging and locking flags */ btr_cur_t* cursor, /* in: cursor on record to update */ upd_t* update, /* in: update vector */ ulint cmpl_info,/* in: compiler info on secondary index updates */ que_thr_t* thr, /* in: query thread */ dulint* roll_ptr)/* out: roll pointer */{ dict_index_t* index; rec_t* rec; ulint err; ut_ad(cursor && update && thr && roll_ptr); rec = btr_cur_get_rec(cursor); index = cursor->index; if (!(index->type & DICT_CLUSTERED)) { /* We do undo logging only when we update a clustered index record */ return(lock_sec_rec_modify_check_and_lock(flags, rec, index, thr)); } /* Check if we have to wait for a lock: enqueue an explicit lock request if yes */ err = DB_SUCCESS; if (!(flags & BTR_NO_LOCKING_FLAG)) { mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; *offsets_ = (sizeof offsets_) / sizeof *offsets_; err = lock_clust_rec_modify_check_and_lock(flags, rec, index, rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap), thr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } if (err != DB_SUCCESS) { return(err); } } /* Append the info about the update in the undo log */ err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr, index, NULL, update, cmpl_info, rec, roll_ptr); return(err);}/***************************************************************Writes a redo log record of updating a record in-place. */UNIV_INLINEvoidbtr_cur_update_in_place_log(/*========================*/ ulint flags, /* in: flags */ rec_t* rec, /* in: record */ dict_index_t* index, /* in: index where cursor positioned */ upd_t* update, /* in: update vector */ trx_t* trx, /* in: transaction */ dulint roll_ptr, /* in: roll ptr */ mtr_t* mtr) /* in: mtr */{ byte* log_ptr; page_t* page = ut_align_down(rec, UNIV_PAGE_SIZE); ut_ad(flags < 256); ut_ad(!!page_is_comp(page) == index->table->comp); log_ptr = mlog_open_and_write_index(mtr, rec, index, page_is_comp(page) ? MLOG_COMP_REC_UPDATE_IN_PLACE : MLOG_REC_UPDATE_IN_PLACE, 1 + DATA_ROLL_PTR_LEN + 14 + 2 + MLOG_BUF_MARGIN); if (!log_ptr) { /* Logging in mtr is switched off during crash recovery */ return; } /* The code below assumes index is a clustered index: change index to the clustered index if we are updating a secondary index record (or we could as well skip writing the sys col values to the log in this case because they are not needed for a secondary index record update) */ index = dict_table_get_first_index(index->table); mach_write_to_1(log_ptr, flags); log_ptr++; log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr, mtr); mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE)); log_ptr += 2; row_upd_index_write_log(update, log_ptr, mtr);} /***************************************************************Parses a redo log record of updating a record in-place. */byte*btr_cur_parse_update_in_place(/*==========================*/ /* out: end of log record or NULL */ byte* ptr, /* in: buffer */ byte* end_ptr,/* in: buffer end */ page_t* page, /* in: page or NULL */ dict_index_t* index) /* in: index corresponding to page */{ ulint flags; rec_t* rec; upd_t* update; ulint pos; dulint trx_id; dulint roll_ptr; ulint rec_offset; mem_heap_t* heap; ulint* offsets; if (end_ptr < ptr + 1) { return(NULL); } flags = mach_read_from_1(ptr); ptr++; ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr); if (ptr == NULL) { return(NULL); } if (end_ptr < ptr + 2) { return(NULL); } rec_offset = mach_read_from_2(ptr); ptr += 2; ut_a(rec_offset <= UNIV_PAGE_SIZE); heap = mem_heap_create(256); ptr = row_upd_index_parse(ptr, end_ptr, heap, &update); if (!ptr || !page) { goto func_exit; } ut_a((ibool)!!page_is_comp(page) == index->table->comp); rec = page + rec_offset; /* We do not need to reserve btr_search_latch, as the page is only being recovered, and there cannot be a hash index to it. */ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); if (!(flags & BTR_KEEP_SYS_FLAG)) { row_upd_rec_sys_fields_in_recovery(rec, offsets, pos, trx_id, roll_ptr); } row_upd_rec_in_place(rec, offsets, update);func_exit: mem_heap_free(heap); return(ptr);}/*****************************************************************Updates a record when the update causes no size changes in its fields.We assume here that the ordering fields of the record do not change. */ulintbtr_cur_update_in_place(/*====================*/ /* out: DB_SUCCESS or error number */ ulint flags, /* in: undo logging and locking flags */ btr_cur_t* cursor, /* in: cursor on the record to update; cursor stays valid and positioned on the same record */ upd_t* update, /* in: update vector */ ulint cmpl_info,/* in: compiler info on secondary index updates */ que_thr_t* thr, /* in: query thread */ mtr_t* mtr) /* in: mtr */{ dict_index_t* index; buf_block_t* block; ulint err; rec_t* rec; dulint roll_ptr = ut_dulint_zero; trx_t* trx; ulint was_delete_marked; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; rec = btr_cur_get_rec(cursor); index = cursor->index; ut_ad(!!page_rec_is_comp(rec) == index->table->comp); trx = thr_get_trx(thr); offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);#ifdef UNIV_DEBUG if (btr_cur_print_record_ops && thr) { btr_cur_trx_report(trx, index, "update "); rec_print_new(stderr, rec, offsets); }#endif /* UNIV_DEBUG */ /* Do lock checking and undo logging */ err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, thr, &roll_ptr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -