diff options
Diffstat (limited to 'storage/innobase/trx/trx0purge.cc')
-rw-r--r-- | storage/innobase/trx/trx0purge.cc | 182 |
1 files changed, 72 insertions, 110 deletions
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index a7044dd60c5..9e6c2741b99 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -110,7 +110,7 @@ inline bool TrxUndoRsegsIterator::set_next() purge_sys.rseg = *m_iter++; mysql_mutex_unlock(&purge_sys.pq_mutex); - mysql_mutex_lock(&purge_sys.rseg->mutex); + purge_sys.rseg->latch.rd_lock(); ut_a(purge_sys.rseg->last_page_no != FIL_NULL); ut_ad(purge_sys.rseg->last_trx_no() == m_rsegs.trx_no); @@ -126,8 +126,7 @@ inline bool TrxUndoRsegsIterator::set_next() purge_sys.hdr_offset = purge_sys.rseg->last_offset(); purge_sys.hdr_page_no = purge_sys.rseg->last_page_no; - mysql_mutex_unlock(&purge_sys.rseg->mutex); - + purge_sys.rseg->latch.rd_unlock(); return(true); } @@ -312,10 +311,10 @@ 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->needs_purge = true; + rseg->set_needs_purge(); } - trx_sys.rseg_history_len++; + rseg->history_size++; if (undo->state == TRX_UNDO_CACHED) { UT_LIST_ADD_FIRST(rseg->undo_cached, undo); @@ -338,24 +337,25 @@ static void trx_purge_remove_log_hdr(buf_block_t *rseg, buf_block_t* log, { flst_remove(rseg, TRX_RSEG + TRX_RSEG_HISTORY, log, static_cast<uint16_t>(offset + TRX_UNDO_HISTORY_NODE), mtr); - trx_sys.rseg_history_len--; } /** Free an undo log segment, and remove the header from the history list. @param[in,out] rseg rollback segment @param[in] hdr_addr file address of log_hdr */ -static -void -trx_purge_free_segment(trx_rseg_t* rseg, fil_addr_t hdr_addr) +static void trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr) { mtr_t mtr; mtr.start(); - mysql_mutex_lock(&rseg->mutex); + const page_id_t hdr_page_id(rseg->space->id, hdr_addr.page); + + /* 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(); buf_block_t* rseg_hdr = trx_rsegf_get(rseg->space, rseg->page_no, &mtr); - buf_block_t* block = trx_undo_page_get( - page_id_t(rseg->space->id, hdr_addr.page), &mtr); + buf_block_t* block = trx_undo_page_get(hdr_page_id, &mtr); /* Mark the last undo log totally purged, so that if the system crashes, the tail of the undo log will not get accessed @@ -368,17 +368,14 @@ 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->frame, &mtr)) { - mysql_mutex_unlock(&rseg->mutex); - + rseg->latch.wr_unlock(); mtr.commit(); mtr.start(); - - mysql_mutex_lock(&rseg->mutex); + rseg->latch.wr_lock(); rseg_hdr = trx_rsegf_get(rseg->space, rseg->page_no, &mtr); - block = trx_undo_page_get( - page_id_t(rseg->space->id, hdr_addr.page), &mtr); + block = trx_undo_page_get(hdr_page_id, &mtr); } /* The page list may now be inconsistent, but the length field @@ -412,11 +409,12 @@ trx_purge_free_segment(trx_rseg_t* rseg, fil_addr_t hdr_addr) ut_ad(rseg->curr_size >= seg_size); + rseg->history_size--; rseg->curr_size -= seg_size; - mysql_mutex_unlock(&rseg->mutex); + rseg->latch.wr_unlock(); - mtr_commit(&mtr); + mtr.commit(); } /** Remove unnecessary history data from a rollback segment. @@ -435,7 +433,7 @@ trx_purge_truncate_rseg_history( mtr.start(); ut_ad(rseg.is_persistent()); - mysql_mutex_lock(&rseg.mutex); + rseg.latch.wr_lock(); buf_block_t* rseg_hdr = trx_rsegf_get(rseg.space, rseg.page_no, &mtr); @@ -447,7 +445,7 @@ trx_purge_truncate_rseg_history( loop: if (hdr_addr.page == FIL_NULL) { func_exit: - mysql_mutex_unlock(&rseg.mutex); + rseg.latch.wr_unlock(); mtr.commit(); return; } @@ -480,7 +478,7 @@ func_exit: /* We can free the whole log segment */ - mysql_mutex_unlock(&rseg.mutex); + rseg.latch.wr_unlock(); mtr.commit(); /* calls the trx_purge_remove_log_hdr() @@ -490,13 +488,13 @@ func_exit: /* Remove the log hdr from the rseg history. */ trx_purge_remove_log_hdr(rseg_hdr, block, hdr_addr.boffset, &mtr); - - mysql_mutex_unlock(&rseg.mutex); + rseg.history_size--; + rseg.latch.wr_unlock(); mtr.commit(); } mtr.start(); - mysql_mutex_lock(&rseg.mutex); + rseg.latch.wr_lock(); rseg_hdr = trx_rsegf_get(rseg.space, rseg.page_no, &mtr); @@ -559,10 +557,9 @@ static void trx_purge_truncate_history() head.undo_no = 0; } - for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) { - if (trx_rseg_t* rseg = trx_sys.rseg_array[i]) { - ut_ad(rseg->id == i); - trx_purge_truncate_rseg_history(*rseg, head); + for (auto& rseg : trx_sys.rseg_array) { + if (rseg.space) { + trx_purge_truncate_rseg_history(rseg, head); } } @@ -608,40 +605,40 @@ static void trx_purge_truncate_history() DBUG_LOG("undo", "marking for truncate: " << file->name); - for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) { - if (trx_rseg_t* rseg = trx_sys.rseg_array[i]) { - ut_ad(rseg->is_persistent()); - if (rseg->space == &space) { - /* Once set, this rseg will - not be allocated to subsequent - transactions, but we will wait - for existing active - transactions to finish. */ - rseg->skip_allocation = true; - } + for (auto& rseg : trx_sys.rseg_array) { + if (rseg.space == &space) { + /* Once set, this rseg will + not be allocated to subsequent + transactions, but we will wait + for existing active + transactions to finish. */ + rseg.set_skip_allocation(); } } - for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) { - trx_rseg_t* rseg = trx_sys.rseg_array[i]; - if (!rseg || rseg->space != &space) { + for (auto& rseg : trx_sys.rseg_array) { + if (rseg.space != &space) { continue; } - mysql_mutex_lock(&rseg->mutex); - ut_ad(rseg->skip_allocation); - if (rseg->trx_ref_count) { + ut_ad(rseg.skip_allocation()); + if (rseg.is_referenced()) { + return; + } + rseg.latch.rd_lock(); + ut_ad(rseg.skip_allocation()); + if (rseg.is_referenced()) { not_free: - mysql_mutex_unlock(&rseg->mutex); + rseg.latch.rd_unlock(); return; } - if (rseg->curr_size != 1) { + 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); + rseg.undo_cached); undo; undo = UT_LIST_GET_NEXT(undo_list, undo)) { @@ -652,14 +649,14 @@ not_free: } } - ut_ad(rseg->curr_size > cached); + ut_ad(rseg.curr_size > cached); - if (rseg->curr_size > cached + 1) { + if (rseg.curr_size > cached + 1) { goto not_free; } } - mysql_mutex_unlock(&rseg->mutex); + rseg.latch.rd_unlock(); } ib::info() << "Truncating " << file->name; @@ -725,58 +722,22 @@ not_free: buf_block_t* sys_header = trx_sysf_get(&mtr); - for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) { - trx_rseg_t* rseg = trx_sys.rseg_array[i]; - if (!rseg || rseg->space != &space) { + for (auto& rseg : trx_sys.rseg_array) { + if (rseg.space != &space) { continue; } - ut_ad(rseg->is_persistent()); - ut_d(const ulint old_page = rseg->page_no); - buf_block_t* rblock = trx_rseg_header_create( purge_sys.truncate.current, - rseg->id, sys_header, &mtr); + i, sys_header, &mtr); ut_ad(rblock); - rseg->page_no = rblock - ? rblock->page.id().page_no() : FIL_NULL; - ut_ad(old_page == rseg->page_no); - - /* Before re-initialization ensure that we - free the existing structure. There can't be - any active transactions. */ - ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0); - - trx_undo_t* next_undo; - - for (trx_undo_t* undo = UT_LIST_GET_FIRST( - rseg->undo_cached); - undo; undo = next_undo) { - - next_undo = UT_LIST_GET_NEXT(undo_list, undo); - UT_LIST_REMOVE(rseg->undo_cached, undo); - MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED); - ut_free(undo); - } - - UT_LIST_INIT(rseg->undo_list, - &trx_undo_t::undo_list); - UT_LIST_INIT(rseg->undo_cached, - &trx_undo_t::undo_list); - /* These were written by trx_rseg_header_create(). */ ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + rblock->frame)); ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rblock->frame)); - - /* Initialize the undo log lists according to - the rseg header */ - rseg->curr_size = 1; - rseg->trx_ref_count = 0; - rseg->last_page_no = FIL_NULL; - rseg->last_commit_and_offset = 0; - rseg->needs_purge = false; + rseg.reinit(rblock + ? rblock->page.id().page_no() : FIL_NULL); } mtr.commit(); @@ -820,12 +781,9 @@ not_free: log_write_up_to(LSN_MAX, true); DBUG_SUICIDE();); - for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) { - if (trx_rseg_t* rseg = trx_sys.rseg_array[i]) { - ut_ad(rseg->is_persistent()); - if (rseg->space == &space) { - rseg->skip_allocation = false; - } + for (auto& rseg : trx_sys.rseg_array) { + if (rseg.space == &space) { + rseg.clear_skip_allocation(); } } @@ -846,7 +804,9 @@ static void trx_purge_rseg_get_next_history_log( trx_id_t trx_no; mtr_t mtr; - mysql_mutex_lock(&purge_sys.rseg->mutex); + mtr.start(); + + purge_sys.rseg->latch.wr_lock(); ut_a(purge_sys.rseg->last_page_no != FIL_NULL); @@ -854,8 +814,6 @@ static void trx_purge_rseg_get_next_history_log( purge_sys.tail.undo_no = 0; purge_sys.next_stored = false; - mtr.start(); - const buf_block_t* undo_page = trx_undo_page_get_s_latched( page_id_t(purge_sys.rseg->space->id, purge_sys.rseg->last_page_no), &mtr); @@ -879,7 +837,7 @@ static void trx_purge_rseg_get_next_history_log( purge_sys.rseg->last_page_no = FIL_NULL; } - mysql_mutex_unlock(&purge_sys.rseg->mutex); + purge_sys.rseg->latch.wr_unlock(); mtr.commit(); if (empty) { @@ -899,11 +857,15 @@ static void trx_purge_rseg_get_next_history_log( mtr_commit(&mtr); - mysql_mutex_lock(&purge_sys.rseg->mutex); + purge_sys.rseg->latch.wr_lock(); purge_sys.rseg->last_page_no = prev_log_addr.page; purge_sys.rseg->set_last_commit(prev_log_addr.boffset, trx_no); - purge_sys.rseg->needs_purge = log_hdr[TRX_UNDO_NEEDS_PURGE + 1] != 0; + if (log_hdr[TRX_UNDO_NEEDS_PURGE + 1]) { + 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 @@ -916,7 +878,7 @@ static void trx_purge_rseg_get_next_history_log( mysql_mutex_unlock(&purge_sys.pq_mutex); - mysql_mutex_unlock(&purge_sys.rseg->mutex); + purge_sys.rseg->latch.wr_unlock(); } /** Position the purge sys "iterator" on the undo record to use for purging. */ @@ -929,7 +891,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(); buf_block_t* undo_page; @@ -1095,7 +1057,7 @@ trx_purge_fetch_next_rec( /* row_purge_record_func() will later set ROLL_PTR_INSERT_FLAG for TRX_UNDO_INSERT_REC */ false, - purge_sys.rseg->id, + trx_sys.rseg_id(purge_sys.rseg, true), purge_sys.page_no, purge_sys.offset); /* The following call will advance the stored values of the @@ -1229,7 +1191,7 @@ trx_purge_dml_delay(void) /* If purge lag is set then calculate the new DML delay. */ if (srv_max_purge_lag > 0) { - double ratio = static_cast<double>(trx_sys.rseg_history_len) / + double ratio = static_cast<double>(trx_sys.history_size()) / static_cast<double>(srv_max_purge_lag); if (ratio > 1.0) { |