diff options
Diffstat (limited to 'storage/innobase/trx/trx0rec.cc')
-rw-r--r-- | storage/innobase/trx/trx0rec.cc | 417 |
1 files changed, 181 insertions, 236 deletions
diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index eb7d0967901..52130b50eb1 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -52,96 +52,6 @@ const dtuple_t trx_undo_metadata = { /*=========== UNDO LOG RECORD CREATION AND DECODING ====================*/ -/** Write redo log of writing an undo log record. -@param[in] undo_block undo log page -@param[in] old_free start offset of the undo log record -@param[in] new_free end offset of the undo log record -@param[in,out] mtr mini-transaction */ -static void trx_undof_page_add_undo_rec_log(const buf_block_t* undo_block, - ulint old_free, ulint new_free, - mtr_t* mtr) -{ - ut_ad(old_free >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); - ut_ad(new_free >= old_free); - ut_ad(new_free < srv_page_size); - ut_ad(mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->frame) - == new_free); - mtr->set_modified(); - switch (mtr->get_log_mode()) { - case MTR_LOG_NONE: - case MTR_LOG_NO_REDO: - return; - case MTR_LOG_SHORT_INSERTS: - ut_ad(0); - /* fall through */ - case MTR_LOG_ALL: - break; - } - - const uint32_t - len = uint32_t(new_free - old_free - 4), - reserved = std::min<uint32_t>(11 + 13 + len, - mtr->get_log()->MAX_DATA_SIZE); - byte* log_ptr = mtr->get_log()->open(reserved); - const byte* log_end = log_ptr + reserved; - log_ptr = mlog_write_initial_log_record_low( - MLOG_UNDO_INSERT, - undo_block->page.id.space(), undo_block->page.id.page_no(), - log_ptr, mtr); - mach_write_to_2(log_ptr, len); - if (log_ptr + 2 + len <= log_end) { - memcpy(log_ptr + 2, undo_block->frame + old_free + 2, len); - mlog_close(mtr, log_ptr + 2 + len); - } else { - mlog_close(mtr, log_ptr + 2); - mtr->get_log()->push(undo_block->frame + old_free + 2, len); - } -} - -/** Parse MLOG_UNDO_INSERT. -@param[in] ptr log record -@param[in] end_ptr end of log record buffer -@param[in,out] page page or NULL -@return end of log record -@retval NULL if the log record is incomplete */ -byte* -trx_undo_parse_add_undo_rec( - const byte* ptr, - const byte* end_ptr, - page_t* page) -{ - ulint len; - - if (end_ptr < ptr + 2) { - - return(NULL); - } - - len = mach_read_from_2(ptr); - ptr += 2; - - if (end_ptr < ptr + len) { - - return(NULL); - } - - if (page) { - ulint first_free = mach_read_from_2(page + TRX_UNDO_PAGE_HDR - + TRX_UNDO_PAGE_FREE); - byte* rec = page + first_free; - - mach_write_to_2(rec, first_free + 4 + len); - mach_write_to_2(rec + 2 + len, first_free); - - mach_write_to_2(page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE, - first_free + 4 + len); - memcpy(rec + 2, ptr, len); - } - - return(const_cast<byte*>(ptr + len)); -} - /** Calculate the free space left for extending an undo log record. @param[in] undo_block undo log page @param[in] ptr current end of the undo page @@ -160,7 +70,7 @@ that was written to ptr. Update the first free value by the number of bytes written for this undo record. @return offset of the inserted entry on the page if succeeded, 0 if fail */ static -ulint +uint16_t trx_undo_page_set_next_prev_and_add( /*================================*/ buf_block_t* undo_block, /*!< in/out: undo log page */ @@ -168,42 +78,31 @@ trx_undo_page_set_next_prev_and_add( written on this undo page. */ mtr_t* mtr) /*!< in: mtr */ { - ulint first_free; /*!< offset within undo_page */ - ulint end_of_rec; /*!< offset within undo_page */ - byte* ptr_to_first_free; - /* pointer within undo_page - that points to the next free - offset value within undo_page.*/ + ut_ad(page_align(ptr) == undo_block->frame); - ut_ad(ptr > undo_block->frame); - ut_ad(ptr < undo_block->frame + srv_page_size); + if (UNIV_UNLIKELY(trx_undo_left(undo_block, ptr) < 2)) + return 0; - if (UNIV_UNLIKELY(trx_undo_left(undo_block, ptr) < 2)) { - return(0); - } - - ptr_to_first_free = TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->frame; + byte *ptr_to_first_free= my_assume_aligned<2>(TRX_UNDO_PAGE_HDR + + TRX_UNDO_PAGE_FREE + + undo_block->frame); - first_free = mach_read_from_2(ptr_to_first_free); + const uint16_t first_free= mach_read_from_2(ptr_to_first_free); - /* Write offset of the previous undo log record */ - mach_write_to_2(ptr, first_free); - ptr += 2; + /* Write offset of the previous undo log record */ + memcpy(ptr, ptr_to_first_free, 2); + ptr += 2; - end_of_rec = ulint(ptr - undo_block->frame); + const uint16_t end_of_rec= static_cast<uint16_t>(ptr - undo_block->frame); - /* Write offset of the next undo log record */ - mach_write_to_2(undo_block->frame + first_free, end_of_rec); + /* Update the offset to first free undo record */ + mach_write_to_2(ptr_to_first_free, end_of_rec); + /* Write offset of the next undo log record */ + memcpy(undo_block->frame + first_free, ptr_to_first_free, 2); + const byte *start= undo_block->frame + first_free + 2; - /* Update the offset to first free undo record */ - mach_write_to_2(ptr_to_first_free, end_of_rec); - - /* Write this log entry to the UNDO log */ - trx_undof_page_add_undo_rec_log(undo_block, first_free, - end_of_rec, mtr); - - return(first_free); + mtr->undo_append(*undo_block, start, ptr - start - 2); + return first_free; } /** Virtual column undo log version. To distinguish it from a length value @@ -289,7 +188,7 @@ trx_undo_log_v_idx( indexed, and return its position @param[in] table the table @param[in] ptr undo log pointer -@param[out] col_pos the column number or ULINT_UNDEFINED +@param[out] col_pos the column number or FIL_NULL if the column is not indexed any more @return remaining part of undo log record after reading these values */ static @@ -297,12 +196,12 @@ const byte* trx_undo_read_v_idx_low( const dict_table_t* table, const byte* ptr, - ulint* col_pos) + uint32_t* col_pos) { ulint len = mach_read_from_2(ptr); const byte* old_ptr = ptr; - *col_pos = ULINT_UNDEFINED; + *col_pos = FIL_NULL; ptr += 2; @@ -350,7 +249,7 @@ still indexed, and output its position check to see if this is undo log. When first_v_col is true, is_undo_log is output, when first_v_col is false, is_undo_log is input -@param[in,out] field_no the column number +@param[out] field_no the column number, or FIL_NULL if not indexed @return remaining part of undo log record after reading these values */ const byte* trx_undo_read_v_idx( @@ -358,7 +257,7 @@ trx_undo_read_v_idx( const byte* ptr, bool first_v_col, bool* is_undo_log, - ulint* field_no) + uint32_t* field_no) { /* Version marker only put on the first virtual column */ if (first_v_col) { @@ -471,7 +370,7 @@ trx_undo_report_insert_virtual( Reports in the undo log of an insert of a clustered index record. @return offset of the inserted entry on the page if succeed, 0 if fail */ static -ulint +uint16_t trx_undo_page_report_insert( /*========================*/ buf_block_t* undo_block, /*!< in: undo log page */ @@ -481,11 +380,7 @@ trx_undo_page_report_insert( inserted to the clustered index */ mtr_t* mtr) /*!< in: mtr */ { - ulint first_free; - byte* ptr; - ulint i; - - ut_ad(dict_index_is_clust(index)); + ut_ad(index->is_primary()); /* MariaDB 10.3.1+ in trx_undo_page_init() always initializes TRX_UNDO_PAGE_TYPE as 0, but previous versions wrote TRX_UNDO_INSERT == 1 into insert_undo pages, @@ -493,11 +388,14 @@ trx_undo_page_report_insert( ut_ad(mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + undo_block->frame) <= 2); - first_free = mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->frame); - ptr = undo_block->frame + first_free; + uint16_t first_free = mach_read_from_2(my_assume_aligned<2> + (TRX_UNDO_PAGE_HDR + + TRX_UNDO_PAGE_FREE + + undo_block->frame)); + byte* ptr = undo_block->frame + first_free; - ut_ad(first_free <= srv_page_size); + ut_ad(first_free >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); + ut_ad(first_free <= srv_page_size - FIL_PAGE_DATA_END); if (trx_undo_left(undo_block, ptr) < 2 + 1 + 11 + 11) { /* Not enough space for writing the general parameters */ @@ -523,7 +421,7 @@ trx_undo_page_report_insert( goto done; } - for (i = 0; i < dict_index_get_n_unique(index); i++) { + for (unsigned i = 0; i < dict_index_get_n_unique(index); i++) { const dfield_t* field = dtuple_get_nth_field(clust_entry, i); ulint flen = dfield_get_len(field); @@ -586,12 +484,14 @@ trx_undo_rec_get_pars( *updated_extern = !!(type_cmpl & TRX_UNDO_UPD_EXTERN); type_cmpl &= ~TRX_UNDO_UPD_EXTERN; - *type = type_cmpl & (TRX_UNDO_CMPL_INFO_MULT - 1); + ut_ad(*type >= TRX_UNDO_RENAME_TABLE); + ut_ad(*type <= TRX_UNDO_DEL_MARK_REC); *cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT; *undo_no = mach_read_next_much_compressed(&ptr); *table_id = mach_read_next_much_compressed(&ptr); + ut_ad(*table_id); return(const_cast<byte*>(ptr)); } @@ -607,8 +507,8 @@ byte* trx_undo_rec_get_col_val( const byte* ptr, const byte** field, - ulint* len, - ulint* orig_len) + uint32_t* len, + uint32_t* orig_len) { *len = mach_read_next_compressed(&ptr); *orig_len = 0; @@ -681,8 +581,7 @@ trx_undo_rec_get_row_ref( for (i = 0; i < ref_len; i++) { const byte* field; - ulint len; - ulint orig_len; + uint32_t len, orig_len; dfield_t* dfield = dtuple_get_nth_field(tuple, i); @@ -715,8 +614,7 @@ trx_undo_rec_skip_row_ref( for (i = 0; i < ref_len; i++) { const byte* field; - ulint len; - ulint orig_len; + uint32_t len, orig_len; ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len); } @@ -870,7 +768,7 @@ record. @return byte offset of the inserted undo log entry on the page if succeed, 0 if fail */ static -ulint +uint16_t trx_undo_page_report_modify( /*========================*/ buf_block_t* undo_block, /*!< in: undo log page */ @@ -889,9 +787,6 @@ trx_undo_page_report_modify( virtual column info */ mtr_t* mtr) /*!< in: mtr */ { - ulint first_free; - byte* ptr; - ut_ad(index->is_primary()); ut_ad(rec_offs_validate(rec, index, offsets)); /* MariaDB 10.3.1+ in trx_undo_page_init() always initializes @@ -901,11 +796,15 @@ trx_undo_page_report_modify( ut_ad(mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + undo_block->frame) <= 2); - first_free = mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->frame); - ptr = undo_block->frame + first_free; + byte* ptr_to_first_free = my_assume_aligned<2>(TRX_UNDO_PAGE_HDR + + TRX_UNDO_PAGE_FREE + + undo_block->frame); - ut_ad(first_free <= srv_page_size); + const uint16_t first_free = mach_read_from_2(ptr_to_first_free); + byte *ptr = undo_block->frame + first_free; + + ut_ad(first_free >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); + ut_ad(first_free <= srv_page_size - FIL_PAGE_DATA_END); if (trx_undo_left(undo_block, ptr) < 50) { /* NOTE: the value 50 must be big enough so that the general @@ -1493,15 +1392,14 @@ already_logged: } mach_write_to_2(ptr, first_free); - ptr += 2; - const ulint new_free = ulint(ptr - undo_block->frame); + const uint16_t new_free = static_cast<uint16_t>( + ptr + 2 - undo_block->frame); mach_write_to_2(undo_block->frame + first_free, new_free); - mach_write_to_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + undo_block->frame, new_free); + mach_write_to_2(ptr_to_first_free, new_free); - /* Write to the REDO log about this change in the UNDO log */ - trx_undof_page_add_undo_rec_log(undo_block, first_free, new_free, mtr); + const byte* start = &undo_block->frame[first_free + 2]; + mtr->undo_append(*undo_block, start, ptr - start); return(first_free); } @@ -1517,11 +1415,10 @@ trx_undo_update_rec_get_sys_cols( general parameters */ trx_id_t* trx_id, /*!< out: trx id */ roll_ptr_t* roll_ptr, /*!< out: roll ptr */ - ulint* info_bits) /*!< out: info bits state */ + byte* info_bits) /*!< out: info bits state */ { /* Read the state of the info bits */ - *info_bits = mach_read_from_1(ptr); - ptr += 1; + *info_bits = *ptr++; /* Read the values of the system columns */ @@ -1552,7 +1449,7 @@ trx_undo_update_rec_get_update( the update vector */ trx_id_t trx_id, /*!< in: transaction id from this undo record */ roll_ptr_t roll_ptr,/*!< in: roll pointer from this undo record */ - ulint info_bits,/*!< in: info bits from this undo record */ + byte info_bits,/*!< in: info bits from this undo record */ mem_heap_t* heap, /*!< in: memory heap from which the memory needed is allocated */ upd_t** upd) /*!< out, own: update vector */ @@ -1600,12 +1497,11 @@ trx_undo_update_rec_get_update( /* Store then the updated ordinary columns to the update vector */ for (ulint i = 0; i < n_fields; i++) { - const byte* field; - ulint len; - ulint orig_len; + const byte* field; + uint32_t len, orig_len; upd_field = upd_get_nth_field(update, i); - ulint field_no = mach_read_next_compressed(&ptr); + uint32_t field_no = mach_read_next_compressed(&ptr); const bool is_virtual = (field_no >= REC_MAX_N_FIELDS); @@ -1617,7 +1513,7 @@ trx_undo_update_rec_get_update( &field_no); first_v_col = false; /* This column could be dropped or no longer indexed */ - if (field_no == ULINT_UNDEFINED) { + if (field_no >= index->n_fields) { /* Mark this is no longer needed */ upd_field->field_no = REC_MAX_N_FIELDS; @@ -1629,12 +1525,14 @@ trx_undo_update_rec_get_update( continue; } - upd_field_set_v_field_no(upd_field, field_no, index); + upd_field_set_v_field_no( + upd_field, static_cast<uint16_t>(field_no), + index); } else if (UNIV_UNLIKELY((update->info_bits & ~REC_INFO_DELETED_FLAG) == REC_INFO_MIN_REC_FLAG)) { ut_ad(type == TRX_UNDO_UPD_EXIST_REC); - const ulint uf = index->first_user_field(); + const uint32_t uf = index->first_user_field(); ut_ad(field_no >= uf); if (update->info_bits != REC_INFO_MIN_REC_FLAG) { @@ -1684,9 +1582,12 @@ trx_undo_update_rec_get_update( field_no), &upd_field->new_val.type); } - upd_field->field_no = field_no; + upd_field->field_no = field_no + & dict_index_t::MAX_N_FIELDS; } else if (field_no < index->n_fields) { - upd_field_set_field_no(upd_field, field_no, index); + upd_field_set_field_no(upd_field, + static_cast<uint16_t>(field_no), + index); } else { ib::error() << "Trying to access update undo rec" " field " << field_no @@ -1706,7 +1607,7 @@ trx_undo_update_rec_get_update( ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len); - upd_field->orig_len = orig_len; + upd_field->orig_len = static_cast<uint16_t>(orig_len); if (len == UNIV_SQL_NULL) { dfield_set_null(&upd_field->new_val); @@ -1826,15 +1727,13 @@ trx_undo_rec_get_partial_row( while (ptr != end_ptr) { dfield_t* dfield; const byte* field; - ulint field_no; + uint32_t field_no; const dict_col_t* col; - ulint len; - ulint orig_len; - bool is_virtual; + uint32_t len, orig_len; field_no = mach_read_next_compressed(&ptr); - is_virtual = (field_no >= REC_MAX_N_FIELDS); + const bool is_virtual = (field_no >= REC_MAX_N_FIELDS); if (is_virtual) { ptr = trx_undo_read_v_idx( @@ -1846,7 +1745,7 @@ trx_undo_rec_get_partial_row( ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len); /* This column could be dropped or no longer indexed */ - if (field_no == ULINT_UNDEFINED) { + if (field_no == FIL_NULL) { ut_ad(is_virtual); continue; } @@ -1943,22 +1842,6 @@ trx_undo_rec_get_partial_row( return(const_cast<byte*>(ptr)); } -/** Erase the unused undo log page end. -@param[in,out] undo_page undo log page -@return whether the page contained something */ -bool -trx_undo_erase_page_end(page_t* undo_page) -{ - ulint first_free; - - first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR - + TRX_UNDO_PAGE_FREE); - memset(undo_page + first_free, 0, - (srv_page_size - FIL_PAGE_DATA_END) - first_free); - - return(first_free != TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); -} - /** Report a RENAME TABLE operation. @param[in,out] trx transaction @param[in] table table that is being renamed @@ -1967,16 +1850,17 @@ trx_undo_erase_page_end(page_t* undo_page) @return byte offset of the undo log record @retval 0 in case of failure */ static -ulint +uint16_t trx_undo_page_report_rename(trx_t* trx, const dict_table_t* table, buf_block_t* block, mtr_t* mtr) { - byte* ptr_first_free = TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE - + block->frame; - ulint first_free = mach_read_from_2(ptr_first_free); + byte* ptr_first_free = my_assume_aligned<2>(TRX_UNDO_PAGE_HDR + + TRX_UNDO_PAGE_FREE + + block->frame); + const uint16_t first_free = mach_read_from_2(ptr_first_free); ut_ad(first_free >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); - ut_ad(first_free <= srv_page_size); - byte* start = block->frame + first_free; + ut_ad(first_free <= srv_page_size - FIL_PAGE_DATA_END); + byte* const start = block->frame + first_free; size_t len = strlen(table->name.m_name); const size_t fixed = 2 + 1 + 11 + 11 + 2; ut_ad(len <= NAME_LEN * 2 + 1); @@ -1998,12 +1882,9 @@ trx_undo_page_report_rename(trx_t* trx, const dict_table_t* table, memcpy(ptr, table->name.m_name, len); ptr += len; mach_write_to_2(ptr, first_free); - ptr += 2; - ulint offset = page_offset(ptr); - mach_write_to_2(start, offset); - mach_write_to_2(ptr_first_free, offset); - - trx_undof_page_add_undo_rec_log(block, first_free, offset, mtr); + mach_write_to_2(ptr_first_free, ptr + 2 - block->frame); + memcpy(start, ptr_first_free, 2); + mtr->undo_append(*block, start + 2, ptr - start - 2); return first_free; } @@ -2026,9 +1907,10 @@ dberr_t trx_undo_report_rename(trx_t* trx, const dict_table_t* table) ut_ad(undo); for (ut_d(int loop_count = 0);;) { ut_ad(loop_count++ < 2); - ut_ad(undo->last_page_no == block->page.id.page_no()); + ut_ad(undo->last_page_no + == block->page.id().page_no()); - if (ulint offset = trx_undo_page_report_rename( + if (uint16_t offset = trx_undo_page_report_rename( trx, table, block, &mtr)) { undo->top_page_no = undo->last_page_no; undo->top_offset = offset; @@ -2130,7 +2012,7 @@ trx_undo_report_row_operation( ut_ad(undo != NULL); do { - ulint offset = !rec + uint16_t offset = !rec ? trx_undo_page_report_insert( undo_block, trx, index, clust_entry, &mtr) : trx_undo_page_report_modify( @@ -2138,7 +2020,15 @@ trx_undo_report_row_operation( cmpl_info, clust_entry, &mtr); if (UNIV_UNLIKELY(offset == 0)) { - if (!trx_undo_erase_page_end(undo_block->frame)) { + const uint16_t first_free = mach_read_from_2( + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + + undo_block->frame); + memset(undo_block->frame + first_free, 0, + (srv_page_size - FIL_PAGE_DATA_END) + - first_free); + + if (first_free + == TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE) { /* The record did not fit on an empty undo page. Discard the freshly allocated page and return an error. */ @@ -2164,6 +2054,21 @@ trx_undo_report_row_operation( err = DB_UNDO_RECORD_TOO_BIG; goto err_exit; + } else { + /* Write log for clearing the unused + tail of the undo page. It might + contain some garbage from a previously + written record, and mtr_t::write() + will optimize away writes of unchanged + bytes. Failure to write this caused a + recovery failure when we avoided + reading the undo log page from the + data file and initialized it based on + redo log records (which included the + write of the previous garbage). */ + mtr.memset(*undo_block, first_free, + srv_page_size - first_free + - FIL_PAGE_DATA_END, 0); } mtr_commit(&mtr); @@ -2171,7 +2076,7 @@ trx_undo_report_row_operation( /* Success */ mtr_commit(&mtr); - undo->top_page_no = undo_block->page.id.page_no(); + undo->top_page_no = undo_block->page.id().page_no(); undo->top_offset = offset; undo->top_undo_no = trx->undo_no++; undo->guess_block = undo_block; @@ -2203,7 +2108,7 @@ trx_undo_report_row_operation( return(DB_SUCCESS); } - ut_ad(undo_block->page.id.page_no() == undo->last_page_no); + ut_ad(undo_block->page.id().page_no() == undo->last_page_no); /* We have to extend the undo log by one page */ @@ -2251,11 +2156,10 @@ trx_undo_get_undo_rec_low( { trx_undo_rec_t* undo_rec; ulint rseg_id; - ulint page_no; - ulint offset; - const page_t* undo_page; + uint32_t page_no; + uint16_t offset; trx_rseg_t* rseg; - ibool is_insert; + bool is_insert; mtr_t mtr; trx_undo_decode_roll_ptr(roll_ptr, &is_insert, &rseg_id, &page_no, @@ -2265,14 +2169,14 @@ trx_undo_get_undo_rec_low( rseg = trx_sys.rseg_array[rseg_id]; ut_ad(rseg->is_persistent()); - mtr_start(&mtr); + mtr.start(); - undo_page = trx_undo_page_get_s_latched( + buf_block_t* undo_page = trx_undo_page_get_s_latched( page_id_t(rseg->space->id, page_no), &mtr); - undo_rec = trx_undo_rec_copy(undo_page + offset, heap); + undo_rec = trx_undo_rec_copy(undo_page->frame + offset, heap); - mtr_commit(&mtr); + mtr.commit(); return(undo_rec); } @@ -2298,11 +2202,9 @@ trx_undo_get_undo_rec( const table_name_t& name, trx_undo_rec_t** undo_rec) { - bool missing_history; - rw_lock_s_lock(&purge_sys.latch); - missing_history = purge_sys.view.changes_visible(trx_id, name); + bool missing_history = purge_sys.changes_visible(trx_id, name); if (!missing_history) { *undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap); } @@ -2364,16 +2266,16 @@ trx_undo_prev_version_build( roll_ptr_t roll_ptr; upd_t* update; byte* ptr; - ulint info_bits; + byte info_bits; ulint cmpl_info; bool dummy_extern; byte* buf; ut_ad(!index->table->is_temporary()); ut_ad(!rw_lock_own(&purge_sys.latch, RW_LOCK_S)); - ut_ad(mtr_memo_contains_page_flagged(index_mtr, index_rec, - MTR_MEMO_PAGE_S_FIX - | MTR_MEMO_PAGE_X_FIX)); + ut_ad(index_mtr->memo_contains_page_flagged(index_rec, + MTR_MEMO_PAGE_S_FIX + | MTR_MEMO_PAGE_X_FIX)); ut_ad(rec_offs_validate(rec, index, offsets)); ut_a(index->is_primary()); @@ -2468,7 +2370,7 @@ trx_undo_prev_version_build( rw_lock_s_lock(&purge_sys.latch); - missing_extern = purge_sys.view.changes_visible( + missing_extern = purge_sys.changes_visible( trx_id, index->table->name); rw_lock_s_unlock(&purge_sys.latch); @@ -2511,7 +2413,53 @@ trx_undo_prev_version_build( *old_vers = rec_copy(buf, rec, offsets); rec_offs_make_valid(*old_vers, index, true, offsets); - row_upd_rec_in_place(*old_vers, index, offsets, update, NULL); + rec_set_bit_field_1(*old_vers, update->info_bits, + rec_offs_comp(offsets) + ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS, + REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT); + for (ulint i = 0; i < update->n_fields; i++) { + const upd_field_t* uf = upd_get_nth_field(update, i); + if (upd_fld_is_virtual_col(uf)) { + /* There are no virtual columns in + a clustered index record. */ + continue; + } + const ulint n = uf->field_no; + ut_ad(!dfield_is_ext(&uf->new_val) + == !rec_offs_nth_extern(offsets, n)); + ut_ad(!rec_offs_nth_default(offsets, n)); + + if (UNIV_UNLIKELY(dfield_is_null(&uf->new_val))) { + if (rec_offs_nth_sql_null(offsets, n)) { + ut_ad(index->table->is_instant()); + ut_ad(n >= index->n_core_fields); + continue; + } + ut_ad(!index->table->not_redundant()); + ulint l = rec_get_1byte_offs_flag(*old_vers) + ? (n + 1) : (n + 1) * 2; + byte* b = *old_vers - REC_N_OLD_EXTRA_BYTES + - l; + *b= byte(*b | REC_1BYTE_SQL_NULL_MASK); + compile_time_assert(REC_1BYTE_SQL_NULL_MASK << 8 + == REC_2BYTE_SQL_NULL_MASK); + continue; + } + + ulint len; + memcpy(rec_get_nth_field(*old_vers, offsets, n, &len), + uf->new_val.data, uf->new_val.len); + if (UNIV_UNLIKELY(len != uf->new_val.len)) { + ut_ad(len == UNIV_SQL_NULL); + ut_ad(!rec_offs_comp(offsets)); + ut_ad(uf->new_val.len + == rec_get_nth_field_size(rec, n)); + ulint l = rec_get_1byte_offs_flag(*old_vers) + ? (n + 1) : (n + 1) * 2; + (*old_vers)[-REC_N_OLD_EXTRA_BYTES - l] + &= byte(~REC_1BYTE_SQL_NULL_MASK); + } + } } /* Set the old value (which is the after image of an update) in the @@ -2565,17 +2513,14 @@ trx_undo_read_v_cols( end_ptr = ptr + mach_read_from_2(ptr); ptr += 2; while (ptr < end_ptr) { - dfield_t* dfield; - const byte* field; - ulint field_no; - ulint len; - ulint orig_len; - bool is_virtual; + dfield_t* dfield; + const byte* field; + uint32_t field_no, len, orig_len; field_no = mach_read_next_compressed( const_cast<const byte**>(&ptr)); - is_virtual = (field_no >= REC_MAX_N_FIELDS); + const bool is_virtual = (field_no >= REC_MAX_N_FIELDS); if (is_virtual) { ptr = trx_undo_read_v_idx( @@ -2590,7 +2535,7 @@ trx_undo_read_v_cols( /* The virtual column is no longer indexed or does not exist. This needs to put after trx_undo_rec_get_col_val() so the undo ptr advances */ - if (field_no == ULINT_UNDEFINED) { + if (field_no == FIL_NULL) { ut_ad(is_virtual); continue; } |