/***********************************************************************//** Position the purge sys "iterator" on the undo record to use for purging. */ static void trx_purge_read_undo_rec( /*====================*/ trx_purge_t* purge_sys, /*!< in/out: purge instance */ ulint zip_size) /*!< in: block size or 0 */ { ulint page_no; ulint offset = 0; ib_uint64_t undo_no = 0; purge_sys->hdr_offset = purge_sys->rseg->last_offset; page_no = purge_sys->hdr_page_no = purge_sys->rseg->last_page_no; if (purge_sys->rseg->last_del_marks) { mtr_t mtr; trx_undo_rec_t* undo_rec; mtr_start(&mtr); undo_rec = trx_undo_get_first_rec( 0 /* System space id */, zip_size, purge_sys->hdr_page_no, purge_sys->hdr_offset, RW_S_LATCH, &mtr); if (undo_rec != NULL) { offset = page_offset(undo_rec); undo_no = trx_undo_rec_get_undo_no(undo_rec); page_no = page_get_page_no(page_align(undo_rec)); } mtr_commit(&mtr); } purge_sys->offset = offset; purge_sys->page_no = page_no; purge_sys->purge_undo_no = undo_no; purge_sys->next_stored = TRUE; }
/********************************************************************//** Prints info of a file-based list. */ UNIV_INTERN void flst_print( /*=======*/ const flst_base_node_t* base, /*!< in: pointer to base node of list */ mtr_t* mtr) /*!< in: mtr */ { const buf_frame_t* frame; ulint len; ut_ad(base && mtr); ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX)); frame = page_align((byte*) base); len = flst_get_len(base, mtr); fprintf(stderr, "FILE-BASED LIST:\n" "Base node in space %lu page %lu byte offset %lu; len %lu\n", (ulong) page_get_space_id(frame), (ulong) page_get_page_no(frame), (ulong) page_offset(base), (ulong) len); }
/***********************************************************************//** Gets the next record to purge and updates the info in the purge system. @return copy of an undo log record or pointer to the dummy undo log record */ static trx_undo_rec_t* trx_purge_get_next_rec( /*===================*/ 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 zip_size; ulint type; ulint cmpl_info; mtr_t mtr; ut_ad(purge_sys->next_stored); space = purge_sys->rseg->space; zip_size = purge_sys->rseg->zip_size; 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, zip_size, 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, zip_size, page_no, &mtr); rec = undo_page + offset; } else { page = page_align(rec2); purge_sys->purge_undo_no = trx_undo_rec_get_undo_no(rec2); purge_sys->page_no = page_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); }
/**************************************************************//** The position of the cursor is stored by taking an initial segment of the record the cursor is positioned on, before, or after, and copying it to the cursor data structure, or just setting a flag if the cursor id before the first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the page where the cursor is positioned must not be empty if the index tree is not totally empty! */ UNIV_INTERN void btr_pcur_store_position( /*====================*/ btr_pcur_t* cursor, /*!< in: persistent cursor */ mtr_t* mtr) /*!< in: mtr */ { page_cur_t* page_cursor; buf_block_t* block; rec_t* rec; dict_index_t* index; page_t* page; ulint offs; ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); block = btr_pcur_get_block(cursor); if (srv_pass_corrupt_table && !block) { return; } ut_a(block); index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor)); page_cursor = btr_pcur_get_page_cur(cursor); rec = page_cur_get_rec(page_cursor); page = page_align(rec); offs = page_offset(rec); ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX) || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); ut_a(cursor->latch_mode != BTR_NO_LATCHES); if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) { /* It must be an empty index tree; NOTE that in this case we do not store the modify_clock, but always do a search if we restore the cursor position */ ut_a(btr_page_get_next(page, mtr) == FIL_NULL); ut_a(btr_page_get_prev(page, mtr) == FIL_NULL); ut_ad(page_is_leaf(page)); ut_ad(page_get_page_no(page) == index->page); cursor->old_stored = BTR_PCUR_OLD_STORED; if (page_rec_is_supremum_low(offs)) { cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE; } else { cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE; } return; } if (page_rec_is_supremum_low(offs)) { rec = page_rec_get_prev(rec); cursor->rel_pos = BTR_PCUR_AFTER; } else if (page_rec_is_infimum_low(offs)) { rec = page_rec_get_next(rec); cursor->rel_pos = BTR_PCUR_BEFORE; } else { cursor->rel_pos = BTR_PCUR_ON; } cursor->old_stored = BTR_PCUR_OLD_STORED; cursor->old_rec = dict_index_copy_rec_order_prefix( index, rec, &cursor->old_n_fields, &cursor->old_rec_buf, &cursor->buf_size); cursor->block_when_stored = block; cursor->modify_clock = buf_block_get_modify_clock(block); }
/***********************************************************************//** 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; trx_id_t min_trx_no; ulint space = 0; /* remove warning (??? bug ???) */ ulint zip_size = 0; 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; zip_size = rseg->zip_size; 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, zip_size, 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 = page_get_page_no(page_align(rec)); purge_sys->offset = page_offset(rec); } mtr_commit(&mtr); }