/************************************************************************ Adds a node to an empty list. */ static void flst_add_to_empty( /*==============*/ flst_base_node_t* base, /* in: pointer to base node of empty list */ flst_node_t* node, /* in: node to add */ mtr_t* mtr) /* in: mini-transaction handle */ { ulint space; fil_addr_t node_addr; ulint len; ut_ad(mtr && base && node); ut_ad(base != node); ut_ad(mtr_memo_contains(mtr, buf_block_align(base), MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains(mtr, buf_block_align(node), MTR_MEMO_PAGE_X_FIX)); len = flst_get_len(base, mtr); ut_a(len == 0); buf_ptr_get_fsp_addr(node, &space, &node_addr); /* Update first and last fields of base node */ flst_write_addr(base + FLST_FIRST, node_addr, mtr); flst_write_addr(base + FLST_LAST, node_addr, mtr); /* Set prev and next fields of node to add */ flst_write_addr(node + FLST_PREV, fil_addr_null, mtr); flst_write_addr(node + FLST_NEXT, fil_addr_null, mtr); /* Update len of base node */ mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr); }
void rec_set_nth_field_extern_bit( /*=========================*/ rec_t* rec, /* in: record */ ulint i, /* in: ith field */ ibool val, /* in: value to set */ mtr_t* mtr) /* in: mtr holding an X-latch to the page where rec is, or NULL; in the NULL case we do not write to log about the change */ { ulint info; ut_a(!rec_get_1byte_offs_flag(rec)); ut_a(i < rec_get_n_fields(rec)); info = rec_2_get_field_end_info(rec, i); if (val) { info = info | REC_2BYTE_EXTERN_MASK; } else { info = info & ~REC_2BYTE_EXTERN_MASK; } if (mtr) { mlog_write_ulint(rec - REC_N_EXTRA_BYTES - 2 * (i + 1), info, MLOG_2BYTES, mtr); } else { rec_2_set_field_end_info(rec, i, info); } }
void flst_cut_end( /*=========*/ flst_base_node_t* base, /* in: pointer to base node of list */ flst_node_t* node2, /* in: first node to remove */ ulint n_nodes,/* in: number of nodes to remove, must be >= 1 */ mtr_t* mtr) /* in: mini-transaction handle */ { ulint space; flst_node_t* node1; fil_addr_t node1_addr; fil_addr_t node2_addr; ulint len; ut_ad(mtr && node2 && base); ut_ad(mtr_memo_contains(mtr, buf_block_align(base), MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains(mtr, buf_block_align(node2), MTR_MEMO_PAGE_X_FIX)); ut_ad(n_nodes > 0); buf_ptr_get_fsp_addr(node2, &space, &node2_addr); node1_addr = flst_get_prev_addr(node2, mtr); if (!fil_addr_is_null(node1_addr)) { /* Update next field of node1 */ if (node1_addr.page == node2_addr.page) { node1 = buf_frame_align(node2) + node1_addr.boffset; } else { node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH, mtr); } flst_write_addr(node1 + FLST_NEXT, fil_addr_null, mtr); } else { /* node2 was first in list: update the field in base */ flst_write_addr(base + FLST_FIRST, fil_addr_null, mtr); } flst_write_addr(base + FLST_LAST, node1_addr, mtr); /* Update len of base node */ len = flst_get_len(base, mtr); ut_ad(len >= n_nodes); mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr); }
/********************************************************************//** Inserts a node after another in a list. */ UNIV_INTERN void flst_insert_after( /*==============*/ flst_base_node_t* base, /*!< in: pointer to base node of list */ flst_node_t* node1, /*!< in: node to insert after */ flst_node_t* node2, /*!< in: node to add */ mtr_t* mtr) /*!< in: mini-transaction handle */ { ulint space; fil_addr_t node1_addr; fil_addr_t node2_addr; flst_node_t* node3; fil_addr_t node3_addr; ulint len; ut_ad(mtr && node1 && node2 && base); ut_ad(base != node1); ut_ad(base != node2); ut_ad(node2 != node1); ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains_page(mtr, node1, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX)); buf_ptr_get_fsp_addr(node1, &space, &node1_addr); buf_ptr_get_fsp_addr(node2, &space, &node2_addr); node3_addr = flst_get_next_addr(node1, mtr); /* Set prev and next fields of node2 */ flst_write_addr(node2 + FLST_PREV, node1_addr, mtr); flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr); if (!fil_addr_is_null(node3_addr)) { /* Update prev field of node3 */ ulint zip_size = fil_space_get_zip_size(space); node3 = fut_get_ptr(space, zip_size, node3_addr, RW_X_LATCH, mtr); flst_write_addr(node3 + FLST_PREV, node2_addr, mtr); } else { /* node1 was last in list: update last field in base */ flst_write_addr(base + FLST_LAST, node2_addr, mtr); } /* Set next field of node1 */ flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr); /* Update len of base node */ len = flst_get_len(base, mtr); mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr); }
void flst_insert_before( /*===============*/ flst_base_node_t* base, /* in: pointer to base node of list */ flst_node_t* node2, /* in: node to insert */ flst_node_t* node3, /* in: node to insert before */ mtr_t* mtr) /* in: mini-transaction handle */ { ulint space; flst_node_t* node1; fil_addr_t node1_addr; fil_addr_t node2_addr; fil_addr_t node3_addr; ulint len; ut_ad(mtr && node2 && node3 && base); ut_ad(base != node2); ut_ad(base != node3); ut_ad(node2 != node3); ut_ad(mtr_memo_contains(mtr, buf_block_align(base), MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains(mtr, buf_block_align(node2), MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains(mtr, buf_block_align(node3), MTR_MEMO_PAGE_X_FIX)); buf_ptr_get_fsp_addr(node2, &space, &node2_addr); buf_ptr_get_fsp_addr(node3, &space, &node3_addr); node1_addr = flst_get_prev_addr(node3, mtr); /* Set prev and next fields of node2 */ flst_write_addr(node2 + FLST_PREV, node1_addr, mtr); flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr); if (!fil_addr_is_null(node1_addr)) { /* Update next field of node1 */ node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH, mtr); flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr); } else { /* node3 was first in list: update first field in base */ flst_write_addr(base + FLST_FIRST, node2_addr, mtr); } /* Set prev field of node3 */ flst_write_addr(node3 + FLST_PREV, node2_addr, mtr); /* Update len of base node */ len = flst_get_len(base, mtr); mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr); }
/**********************************************************************//** Returns a new table, index, or space id. */ UNIV_INTERN void dict_hdr_get_new_id( /*================*/ table_id_t* table_id, /*!< out: table id (not assigned if NULL) */ index_id_t* index_id, /*!< out: index id (not assigned if NULL) */ ulint* space_id) /*!< out: space id (not assigned if NULL) */ { dict_hdr_t* dict_hdr; ib_id_t id; mtr_t mtr; mtr_start(&mtr); dict_hdr = dict_hdr_get(&mtr); if (table_id) { id = mach_read_from_8(dict_hdr + DICT_HDR_TABLE_ID); id++; mlog_write_ull(dict_hdr + DICT_HDR_TABLE_ID, id, &mtr); *table_id = id; } if (index_id) { id = mach_read_from_8(dict_hdr + DICT_HDR_INDEX_ID); id++; mlog_write_ull(dict_hdr + DICT_HDR_INDEX_ID, id, &mtr); *index_id = id; } if (space_id) { *space_id = mtr_read_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, MLOG_4BYTES, &mtr); if (fil_assign_new_space_id(space_id)) { mlog_write_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, *space_id, MLOG_4BYTES, &mtr); } } mtr_commit(&mtr); }
void flst_truncate_end( /*==============*/ flst_base_node_t* base, /* in: pointer to base node of list */ flst_node_t* node2, /* in: first node not to remove */ ulint n_nodes,/* in: number of nodes to remove */ mtr_t* mtr) /* in: mini-transaction handle */ { fil_addr_t node2_addr; ulint len; ulint space; ut_ad(mtr && node2 && base); ut_ad(mtr_memo_contains(mtr, buf_block_align(base), MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains(mtr, buf_block_align(node2), MTR_MEMO_PAGE_X_FIX)); if (n_nodes == 0) { ut_ad(fil_addr_is_null(flst_get_next_addr(node2, mtr))); return; } buf_ptr_get_fsp_addr(node2, &space, &node2_addr); /* Update next field of node2 */ flst_write_addr(node2 + FLST_NEXT, fil_addr_null, mtr); flst_write_addr(base + FLST_LAST, node2_addr, mtr); /* Update len of base node */ len = flst_get_len(base, mtr); ut_ad(len >= n_nodes); mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr); }
/**********************************************************************//** Frees an undo log segment which is in the history list. Cuts the end of the history list at the youngest undo log in this segment. */ static void trx_purge_free_segment( /*===================*/ trx_rseg_t* rseg, /*!< in: rollback segment */ fil_addr_t hdr_addr, /*!< in: the file address of log_hdr */ ulint n_removed_logs) /*!< in: count of how many undo logs we will cut off from the end of the history list */ { page_t* undo_page; trx_rsegf_t* rseg_hdr; trx_ulogf_t* log_hdr; trx_usegf_t* seg_hdr; ibool freed; ulint seg_size; ulint hist_size; ibool marked = FALSE; mtr_t mtr; /* fputs("Freeing an update undo log segment\n", stderr); */ loop: mtr_start(&mtr); mutex_enter(&(rseg->mutex)); rseg_hdr = trx_rsegf_get(rseg->space, rseg->zip_size, rseg->page_no, &mtr); undo_page = trx_undo_page_get(rseg->space, rseg->zip_size, hdr_addr.page, &mtr); seg_hdr = undo_page + TRX_UNDO_SEG_HDR; log_hdr = undo_page + hdr_addr.boffset; /* Mark the last undo log totally purged, so that if the system crashes, the tail of the undo log will not get accessed again. The list of pages in the undo log tail gets inconsistent during the freeing of the segment, and therefore purge should not try to access them again. */ if (!marked) { mlog_write_ulint(log_hdr + TRX_UNDO_DEL_MARKS, FALSE, MLOG_2BYTES, &mtr); marked = TRUE; } freed = fseg_free_step_not_header(seg_hdr + TRX_UNDO_FSEG_HEADER, &mtr); if (!freed) { mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); goto loop; } /* The page list may now be inconsistent, but the length field stored in the list base node tells us how big it was before we started the freeing. */ seg_size = flst_get_len(seg_hdr + TRX_UNDO_PAGE_LIST, &mtr); /* We may free the undo log segment header page; it must be freed within the same mtr as the undo log header is removed from the history list: otherwise, in case of a database crash, the segment could become inaccessible garbage in the file space. */ flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY, log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr); mutex_enter(&kernel_mutex); ut_ad(trx_sys->rseg_history_len >= n_removed_logs); trx_sys->rseg_history_len -= n_removed_logs; mutex_exit(&kernel_mutex); freed = FALSE; while (!freed) { /* Here we assume that a file segment with just the header page can be freed in a few steps, so that the buffer pool is not flooded with bufferfixed pages: see the note in fsp0fsp.c. */ freed = fseg_free_step(seg_hdr + TRX_UNDO_FSEG_HEADER, &mtr); } hist_size = mtr_read_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, &mtr); ut_ad(hist_size >= seg_size); mlog_write_ulint(rseg_hdr + TRX_RSEG_HISTORY_SIZE, hist_size - seg_size, MLOG_4BYTES, &mtr); ut_ad(rseg->curr_size >= seg_size); rseg->curr_size -= seg_size; mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); }
/********************************************************************//** Adds the update undo log as the first log in the history list. Removes the update undo log segment from the rseg slot if it is too big for reuse. */ UNIV_INTERN void trx_purge_add_update_undo_to_history( /*=================================*/ trx_t* trx, /*!< in: transaction */ page_t* undo_page, /*!< in: update undo log header page, x-latched */ mtr_t* mtr) /*!< in: mtr */ { trx_undo_t* undo; trx_rsegf_t* rseg_header; trx_ulogf_t* undo_header; undo = trx->update_undo; ut_ad(undo); ut_ad(mutex_own(&undo->rseg->mutex)); rseg_header = trx_rsegf_get( undo->rseg->space, undo->rseg->zip_size, undo->rseg->page_no, mtr); undo_header = undo_page + undo->hdr_offset; /* Add the log as the first in the history list */ if (undo->state != TRX_UNDO_CACHED) { ulint hist_size; #ifdef UNIV_DEBUG trx_usegf_t* seg_header = undo_page + TRX_UNDO_SEG_HDR; #endif /* UNIV_DEBUG */ /* The undo log segment will not be reused */ if (UNIV_UNLIKELY(undo->id >= TRX_RSEG_N_SLOTS)) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id); ut_error; } trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL, mtr); hist_size = mtr_read_ulint( rseg_header + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, mtr); ut_ad(undo->size == flst_get_len( seg_header + TRX_UNDO_PAGE_LIST, mtr)); mlog_write_ulint( rseg_header + TRX_RSEG_HISTORY_SIZE, hist_size + undo->size, MLOG_4BYTES, mtr); } flst_add_first( rseg_header + TRX_RSEG_HISTORY, undo_header + TRX_UNDO_HISTORY_NODE, mtr); /* Write the trx number to the undo log header */ mlog_write_ull(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); /* Write information about delete markings to the undo log header */ if (!undo->del_marks) { mlog_write_ulint( undo_header + TRX_UNDO_DEL_MARKS, FALSE, MLOG_2BYTES, mtr); } if (undo->rseg->last_page_no == FIL_NULL) { undo->rseg->last_trx_no = trx->no; undo->rseg->last_offset = undo->hdr_offset; undo->rseg->last_page_no = undo->hdr_page_no; undo->rseg->last_del_marks = undo->del_marks; /* FIXME: Add a bin heap validate function to check that the rseg exists. */ } mutex_enter(&kernel_mutex); trx_sys->rseg_history_len++; mutex_exit(&kernel_mutex); // if (!(trx_sys->rseg_history_len % srv_purge_batch_size)) { /*should wake up always*/ /* Inform the purge thread that there is work to do. */ srv_wake_purge_thread_if_not_active(); // } }
/****************************************************************//** Creates a rollback segment header. This function is called only when a new rollback segment is created in the database. @return page number of the created segment, FIL_NULL if fail */ UNIV_INTERN ulint trx_rseg_header_create( /*===================*/ ulint space, /*!< in: space id */ ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint max_size, /*!< in: max size in pages */ ulint rseg_slot_no, /*!< in: 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; buf_block_t* block; ut_ad(mtr); ut_ad(mutex_own(&kernel_mutex)); ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL), MTR_MEMO_X_LOCK)); /* Allocate a new file segment for the rollback segment */ block = fseg_create(space, 0, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr); if (block == NULL) { /* No space left */ return(FIL_NULL); } buf_block_dbg_add_level(block, SYNC_RSEG_HEADER_NEW); page_no = buf_block_get_page_no(block); /* Get the rollback segment file page */ rsegf = trx_rsegf_get_new(space, zip_size, 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 */ sys_header = trx_sysf_get(mtr); trx_sysf_rseg_set_space(sys_header, rseg_slot_no, space, mtr); trx_sysf_rseg_set_page_no(sys_header, rseg_slot_no, page_no, mtr); return(page_no); }
/********************************************************************//** Adds the update undo log as the first log in the history list. Removes the update undo log segment from the rseg slot if it is too big for reuse. */ UNIV_INTERN void trx_purge_add_update_undo_to_history( /*=================================*/ trx_t* trx, /*!< in: transaction */ page_t* undo_page, /*!< in: update undo log header page, x-latched */ mtr_t* mtr) /*!< in: mtr */ { trx_undo_t* undo; trx_rseg_t* rseg; trx_rsegf_t* rseg_header; #ifdef UNIV_DEBUG trx_usegf_t* seg_header; #endif /* UNIV_DEBUG */ trx_ulogf_t* undo_header; ulint hist_size; undo = trx->update_undo; ut_ad(undo); rseg = undo->rseg; ut_ad(mutex_own(&(rseg->mutex))); rseg_header = trx_rsegf_get(rseg->space, rseg->zip_size, rseg->page_no, mtr); undo_header = undo_page + undo->hdr_offset; #ifdef UNIV_DEBUG seg_header = undo_page + TRX_UNDO_SEG_HDR; #endif /* UNIV_DEBUG */ if (undo->state != TRX_UNDO_CACHED) { /* The undo log segment will not be reused */ if (undo->id >= TRX_RSEG_N_SLOTS) { fprintf(stderr, "InnoDB: Error: undo->id is %lu\n", (ulong) undo->id); ut_error; } trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL, mtr); hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, mtr); ut_ad(undo->size == flst_get_len( seg_header + TRX_UNDO_PAGE_LIST, mtr)); mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE, hist_size + undo->size, MLOG_4BYTES, mtr); } /* Add the log as the first in the history list */ flst_add_first(rseg_header + TRX_RSEG_HISTORY, undo_header + TRX_UNDO_HISTORY_NODE, mtr); mutex_enter(&kernel_mutex); trx_sys->rseg_history_len++; mutex_exit(&kernel_mutex); /* Write the trx number to the undo log header */ mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); /* Write information about delete markings to the undo log header */ if (!undo->del_marks) { mlog_write_ulint(undo_header + TRX_UNDO_DEL_MARKS, FALSE, MLOG_2BYTES, mtr); } if (rseg->last_page_no == FIL_NULL) { rseg->last_page_no = undo->hdr_page_no; rseg->last_offset = undo->hdr_offset; rseg->last_trx_no = trx->no; rseg->last_del_marks = undo->del_marks; } }
/*****************************************************************//** Creates the file page for the dictionary header. This function is called only at the database creation. @return TRUE if succeed */ static ibool dict_hdr_create( /*============*/ mtr_t* mtr) /*!< in: mtr */ { buf_block_t* block; dict_hdr_t* dict_header; ulint root_page_no; ut_ad(mtr); /* Create the dictionary header file block in a new, allocated file segment in the system tablespace */ block = fseg_create(DICT_HDR_SPACE, 0, DICT_HDR + DICT_HDR_FSEG_HEADER, mtr); ut_a(DICT_HDR_PAGE_NO == buf_block_get_page_no(block)); dict_header = dict_hdr_get(mtr); /* Start counting row, table, index, and tree ids from DICT_HDR_FIRST_ID */ mlog_write_dulint(dict_header + DICT_HDR_ROW_ID, ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); mlog_write_dulint(dict_header + DICT_HDR_TABLE_ID, ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID, ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); /* Obsolete, but we must initialize it to 0 anyway. */ mlog_write_dulint(dict_header + DICT_HDR_MIX_ID, ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); /* Create the B-tree roots for the clustered indexes of the basic system tables */ /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, DICT_HDR_SPACE, 0, DICT_TABLES_ID, dict_ind_redundant, mtr); if (root_page_no == FIL_NULL) { return(FALSE); } mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no, MLOG_4BYTES, mtr); /*--------------------------*/ root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE, 0, DICT_TABLE_IDS_ID, dict_ind_redundant, mtr); if (root_page_no == FIL_NULL) { return(FALSE); } mlog_write_ulint(dict_header + DICT_HDR_TABLE_IDS, root_page_no, MLOG_4BYTES, mtr); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, DICT_HDR_SPACE, 0, DICT_COLUMNS_ID, dict_ind_redundant, mtr); if (root_page_no == FIL_NULL) { return(FALSE); } mlog_write_ulint(dict_header + DICT_HDR_COLUMNS, root_page_no, MLOG_4BYTES, mtr); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, DICT_HDR_SPACE, 0, DICT_INDEXES_ID, dict_ind_redundant, mtr); if (root_page_no == FIL_NULL) { return(FALSE); } mlog_write_ulint(dict_header + DICT_HDR_INDEXES, root_page_no, MLOG_4BYTES, mtr); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, DICT_HDR_SPACE, 0, DICT_FIELDS_ID, dict_ind_redundant, mtr); if (root_page_no == FIL_NULL) { return(FALSE); } mlog_write_ulint(dict_header + DICT_HDR_FIELDS, root_page_no, MLOG_4BYTES, mtr); /*--------------------------*/ return(TRUE); }
void flst_remove( /*========*/ flst_base_node_t* base, /* in: pointer to base node of list */ flst_node_t* node2, /* in: node to remove */ mtr_t* mtr) /* in: mini-transaction handle */ { ulint space; flst_node_t* node1; fil_addr_t node1_addr; fil_addr_t node2_addr; flst_node_t* node3; fil_addr_t node3_addr; ulint len; ut_ad(mtr && node2 && base); ut_ad(mtr_memo_contains(mtr, buf_block_align(base), MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains(mtr, buf_block_align(node2), MTR_MEMO_PAGE_X_FIX)); buf_ptr_get_fsp_addr(node2, &space, &node2_addr); node1_addr = flst_get_prev_addr(node2, mtr); node3_addr = flst_get_next_addr(node2, mtr); if (!fil_addr_is_null(node1_addr)) { /* Update next field of node1 */ if (node1_addr.page == node2_addr.page) { node1 = buf_frame_align(node2) + node1_addr.boffset; } else { node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH, mtr); } ut_ad(node1 != node2); flst_write_addr(node1 + FLST_NEXT, node3_addr, mtr); } else { /* node2 was first in list: update first field in base */ flst_write_addr(base + FLST_FIRST, node3_addr, mtr); } if (!fil_addr_is_null(node3_addr)) { /* Update prev field of node3 */ if (node3_addr.page == node2_addr.page) { node3 = buf_frame_align(node2) + node3_addr.boffset; } else { node3 = fut_get_ptr(space, node3_addr, RW_X_LATCH, mtr); } ut_ad(node2 != node3); flst_write_addr(node3 + FLST_PREV, node1_addr, mtr); } else { /* node2 was last in list: update last field in base */ flst_write_addr(base + FLST_LAST, node1_addr, mtr); } /* Update len of base node */ len = flst_get_len(base, mtr); ut_ad(len > 0); mlog_write_ulint(base + FLST_LEN, len - 1, MLOG_4BYTES, mtr); }
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); }