📄 trx0rec.c
字号:
first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE); memset(undo_page + first_free, 0xff, (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END) - first_free); mlog_write_initial_log_record(undo_page, MLOG_UNDO_ERASE_END, mtr);} /***************************************************************Parses a redo log record of erasing of an undo page end. */byte*trx_undo_parse_erase_page_end(/*==========================*/ /* out: end of log record or NULL */ byte* ptr, /* in: buffer */ byte* end_ptr __attribute__((unused)), /* in: buffer end */ page_t* page, /* in: page or NULL */ mtr_t* mtr) /* in: mtr or NULL */{ ut_ad(ptr && end_ptr); if (page == NULL) { return(ptr); } trx_undo_erase_page_end(page, mtr); return(ptr);}/***************************************************************************Writes information to an undo log about an insert, update, or a delete markingof a clustered index record. This information is used in a rollback of thetransaction and in consistent reads that must look to the history of thistransaction. */ulinttrx_undo_report_row_operation(/*==========================*/ /* out: DB_SUCCESS or error code */ ulint flags, /* in: if BTR_NO_UNDO_LOG_FLAG bit is set, does nothing */ ulint op_type, /* in: TRX_UNDO_INSERT_OP or TRX_UNDO_MODIFY_OP */ que_thr_t* thr, /* in: query thread */ dict_index_t* index, /* in: clustered index */ dtuple_t* clust_entry, /* in: in the case of an insert, index entry to insert into the clustered index, otherwise NULL */ upd_t* update, /* in: in the case of an update, the update vector, otherwise NULL */ ulint cmpl_info, /* in: compiler info on secondary index updates */ rec_t* rec, /* in: in case of an update or delete marking, the record in the clustered index, otherwise NULL */ dulint* roll_ptr) /* out: rollback pointer to the inserted undo log record, ut_dulint_zero if BTR_NO_UNDO_LOG flag was specified */{ trx_t* trx; trx_undo_t* undo; page_t* undo_page; ulint offset; ulint page_no; ibool is_insert; trx_rseg_t* rseg; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_a(index->type & DICT_CLUSTERED); if (flags & BTR_NO_UNDO_LOG_FLAG) { *roll_ptr = ut_dulint_zero; return(DB_SUCCESS); } ut_ad(thr); ut_ad((op_type != TRX_UNDO_INSERT_OP) || (clust_entry && !update && !rec)); trx = thr_get_trx(thr); rseg = trx->rseg; mutex_enter(&(trx->undo_mutex)); /* If the undo log is not assigned yet, assign one */ if (op_type == TRX_UNDO_INSERT_OP) { if (trx->insert_undo == NULL) { trx_undo_assign_undo(trx, TRX_UNDO_INSERT); } undo = trx->insert_undo; is_insert = TRUE; } else { ut_ad(op_type == TRX_UNDO_MODIFY_OP); if (trx->update_undo == NULL) { trx_undo_assign_undo(trx, TRX_UNDO_UPDATE); } undo = trx->update_undo; is_insert = FALSE; } if (undo == NULL) { /* Did not succeed: out of space */ mutex_exit(&(trx->undo_mutex)); return(DB_OUT_OF_FILE_SPACE); } page_no = undo->last_page_no; mtr_start(&mtr); for (;;) { undo_page = buf_page_get_gen(undo->space, page_no, RW_X_LATCH, undo->guess_page, BUF_GET, __FILE__, __LINE__, &mtr);#ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(undo_page, SYNC_TRX_UNDO_PAGE);#endif /* UNIV_SYNC_DEBUG */ if (op_type == TRX_UNDO_INSERT_OP) { offset = trx_undo_page_report_insert(undo_page, trx, index, clust_entry, &mtr); } else { offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); offset = trx_undo_page_report_modify(undo_page, trx, index, rec, offsets, update, cmpl_info, &mtr); } if (offset == 0) { /* The record did not fit on the page. We erase the end segment of the undo log page and write a log record of it: this is to ensure that in the debug version the replicate page constructed using the log records stays identical to the original page */ trx_undo_erase_page_end(undo_page, &mtr); } mtr_commit(&mtr); if (offset != 0) { /* Success */ break; } ut_ad(page_no == undo->last_page_no); /* We have to extend the undo log by one page */ mtr_start(&mtr); /* When we add a page to an undo log, this is analogous to a pessimistic insert in a B-tree, and we must reserve the counterpart of the tree latch, which is the rseg mutex. */ mutex_enter(&(rseg->mutex)); page_no = trx_undo_add_page(trx, undo, &mtr); mutex_exit(&(rseg->mutex)); if (page_no == FIL_NULL) { /* Did not succeed: out of space */ mutex_exit(&(trx->undo_mutex)); mtr_commit(&mtr); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } return(DB_OUT_OF_FILE_SPACE); } } undo->empty = FALSE; undo->top_page_no = page_no; undo->top_offset = offset; undo->top_undo_no = trx->undo_no; undo->guess_page = undo_page; UT_DULINT_INC(trx->undo_no); mutex_exit(&(trx->undo_mutex)); *roll_ptr = trx_undo_build_roll_ptr(is_insert, rseg->id, page_no, offset); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } return(DB_SUCCESS);}/*============== BUILDING PREVIOUS VERSION OF A RECORD ===============*//**********************************************************************Copies an undo record to heap. This function can be called if we know thatthe undo log record exists. */trx_undo_rec_t*trx_undo_get_undo_rec_low(/*======================*/ /* out, own: copy of the record */ dulint roll_ptr, /* in: roll pointer to record */ mem_heap_t* heap) /* in: memory heap where copied */{ trx_undo_rec_t* undo_rec; ulint rseg_id; ulint page_no; ulint offset; page_t* undo_page; trx_rseg_t* rseg; ibool is_insert; mtr_t mtr; trx_undo_decode_roll_ptr(roll_ptr, &is_insert, &rseg_id, &page_no, &offset); rseg = trx_rseg_get_on_id(rseg_id); mtr_start(&mtr); undo_page = trx_undo_page_get_s_latched(rseg->space, page_no, &mtr); undo_rec = trx_undo_rec_copy(undo_page + offset, heap); mtr_commit(&mtr); return(undo_rec);}/**********************************************************************Copies an undo record to heap. */ulinttrx_undo_get_undo_rec(/*==================*/ /* out: DB_SUCCESS, or DB_MISSING_HISTORY if the undo log has been truncated and we cannot fetch the old version; NOTE: the caller must have latches on the clustered index page and purge_view */ dulint roll_ptr, /* in: roll pointer to record */ dulint trx_id, /* in: id of the trx that generated the roll pointer: it points to an undo log of this transaction */ trx_undo_rec_t** undo_rec, /* out, own: copy of the record */ mem_heap_t* heap) /* in: memory heap where copied */{#ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));#endif /* UNIV_SYNC_DEBUG */ if (!trx_purge_update_undo_must_exist(trx_id)) { /* It may be that the necessary undo log has already been deleted */ return(DB_MISSING_HISTORY); } *undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap); return(DB_SUCCESS);}/***********************************************************************Build a previous version of a clustered index record. This function checksthat the caller has a latch on the index page of the clustered index recordand an s-latch on the purge_view. This guarantees that the stack of versionsis locked. */ulinttrx_undo_prev_version_build(/*========================*/ /* out: DB_SUCCESS, or DB_MISSING_HISTORY if the previous version is not >= purge_view, which means that it may have been removed, DB_ERROR if corrupted record */ rec_t* index_rec,/* in: clustered index record in the index tree */ mtr_t* index_mtr __attribute__((unused)), /* in: mtr which contains the latch to index_rec page and purge_view */ rec_t* rec, /* in: version of a clustered index record */ dict_index_t* index, /* in: clustered index */ ulint* offsets,/* in: rec_get_offsets(rec, index) */ mem_heap_t* heap, /* in: memory heap from which the memory needed is allocated */ rec_t** old_vers)/* out, own: previous version, or NULL if rec is the first inserted version, or if history data has been deleted */{ trx_undo_rec_t* undo_rec; dtuple_t* entry; dulint rec_trx_id; ulint type; dulint undo_no; dulint table_id; dulint trx_id; dulint roll_ptr; dulint old_roll_ptr; upd_t* update; byte* ptr; ulint info_bits; ulint cmpl_info; ibool dummy_extern; byte* buf; ulint err;#ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));#endif /* UNIV_SYNC_DEBUG */ ut_ad(mtr_memo_contains(index_mtr, buf_block_align(index_rec), MTR_MEMO_PAGE_S_FIX) || mtr_memo_contains(index_mtr, buf_block_align(index_rec), MTR_MEMO_PAGE_X_FIX)); ut_ad(rec_offs_validate(rec, index, offsets)); if (!(index->type & DICT_CLUSTERED)) { fprintf(stderr, "InnoDB: Error: trying to access" " update undo rec for non-clustered index %s\n" "InnoDB: Submit a detailed bug report to" " http://bugs.mysql.com\n" "InnoDB: index record ", index->name); rec_print(stderr, index_rec, index); fputs("\n" "InnoDB: record version ", stderr); rec_print_new(stderr, rec, offsets); putc('\n', stderr); return(DB_ERROR); } roll_ptr = row_get_rec_roll_ptr(rec, index, offsets); old_roll_ptr = roll_ptr; *old_vers = NULL; if (trx_undo_roll_ptr_is_insert(roll_ptr)) { /* The record rec is the first inserted version */ return(DB_SUCCESS); } rec_trx_id = row_get_rec_trx_id(rec, index, offsets); err = trx_undo_get_undo_rec(roll_ptr, rec_trx_id, &undo_rec, heap); if (err != DB_SUCCESS) { return(err); } ptr = trx_undo_rec_get_pars(undo_rec, &type, &cmpl_info, &dummy_extern, &undo_no, &table_id); ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr, &info_bits); ptr = trx_undo_rec_skip_row_ref(ptr, index); ptr = trx_undo_update_rec_get_update(ptr, index, type, trx_id, roll_ptr, info_bits, NULL, heap, &update); if (ut_dulint_cmp(table_id, index->table->id) != 0) { ptr = NULL; fprintf(stderr,"InnoDB: Error: trying to access update undo rec for table %s\n""InnoDB: but the table id in the undo record is wrong\n""InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n""InnoDB: Run also CHECK TABLE %s\n", index->table_name, index->table_name); } if (ptr == NULL) { /* The record was corrupted, return an error; these printfs should catch an elusive bug in row_vers_old_has_index_entry */ fprintf(stderr, "InnoDB: table %s, index %s, n_uniq %lu\n" "InnoDB: undo rec address %p, type %lu cmpl_info %lu\n" "InnoDB: undo rec table id %lu %lu, index table id %lu %lu\n" "InnoDB: dump of 150 bytes in undo rec: ", index->table_name, index->name, (ulong) dict_index_get_n_unique(index), undo_rec, (ulong) type, (ulong) cmpl_info, (ulong) ut_dulint_get_high(table_id), (ulong) ut_dulint_get_low(table_id), (ulong) ut_dulint_get_high(index->table->id), (ulong) ut_dulint_get_low(index->table->id)); ut_print_buf(stderr, undo_rec, 150); fputs("\n" "InnoDB: index record ", stderr); rec_print(stderr, index_rec, index); fputs("\n" "InnoDB: record version ", stderr); rec_print_new(stderr, rec, offsets); fprintf(stderr, "\n" "InnoDB: Record trx id %lu %lu, update rec trx id %lu %lu\n" "InnoDB: Roll ptr in rec %lu %lu, in update rec %lu %lu\n", (ulong) ut_dulint_get_high(rec_trx_id), (ulong) ut_dulint_get_low(rec_trx_id), (ulong) ut_dulint_get_high(trx_id), (ulong) ut_dulint_get_low(trx_id), (ulong) ut_dulint_get_high(old_roll_ptr), (ulong) ut_dulint_get_low(old_roll_ptr), (ulong) ut_dulint_get_high(roll_ptr), (ulong) ut_dulint_get_low(roll_ptr)); trx_purge_sys_print(); return(DB_ERROR); } if (row_upd_changes_field_size_or_external(index, offsets, update)) { ulint* ext_vect; ulint n_ext_vect; /* We have to set the appropriate extern storage bits in the old version of the record: the extern bits in rec for those fields that update does NOT update, as well as the the bits for those fields that update updates to become externally stored fields. Store the info to ext_vect: */ ext_vect = mem_alloc(sizeof(ulint) * rec_offs_n_fields(offsets)); n_ext_vect = btr_push_update_extern_fields(ext_vect, offsets, update); entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals(entry, index, update, heap); buf = mem_heap_alloc(heap, rec_get_converted_size(index, entry)); *old_vers = rec_convert_dtuple_to_rec(buf, index, entry); /* Now set the extern bits in the old version of the record */ rec_set_field_extern_bits(*old_vers, index, ext_vect, n_ext_vect, NULL); mem_free(ext_vect); } else { buf = mem_heap_alloc(heap, rec_offs_size(offsets)); *old_vers = rec_copy(buf, rec, offsets); rec_offs_make_valid(*old_vers, index, offsets); row_upd_rec_in_place(*old_vers, offsets, update); } return(DB_SUCCESS);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -