Bug #105914 some undo logs may be truncated, but were not be purged
Description:
--------------------code------------------
/********************************************************************//**
Removes unnecessary history data from a rollback segment. */
static
void
trx_purge_truncate_rseg_history(
/*============================*/
trx_rseg_t* rseg, /*!< in: rollback segment */
const purge_iter_t* limit) /*!< in: truncate offset */
{
...
if (undo_trx_no >= limit->trx_no) {
/* limit space_id should match the rollback segment
space id to avoid freeing of the page belongs to
different rollback segment for the same trx_no. */
if (undo_trx_no == limit->trx_no
&& rseg->space == limit->undo_rseg_space) {
trx_undo_truncate_start(
rseg, hdr_addr.page,
hdr_addr.boffset, limit->undo_no);
}
mutex_exit(&(rseg->mutex));
mtr_commit(&mtr);
return;
}
...
if ((mach_read_from_2(seg_hdr + TRX_UNDO_STATE) == TRX_UNDO_TO_PURGE)
&& (mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)) {
/* We can free the whole log segment */
mutex_exit(&(rseg->mutex));
mtr_commit(&mtr);
/* calls the trx_purge_remove_log_hdr()
inside trx_purge_free_segment(). */
trx_purge_free_segment(rseg, hdr_addr, noredo);
} else {
/* Remove the log hdr from the rseg history. */
trx_purge_remove_log_hdr(rseg_hdr, log_hdr, &mtr);
mutex_exit(&(rseg->mutex));
mtr_commit(&mtr);
}
...
}
--------------------code------------------
When truncate rseg history; if trx_no bigger than limit->trx_no, can't truncate this trx_no's undo logs.
--------------------code------------------
/** Iterate over selected UNDO tablespace and check if all the rsegs
that resides in the tablespace are free.
@param[in] limit truncate_limit
@param[in,out] undo_trunc undo truncate tracker */
static
void
trx_purge_initiate_truncate(
purge_iter_t* limit,
undo::Truncate* undo_trunc)
{
...
for (trx_undo_t* undo =
UT_LIST_GET_FIRST(rseg->update_undo_cached);
undo != NULL && all_free;
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
if (limit->trx_no < undo->trx_id) {
all_free = false;
} else {
cached_undo_size += undo->size;
}
}
for (trx_undo_t* undo =
UT_LIST_GET_FIRST(rseg->insert_undo_cached);
undo != NULL && all_free;
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
if (limit->trx_no < undo->trx_id) {
all_free = false;
} else {
cached_undo_size += undo->size;
}
}
...
if (!all_free) {
/* rseg still holds active data.*/
return;
}
...
}
--------------------code------------------
When truncate undo file; if trx_id bigger than limit->trx_no in undo cache, can't truncate this undo file.
But if such a trx exists, this trx's trx_no bigger than limit->trx_no, and trx's trx_id less than limit->trx_no; and this undo file may be truncated, but this trx's undo logs may not be purged.
How to repeat:
no repeat
Suggested fix:
When truncate undo file; if trx_no bigger than limit->trx_no in undo cache, can't truncate this undo file, not trx_id.
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.040 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: --------------------code------------------ /********************************************************************//** Removes unnecessary history data from a rollback segment. */ static void trx_purge_truncate_rseg_history( /*============================*/ trx_rseg_t* rseg, /*!< in: rollback segment */ const purge_iter_t* limit) /*!< in: truncate offset */ { ... if (undo_trx_no >= limit->trx_no) { /* limit space_id should match the rollback segment space id to avoid freeing of the page belongs to different rollback segment for the same trx_no. */ if (undo_trx_no == limit->trx_no && rseg->space == limit->undo_rseg_space) { trx_undo_truncate_start( rseg, hdr_addr.page, hdr_addr.boffset, limit->undo_no); } mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); return; } ... if ((mach_read_from_2(seg_hdr + TRX_UNDO_STATE) == TRX_UNDO_TO_PURGE) && (mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)) { /* We can free the whole log segment */ mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); /* calls the trx_purge_remove_log_hdr() inside trx_purge_free_segment(). */ trx_purge_free_segment(rseg, hdr_addr, noredo); } else { /* Remove the log hdr from the rseg history. */ trx_purge_remove_log_hdr(rseg_hdr, log_hdr, &mtr); mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); } ... } --------------------code------------------ When truncate rseg history; if trx_no bigger than limit->trx_no, can't truncate this trx_no's undo logs. --------------------code------------------ /** Iterate over selected UNDO tablespace and check if all the rsegs that resides in the tablespace are free. @param[in] limit truncate_limit @param[in,out] undo_trunc undo truncate tracker */ static void trx_purge_initiate_truncate( purge_iter_t* limit, undo::Truncate* undo_trunc) { ... for (trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->update_undo_cached); undo != NULL && all_free; undo = UT_LIST_GET_NEXT(undo_list, undo)) { if (limit->trx_no < undo->trx_id) { all_free = false; } else { cached_undo_size += undo->size; } } for (trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached); undo != NULL && all_free; undo = UT_LIST_GET_NEXT(undo_list, undo)) { if (limit->trx_no < undo->trx_id) { all_free = false; } else { cached_undo_size += undo->size; } } ... if (!all_free) { /* rseg still holds active data.*/ return; } ... } --------------------code------------------ When truncate undo file; if trx_id bigger than limit->trx_no in undo cache, can't truncate this undo file. But if such a trx exists, this trx's trx_no bigger than limit->trx_no, and trx's trx_id less than limit->trx_no; and this undo file may be truncated, but this trx's undo logs may not be purged. How to repeat: no repeat Suggested fix: When truncate undo file; if trx_no bigger than limit->trx_no in undo cache, can't truncate this undo file, not trx_id.