/*************************************************************************** Gets the next record in an undo log from the next page. */ static trx_undo_rec_t* trx_undo_get_next_rec_from_next_page( /*=================================*/ /* out: undo log record, the page latched, NULL if none */ page_t* undo_page, /* in: undo log page */ ulint page_no,/* in: undo log header page number */ ulint offset, /* in: undo log header offset on page */ ulint mode, /* in: latch mode: RW_S_LATCH or RW_X_LATCH */ mtr_t* mtr) /* in: mtr */ { trx_ulogf_t* log_hdr; ulint next_page_no; page_t* next_page; ulint space; ulint next; if (page_no == buf_frame_get_page_no(undo_page)) { log_hdr = undo_page + offset; next = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG); if (next != 0) { return(NULL); } } space = buf_frame_get_space_id(undo_page); next_page_no = flst_get_next_addr(undo_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr) .page; if (next_page_no == FIL_NULL) { return(NULL); } if (mode == RW_S_LATCH) { next_page = trx_undo_page_get_s_latched(space, next_page_no, mtr); } else { ut_ad(mode == RW_X_LATCH); next_page = trx_undo_page_get(space, next_page_no, mtr); } return(trx_undo_page_get_first_rec(next_page, page_no, offset)); }
void flst_print( /*=======*/ flst_base_node_t* base, /* in: pointer to base node of list */ mtr_t* mtr) /* in: mtr */ { buf_frame_t* frame; ulint len; ut_ad(base && mtr); ut_ad(mtr_memo_contains(mtr, buf_block_align(base), MTR_MEMO_PAGE_X_FIX)); frame = buf_frame_align(base); len = flst_get_len(base, mtr); printf("FILE-BASED LIST:\n"); printf("Base node in space %lu page %lu byte offset %lu; len %lu\n", buf_frame_get_space_id(frame), buf_frame_get_page_no(frame), (ulint) (base - frame), len); }
void btr_pcur_move_to_next_page( /*=======================*/ btr_pcur_t* cursor, /* in: persistent cursor; must be on the last record of the current page */ mtr_t* mtr) /* in: mtr */ { ulint next_page_no; ulint space; page_t* page; page_t* next_page; ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); ut_ad(btr_pcur_is_after_last_on_page(cursor, mtr)); cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; page = btr_pcur_get_page(cursor); next_page_no = btr_page_get_next(page, mtr); space = buf_frame_get_space_id(page); ut_ad(next_page_no != FIL_NULL); next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr); #ifdef UNIV_BTR_DEBUG ut_a(btr_page_get_prev(next_page, mtr) == buf_frame_get_page_no(page)); #endif /* UNIV_BTR_DEBUG */ ut_a(page_is_comp(next_page) == page_is_comp(page)); buf_block_align(next_page)->check_index_page_at_flush = TRUE; btr_leaf_page_release(page, cursor->latch_mode, mtr); page_cur_set_before_first(next_page, btr_pcur_get_page_cur(cursor)); page_check_dir(next_page); }
ulint trx_rseg_header_create( /*===================*/ /* out: page number of the created segment, FIL_NULL if fail */ ulint space, /* in: space id */ ulint max_size, /* in: max size in pages */ ulint* slot_no, /* out: rseg id == slot number in trx sys */ mtr_t* mtr) /* in: mtr */ { ulint page_no; trx_rsegf_t* rsegf; trx_sysf_t* sys_header; ulint i; page_t* page; ut_ad(mtr); #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&kernel_mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space), MTR_MEMO_X_LOCK)); sys_header = trx_sysf_get(mtr); *slot_no = trx_sysf_rseg_find_free(mtr); if (*slot_no == ULINT_UNDEFINED) { return(FIL_NULL); } /* Allocate a new file segment for the rollback segment */ page = fseg_create(space, 0, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr); if (page == NULL) { /* No space left */ return(FIL_NULL); } #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(page, SYNC_RSEG_HEADER_NEW); #endif /* UNIV_SYNC_DEBUG */ page_no = buf_frame_get_page_no(page); /* Get the rollback segment file page */ rsegf = trx_rsegf_get_new(space, page_no, mtr); /* Initialize max size field */ mlog_write_ulint(rsegf + TRX_RSEG_MAX_SIZE, max_size, MLOG_4BYTES, mtr); /* Initialize the history list */ mlog_write_ulint(rsegf + TRX_RSEG_HISTORY_SIZE, 0, MLOG_4BYTES, mtr); flst_init(rsegf + TRX_RSEG_HISTORY, mtr); /* Reset the undo log slots */ for (i = 0; i < TRX_RSEG_N_SLOTS; i++) { trx_rsegf_set_nth_undo(rsegf, i, FIL_NULL, mtr); } /* Add the rollback segment info to the free slot in the trx system header */ trx_sysf_rseg_set_space(sys_header, *slot_no, space, mtr); trx_sysf_rseg_set_page_no(sys_header, *slot_no, page_no, mtr); return(page_no); }
/*************************************************************************** Gets the next record to purge and updates the info in the purge system. */ static trx_undo_rec_t* trx_purge_get_next_rec( /*===================*/ /* out: copy of an undo log record or pointer to the dummy undo log record */ mem_heap_t* heap) /* in: memory heap where copied */ { trx_undo_rec_t* rec; trx_undo_rec_t* rec_copy; trx_undo_rec_t* rec2; trx_undo_rec_t* next_rec; page_t* undo_page; page_t* page; ulint offset; ulint page_no; ulint space; ulint type; ulint cmpl_info; mtr_t mtr; ut_ad(mutex_own(&(purge_sys->mutex))); ut_ad(purge_sys->next_stored); space = purge_sys->rseg->space; page_no = purge_sys->page_no; offset = purge_sys->offset; if (offset == 0) { /* It is the dummy undo log record, which means that there is no need to purge this undo log */ trx_purge_rseg_get_next_history_log(purge_sys->rseg); /* Look for the next undo log and record to purge */ trx_purge_choose_next_log(); return(&trx_purge_dummy_rec); } mtr_start(&mtr); undo_page = trx_undo_page_get_s_latched(space, page_no, &mtr); rec = undo_page + offset; rec2 = rec; for (;;) { /* Try first to find the next record which requires a purge operation from the same page of the same undo log */ next_rec = trx_undo_page_get_next_rec(rec2, purge_sys->hdr_page_no, purge_sys->hdr_offset); if (next_rec == NULL) { rec2 = trx_undo_get_next_rec( rec2, purge_sys->hdr_page_no, purge_sys->hdr_offset, &mtr); break; } rec2 = next_rec; type = trx_undo_rec_get_type(rec2); if (type == TRX_UNDO_DEL_MARK_REC) { break; } cmpl_info = trx_undo_rec_get_cmpl_info(rec2); if (trx_undo_rec_get_extern_storage(rec2)) { break; } if ((type == TRX_UNDO_UPD_EXIST_REC) && !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { break; } } if (rec2 == NULL) { mtr_commit(&mtr); trx_purge_rseg_get_next_history_log(purge_sys->rseg); /* Look for the next undo log and record to purge */ trx_purge_choose_next_log(); mtr_start(&mtr); undo_page = trx_undo_page_get_s_latched(space, page_no, &mtr); rec = undo_page + offset; } else { page = buf_frame_align(rec2); purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec2); purge_sys->page_no = buf_frame_get_page_no(page); purge_sys->offset = rec2 - page; if (undo_page != page) { /* We advance to a new page of the undo log: */ purge_sys->n_pages_handled++; } } rec_copy = trx_undo_rec_copy(rec, heap); mtr_commit(&mtr); return(rec_copy); }
/*************************************************************************** Chooses the next undo log to purge and updates the info in purge_sys. This function is used to initialize purge_sys when the next record to purge is not known, and also to update the purge system info on the next record when purge has handled the whole undo log for a transaction. */ static void trx_purge_choose_next_log(void) /*===========================*/ { trx_undo_rec_t* rec; trx_rseg_t* rseg; trx_rseg_t* min_rseg; dulint min_trx_no; ulint space = 0; /* remove warning (??? bug ???) */ ulint page_no = 0; /* remove warning (??? bug ???) */ ulint offset = 0; /* remove warning (??? bug ???) */ mtr_t mtr; ut_ad(mutex_own(&(purge_sys->mutex))); ut_ad(purge_sys->next_stored == FALSE); rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); min_trx_no = ut_dulint_max; min_rseg = NULL; while (rseg) { mutex_enter(&(rseg->mutex)); if (rseg->last_page_no != FIL_NULL) { if ((min_rseg == NULL) || (ut_dulint_cmp(min_trx_no, rseg->last_trx_no) > 0)) { min_rseg = rseg; min_trx_no = rseg->last_trx_no; space = rseg->space; ut_a(space == 0); /* We assume in purge of externally stored fields that space id == 0 */ page_no = rseg->last_page_no; offset = rseg->last_offset; } } mutex_exit(&(rseg->mutex)); rseg = UT_LIST_GET_NEXT(rseg_list, rseg); } if (min_rseg == NULL) { return; } mtr_start(&mtr); if (!min_rseg->last_del_marks) { /* No need to purge this log */ rec = &trx_purge_dummy_rec; } else { rec = trx_undo_get_first_rec(space, page_no, offset, RW_S_LATCH, &mtr); if (rec == NULL) { /* Undo log empty */ rec = &trx_purge_dummy_rec; } } purge_sys->next_stored = TRUE; purge_sys->rseg = min_rseg; purge_sys->hdr_page_no = page_no; purge_sys->hdr_offset = offset; purge_sys->purge_trx_no = min_trx_no; if (rec == &trx_purge_dummy_rec) { purge_sys->purge_undo_no = ut_dulint_zero; purge_sys->page_no = page_no; purge_sys->offset = 0; } else { purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec); purge_sys->page_no = buf_frame_get_page_no(rec); purge_sys->offset = rec - buf_frame_align(rec); } mtr_commit(&mtr); }