📄 trx0undo.c
字号:
staticvoidtrx_undo_mem_init_for_reuse(/*========================*/ trx_undo_t* undo, /* in: undo log to init */ dulint trx_id, /* in: id of the trx for which the undo log is created */ XID* xid, /* in: X/Open XA transaction identification*/ ulint offset) /* in: undo log header byte offset on page */{#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&((undo->rseg)->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (undo->id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id); mem_analyze_corruption((byte*)undo); ut_error; } undo->state = TRX_UNDO_ACTIVE; undo->del_marks = FALSE; undo->trx_id = trx_id; undo->xid = *xid; undo->dict_operation = FALSE; undo->hdr_offset = offset; undo->empty = TRUE;}/************************************************************************Frees an undo log memory copy. */staticvoidtrx_undo_mem_free(/*==============*/ trx_undo_t* undo) /* in: the undo object to be freed */{ if (undo->id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id); ut_error; } mem_free(undo);}/**************************************************************************Creates a new undo log. */statictrx_undo_t*trx_undo_create(/*============*/ /* out: undo log object, NULL if did not succeed: out of space */ trx_t* trx, /* in: transaction */ trx_rseg_t* rseg, /* in: rollback segment memory copy */ 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*/ mtr_t* mtr) /* in: mtr */{ trx_rsegf_t* rseg_header; ulint page_no; ulint offset; ulint id; trx_undo_t* undo; page_t* undo_page; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(rseg->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (rseg->curr_size == rseg->max_size) { return(NULL); } rseg->curr_size++; rseg_header = trx_rsegf_get(rseg->space, rseg->page_no, mtr); undo_page = trx_undo_seg_create(rseg, rseg_header, type, &id, mtr); if (undo_page == NULL) { /* Did not succeed */ rseg->curr_size--; return(NULL); } page_no = buf_frame_get_page_no(undo_page); offset = trx_undo_header_create(undo_page, trx_id, mtr); if (trx->support_xa) { trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr); } undo = trx_undo_mem_create(rseg, id, type, trx_id, xid, page_no, offset); return(undo);}/*================ UNDO LOG ASSIGNMENT AND CLEANUP =====================*//************************************************************************Reuses a cached undo log. */statictrx_undo_t*trx_undo_reuse_cached(/*==================*/ /* out: the undo log memory object, NULL if none cached */ trx_t* trx, /* in: transaction */ trx_rseg_t* rseg, /* in: rollback segment memory object */ 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 used */ XID* xid, /* in: X/Open XA transaction identification */ mtr_t* mtr) /* in: mtr */{ trx_undo_t* undo; page_t* undo_page; ulint offset;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(rseg->mutex)));#endif /* UNIV_SYNC_DEBUG */ if (type == TRX_UNDO_INSERT) { undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached); if (undo == NULL) { return(NULL); } UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, undo); } else { ut_ad(type == TRX_UNDO_UPDATE); undo = UT_LIST_GET_FIRST(rseg->update_undo_cached); if (undo == NULL) { return(NULL); } UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, undo); } ut_ad(undo->size == 1); if (undo->id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id); mem_analyze_corruption((byte*)undo); ut_error; } undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr); if (type == TRX_UNDO_INSERT) { offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr); if (trx->support_xa) { trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr); } } else { ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_UPDATE); offset = trx_undo_header_create(undo_page, trx_id, mtr); if (trx->support_xa) { trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr); } } trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset); return(undo);}/**************************************************************************Marks an undo log header as a header of a data dictionary operationtransaction. */staticvoidtrx_undo_mark_as_dict_operation(/*============================*/ trx_t* trx, /* in: dict op transaction */ trx_undo_t* undo, /* in: assigned undo log */ mtr_t* mtr) /* in: mtr */{ page_t* hdr_page; ut_a(trx->dict_operation); hdr_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr); mlog_write_ulint(hdr_page + undo->hdr_offset + TRX_UNDO_DICT_TRANS, trx->dict_operation, MLOG_1BYTE, mtr); mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID, trx->table_id, mtr); undo->dict_operation = trx->dict_operation; undo->table_id = trx->table_id;}/**************************************************************************Assigns an undo log for a transaction. A new undo log is created or a cachedundo log reused. */trx_undo_t*trx_undo_assign_undo(/*=================*/ /* out: the undo log, NULL if did not succeed: out of space */ trx_t* trx, /* in: transaction */ ulint type) /* in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */{ trx_rseg_t* rseg; trx_undo_t* undo; mtr_t mtr; ut_ad(trx); ut_ad(trx->rseg); rseg = trx->rseg;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(trx->undo_mutex)));#endif /* UNIV_SYNC_DEBUG */ mtr_start(&mtr);#ifdef UNIV_SYNC_DEBUG ut_ad(!mutex_own(&kernel_mutex));#endif /* UNIV_SYNC_DEBUG */ mutex_enter(&(rseg->mutex)); undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, &trx->xid, &mtr); if (undo == NULL) { undo = trx_undo_create(trx, rseg, type, trx->id, &trx->xid, &mtr); if (undo == NULL) { /* Did not succeed */ mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); return(NULL); } } if (type == TRX_UNDO_INSERT) { UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_list, undo); ut_ad(trx->insert_undo == NULL); trx->insert_undo = undo; } else { UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_list, undo); ut_ad(trx->update_undo == NULL); trx->update_undo = undo; } if (trx->dict_operation) { trx_undo_mark_as_dict_operation(trx, undo, &mtr); } mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); return(undo);}/**********************************************************************Sets the state of the undo log segment at a transaction finish. */page_t*trx_undo_set_state_at_finish(/*=========================*/ /* out: undo log segment header page, x-latched */ trx_t* trx __attribute__((unused)), /* in: transaction */ trx_undo_t* undo, /* in: undo log memory copy */ mtr_t* mtr) /* in: mtr */{ trx_usegf_t* seg_hdr; trx_upagef_t* page_hdr; page_t* undo_page; ulint state; ut_ad(trx && undo && mtr); if (undo->id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id); mem_analyze_corruption((byte*)undo); ut_error; } undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr); seg_hdr = undo_page + TRX_UNDO_SEG_HDR; page_hdr = undo_page + TRX_UNDO_PAGE_HDR; if (undo->size == 1 && mach_read_from_2(page_hdr + TRX_UNDO_PAGE_FREE) < TRX_UNDO_PAGE_REUSE_LIMIT) { state = TRX_UNDO_CACHED; } else if (undo->type == TRX_UNDO_INSERT) { state = TRX_UNDO_TO_FREE; } else { state = TRX_UNDO_TO_PURGE; } undo->state = state; mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, state, MLOG_2BYTES, mtr); return(undo_page);}/**********************************************************************Sets the state of the undo log segment at a transaction prepare. */page_t*trx_undo_set_state_at_prepare(/*==========================*/ /* out: undo log segment header page, x-latched */ trx_t* trx, /* in: transaction */ trx_undo_t* undo, /* in: undo log memory copy */ mtr_t* mtr) /* in: mtr */{ trx_usegf_t* seg_hdr; trx_upagef_t* page_hdr; trx_ulogf_t* undo_header; page_t* undo_page; ulint offset; ut_ad(trx && undo && mtr); if (undo->id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id); mem_analyze_corruption((byte*)undo); ut_error; } undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr); seg_hdr = undo_page + TRX_UNDO_SEG_HDR; page_hdr = undo_page + TRX_UNDO_PAGE_HDR; /*------------------------------*/ undo->state = TRX_UNDO_PREPARED; undo->xid = trx->xid; /*------------------------------*/ mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state, MLOG_2BYTES, mtr); offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG); undo_header = undo_page + offset; mlog_write_ulint(undo_header + TRX_UNDO_XID_EXISTS, TRUE, MLOG_1BYTE, mtr); trx_undo_write_xid(undo_header, &undo->xid, mtr); return(undo_page);}/**************************************************************************Adds the update undo log header as the first in the history list, andfrees the memory object, or puts it to the list of cached update undo logsegments. */voidtrx_undo_update_cleanup(/*====================*/ trx_t* trx, /* in: trx owning the update undo log */ page_t* undo_page, /* in: update undo log header page, x-latched */ mtr_t* mtr) /* in: mtr */{ trx_rseg_t* rseg; trx_undo_t* undo; undo = trx->update_undo; rseg = trx->rseg;#ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(rseg->mutex)));#endif /* UNIV_SYNC_DEBUG */ trx_purge_add_update_undo_to_history(trx, undo_page, mtr); UT_LIST_REMOVE(undo_list, rseg->update_undo_list, undo); trx->update_undo = NULL; if (undo->state == TRX_UNDO_CACHED) { UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo); } else { ut_ad(undo->state == TRX_UNDO_TO_PURGE); trx_undo_mem_free(undo); }}/**********************************************************************Frees or caches an insert undo log after a transaction commit or rollback.Knowledge of inserts is not needed after a commit or rollback, thereforethe data can be discarded. */voidtrx_undo_insert_cleanup(/*====================*/ trx_t* trx) /* in: transaction handle */{ trx_undo_t* undo; trx_rseg_t* rseg; undo = trx->insert_undo; ut_ad(undo); rseg = trx->rseg; mutex_enter(&(rseg->mutex)); UT_LIST_REMOVE(undo_list, rseg->insert_undo_list, undo); trx->insert_undo = NULL; if (undo->state == TRX_UNDO_CACHED) { UT_LIST_ADD_FIRST(undo_list, rseg->insert_undo_cached, undo); } else { ut_ad(undo->state == TRX_UNDO_TO_FREE); /* Delete first the undo log segment in the file */ mutex_exit(&(rseg->mutex)); trx_undo_seg_free(undo); mutex_enter(&(rseg->mutex)); ut_ad(rseg->curr_size > undo->size); rseg->curr_size -= undo->size; trx_undo_mem_free(undo); } mutex_exit(&(rseg->mutex));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -