Commit 51e62cb3 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-26782 InnoDB temporary tablespace: reclaiming of free space does not work

The motivation of this change is to allow undo pages for temporary tables
to be marked free as often as possible, so that we can avoid buf_pool.LRU
eviction (and writes) of undo pages that contain data that is
no longer needed. For temporary tables, no MVCC or purge of history
is needed, and reusing cached undo log pages might not help that much.

It is possible that this may cause some performance regression due to
more frequent allocation and freeing of undo log pages, but I only
measured a performance improvement.

trx_write_serialisation_history(): Never cache temporary undo log pages.

trx_undo_reuse_cached(): Assert that the rollback segment is persistent.

trx_undo_assign_low(): Add template<bool is_temp>. Never invoke
trx_undo_reuse_cached() for temporary tables.

Tested by: Matthias Leich
parent 204e7225
......@@ -203,16 +203,18 @@ trx_undo_assign(trx_t* trx, dberr_t* err, mtr_t* mtr)
MY_ATTRIBUTE((nonnull));
/** Assign an undo log for a transaction.
A new undo log is created or a cached undo log reused.
@tparam is_temp whether this is temporary undo log
@param[in,out] trx transaction
@param[in] rseg rollback segment
@param[out] undo the undo log
@param[out] err error code
@param[in,out] mtr mini-transaction
@param[out] err error code
@return the undo log block
@retval NULL on error */
@retval nullptr on error */
template<bool is_temp>
buf_block_t*
trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
dberr_t* err, mtr_t* mtr)
trx_undo_assign_low(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
mtr_t *mtr, dberr_t *err)
MY_ATTRIBUTE((nonnull, warn_unused_result));
/******************************************************************//**
Sets the state of the undo log segment at a transaction finish.
......
......@@ -1868,26 +1868,28 @@ trx_undo_report_row_operation(
}
mtr_t mtr;
dberr_t err;
mtr.start();
trx_undo_t** pundo;
trx_rseg_t* rseg;
const bool is_temp = index->table->is_temporary();
buf_block_t* undo_block;
if (is_temp) {
mtr.set_log_mode(MTR_LOG_NO_REDO);
rseg = trx->get_temp_rseg();
pundo = &trx->rsegs.m_noredo.undo;
undo_block = trx_undo_assign_low<true>(trx, rseg, pundo,
&mtr, &err);
} else {
ut_ad(!trx->read_only);
ut_ad(trx->id);
pundo = &trx->rsegs.m_redo.undo;
rseg = trx->rsegs.m_redo.rseg;
undo_block = trx_undo_assign_low<false>(trx, rseg, pundo,
&mtr, &err);
}
dberr_t err;
buf_block_t* undo_block = trx_undo_assign_low(trx, rseg, pundo,
&err, &mtr);
trx_undo_t* undo = *pundo;
ut_ad((err == DB_SUCCESS) == (undo_block != NULL));
if (UNIV_UNLIKELY(undo_block == NULL)) {
......
......@@ -1023,7 +1023,13 @@ trx_write_serialisation_history(
mtr_t temp_mtr;
temp_mtr.start();
temp_mtr.set_log_mode(MTR_LOG_NO_REDO);
trx_undo_set_state_at_finish(undo, &temp_mtr);
buf_block_t* block= buf_page_get(page_id_t(SRV_TMP_SPACE_ID,
undo->hdr_page_no),
0, RW_X_LATCH, mtr);
ut_a(block);
temp_mtr.write<2>(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
+ block->page.frame, TRX_UNDO_TO_PURGE);
undo->state = TRX_UNDO_TO_PURGE;
temp_mtr.commit();
}
......
......@@ -1290,14 +1290,15 @@ trx_undo_create(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
@param[in,out] rseg rollback segment
@param[out] pundo the undo log memory object
@param[in,out] mtr mini-transaction
@param[out] err error code
@return the undo log block
@retval NULL if none cached */
static
buf_block_t*
trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
mtr_t* mtr)
mtr_t* mtr, dberr_t *err)
{
if (rseg->is_persistent()) {
ut_ad(rseg->is_persistent());
ut_ad(rseg->is_referenced());
if (rseg->needs_purge <= trx->id) {
/* trx_purge_truncate_history() compares
......@@ -1309,9 +1310,6 @@ trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
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) {
......@@ -1321,9 +1319,10 @@ trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
ut_ad(undo->size == 1);
ut_ad(undo->id < TRX_RSEG_N_SLOTS);
buf_block_t* block = buf_page_get(page_id_t(undo->rseg->space->id,
buf_block_t* block = buf_page_get_gen(page_id_t(undo->rseg->space->id,
undo->hdr_page_no),
0, RW_X_LATCH, mtr);
0, RW_X_LATCH, nullptr, BUF_GET,
mtr, err);
if (!block) {
return NULL;
}
......@@ -1374,11 +1373,12 @@ trx_undo_assign(trx_t* trx, dberr_t* err, mtr_t* mtr)
BUF_GET, mtr, err);
}
*err = DB_SUCCESS;
trx_rseg_t* rseg = trx->rsegs.m_redo.rseg;
rseg->latch.wr_lock(SRW_LOCK_CALL);
buf_block_t* block = trx_undo_reuse_cached(
trx, rseg, &trx->rsegs.m_redo.undo, mtr);
trx, rseg, &trx->rsegs.m_redo.undo, mtr, err);
if (!block) {
block = trx_undo_create(trx, rseg, &trx->rsegs.m_redo.undo,
......@@ -1387,8 +1387,6 @@ trx_undo_assign(trx_t* trx, dberr_t* err, mtr_t* mtr)
if (!block) {
goto func_exit;
}
} else {
*err = DB_SUCCESS;
}
UT_LIST_ADD_FIRST(rseg->undo_list, trx->rsegs.m_redo.undo);
......@@ -1400,18 +1398,20 @@ trx_undo_assign(trx_t* trx, dberr_t* err, mtr_t* mtr)
/** Assign an undo log for a transaction.
A new undo log is created or a cached undo log reused.
@tparam is_temp whether this is temporary undo log
@param[in,out] trx transaction
@param[in] rseg rollback segment
@param[out] undo the undo log
@param[out] err error code
@param[in,out] mtr mini-transaction
@param[out] err error code
@return the undo log block
@retval NULL on error */
@retval nullptr on error */
template<bool is_temp>
buf_block_t*
trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
dberr_t* err, mtr_t* mtr)
trx_undo_assign_low(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
mtr_t *mtr, dberr_t *err)
{
ut_d(const bool is_temp = rseg == trx->rsegs.m_noredo.rseg);
ut_ad(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
......@@ -1431,19 +1431,24 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
*err = DB_TOO_MANY_CONCURRENT_TRXS; return NULL;
);
*err = DB_SUCCESS;
rseg->latch.wr_lock(SRW_LOCK_CALL);
buf_block_t* block = trx_undo_reuse_cached(trx, rseg, undo, mtr);
if (!block) {
buf_block_t* block;
if (is_temp) {
ut_ad(!UT_LIST_GET_LEN(rseg->undo_cached));
} else {
block = trx_undo_reuse_cached(trx, rseg, undo, mtr, err);
if (block) {
goto got_block;
}
}
block = trx_undo_create(trx, rseg, undo, err, mtr);
ut_ad(!block == (*err != DB_SUCCESS));
if (!block) {
goto func_exit;
}
} else {
*err = DB_SUCCESS;
}
got_block:
UT_LIST_ADD_FIRST(rseg->undo_list, *undo);
func_exit:
......@@ -1451,6 +1456,13 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
return block;
}
template buf_block_t*
trx_undo_assign_low<false>(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
mtr_t *mtr, dberr_t *err);
template buf_block_t*
trx_undo_assign_low<true>(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
mtr_t *mtr, dberr_t *err);
/******************************************************************//**
Sets the state of the undo log segment at a transaction finish.
@return undo log segment header page, x-latched */
......@@ -1461,6 +1473,7 @@ trx_undo_set_state_at_finish(
mtr_t* mtr) /*!< in: mtr */
{
ut_ad(undo->id < TRX_RSEG_N_SLOTS);
ut_ad(undo->rseg->is_persistent());
buf_block_t *block=
buf_page_get(page_id_t(undo->rseg->space->id, undo->hdr_page_no), 0,
......@@ -1532,25 +1545,16 @@ the data can be discarded.
@param undo temporary undo log */
void trx_undo_commit_cleanup(trx_undo_t *undo)
{
trx_rseg_t* rseg = undo->rseg;
trx_rseg_t *rseg= undo->rseg;
ut_ad(rseg->space == fil_system.temp_space);
rseg->latch.wr_lock(SRW_LOCK_CALL);
UT_LIST_REMOVE(rseg->undo_list, undo);
if (undo->state == TRX_UNDO_CACHED) {
UT_LIST_ADD_FIRST(rseg->undo_cached, undo);
undo = nullptr;
} else {
ut_ad(undo->state == TRX_UNDO_TO_PURGE);
/* Delete first the undo log segment in the file */
trx_undo_seg_free(undo);
ut_ad(rseg->curr_size > undo->size);
rseg->curr_size -= undo->size;
}
rseg->curr_size-= undo->size;
rseg->latch.wr_unlock();
ut_free(undo);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment