diff options
Diffstat (limited to 'storage/innobase/trx')
| -rw-r--r-- | storage/innobase/trx/trx0purge.cc | 129 | ||||
| -rw-r--r-- | storage/innobase/trx/trx0rseg.cc | 42 | ||||
| -rw-r--r-- | storage/innobase/trx/trx0trx.cc | 72 | ||||
| -rw-r--r-- | storage/innobase/trx/trx0undo.cc | 57 |
4 files changed, 132 insertions, 168 deletions
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index a1d569571c8..e5f8f38ce6c 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -263,6 +263,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) + undo->hdr_offset; ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1); + ut_ad(rseg->needs_purge > trx->id); if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + rseg_header->page.frame))) { @@ -356,7 +357,6 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) rseg->last_page_no = undo->hdr_page_no; rseg->set_last_commit(undo->hdr_offset, trx->rw_trx_hash_element->no); - rseg->set_needs_purge(); } rseg->history_size++; @@ -387,24 +387,21 @@ static dberr_t trx_purge_remove_log_hdr(buf_block_t *rseg, buf_block_t* log, MY_ATTRIBUTE((nonnull, warn_unused_result)) /** Free an undo log segment, and remove the header from the history list. +@param[in,out] mtr mini-transaction @param[in,out] rseg rollback segment @param[in] hdr_addr file address of log_hdr @return error code */ -static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr) +static dberr_t +trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr) { - const page_id_t hdr_page_id{rseg->space->id, hdr_addr.page}; - mtr_t mtr; + mtr.commit(); mtr.start(); - /* We only need the latch to maintain rseg->curr_size. To follow the - latching order, we must acquire it before acquiring any related - page latch. */ - rseg->latch.wr_lock(SRW_LOCK_CALL); - + const page_id_t hdr_page_id{rseg->space->id, hdr_addr.page}; dberr_t err; buf_block_t *rseg_hdr= rseg->get(&mtr, &err); if (!rseg_hdr) - goto func_exit; + return err; if (buf_block_t *block= buf_page_get_gen(hdr_page_id, 0, RW_X_LATCH, nullptr, BUF_GET_POSSIBLY_FREED, &mtr, &err)) @@ -419,12 +416,10 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr) while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + block->page.frame, &mtr)) { - rseg->latch.wr_unlock(); rseg_hdr->fix(); block->fix(); mtr.commit(); mtr.start(); - rseg->latch.wr_lock(SRW_LOCK_CALL); rseg_hdr->page.lock.x_lock(); block->page.lock.x_lock(); mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX); @@ -443,13 +438,10 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr) could become inaccessible garbage in the file space. */ err= trx_purge_remove_log_hdr(rseg_hdr, block, hdr_addr.boffset, &mtr); if (UNIV_UNLIKELY(err != DB_SUCCESS)) - goto func_exit; + return err; byte *hist= TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->page.frame; if (UNIV_UNLIKELY(mach_read_from_4(hist) < seg_size)) - { - err= DB_CORRUPTION; - goto func_exit; - } + return DB_CORRUPTION; mtr.write<4>(*rseg_hdr, hist, mach_read_from_4(hist) - seg_size); /* Here we assume that a file segment with just the header page @@ -464,9 +456,6 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr) rseg->curr_size -= seg_size; } -func_exit: - rseg->latch.wr_unlock(); - mtr.commit(); return err; } @@ -484,8 +473,6 @@ trx_purge_truncate_rseg_history( mtr_t mtr; mtr.start(); - ut_ad(rseg.is_persistent()); - rseg.latch.wr_lock(SRW_LOCK_CALL); dberr_t err; buf_block_t* rseg_hdr = rseg.get(&mtr, &err); @@ -501,7 +488,6 @@ trx_purge_truncate_rseg_history( loop: if (hdr_addr.page == FIL_NULL) { func_exit: - rseg.latch.wr_unlock(); mtr.commit(); return err; } @@ -533,38 +519,30 @@ func_exit: prev_hdr_addr.boffset = static_cast<uint16_t>(prev_hdr_addr.boffset - TRX_UNDO_HISTORY_NODE); - if (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE - + block->page.frame) + if (!rseg.is_referenced() + && rseg.needs_purge <= (purge_sys.head.trx_no + ? purge_sys.head.trx_no + : purge_sys.tail.trx_no) + && mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + + block->page.frame) == TRX_UNDO_TO_PURGE && !mach_read_from_2(block->page.frame + hdr_addr.boffset + TRX_UNDO_NEXT_LOG)) { - - /* We can free the whole log segment */ - - rseg.latch.wr_unlock(); - mtr.commit(); - - /* calls the trx_purge_remove_log_hdr() - inside trx_purge_free_segment(). */ - err = trx_purge_free_segment(&rseg, hdr_addr); - if (err != DB_SUCCESS) { - return err; - } + /* We can free the whole log segment. + This will call trx_purge_remove_log_hdr(). */ + err = trx_purge_free_segment(mtr, &rseg, hdr_addr); } else { /* Remove the log hdr from the rseg history. */ + rseg.history_size--; err = trx_purge_remove_log_hdr(rseg_hdr, block, hdr_addr.boffset, &mtr); - if (err != DB_SUCCESS) { - goto func_exit; - } - - rseg.history_size--; - rseg.latch.wr_unlock(); - mtr.commit(); } + mtr.commit(); + if (err != DB_SUCCESS) { + return err; + } mtr.start(); - rseg.latch.wr_lock(SRW_LOCK_CALL); hdr_addr = prev_hdr_addr; @@ -640,8 +618,13 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history() dberr_t err= DB_SUCCESS; for (auto &rseg : trx_sys.rseg_array) if (rseg.space) + { + ut_ad(rseg.is_persistent()); + rseg.latch.wr_lock(SRW_LOCK_CALL); if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head)) err= e; + rseg.latch.wr_unlock(); + } if (err != DB_SUCCESS || srv_undo_tablespaces_active < 2) return; @@ -693,43 +676,34 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history() { if (rseg.space != &space) continue; -#ifdef SUX_LOCK_GENERIC + rseg.latch.rd_lock(SRW_LOCK_CALL); -#else - transactional_shared_lock_guard<srw_spin_lock> g{rseg.latch}; -#endif ut_ad(rseg.skip_allocation()); - if (rseg.is_referenced()) + if (rseg.is_referenced() || rseg.needs_purge > head.trx_no) { not_free: -#ifdef SUX_LOCK_GENERIC rseg.latch.rd_unlock(); -#endif return; } - if (rseg.curr_size != 1) - { - /* Check if all segments are cached and safe to remove. */ - ulint cached= 0; - for (trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo; - undo= UT_LIST_GET_NEXT(undo_list, undo)) - { - if (head.trx_no < undo->trx_id) - goto not_free; - else - cached+= undo->size; - } - - ut_ad(rseg.curr_size > cached); + ut_ad(UT_LIST_GET_LEN(rseg.undo_list) == 0); + /* Check if all segments are cached and safe to remove. */ + ulint cached= 0; - if (rseg.curr_size > cached + 1) + for (const trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo; + undo= UT_LIST_GET_NEXT(undo_list, undo)) + { + if (head.trx_no < undo->trx_id) goto not_free; + else + cached+= undo->size; } -#ifdef SUX_LOCK_GENERIC + ut_ad(rseg.curr_size > cached); + if (rseg.curr_size > cached + 1) + goto not_free; + rseg.latch.rd_unlock(); -#endif } ib::info() << "Truncating " << file->name; @@ -848,7 +822,9 @@ not_free: if (rseg.space != &space) continue; - dberr_t err; + ut_ad(!rseg.is_referenced()); + ut_ad(rseg.needs_purge <= head.trx_no); + buf_block_t *rblock= trx_rseg_header_create(&space, &rseg - trx_sys.rseg_array, trx_sys.get_max_trx_id(), @@ -883,10 +859,6 @@ not_free: log_buffer_flush_to_disk(); DBUG_SUICIDE();); - for (auto &rseg : trx_sys.rseg_array) - if (rseg.space == &space) - rseg.clear_skip_allocation(); - ib::info() << "Truncated " << file->name; purge_sys.truncate.last= purge_sys.truncate.current; ut_ad(&space == purge_sys.truncate.current); @@ -946,7 +918,6 @@ static void trx_purge_rseg_get_next_history_log( /* Read the previous log header. */ mtr.start(); - byte needs_purge= 0; trx_id_t trx_no= 0; if (const buf_block_t* undo_page= @@ -957,7 +928,6 @@ static void trx_purge_rseg_get_next_history_log( trx_no= mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO); ut_ad(mach_read_from_2(log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1); - needs_purge= log_hdr[TRX_UNDO_NEEDS_PURGE + 1]; } mtr.commit(); @@ -969,11 +939,6 @@ static void trx_purge_rseg_get_next_history_log( purge_sys.rseg->last_page_no= prev_log_addr.page; purge_sys.rseg->set_last_commit(prev_log_addr.boffset, trx_no); - if (needs_purge) - purge_sys.rseg->set_needs_purge(); - else - purge_sys.rseg->clear_needs_purge(); - /* Purge can also produce events, however these are already ordered in the rollback segment and any user generated event will be greater than the events that Purge produces. ie. Purge can never produce @@ -995,7 +960,7 @@ static void trx_purge_read_undo_rec() 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->needs_purge()) { + if (purge_sys.rseg->needs_purge) { mtr_t mtr; mtr.start(); const buf_block_t* undo_page; diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 760c4e707ce..d30300d70a7 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -399,7 +399,7 @@ void trx_rseg_t::reinit(uint32_t page) } ut_ad(!is_referenced()); - clear_needs_purge(); + needs_purge= 0; last_commit_and_offset= 0; last_page_no= FIL_NULL; curr_size= 1; @@ -407,10 +407,9 @@ void trx_rseg_t::reinit(uint32_t page) /** Read the undo log lists. @param[in,out] rseg rollback segment -@param[in,out] max_trx_id maximum observed transaction identifier @param[in] rseg_header rollback segment header @return error code */ -static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id, +static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, const buf_block_t *rseg_header) { ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN); @@ -420,8 +419,8 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id, uint32_t page_no= trx_rsegf_get_nth_undo(rseg_header, i); if (page_no != FIL_NULL) { - const trx_undo_t *undo= trx_undo_mem_create_at_db_start(rseg, i, page_no, - max_trx_id); + const trx_undo_t *undo= + trx_undo_mem_create_at_db_start(rseg, i, page_no); if (!undo) return DB_CORRUPTION; rseg->curr_size+= undo->size; @@ -434,11 +433,9 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id, /** Restore the state of a persistent rollback segment. @param[in,out] rseg persistent rollback segment -@param[in,out] max_trx_id maximum observed transaction identifier @param[in,out] mtr mini-transaction @return error code */ -static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id, - mtr_t *mtr) +static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr) { if (!rseg->space) return DB_TABLESPACE_NOT_FOUND; @@ -454,8 +451,8 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id, trx_id_t id= mach_read_from_8(TRX_RSEG + TRX_RSEG_MAX_TRX_ID + rseg_hdr->page.frame); - if (id > max_trx_id) - max_trx_id= id; + if (id > rseg->needs_purge) + rseg->needs_purge= id; const byte *binlog_name= TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_hdr->page.frame; @@ -491,7 +488,7 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id, rseg->curr_size = mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->page.frame) + 1; - err= trx_undo_lists_init(rseg, max_trx_id, rseg_hdr); + err= trx_undo_lists_init(rseg, rseg_hdr); if (err != DB_SUCCESS); else if (auto len= flst_get_len(TRX_RSEG + TRX_RSEG_HISTORY + rseg_hdr->page.frame)) @@ -512,19 +509,16 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id, trx_id_t id= mach_read_from_8(block->page.frame + node_addr.boffset + TRX_UNDO_TRX_ID); - if (id > max_trx_id) - max_trx_id= id; + if (id > rseg->needs_purge) + rseg->needs_purge= id; id= mach_read_from_8(block->page.frame + node_addr.boffset + TRX_UNDO_TRX_NO); - if (id > max_trx_id) - max_trx_id= id; + if (id > rseg->needs_purge) + rseg->needs_purge= id; rseg->set_last_commit(node_addr.boffset, id); - unsigned purge= mach_read_from_2(block->page.frame + node_addr.boffset + - TRX_UNDO_NEEDS_PURGE); - ut_ad(purge <= 1); - if (purge != 0) - rseg->set_needs_purge(); + ut_ad(mach_read_from_2(block->page.frame + node_addr.boffset + + TRX_UNDO_NEEDS_PURGE) <= 1); if (rseg->last_page_no != FIL_NULL) /* There is no need to cover this operation by the purge @@ -597,9 +591,11 @@ dberr_t trx_rseg_array_init() sys, rseg_id)), page_no); ut_ad(rseg.is_persistent()); - if ((err = trx_rseg_mem_restore( - &rseg, max_trx_id, &mtr)) - != DB_SUCCESS) { + err = trx_rseg_mem_restore(&rseg, &mtr); + if (rseg.needs_purge > max_trx_id) { + max_trx_id = rseg.needs_purge; + } + if (err != DB_SUCCESS) { mtr.commit(); break; } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 0f471402e73..4975e72ef0f 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -651,6 +651,7 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, uint64_t *rows_to_undo) { trx_state_t state; + ut_ad(rseg->needs_purge >= undo->trx_id); /* This is single-threaded startup code, we do not need the protection of trx->mutex here. @@ -673,6 +674,7 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, return DB_SUCCESS; } + rseg->acquire(); trx_t *trx= trx_create(); trx->state= state; ut_d(trx->start_file= __FILE__); @@ -681,12 +683,6 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg, trx->rsegs.m_redo.undo= undo; trx->undo_no= undo->top_undo_no + 1; trx->rsegs.m_redo.rseg= rseg; - /* - For transactions with active data will not have rseg size = 1 - or will not qualify for purge limit criteria. So it is safe to increment - this trx_ref_count w/o mutex protection. - */ - trx->rsegs.m_redo.rseg->acquire(); trx->xid= undo->xid; trx->id= undo->trx_id; trx->is_recovered= true; @@ -759,6 +755,7 @@ corrupted: ut_ad(trx->is_recovered); ut_ad(trx->rsegs.m_redo.rseg == &rseg); ut_ad(rseg.is_referenced()); + ut_ad(rseg.needs_purge); trx->rsegs.m_redo.undo = undo; if (undo->top_undo_no >= trx->undo_no) { @@ -794,20 +791,18 @@ corrupted: /** Assign a persistent rollback segment in a round-robin fashion, evenly distributed between 0 and innodb_undo_logs-1 -@return persistent rollback segment -@retval NULL if innodb_read_only */ -static trx_rseg_t* trx_assign_rseg_low() +@param trx transaction */ +static void trx_assign_rseg_low(trx_t *trx) { - if (high_level_read_only) { - ut_ad(!srv_available_undo_logs); - return(NULL); - } - + ut_ad(!trx->rsegs.m_redo.rseg); ut_ad(srv_available_undo_logs == TRX_SYS_N_RSEGS); /* The first slot is always assigned to the system tablespace. */ ut_ad(trx_sys.rseg_array[0].space == fil_system.sys_space); + trx_sys.register_rw(trx); + ut_ad(trx->id); + /* Choose a rollback segment evenly distributed between 0 and innodb_undo_logs-1 in a round-robin fashion, skipping those undo tablespaces that are scheduled for truncation. */ @@ -821,7 +816,7 @@ static trx_rseg_t* trx_assign_rseg_low() bool look_for_rollover = false; #endif /* UNIV_DEBUG */ - bool allocated = false; + bool allocated; do { for (;;) { @@ -871,9 +866,7 @@ static trx_rseg_t* trx_assign_rseg_low() allocated = rseg->acquire_if_available(); } while (!allocated); - ut_ad(rseg->is_referenced()); - ut_ad(rseg->is_persistent()); - return(rseg); + trx->rsegs.m_redo.rseg = rseg; } /** Assign a rollback segment for modifying temporary tables. @@ -956,15 +949,11 @@ trx_start_low( if (!trx->read_only && (!trx->mysql_thd || read_write || trx->dict_operation)) { - /* Temporary rseg is assigned only if the transaction updates a temporary table */ - trx->rsegs.m_redo.rseg = trx_assign_rseg_low(); - ut_ad(trx->rsegs.m_redo.rseg != 0 - || srv_read_only_mode - || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO); - - trx_sys.register_rw(trx); + if (!high_level_read_only) { + trx_assign_rseg_low(trx); + } } else { if (!trx->is_autocommit_non_locking()) { @@ -1055,25 +1044,21 @@ trx_write_serialisation_history( trx_undo_t*& undo = trx->rsegs.m_redo.undo; - if (!undo) { - return; - } - ut_ad(!trx->read_only); - ut_ad(!undo || undo->rseg == rseg); - rseg->latch.wr_lock(SRW_LOCK_CALL); /* Assign the transaction serialisation number and add any undo log to the purge queue. */ - trx_serialise(trx); if (undo) { + rseg->latch.wr_lock(SRW_LOCK_CALL); + ut_ad(undo->rseg == rseg); + trx_serialise(trx); UT_LIST_REMOVE(rseg->undo_list, undo); trx_purge_add_undo_to_history(trx, undo, mtr); + MONITOR_INC(MONITOR_TRX_COMMIT_UNDO); + rseg->latch.wr_unlock(); } - rseg->latch.wr_unlock(); - - MONITOR_INC(MONITOR_TRX_COMMIT_UNDO); + rseg->release(); } /******************************************************************** @@ -1309,10 +1294,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr) release_locks(); } - if (trx_rseg_t *rseg= rsegs.m_redo.rseg) - /* This is safe due to us having detached the persistent undo log. */ - rseg->release(); - if (mtr) { if (trx_undo_t *&undo= rsegs.m_noredo.undo) @@ -1450,6 +1431,13 @@ TRANSACTIONAL_TARGET void trx_t::commit_low(mtr_t *mtr) mtr->commit(); } + else if (trx_rseg_t *rseg= rsegs.m_redo.rseg) + { + ut_ad(id); + ut_ad(!rsegs.m_redo.undo); + rseg->release(); + } + #ifdef ENABLED_DEBUG_SYNC if (debug_sync) DEBUG_SYNC_C("before_trx_state_committed_in_memory"); @@ -2166,11 +2154,7 @@ trx_set_rw_mode( return; } - trx->rsegs.m_redo.rseg = trx_assign_rseg_low(); - ut_ad(trx->rsegs.m_redo.rseg != 0); - - trx_sys.register_rw(trx); - ut_ad(trx->id); + trx_assign_rseg_low(trx); /* So that we can see our own changes. */ if (trx->read_view.is_open()) { diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index cd21ebe1319..33b1f93ff65 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1011,12 +1011,10 @@ static void trx_undo_seg_free(const trx_undo_t *undo) @param[in,out] rseg rollback segment @param[in] id rollback segment slot @param[in] page_no undo log segment page number -@param[in,out] max_trx_id the largest observed transaction ID @return the undo log @retval nullptr on error */ trx_undo_t * -trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no, - trx_id_t &max_trx_id) +trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no) { mtr_t mtr; XID xid; @@ -1054,10 +1052,21 @@ corrupted_type: const trx_ulogf_t* const undo_header = block->page.frame + offset; uint16_t state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + block->page.frame); + + const trx_id_t trx_id= mach_read_from_8(undo_header + TRX_UNDO_TRX_ID); + if (trx_id >> 48) { + sql_print_error("InnoDB: corrupted TRX_ID %llx", trx_id); + goto corrupted; + } + /* We will increment rseg->needs_purge, like trx_undo_reuse_cached() + would do it, to avoid trouble on rollback or XA COMMIT. */ + trx_id_t trx_no = trx_id + 1; + switch (state) { case TRX_UNDO_ACTIVE: case TRX_UNDO_PREPARED: if (UNIV_LIKELY(type != 1)) { + trx_no = trx_id + 1; break; } sql_print_error("InnoDB: upgrade from older version than" @@ -1080,13 +1089,14 @@ corrupted_type: goto corrupted_type; } read_trx_no: - trx_id_t id = mach_read_from_8(TRX_UNDO_TRX_NO + undo_header); - if (id >> 48) { - sql_print_error("InnoDB: corrupted TRX_NO %llx", id); + trx_no = mach_read_from_8(TRX_UNDO_TRX_NO + undo_header); + if (trx_no >> 48) { + sql_print_error("InnoDB: corrupted TRX_NO %llx", + trx_no); goto corrupted; } - if (id > max_trx_id) { - max_trx_id = id; + if (trx_no < trx_id) { + trx_no = trx_id; } } @@ -1099,13 +1109,8 @@ corrupted_type: xid.null(); } - trx_id_t trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID); - if (trx_id >> 48) { - sql_print_error("InnoDB: corrupted TRX_ID %llx", trx_id); - goto corrupted; - } - if (trx_id > max_trx_id) { - max_trx_id = trx_id; + if (trx_no > rseg->needs_purge) { + rseg->needs_purge = trx_no; } trx_undo_t* undo = trx_undo_mem_create( @@ -1296,6 +1301,22 @@ buf_block_t* trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo, mtr_t* mtr) { + if (rseg->is_persistent()) { + ut_ad(rseg->is_referenced()); + if (rseg->needs_purge <= trx->id) { + /* trx_purge_truncate_history() compares + rseg->needs_purge <= head.trx_no + so we need to compensate for that. + The rseg->needs_purge after crash + recovery would be at least trx->id + 1, + because that is the minimum possible value + assigned by trx_serialise() on commit. */ + rseg->needs_purge = trx->id + 1; + } + } else { + ut_ad(!rseg->is_referenced()); + } + trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached); if (!undo) { return NULL; @@ -1395,9 +1416,8 @@ buf_block_t* trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo, dberr_t* err, mtr_t* mtr) { - ut_d(const bool is_temp = rseg == trx->rsegs.m_noredo.rseg); - ut_ad(rseg == trx->rsegs.m_redo.rseg - || rseg == trx->rsegs.m_noredo.rseg); + ut_d(const bool is_temp = rseg == trx->rsegs.m_noredo.rseg); + ut_ad(is_temp || rseg == trx->rsegs.m_redo.rseg); ut_ad(undo == (is_temp ? &trx->rsegs.m_noredo.undo : &trx->rsegs.m_redo.undo)); @@ -1417,7 +1437,6 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo, ); rseg->latch.wr_lock(SRW_LOCK_CALL); - buf_block_t* block = trx_undo_reuse_cached(trx, rseg, undo, mtr); if (!block) { |
