trx_rseg_t* trx_rseg_create( /*============*/ /* out: the created segment object, NULL if fail */ ulint space, /* in: space id */ ulint max_size, /* in: max size in pages */ ulint* id, /* out: rseg id */ mtr_t* mtr) /* in: mtr */ { ulint page_no; trx_rseg_t* rseg; mtr_x_lock(fil_space_get_latch(space), mtr); mutex_enter(&kernel_mutex); page_no = trx_rseg_header_create(space, max_size, id, mtr); if (page_no == FIL_NULL) { mutex_exit(&kernel_mutex); return(NULL); } rseg = trx_rseg_mem_create(*id, space, page_no, mtr); mutex_exit(&kernel_mutex); return(rseg); }
/****************************************************************//** Creates a new rollback segment to the database. @return the created segment object, NULL if fail */ UNIV_INTERN trx_rseg_t* trx_rseg_create( /*============*/ ulint space, /*!< in: space id */ ulint max_size, /*!< in: max size in pages */ ulint* id, /*!< out: rseg id */ mtr_t* mtr) /*!< in: mtr */ { ulint flags; ulint zip_size; ulint page_no; trx_rseg_t* rseg; mtr_x_lock(fil_space_get_latch(space, &flags), mtr); zip_size = dict_table_flags_to_zip_size(flags); mutex_enter(&kernel_mutex); page_no = trx_rseg_header_create(space, zip_size, max_size, id, mtr); if (page_no == FIL_NULL) { mutex_exit(&kernel_mutex); return(NULL); } rseg = trx_rseg_mem_create(*id, space, zip_size, page_no, mtr); mutex_exit(&kernel_mutex); return(rseg); }
/********************************************************************* Creates a rollback segment. @return pointer to new rollback segment if create successful */ UNIV_INTERN trx_rseg_t* trx_rseg_create(void) /*=================*/ { mtr_t mtr; ulint slot_no; trx_rseg_t* rseg = NULL; mtr_start(&mtr); /* To obey the latching order, acquire the file space x-latch before the kernel mutex. */ mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), &mtr); mutex_enter(&kernel_mutex); slot_no = trx_sysf_rseg_find_free(&mtr); if (slot_no != ULINT_UNDEFINED) { ulint space; ulint page_no; ulint zip_size; trx_sysf_t* sys_header; page_no = trx_rseg_header_create( TRX_SYS_SPACE, 0, ULINT_MAX, slot_no, &mtr); ut_a(page_no != FIL_NULL); ut_ad(!trx_rseg_get_on_id(slot_no)); sys_header = trx_sysf_get(&mtr); space = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr); zip_size = space ? fil_space_get_zip_size(space) : 0; rseg = trx_rseg_mem_create( slot_no, space, zip_size, page_no, &mtr); } mutex_exit(&kernel_mutex); mtr_commit(&mtr); return(rseg); }
/***********************************************************//** Purges an update of an existing record. Also purges an update of a delete marked record if that record contained an externally stored field. */ static void row_purge_upd_exist_or_extern_func( /*===============================*/ #ifdef UNIV_DEBUG const que_thr_t*thr, /*!< in: query thread */ #endif /* UNIV_DEBUG */ purge_node_t* node) /*!< in: row purge node */ { mem_heap_t* heap; dtuple_t* entry; dict_index_t* index; ibool is_insert; ulint rseg_id; ulint page_no; ulint offset; ulint i; mtr_t mtr; ut_ad(node); if (node->rec_type == TRX_UNDO_UPD_DEL_REC || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { goto skip_secondaries; } heap = mem_heap_create(1024); while (node->index != NULL) { dict_table_skip_corrupt_index(node->index); if (!node->index) { break; } index = node->index; if (row_upd_changes_ord_field_binary(node->index, node->update, thr, NULL, NULL)) { /* Build the older version of the index entry */ entry = row_build_index_entry(node->row, NULL, index, heap); ut_a(entry); row_purge_remove_sec_if_poss(node, index, entry); } node->index = dict_table_get_next_index(node->index); } mem_heap_free(heap); skip_secondaries: /* Free possible externally stored fields */ for (i = 0; i < upd_get_n_fields(node->update); i++) { const upd_field_t* ufield = upd_get_nth_field(node->update, i); if (dfield_is_ext(&ufield->new_val)) { buf_block_t* block; ulint internal_offset; byte* data_field; /* We use the fact that new_val points to node->undo_rec and get thus the offset of dfield data inside the undo record. Then we can calculate from node->roll_ptr the file address of the new_val data */ internal_offset = ((const byte*) dfield_get_data(&ufield->new_val)) - node->undo_rec; ut_a(internal_offset < UNIV_PAGE_SIZE); trx_undo_decode_roll_ptr(node->roll_ptr, &is_insert, &rseg_id, &page_no, &offset); mtr_start(&mtr); /* We have to acquire an X-latch to the clustered index tree */ index = dict_table_get_first_index(node->table); mtr_x_lock(dict_index_get_lock(index), &mtr); /* NOTE: we must also acquire an X-latch to the root page of the tree. We will need it when we free pages from the tree. If the tree is of height 1, the tree X-latch does NOT protect the root page, because it is also a leaf page. Since we will have a latch on an undo log page, we would break the latching order if we would only later latch the root page of such a tree! */ btr_root_get(index, &mtr); /* We assume in purge of externally stored fields that the space id of the undo log record is 0! */ block = buf_page_get(0, 0, page_no, RW_X_LATCH, &mtr); buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE); data_field = buf_block_get_frame(block) + offset + internal_offset; ut_a(dfield_get_len(&ufield->new_val) >= BTR_EXTERN_FIELD_REF_SIZE); btr_free_externally_stored_field( index, data_field + dfield_get_len(&ufield->new_val) - BTR_EXTERN_FIELD_REF_SIZE, NULL, NULL, NULL, 0, RB_NONE, &mtr); mtr_commit(&mtr); } } }
/*************************************************************** Purges an update of an existing record. Also purges an update of a delete marked record if that record contained an externally stored field. */ static void row_purge_upd_exist_or_extern( /*==========================*/ purge_node_t* node, /* in: row purge node */ que_thr_t* thr) /* in: query thread */ { mem_heap_t* heap; dtuple_t* entry; dict_index_t* index; upd_field_t* ufield; ibool is_insert; ulint rseg_id; ulint page_no; ulint offset; ulint internal_offset; byte* data_field; ulint data_field_len; ulint i; mtr_t mtr; ut_ad(node && thr); if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { goto skip_secondaries; } heap = mem_heap_create(1024); while (node->index != NULL) { index = node->index; if (row_upd_changes_ord_field_binary(NULL, node->index, node->update)) { /* Build the older version of the index entry */ entry = row_build_index_entry(node->row, index, heap); row_purge_remove_sec_if_poss(node, thr, index, entry); } node->index = dict_table_get_next_index(node->index); } mem_heap_free(heap); skip_secondaries: /* Free possible externally stored fields */ for (i = 0; i < upd_get_n_fields(node->update); i++) { ufield = upd_get_nth_field(node->update, i); if (ufield->extern_storage) { /* We use the fact that new_val points to node->undo_rec and get thus the offset of dfield data inside the unod record. Then we can calculate from node->roll_ptr the file address of the new_val data */ internal_offset = ((byte*)ufield->new_val.data) - node->undo_rec; ut_a(internal_offset < UNIV_PAGE_SIZE); trx_undo_decode_roll_ptr(node->roll_ptr, &is_insert, &rseg_id, &page_no, &offset); mtr_start(&mtr); /* We have to acquire an X-latch to the clustered index tree */ index = dict_table_get_first_index(node->table); mtr_x_lock(dict_tree_get_lock(index->tree), &mtr); /* We assume in purge of externally stored fields that the space id of the undo log record is 0! */ data_field = buf_page_get(0, page_no, RW_X_LATCH, &mtr) + offset + internal_offset; buf_page_dbg_add_level(buf_frame_align(data_field), SYNC_TRX_UNDO_PAGE); data_field_len = ufield->new_val.len; btr_free_externally_stored_field(index, data_field, data_field_len, FALSE, &mtr); mtr_commit(&mtr); } } }
/*************************************************************** Purges an update of an existing record. Also purges an update of a delete marked record if that record contained an externally stored field. */ static void row_purge_upd_exist_or_extern( /*==========================*/ purge_node_t* node) /* in: row purge node */ { mem_heap_t* heap; dtuple_t* entry; dict_index_t* index; upd_field_t* ufield; ibool is_insert; ulint rseg_id; ulint page_no; ulint offset; ulint internal_offset; byte* data_field; ulint data_field_len; ulint i; mtr_t mtr; ut_ad(node); if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { goto skip_secondaries; } heap = mem_heap_create(1024); while (node->index != NULL) { index = node->index; if (row_upd_changes_ord_field_binary(NULL, node->index, node->update)) { /* Build the older version of the index entry */ entry = row_build_index_entry(node->row, index, heap); row_purge_remove_sec_if_poss(node, index, entry); } node->index = dict_table_get_next_index(node->index); } mem_heap_free(heap); skip_secondaries: /* Free possible externally stored fields */ for (i = 0; i < upd_get_n_fields(node->update); i++) { ufield = upd_get_nth_field(node->update, i); if (ufield->extern_storage) { /* We use the fact that new_val points to node->undo_rec and get thus the offset of dfield data inside the unod record. Then we can calculate from node->roll_ptr the file address of the new_val data */ internal_offset = ((byte*)ufield->new_val.data) - node->undo_rec; ut_a(internal_offset < UNIV_PAGE_SIZE); trx_undo_decode_roll_ptr(node->roll_ptr, &is_insert, &rseg_id, &page_no, &offset); mtr_start(&mtr); /* We have to acquire an X-latch to the clustered index tree */ index = dict_table_get_first_index(node->table); mtr_x_lock(dict_index_get_lock(index), &mtr); /* NOTE: we must also acquire an X-latch to the root page of the tree. We will need it when we free pages from the tree. If the tree is of height 1, the tree X-latch does NOT protect the root page, because it is also a leaf page. Since we will have a latch on an undo log page, we would break the latching order if we would only later latch the root page of such a tree! */ btr_root_get(index, &mtr); /* We assume in purge of externally stored fields that the space id of the undo log record is 0! */ data_field = buf_page_get(0, page_no, RW_X_LATCH, &mtr) + offset + internal_offset; #ifdef UNIV_SYNC_DEBUG buf_page_dbg_add_level(buf_frame_align(data_field), SYNC_TRX_UNDO_PAGE); #endif /* UNIV_SYNC_DEBUG */ data_field_len = ufield->new_val.len; btr_free_externally_stored_field(index, data_field, data_field_len, FALSE, &mtr); mtr_commit(&mtr); } } }