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.