mariadb/storage/innobase/include/trx0undo.ic
Marko Mäkelä 13e5c9de80 MDEV-12219 Discard temporary undo logs at transaction commit
Starting with MySQL 5.7, temporary tables in InnoDB are handled
differently from persistent tables. Because temporary tables are
private to a connection, concurrency control and multi-versioning
(MVCC) are not applicable. For performance reasons, purge is
disabled as well. Rollback is supported for temporary tables;
that is why we have the temporary undo logs in the first place.

Because MVCC and purge are disabled for temporary tables, we should
discard all temporary undo logs already at transaction commit,
just like we discard the persistent insert_undo logs. Before this
change, update_undo logs were being preserved.

trx_temp_undo_t: A wrapper for temporary undo logs, comprising
a rollback segment and a single temporary undo log.

trx_rsegs_t::m_noredo: Use trx_temp_undo_t.
(Instead of insert_undo, update_undo, there will be a single undo.)

trx_is_noredo_rseg_updated(), trx_is_rseg_assigned(): Remove.

trx_undo_add_page(): Remove the parameter undo_ptr.
Acquire and release the rollback segment mutex inside the function.

trx_undo_free_last_page(): Remove the parameter trx.

trx_undo_truncate_end(): Remove the parameter trx, and add the
parameter is_temp. Clean up the code a bit.

trx_undo_assign_undo(): Split the parameter undo_ptr into rseg, undo.

trx_undo_commit_cleanup(): Renamed from trx_undo_insert_cleanup().
Replace the parameter undo_ptr with undo.
This will discard the temporary undo or insert_undo log at
commit/rollback.

trx_purge_add_update_undo_to_history(), trx_undo_update_cleanup():
Remove 3 parameters. Always operate on the persistent update_undo.

trx_serialise(): Renamed from trx_serialisation_number_get().

trx_write_serialisation_history(): Simplify the code flow.
If there are no persistent changes, do not update MONITOR_TRX_COMMIT_UNDO.

trx_commit_in_memory(): Simplify the logic, and add assertions.

trx_undo_page_report_modify(): Keep a direct reference to the
persistent update_undo log.

trx_undo_report_row_operation(): Simplify some code.
Always assign TRX_UNDO_INSERT for temporary undo logs.

trx_prepare_low(): Keep only one parameter. Prepare all 3 undo logs.

trx_roll_try_truncate(): Remove the parameter undo_ptr.
Try to truncate all 3 undo logs of the transaction.

trx_roll_pop_top_rec_of_trx_low(): Remove.

trx_roll_pop_top_rec_of_trx(): Remove the redundant parameter
trx->roll_limit. Clear roll_limit when exhausting the undo logs.
Consider all 3 undo logs at once, prioritizing the persistent
undo logs.

row_undo(): Minor cleanup. Let trx_roll_pop_top_rec_of_trx()
reset the trx->roll_limit.
2017-03-13 18:57:17 +02:00

352 lines
9.5 KiB
Text

/*****************************************************************************
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/trx0undo.ic
Transaction undo log
Created 3/26/1996 Heikki Tuuri
*******************************************************/
#include "data0type.h"
#include "page0page.h"
/***********************************************************************//**
Builds a roll pointer.
@return roll pointer */
UNIV_INLINE
roll_ptr_t
trx_undo_build_roll_ptr(
/*====================*/
ibool is_insert, /*!< in: TRUE if insert undo log */
ulint rseg_id, /*!< in: rollback segment id */
ulint page_no, /*!< in: page number */
ulint offset) /*!< in: offset of the undo entry within page */
{
roll_ptr_t roll_ptr;
#if DATA_ROLL_PTR_LEN != 7
# error "DATA_ROLL_PTR_LEN != 7"
#endif
ut_ad(is_insert == 0 || is_insert == 1);
ut_ad(rseg_id < TRX_SYS_N_RSEGS);
ut_ad(offset < 65536);
roll_ptr = (roll_ptr_t) is_insert << ROLL_PTR_INSERT_FLAG_POS
| (roll_ptr_t) rseg_id << ROLL_PTR_RSEG_ID_POS
| (roll_ptr_t) page_no << ROLL_PTR_PAGE_POS
| offset;
return(roll_ptr);
}
/***********************************************************************//**
Decodes a roll pointer. */
UNIV_INLINE
void
trx_undo_decode_roll_ptr(
/*=====================*/
roll_ptr_t roll_ptr, /*!< in: roll pointer */
ibool* is_insert, /*!< out: TRUE if insert undo log */
ulint* rseg_id, /*!< out: rollback segment id */
ulint* page_no, /*!< out: page number */
ulint* offset) /*!< out: offset of the undo
entry within page */
{
#if DATA_ROLL_PTR_LEN != 7
# error "DATA_ROLL_PTR_LEN != 7"
#endif
#if TRUE != 1
# error "TRUE != 1"
#endif
ut_ad(roll_ptr < (1ULL << 56));
*offset = (ulint) roll_ptr & 0xFFFF;
roll_ptr >>= 16;
*page_no = (ulint) roll_ptr & 0xFFFFFFFF;
roll_ptr >>= 32;
*rseg_id = (ulint) roll_ptr & 0x7F;
roll_ptr >>= 7;
*is_insert = (ibool) roll_ptr; /* TRUE==1 */
}
/***********************************************************************//**
Returns TRUE if the roll pointer is of the insert type.
@return TRUE if insert undo log */
UNIV_INLINE
ibool
trx_undo_roll_ptr_is_insert(
/*========================*/
roll_ptr_t roll_ptr) /*!< in: roll pointer */
{
#if DATA_ROLL_PTR_LEN != 7
# error "DATA_ROLL_PTR_LEN != 7"
#endif
#if TRUE != 1
# error "TRUE != 1"
#endif
ut_ad(roll_ptr < (1ULL << 56));
return((ibool) (roll_ptr >> 55));
}
/***********************************************************************//**
Returns true if the record is of the insert type.
@return true if the record was freshly inserted (not updated). */
UNIV_INLINE
bool
trx_undo_trx_id_is_insert(
/*======================*/
const byte* trx_id) /*!< in: DB_TRX_ID, followed by DB_ROLL_PTR */
{
#if DATA_TRX_ID + 1 != DATA_ROLL_PTR
# error
#endif
return(static_cast<bool>(trx_id[DATA_TRX_ID_LEN] >> 7));
}
/*****************************************************************//**
Writes a roll ptr to an index page. In case that the size changes in
some future version, this function should be used instead of
mach_write_... */
UNIV_INLINE
void
trx_write_roll_ptr(
/*===============*/
byte* ptr, /*!< in: pointer to memory where
written */
roll_ptr_t roll_ptr) /*!< in: roll ptr */
{
#if DATA_ROLL_PTR_LEN != 7
# error "DATA_ROLL_PTR_LEN != 7"
#endif
mach_write_to_7(ptr, roll_ptr);
}
/*****************************************************************//**
Reads a roll ptr from an index page. In case that the roll ptr size
changes in some future version, this function should be used instead of
mach_read_...
@return roll ptr */
UNIV_INLINE
roll_ptr_t
trx_read_roll_ptr(
/*==============*/
const byte* ptr) /*!< in: pointer to memory from where to read */
{
#if DATA_ROLL_PTR_LEN != 7
# error "DATA_ROLL_PTR_LEN != 7"
#endif
return(mach_read_from_7(ptr));
}
/** Gets an undo log page and x-latches it.
@param[in] page_id page id
@param[in,out] mtr mini-transaction
@return pointer to page x-latched */
UNIV_INLINE
page_t*
trx_undo_page_get(const page_id_t& page_id, mtr_t* mtr)
{
buf_block_t* block = buf_page_get(page_id, univ_page_size,
RW_X_LATCH, mtr);
buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
return(buf_block_get_frame(block));
}
/** Gets an undo log page and s-latches it.
@param[in] page_id page id
@param[in,out] mtr mini-transaction
@return pointer to page s-latched */
UNIV_INLINE
page_t*
trx_undo_page_get_s_latched(const page_id_t& page_id, mtr_t* mtr)
{
buf_block_t* block = buf_page_get(page_id, univ_page_size,
RW_S_LATCH, mtr);
buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
return(buf_block_get_frame(block));
}
/******************************************************************//**
Returns the start offset of the undo log records of the specified undo
log on the page.
@return start offset */
UNIV_INLINE
ulint
trx_undo_page_get_start(
/*====================*/
page_t* undo_page,/*!< in: undo log page */
ulint page_no,/*!< in: undo log header page number */
ulint offset) /*!< in: undo log header offset on page */
{
ulint start;
if (page_no == page_get_page_no(undo_page)) {
start = mach_read_from_2(offset + undo_page
+ TRX_UNDO_LOG_START);
} else {
start = TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE;
}
return(start);
}
/******************************************************************//**
Returns the end offset of the undo log records of the specified undo
log on the page.
@return end offset */
UNIV_INLINE
ulint
trx_undo_page_get_end(
/*==================*/
page_t* undo_page,/*!< in: undo log page */
ulint page_no,/*!< in: undo log header page number */
ulint offset) /*!< in: undo log header offset on page */
{
trx_ulogf_t* log_hdr;
ulint end;
if (page_no == page_get_page_no(undo_page)) {
log_hdr = undo_page + offset;
end = mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG);
if (end == 0) {
end = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_FREE);
}
} else {
end = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_FREE);
}
return(end);
}
/******************************************************************//**
Returns the previous undo record on the page in the specified log, or
NULL if none exists.
@return pointer to record, NULL if none */
UNIV_INLINE
trx_undo_rec_t*
trx_undo_page_get_prev_rec(
/*=======================*/
trx_undo_rec_t* rec, /*!< in: undo log record */
ulint page_no,/*!< in: undo log header page number */
ulint offset) /*!< in: undo log header offset on page */
{
page_t* undo_page;
ulint start;
undo_page = (page_t*) ut_align_down(rec, UNIV_PAGE_SIZE);
start = trx_undo_page_get_start(undo_page, page_no, offset);
if (start + undo_page == rec) {
return(NULL);
}
return(undo_page + mach_read_from_2(rec - 2));
}
/******************************************************************//**
Returns the next undo log record on the page in the specified log, or
NULL if none exists.
@return pointer to record, NULL if none */
UNIV_INLINE
trx_undo_rec_t*
trx_undo_page_get_next_rec(
/*=======================*/
trx_undo_rec_t* rec, /*!< in: undo log record */
ulint page_no,/*!< in: undo log header page number */
ulint offset) /*!< in: undo log header offset on page */
{
page_t* undo_page;
ulint end;
ulint next;
undo_page = (page_t*) ut_align_down(rec, UNIV_PAGE_SIZE);
end = trx_undo_page_get_end(undo_page, page_no, offset);
next = mach_read_from_2(rec);
if (next == end) {
return(NULL);
}
return(undo_page + next);
}
/******************************************************************//**
Returns the last undo record on the page in the specified undo log, or
NULL if none exists.
@return pointer to record, NULL if none */
UNIV_INLINE
trx_undo_rec_t*
trx_undo_page_get_last_rec(
/*=======================*/
page_t* undo_page,/*!< in: undo log page */
ulint page_no,/*!< in: undo log header page number */
ulint offset) /*!< in: undo log header offset on page */
{
ulint start;
ulint end;
start = trx_undo_page_get_start(undo_page, page_no, offset);
end = trx_undo_page_get_end(undo_page, page_no, offset);
if (start == end) {
return(NULL);
}
return(undo_page + mach_read_from_2(undo_page + end - 2));
}
/******************************************************************//**
Returns the first undo record on the page in the specified undo log, or
NULL if none exists.
@return pointer to record, NULL if none */
UNIV_INLINE
trx_undo_rec_t*
trx_undo_page_get_first_rec(
/*========================*/
page_t* undo_page,/*!< in: undo log page */
ulint page_no,/*!< in: undo log header page number */
ulint offset) /*!< in: undo log header offset on page */
{
ulint start;
ulint end;
start = trx_undo_page_get_start(undo_page, page_no, offset);
end = trx_undo_page_get_end(undo_page, page_no, offset);
if (start == end) {
return(NULL);
}
return(undo_page + start);
}