📄 trx0undo.c
字号:
header page */ mtr_t* mtr) /* in: mtr which does not have a latch to any undo log page; the caller must have reserved the rollback segment mutex */{ ulint last_page_no; ut_ad(undo->hdr_page_no != page_no);#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(trx->undo_mutex)));#endif /* UNIV_SYNC_DEBUG */ last_page_no = trx_undo_free_page(undo->rseg, FALSE, undo->space, undo->hdr_page_no, page_no, mtr); undo->last_page_no = last_page_no; undo->size--;}/************************************************************************Empties an undo log header page of undo records for that undo log. Otherundo logs may still have records on that page, if it is an update undo log. */staticvoidtrx_undo_empty_header_page(/*=======================*/ ulint space, /* in: space */ ulint hdr_page_no, /* in: header page number */ ulint hdr_offset, /* in: header offset */ mtr_t* mtr) /* in: mtr */{ page_t* header_page; trx_ulogf_t* log_hdr; ulint end; header_page = trx_undo_page_get(space, hdr_page_no, mtr); log_hdr = header_page + hdr_offset; end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset); mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);}/***************************************************************************Truncates an undo log from the end. This function is used during a rollbackto free space from an undo log. */voidtrx_undo_truncate_end(/*==================*/ trx_t* trx, /* in: transaction whose undo log it is */ trx_undo_t* undo, /* in: undo log */ dulint limit) /* in: all undo records with undo number >= this value should be truncated */{ page_t* undo_page; ulint last_page_no; trx_undo_rec_t* rec; trx_undo_rec_t* trunc_here; trx_rseg_t* rseg; mtr_t mtr;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(trx->undo_mutex))); ut_ad(mutex_own(&(trx->rseg->mutex)));#endif /* UNIV_SYNC_DEBUG */ rseg = trx->rseg; for (;;) { mtr_start(&mtr); trunc_here = NULL; last_page_no = undo->last_page_no; undo_page = trx_undo_page_get(undo->space, last_page_no, &mtr); rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no, undo->hdr_offset); for (;;) { if (rec == NULL) { if (last_page_no == undo->hdr_page_no) { goto function_exit; } trx_undo_free_page_in_rollback(trx, undo, last_page_no, &mtr); break; } if (ut_dulint_cmp(trx_undo_rec_get_undo_no(rec), limit) >= 0) { /* Truncate at least this record off, maybe more */ trunc_here = rec; } else { goto function_exit; } rec = trx_undo_page_get_prev_rec(rec, undo->hdr_page_no, undo->hdr_offset); } mtr_commit(&mtr); }function_exit: if (trunc_here) { mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE, trunc_here - undo_page, MLOG_2BYTES, &mtr); } mtr_commit(&mtr);}/***************************************************************************Truncates an undo log from the start. This function is used during a purgeoperation. */voidtrx_undo_truncate_start(/*====================*/ trx_rseg_t* rseg, /* in: rollback segment */ ulint space, /* in: space id of the log */ ulint hdr_page_no, /* in: header page number */ ulint hdr_offset, /* in: header offset on the page */ dulint limit) /* in: all undo pages with undo numbers < this value should be truncated; NOTE that the function only frees whole pages; the header page is not freed, but emptied, if all the records there are < limit */{ page_t* undo_page; trx_undo_rec_t* rec; trx_undo_rec_t* last_rec; ulint page_no; mtr_t mtr;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(rseg->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (0 == ut_dulint_cmp(limit, ut_dulint_zero)) { return; }loop: mtr_start(&mtr); rec = trx_undo_get_first_rec(space, hdr_page_no, hdr_offset, RW_X_LATCH, &mtr); if (rec == NULL) { /* Already empty */ mtr_commit(&mtr); return; } undo_page = buf_frame_align(rec); last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no, hdr_offset); if (ut_dulint_cmp(trx_undo_rec_get_undo_no(last_rec), limit) >= 0) { mtr_commit(&mtr); return; } page_no = buf_frame_get_page_no(undo_page); if (page_no == hdr_page_no) { trx_undo_empty_header_page(space, hdr_page_no, hdr_offset, &mtr); } else { trx_undo_free_page(rseg, TRUE, space, hdr_page_no, page_no, &mtr); } mtr_commit(&mtr); goto loop;}/**************************************************************************Frees an undo log segment which is not in the history list. */staticvoidtrx_undo_seg_free(/*==============*/ trx_undo_t* undo) /* in: undo log */{ trx_rseg_t* rseg; fseg_header_t* file_seg; trx_rsegf_t* rseg_header; trx_usegf_t* seg_header; ibool finished; mtr_t mtr; finished = FALSE; rseg = undo->rseg; while (!finished) { mtr_start(&mtr);#ifdef UNIV_SYNC_DEBUG ut_ad(!mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ mutex_enter(&(rseg->mutex)); seg_header = trx_undo_page_get(undo->space, undo->hdr_page_no, &mtr) + TRX_UNDO_SEG_HDR; file_seg = seg_header + TRX_UNDO_FSEG_HEADER; finished = fseg_free_step(file_seg, &mtr); if (finished) { /* Update the rseg header */ rseg_header = trx_rsegf_get(rseg->space, rseg->page_no, &mtr); trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL, &mtr); } mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); }}/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*//************************************************************************Creates and initializes an undo log memory object according to the valuesin the header in file, when the database is started. The memory object isinserted in the appropriate list of rseg. */statictrx_undo_t*trx_undo_mem_create_at_db_start(/*============================*/ /* out, own: the undo log memory object */ trx_rseg_t* rseg, /* in: rollback segment memory object */ ulint id, /* in: slot index within rseg */ ulint page_no,/* in: undo log segment page number */ mtr_t* mtr) /* in: mtr */{ page_t* undo_page; trx_upagef_t* page_header; trx_usegf_t* seg_header; trx_ulogf_t* undo_header; trx_undo_t* undo; ulint type; ulint state; dulint trx_id; ulint offset; fil_addr_t last_addr; page_t* last_page; trx_undo_rec_t* rec; XID xid; ibool xid_exists = FALSE; if (id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) id); ut_error; } undo_page = trx_undo_page_get(rseg->space, page_no, mtr); page_header = undo_page + TRX_UNDO_PAGE_HDR; type = mtr_read_ulint(page_header + TRX_UNDO_PAGE_TYPE, MLOG_2BYTES, mtr); seg_header = undo_page + TRX_UNDO_SEG_HDR; state = mach_read_from_2(seg_header + TRX_UNDO_STATE); offset = mach_read_from_2(seg_header + TRX_UNDO_LAST_LOG); undo_header = undo_page + offset; trx_id = mtr_read_dulint(undo_header + TRX_UNDO_TRX_ID, mtr); xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS, MLOG_1BYTE, mtr); /* Read X/Open XA transaction identification if it exists, or set it to NULL. */ memset(&xid, 0, sizeof(xid)); xid.formatID = -1; if (xid_exists == TRUE) { trx_undo_read_xid(undo_header, &xid); } mutex_enter(&(rseg->mutex)); undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid, page_no, offset); mutex_exit(&(rseg->mutex)); undo->dict_operation = mtr_read_ulint( undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr); undo->table_id = mtr_read_dulint(undo_header + TRX_UNDO_TABLE_ID, mtr); undo->state = state; undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr); /* If the log segment is being freed, the page list is inconsistent! */ if (state == TRX_UNDO_TO_FREE) { goto add_to_list; } last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr); undo->last_page_no = last_addr.page; undo->top_page_no = last_addr.page; last_page = trx_undo_page_get(rseg->space, undo->last_page_no, mtr); rec = trx_undo_page_get_last_rec(last_page, page_no, offset); if (rec == NULL) { undo->empty = TRUE; } else { undo->empty = FALSE; undo->top_offset = rec - last_page; undo->top_undo_no = trx_undo_rec_get_undo_no(rec); }add_to_list: if (type == TRX_UNDO_INSERT) { if (state != TRX_UNDO_CACHED) { UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_list, undo); } else { UT_LIST_ADD_LAST(undo_list, rseg->insert_undo_cached, undo); } } else { ut_ad(type == TRX_UNDO_UPDATE); if (state != TRX_UNDO_CACHED) { UT_LIST_ADD_LAST(undo_list, rseg->update_undo_list, undo); } else { UT_LIST_ADD_LAST(undo_list, rseg->update_undo_cached, undo); } } return(undo);}/************************************************************************Initializes the undo log lists for a rollback segment memory copy. Thisfunction is only called when the database is started or a new rollbacksegment is created. */ulinttrx_undo_lists_init(/*================*/ /* out: the combined size of undo log segments in pages */ trx_rseg_t* rseg) /* in: rollback segment memory object */ { ulint page_no; trx_undo_t* undo; ulint size = 0; trx_rsegf_t* rseg_header; ulint i; mtr_t mtr; UT_LIST_INIT(rseg->update_undo_list); UT_LIST_INIT(rseg->update_undo_cached); UT_LIST_INIT(rseg->insert_undo_list); UT_LIST_INIT(rseg->insert_undo_cached); mtr_start(&mtr); rseg_header = trx_rsegf_get_new(rseg->space, rseg->page_no, &mtr); for (i = 0; i < TRX_RSEG_N_SLOTS; i++) { page_no = trx_rsegf_get_nth_undo(rseg_header, i, &mtr); /* In forced recovery: try to avoid operations which look at database pages; undo logs are rapidly changing data, and the probability that they are in an inconsistent state is high */ if (page_no != FIL_NULL && srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) { undo = trx_undo_mem_create_at_db_start(rseg, i, page_no, &mtr); size += undo->size; mtr_commit(&mtr); mtr_start(&mtr); rseg_header = trx_rsegf_get(rseg->space, rseg->page_no, &mtr); } } mtr_commit(&mtr); return(size);} /************************************************************************Creates and initializes an undo log memory object. */statictrx_undo_t*trx_undo_mem_create(/*================*/ /* out, own: the undo log memory object */ trx_rseg_t* rseg, /* in: rollback segment memory object */ ulint id, /* in: slot index within rseg */ ulint type, /* in: type of the log: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */ dulint trx_id, /* in: id of the trx for which the undo log is created */ XID* xid, /* in: X/Open transaction identification */ ulint page_no,/* in: undo log header page number */ ulint offset) /* in: undo log header byte offset on page */{ trx_undo_t* undo;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(rseg->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) id); ut_error; } undo = mem_alloc(sizeof(trx_undo_t)); undo->id = id; undo->type = type; undo->state = TRX_UNDO_ACTIVE; undo->del_marks = FALSE; undo->trx_id = trx_id; undo->xid = *xid; undo->dict_operation = FALSE; undo->rseg = rseg; undo->space = rseg->space; undo->hdr_page_no = page_no; undo->hdr_offset = offset; undo->last_page_no = page_no; undo->size = 1; undo->empty = TRUE; undo->top_page_no = page_no; undo->guess_page = NULL; return(undo);}/************************************************************************Initializes a cached undo log object for new use. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -