summaryrefslogtreecommitdiff
path: root/storage/innobase/trx/trx0undo.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/trx/trx0undo.cc')
-rw-r--r--storage/innobase/trx/trx0undo.cc794
1 files changed, 414 insertions, 380 deletions
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index 9b0c43e4609..88ac0257540 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2014, 2017, MariaDB Corporation.
+Copyright (c) 2014, 2018, 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
@@ -117,6 +117,53 @@ trx_undo_mem_create(
ulint page_no,/*!< in: undo log header page number */
ulint offset);/*!< in: undo log header byte offset on page */
+/** Determine the start offset of undo log records of an undo log page.
+@param[in] undo_page undo log page
+@param[in] page_no undo log header page number
+@param[in] offset undo log header offset
+@return start offset */
+static
+uint16_t
+trx_undo_page_get_start(const page_t* undo_page, ulint page_no, ulint offset)
+{
+ return page_no == page_get_page_no(undo_page)
+ ? mach_read_from_2(offset + TRX_UNDO_LOG_START + undo_page)
+ : TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE;
+}
+
+/** Get the first undo log record on a page.
+@param[in] page undo log page
+@param[in] page_no undo log header page number
+@param[in] offset undo log header page offset
+@return pointer to first record
+@retval NULL if none exists */
+static
+trx_undo_rec_t*
+trx_undo_page_get_first_rec(page_t* page, ulint page_no, ulint offset)
+{
+ ulint start = trx_undo_page_get_start(page, page_no, offset);
+ return start == trx_undo_page_get_end(page, page_no, offset)
+ ? NULL
+ : page + start;
+}
+
+/** Get the last undo log record on a page.
+@param[in] page undo log page
+@param[in] page_no undo log header page number
+@param[in] offset undo log header page offset
+@return pointer to last record
+@retval NULL if none exists */
+static
+trx_undo_rec_t*
+trx_undo_page_get_last_rec(page_t* page, ulint page_no, ulint offset)
+{
+ ulint end = trx_undo_page_get_end(page, page_no, offset);
+
+ return trx_undo_page_get_start(page, page_no, offset) == end
+ ? NULL
+ : page + mach_read_from_2(page + end - 2);
+}
+
/***********************************************************************//**
Gets the previous record in an undo log from the previous page.
@return undo log record, the page s-latched, NULL if none */
@@ -159,6 +206,31 @@ trx_undo_get_prev_rec_from_prev_page(
return(trx_undo_page_get_last_rec(prev_page, page_no, offset));
}
+/** Get the previous undo log record.
+@param[in] rec undo log record
+@param[in] page_no undo log header page number
+@param[in] offset undo log header page offset
+@return pointer to record
+@retval NULL if none */
+static
+trx_undo_rec_t*
+trx_undo_page_get_prev_rec(trx_undo_rec_t* rec, ulint page_no, ulint offset)
+{
+ 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));
+}
+
/***********************************************************************//**
Gets the previous record in an undo log.
@return undo log record, the page s-latched, NULL if none */
@@ -309,43 +381,84 @@ trx_undo_get_first_rec(
/*============== UNDO LOG FILE COPY CREATION AND FREEING ==================*/
-/**********************************************************************//**
-Writes the mtr log entry of an undo log page initialization. */
-UNIV_INLINE
-void
-trx_undo_page_init_log(
-/*===================*/
- page_t* undo_page, /*!< in: undo log page */
- mtr_t* mtr) /*!< in: mtr */
+/** Parse MLOG_UNDO_INIT for crash-upgrade from MariaDB 10.2.
+@param[in] ptr log record
+@param[in] end_ptr end of log record buffer
+@param[in,out] page page or NULL
+@param[in,out] mtr mini-transaction
+@return end of log record
+@retval NULL if the log record is incomplete */
+byte*
+trx_undo_parse_page_init(
+ const byte* ptr,
+ const byte* end_ptr,
+ page_t* page,
+ mtr_t* mtr)
{
- mlog_write_initial_log_record(undo_page, MLOG_UNDO_INIT, mtr);
+ ulint type = mach_parse_compressed(&ptr, end_ptr);
- mlog_catenate_ulint_compressed(mtr, 0);
+ if (!ptr) {
+ } else if (type != 1 && type != 2) {
+ recv_sys->found_corrupt_log = true;
+ } else if (page) {
+ mach_write_to_2(FIL_PAGE_TYPE + page, FIL_PAGE_UNDO_LOG);
+ mach_write_to_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + page,
+ type);
+ mach_write_to_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_START + page,
+ TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
+ mach_write_to_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + page,
+ TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
+ }
+
+ return(const_cast<byte*>(ptr));
}
-/***********************************************************//**
-Parses the redo log entry of an undo log page initialization.
+/** Parse MLOG_UNDO_HDR_REUSE for crash-upgrade from MariaDB 10.2.
+@param[in] ptr redo log record
+@param[in] end_ptr end of log buffer
+@param[in,out] page undo log page or NULL
+@param[in,out] mtr mini-transaction
@return end of log record or NULL */
byte*
-trx_undo_parse_page_init(
-/*=====================*/
- const byte* ptr, /*!< in: buffer */
- const byte* end_ptr,/*!< in: buffer end */
- page_t* page, /*!< in: page or NULL */
- mtr_t* mtr) /*!< in: mtr or NULL */
+trx_undo_parse_page_header_reuse(
+ const byte* ptr,
+ const byte* end_ptr,
+ page_t* undo_page,
+ mtr_t* mtr)
{
- if (mach_parse_compressed(&ptr, end_ptr)) {
- recv_sys->found_corrupt_log = true;
+ trx_id_t trx_id = mach_u64_parse_compressed(&ptr, end_ptr);
+
+ if (!ptr || !undo_page) {
+ return(const_cast<byte*>(ptr));
}
- if (ptr == NULL) {
+ compile_time_assert(TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE
+ + TRX_UNDO_LOG_XA_HDR_SIZE
+ < UNIV_PAGE_SIZE_MIN - 100);
- return(NULL);
- }
+ const ulint new_free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE
+ + TRX_UNDO_LOG_OLD_HDR_SIZE;
- if (page) {
- trx_undo_page_init(page, mtr);
- }
+ /* Insert undo data is not needed after commit: we may free all
+ the space on the page */
+
+ ut_ad(mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE
+ + undo_page)
+ == TRX_UNDO_INSERT);
+
+ byte* page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
+ mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
+ mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
+ mach_write_to_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE + undo_page,
+ TRX_UNDO_ACTIVE);
+
+ byte* log_hdr = undo_page + TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
+
+ mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
+ mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
+
+ mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
+ mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
return(const_cast<byte*>(ptr));
}
@@ -361,59 +474,46 @@ trx_undo_page_init(
{
trx_upagef_t* page_hdr;
- page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
-
- *reinterpret_cast<uint16*>(page_hdr + TRX_UNDO_PAGE_TYPE) = 0;
-
- mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
- TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
- mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE,
- TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
+ mlog_write_ulint(undo_page + FIL_PAGE_TYPE,
+ FIL_PAGE_UNDO_LOG, MLOG_2BYTES, mtr);
+ compile_time_assert(TRX_UNDO_PAGE_TYPE == 0);
+ compile_time_assert(TRX_UNDO_PAGE_START == 2);
+ compile_time_assert(TRX_UNDO_PAGE_NODE == TRX_UNDO_PAGE_FREE + 2);
- fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
-
- trx_undo_page_init_log(undo_page, mtr);
+ page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
+ mlog_write_ulint(page_hdr, TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE,
+ MLOG_4BYTES, mtr);
+ mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
+ TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE,
+ MLOG_2BYTES, mtr);
}
-/***************************************************************//**
-Creates a new undo log segment in file.
-@return DB_SUCCESS if page creation OK possible error codes are:
-DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE */
-static MY_ATTRIBUTE((warn_unused_result))
-dberr_t
-trx_undo_seg_create(
-/*================*/
- trx_rseg_t* rseg MY_ATTRIBUTE((unused)),/*!< in: rollback segment */
- trx_rsegf_t* rseg_hdr,/*!< in: rollback segment header, page
- x-latched */
- ulint* id, /*!< out: slot index within rseg header */
- page_t** undo_page,
- /*!< out: segment header page x-latched, NULL
- if there was an error */
- mtr_t* mtr) /*!< in: mtr */
+/** Create an undo log segment.
+@param[in,out] rseg_hdr rollback segment header (x-latched)
+@param[out] id undo slot number
+@param[out] err error code
+@param[in,out] mtr mini-transaction
+@return undo log block
+@retval NULL on failure */
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
+buf_block_t*
+trx_undo_seg_create(trx_rsegf_t* rseg_hdr, ulint* id, dberr_t* err, mtr_t* mtr)
{
ulint slot_no;
ulint space;
buf_block_t* block;
- trx_upagef_t* page_hdr;
- trx_usegf_t* seg_hdr;
ulint n_reserved;
bool success;
- dberr_t err = DB_SUCCESS;
- ut_ad(mtr != NULL);
- ut_ad(id != NULL);
- ut_ad(rseg_hdr != NULL);
- ut_ad(mutex_own(&(rseg->mutex)));
-
- slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr);
+ slot_no = trx_rsegf_undo_find_free(rseg_hdr);
if (slot_no == ULINT_UNDEFINED) {
ib::warn() << "Cannot find a free slot for an undo log. Do"
" you have too many active transactions running"
" concurrently?";
- return(DB_TOO_MANY_CONCURRENT_TRXS);
+ *err = DB_TOO_MANY_CONCURRENT_TRXS;
+ return NULL;
}
space = page_get_space_id(page_align(rseg_hdr));
@@ -421,8 +521,8 @@ trx_undo_seg_create(
success = fsp_reserve_free_extents(&n_reserved, space, 2, FSP_UNDO,
mtr);
if (!success) {
-
- return(DB_OUT_OF_FILE_SPACE);
+ *err = DB_OUT_OF_FILE_SPACE;
+ return NULL;
}
/* Allocate a new file segment for the undo log */
@@ -433,38 +533,35 @@ trx_undo_seg_create(
fil_space_release_free_extents(space, n_reserved);
if (block == NULL) {
- /* No space left */
-
- return(DB_OUT_OF_FILE_SPACE);
+ *err = DB_OUT_OF_FILE_SPACE;
+ return NULL;
}
buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
- *undo_page = buf_block_get_frame(block);
+ trx_undo_page_init(block->frame, mtr);
- page_hdr = *undo_page + TRX_UNDO_PAGE_HDR;
- seg_hdr = *undo_page + TRX_UNDO_SEG_HDR;
-
- trx_undo_page_init(*undo_page, mtr);
-
- mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
+ mlog_write_ulint(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + block->frame,
TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE,
MLOG_2BYTES, mtr);
- mlog_write_ulint(seg_hdr + TRX_UNDO_LAST_LOG, 0, MLOG_2BYTES, mtr);
+ mlog_write_ulint(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG + block->frame,
+ 0, MLOG_2BYTES, mtr);
- flst_init(seg_hdr + TRX_UNDO_PAGE_LIST, mtr);
+ flst_init(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + block->frame, mtr);
- flst_add_last(seg_hdr + TRX_UNDO_PAGE_LIST,
- page_hdr + TRX_UNDO_PAGE_NODE, mtr);
+ flst_add_last(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + block->frame,
+ TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE + block->frame,
+ mtr);
- trx_rsegf_set_nth_undo(rseg_hdr, slot_no,
- page_get_page_no(*undo_page), mtr);
*id = slot_no;
+ trx_rsegf_set_nth_undo(rseg_hdr, slot_no, block->page.id.page_no(),
+ mtr);
MONITOR_INC(MONITOR_NUM_UNDO_SLOT_USED);
- return(err);
+ *err = DB_SUCCESS;
+ return block;
}
/**********************************************************************//**
@@ -587,10 +684,7 @@ trx_undo_write_xid(
Read X/Open XA Transaction Identification (XID) from undo log header */
static
void
-trx_undo_read_xid(
-/*==============*/
- trx_ulogf_t* log_hdr,/*!< in: undo log header */
- XID* xid) /*!< out: X/Open XA Transaction Identification */
+trx_undo_read_xid(const trx_ulogf_t* log_hdr, XID* xid)
{
xid->formatID=static_cast<long>(mach_read_from_4(
log_hdr + TRX_UNDO_XA_FORMAT));
@@ -686,9 +780,6 @@ trx_undo_add_page(trx_t* trx, trx_undo_t* undo, mtr_t* mtr)
counterpart of the tree latch, which is the rseg mutex. */
mutex_enter(&rseg->mutex);
- if (rseg->curr_size == rseg->max_size) {
- goto func_exit;
- }
header_page = trx_undo_page_get(
page_id_t(undo->space, undo->hdr_page_no), mtr);
@@ -799,34 +890,6 @@ trx_undo_free_last_page(trx_undo_t* undo, mtr_t* mtr)
undo->size--;
}
-/** Empties an undo log header page of undo records for that undo log.
-Other undo logs may still have records on that page, if it is an update
-undo log.
-@param[in] space space
-@param[in] hdr_page_no header page number
-@param[in] hdr_offset header offset
-@param[in,out] mtr mini-transaction */
-static
-void
-trx_undo_empty_header_page(
- ulint space,
- ulint hdr_page_no,
- ulint hdr_offset,
- mtr_t* mtr)
-{
- page_t* header_page;
- trx_ulogf_t* log_hdr;
- ulint end;
-
- header_page = trx_undo_page_get(page_id_t(space, hdr_page_no), mtr);
-
- log_hdr = header_page + hdr_offset;
-
- end = trx_undo_page_get_end(header_page, hdr_page_no, hdr_offset);
-
- mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
-}
-
/** Truncate the tail of an undo log during rollback.
@param[in,out] undo undo log
@param[in] limit all undo logs after this limit will be discarded
@@ -938,9 +1001,16 @@ loop:
page_no = page_get_page_no(undo_page);
if (page_no == hdr_page_no) {
- trx_undo_empty_header_page(rseg->space,
- hdr_page_no, hdr_offset,
- &mtr);
+ uint16_t end = mach_read_from_2(hdr_offset + TRX_UNDO_NEXT_LOG
+ + undo_page);
+ if (end == 0) {
+ end = mach_read_from_2(TRX_UNDO_PAGE_HDR
+ + TRX_UNDO_PAGE_FREE
+ + undo_page);
+ }
+
+ mlog_write_ulint(undo_page + hdr_offset + TRX_UNDO_LOG_START,
+ end, MLOG_2BYTES, &mtr);
} else {
trx_undo_free_page(rseg, TRUE, rseg->space, hdr_page_no,
page_no, &mtr);
@@ -1005,66 +1075,58 @@ trx_undo_seg_free(
/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*/
-/********************************************************************//**
-Creates and initializes an undo log memory object according to the values
-in the header in file, when the database is started. The memory object is
-inserted in the appropriate list of rseg.
-@return own: the undo log memory object */
-static
-trx_undo_t*
-trx_undo_mem_create_at_db_start(
-/*============================*/
- trx_rseg_t* rseg, /*!< in: rollback segment memory object */
- ulint id, /*!< in: slot index within rseg */
- ulint page_no,/*!< in: undo log segment page number */
- mtr_t* mtr) /*!< in: mtr */
+/** Read an undo log when starting up the database.
+@param[in,out] rseg rollback segment
+@param[in] id rollback segment slot
+@param[in] page_no undo log segment page number
+@param[in,out] max_trx_id the largest observed transaction ID
+@return size of the undo log in pages */
+ulint
+trx_undo_mem_create_at_db_start(trx_rseg_t* rseg, ulint id, ulint page_no,
+ trx_id_t& max_trx_id)
{
- page_t* undo_page;
- trx_usegf_t* seg_header;
- trx_ulogf_t* undo_header;
- trx_undo_t* undo;
- ulint state;
- trx_id_t trx_id;
- ulint offset;
+ mtr_t mtr;
XID xid;
- ut_a(id < TRX_RSEG_N_SLOTS);
+ ut_ad(id < TRX_RSEG_N_SLOTS);
- undo_page = trx_undo_page_get(page_id_t(rseg->space, page_no), mtr);
+ mtr.start();
+ const page_t* undo_page = trx_undo_page_get(
+ page_id_t(rseg->space, page_no), &mtr);
const ulint type = mach_read_from_2(
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE + undo_page);
ut_ad(type == 0 || type == TRX_UNDO_INSERT || type == TRX_UNDO_UPDATE);
- seg_header = undo_page + TRX_UNDO_SEG_HDR;
-
- state = mach_read_from_2(seg_header + TRX_UNDO_STATE);
-
- offset = mach_read_from_2(seg_header + TRX_UNDO_LAST_LOG);
-
- undo_header = undo_page + offset;
- trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
+ uint state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
+ + undo_page);
+ uint offset = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_LAST_LOG
+ + undo_page);
- const bool xid_exists = mtr_read_ulint(
- undo_header + TRX_UNDO_XID_EXISTS, MLOG_1BYTE, mtr);
+ const trx_ulogf_t* undo_header = undo_page + offset;
/* Read X/Open XA transaction identification if it exists, or
set it to NULL. */
- xid.null();
- if (xid_exists) {
+ if (undo_header[TRX_UNDO_XID_EXISTS]) {
trx_undo_read_xid(undo_header, &xid);
+ } else {
+ xid.null();
}
- mutex_enter(&(rseg->mutex));
-
- undo = trx_undo_mem_create(rseg, id, trx_id, &xid, page_no, offset);
- mutex_exit(&(rseg->mutex));
+ trx_id_t trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
+ if (trx_id > max_trx_id) {
+ max_trx_id = trx_id;
+ }
- undo->dict_operation = mtr_read_ulint(
- undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr);
+ mutex_enter(&rseg->mutex);
+ trx_undo_t* undo = trx_undo_mem_create(
+ rseg, id, trx_id, &xid, page_no, offset);
+ mutex_exit(&rseg->mutex);
+ undo->dict_operation = undo_header[TRX_UNDO_DICT_TRANS];
undo->table_id = mach_read_from_8(undo_header + TRX_UNDO_TABLE_ID);
- undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST);
+ undo->size = flst_get_len(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST
+ + undo_page);
if (UNIV_UNLIKELY(state == TRX_UNDO_TO_FREE)) {
/* This is an old-format insert_undo log segment that
@@ -1072,14 +1134,24 @@ trx_undo_mem_create_at_db_start(
ut_ad(type == TRX_UNDO_INSERT);
state = TRX_UNDO_TO_PURGE;
} else {
+ if (state == TRX_UNDO_TO_PURGE
+ || state == TRX_UNDO_CACHED) {
+ trx_id_t id = mach_read_from_8(TRX_UNDO_TRX_NO
+ + undo_header);
+ if (id > max_trx_id) {
+ max_trx_id = id;
+ }
+ }
+
fil_addr_t last_addr = flst_get_last(
- seg_header + TRX_UNDO_PAGE_LIST, mtr);
+ TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST + undo_page,
+ &mtr);
undo->last_page_no = last_addr.page;
undo->top_page_no = last_addr.page;
page_t* last_page = trx_undo_page_get(
- page_id_t(rseg->space, undo->last_page_no), mtr);
+ page_id_t(rseg->space, undo->last_page_no), &mtr);
const trx_undo_rec_t* rec = trx_undo_page_get_last_rec(
last_page, page_no, offset);
@@ -1102,63 +1174,8 @@ trx_undo_mem_create_at_db_start(
MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
}
- return(undo);
-}
-
-/********************************************************************//**
-Initializes the undo log lists for a rollback segment memory copy. This
-function is only called when the database is started or a new rollback
-segment is created.
-@return the combined size of undo log segments in pages */
-ulint
-trx_undo_lists_init(
-/*================*/
- trx_rseg_t* rseg) /*!< in: rollback segment memory object */
-{
- ulint size = 0;
- trx_rsegf_t* rseg_header;
- ulint i;
- mtr_t mtr;
-
- mtr_start(&mtr);
-
- rseg_header = trx_rsegf_get_new(rseg->space, rseg->page_no, &mtr);
-
- for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
- ulint page_no;
-
- page_no = trx_rsegf_get_nth_undo(rseg_header, i, &mtr);
-
- /* In forced recovery: try to avoid operations which look
- at database pages; undo logs are rapidly changing data, and
- the probability that they are in an inconsistent state is
- high */
-
- if (page_no != FIL_NULL
- && srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
-
- trx_undo_t* undo;
-
- undo = trx_undo_mem_create_at_db_start(
- rseg, i, page_no, &mtr);
-
- size += undo->size;
-
- mtr_commit(&mtr);
-
- mtr_start(&mtr);
-
- rseg_header = trx_rsegf_get(
- rseg->space, rseg->page_no, &mtr);
-
- /* Found a used slot */
- MONITOR_INC(MONITOR_NUM_UNDO_SLOT_USED);
- }
- }
-
- mtr_commit(&mtr);
-
- return(size);
+ mtr.commit();
+ return undo->size;
}
/********************************************************************//**
@@ -1238,158 +1255,181 @@ trx_undo_mem_init_for_reuse(
undo->empty = TRUE;
}
-/********************************************************************//**
-Frees an undo log memory copy. */
-void
-trx_undo_mem_free(
-/*==============*/
- trx_undo_t* undo) /*!< in: the undo object to be freed */
-{
- ut_a(undo->id < TRX_RSEG_N_SLOTS);
-
- ut_free(undo);
-}
-
-/**********************************************************************//**
-Creates a new undo log.
-@return DB_SUCCESS if successful in creating the new undo lob object,
-possible error codes are: DB_TOO_MANY_CONCURRENT_TRXS
-DB_OUT_OF_FILE_SPACE DB_OUT_OF_MEMORY */
+/** Create an undo log.
+@param[in,out] trx transaction
+@param[in,out] rseg rollback segment
+@param[out] undo undo log object
+@param[out] err error code
+@param[in,out] mtr mini-transaction
+@return undo log block
+@retval NULL on failure */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
-dberr_t
-trx_undo_create(
-/*============*/
- trx_t* trx, /*!< in: transaction */
- trx_rseg_t* rseg, /*!< in: rollback segment memory copy */
- trx_id_t trx_id, /*!< in: id of the trx for which the undo log
- is created */
- const XID* xid, /*!< in: X/Open transaction identification*/
- trx_undo_t** undo, /*!< out: the new undo log object, undefined
- * if did not succeed */
- mtr_t* mtr) /*!< in: mtr */
+buf_block_t*
+trx_undo_create(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
+ dberr_t* err, mtr_t* mtr)
{
- trx_rsegf_t* rseg_header;
- ulint page_no;
- ulint offset;
ulint id;
- page_t* undo_page;
- dberr_t err;
ut_ad(mutex_own(&(rseg->mutex)));
- if (rseg->curr_size == rseg->max_size) {
+ buf_block_t* block = trx_undo_seg_create(
+ trx_rsegf_get(rseg->space, rseg->page_no, mtr), &id, err, mtr);
- return(DB_OUT_OF_FILE_SPACE);
+ if (!block) {
+ return block;
}
rseg->curr_size++;
- rseg_header = trx_rsegf_get(rseg->space, rseg->page_no, mtr);
-
- err = trx_undo_seg_create(rseg, rseg_header, &id, &undo_page, mtr);
+ ulint offset = trx_undo_header_create(block->frame, trx->id, mtr);
- if (err != DB_SUCCESS) {
- /* Did not succeed */
+ trx_undo_header_add_space_for_xid(block->frame, block->frame + offset,
+ mtr);
- rseg->curr_size--;
-
- return(err);
- }
-
- page_no = page_get_page_no(undo_page);
-
- offset = trx_undo_header_create(undo_page, trx_id, mtr);
-
- trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr);
-
- *undo = trx_undo_mem_create(rseg, id, trx_id, xid, page_no, offset);
+ *undo = trx_undo_mem_create(rseg, id, trx->id, trx->xid,
+ block->page.id.page_no(), offset);
if (*undo == NULL) {
+ *err = DB_OUT_OF_MEMORY;
+ /* FIXME: this will not free the undo block to the file */
+ return NULL;
+ } else if (rseg != trx->rsegs.m_redo.rseg) {
+ return block;
+ }
- err = DB_OUT_OF_MEMORY;
+ switch (trx_get_dict_operation(trx)) {
+ case TRX_DICT_OP_NONE:
+ break;
+ case TRX_DICT_OP_INDEX:
+ /* Do not discard the table on recovery. */
+ trx->table_id = 0;
+ /* fall through */
+ case TRX_DICT_OP_TABLE:
+ (*undo)->table_id = trx->table_id;
+ (*undo)->dict_operation = TRUE;
+ mlog_write_ulint(block->frame + offset + TRX_UNDO_DICT_TRANS,
+ TRUE, MLOG_1BYTE, mtr);
+ mlog_write_ull(block->frame + offset + TRX_UNDO_TABLE_ID,
+ trx->table_id, mtr);
}
- return(err);
+ *err = DB_SUCCESS;
+ return block;
}
/*================ UNDO LOG ASSIGNMENT AND CLEANUP =====================*/
-/********************************************************************//**
-Reuses a cached undo log.
-@return the undo log memory object, NULL if none cached */
+/** Reuse a cached undo log block.
+@param[in,out] trx transaction
+@param[in,out] rseg rollback segment
+@param[out] pundo the undo log memory object
+@param[in,out] mtr mini-transaction
+@return the undo log block
+@retval NULL if none cached */
static
-trx_undo_t*
-trx_undo_reuse_cached(
-/*==================*/
- trx_t* trx, /*!< in: transaction */
- trx_rseg_t* rseg, /*!< in: rollback segment memory object */
- trx_id_t trx_id, /*!< in: id of the trx for which the undo log
- is used */
- const XID* xid, /*!< in: X/Open XA transaction identification */
- mtr_t* mtr) /*!< in: mtr */
+buf_block_t*
+trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
+ mtr_t* mtr)
{
- trx_undo_t* undo;
- page_t* undo_page;
- ulint offset;
+ ut_ad(mutex_own(&rseg->mutex));
- ut_ad(mutex_own(&(rseg->mutex)));
-
- undo = UT_LIST_GET_FIRST(rseg->undo_cached);
- if (undo == NULL) {
- return(NULL);
+ trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached);
+ if (!undo) {
+ return NULL;
}
- UT_LIST_REMOVE(rseg->undo_cached, undo);
- MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
ut_ad(undo->size == 1);
- ut_a(undo->id < TRX_RSEG_N_SLOTS);
+ ut_ad(undo->id < TRX_RSEG_N_SLOTS);
- undo_page = trx_undo_page_get(
- page_id_t(undo->space, undo->hdr_page_no), mtr);
+ buf_block_t* block = buf_page_get(page_id_t(undo->space,
+ undo->hdr_page_no),
+ univ_page_size, RW_X_LATCH, mtr);
+ if (!block) {
+ return NULL;
+ }
- offset = trx_undo_header_create(undo_page, trx_id, mtr);
+ buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
- trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr);
- trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
+ UT_LIST_REMOVE(rseg->undo_cached, undo);
+ MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
- return(undo);
-}
+ *pundo = undo;
-/**********************************************************************//**
-Marks an undo log header as a header of a data dictionary operation
-transaction. */
-static
-void
-trx_undo_mark_as_dict_operation(
-/*============================*/
- trx_t* trx, /*!< in: dict op transaction */
- trx_undo_t* undo, /*!< in: assigned undo log */
- mtr_t* mtr) /*!< in: mtr */
-{
- page_t* hdr_page;
+ ulint offset = trx_undo_header_create(block->frame, trx->id, mtr);
- hdr_page = trx_undo_page_get(
- page_id_t(undo->space, undo->hdr_page_no), mtr);
+ trx_undo_header_add_space_for_xid(block->frame, block->frame + offset,
+ mtr);
+
+ trx_undo_mem_init_for_reuse(undo, trx->id, trx->xid, offset);
+
+ if (rseg != trx->rsegs.m_redo.rseg) {
+ return block;
+ }
switch (trx_get_dict_operation(trx)) {
case TRX_DICT_OP_NONE:
- ut_error;
+ return block;
case TRX_DICT_OP_INDEX:
/* Do not discard the table on recovery. */
- undo->table_id = 0;
- break;
+ trx->table_id = 0;
+ /* fall through */
case TRX_DICT_OP_TABLE:
undo->table_id = trx->table_id;
- break;
+ undo->dict_operation = TRUE;
+ mlog_write_ulint(block->frame + offset + TRX_UNDO_DICT_TRANS,
+ TRUE, MLOG_1BYTE, mtr);
+ mlog_write_ull(block->frame + offset + TRX_UNDO_TABLE_ID,
+ trx->table_id, mtr);
}
- mlog_write_ulint(hdr_page + undo->hdr_offset
- + TRX_UNDO_DICT_TRANS,
- TRUE, MLOG_1BYTE, mtr);
+ return block;
+}
- mlog_write_ull(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
- undo->table_id, mtr);
+/** Assign an undo log for a persistent transaction.
+A new undo log is created or a cached undo log reused.
+@param[in,out] trx transaction
+@param[out] err error code
+@param[in,out] mtr mini-transaction
+@return the undo log block
+@retval NULL on error */
+buf_block_t*
+trx_undo_assign(trx_t* trx, dberr_t* err, mtr_t* mtr)
+{
+ ut_ad(mutex_own(&trx->undo_mutex));
+ ut_ad(mtr->get_log_mode() == MTR_LOG_ALL);
+
+ trx_undo_t* undo = trx->rsegs.m_redo.undo;
+
+ if (undo) {
+ return buf_page_get_gen(
+ page_id_t(undo->space, undo->last_page_no),
+ univ_page_size, RW_X_LATCH,
+ buf_pool_is_obsolete(undo->withdraw_clock)
+ ? NULL : undo->guess_block,
+ BUF_GET, __FILE__, __LINE__, mtr, err);
+ }
+
+ trx_rseg_t* rseg = trx->rsegs.m_redo.rseg;
+
+ mutex_enter(&rseg->mutex);
+ buf_block_t* block = trx_undo_reuse_cached(
+ trx, rseg, &trx->rsegs.m_redo.undo, mtr);
+
+ if (!block) {
+ block = trx_undo_create(trx, rseg, &trx->rsegs.m_redo.undo,
+ err, mtr);
+ ut_ad(!block == (*err != DB_SUCCESS));
+ if (!block) {
+ goto func_exit;
+ }
+ } else {
+ *err = DB_SUCCESS;
+ }
+
+ UT_LIST_ADD_FIRST(rseg->undo_list, trx->rsegs.m_redo.undo);
- undo->dict_operation = TRUE;
+func_exit:
+ mutex_exit(&rseg->mutex);
+ return block;
}
/** Assign an undo log for a transaction.
@@ -1397,17 +1437,15 @@ A new undo log is created or a cached undo log reused.
@param[in,out] trx transaction
@param[in] rseg rollback segment
@param[out] undo the undo log
-@retval DB_SUCCESS on success
-@retval DB_TOO_MANY_CONCURRENT_TRXS
-@retval DB_OUT_OF_FILE_SPACE
-@retval DB_READ_ONLY
-@retval DB_OUT_OF_MEMORY */
-dberr_t
-trx_undo_assign_undo(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo)
+@param[out] err error code
+@param[in,out] mtr mini-transaction
+@return the undo log block
+@retval NULL on error */
+buf_block_t*
+trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
+ dberr_t* err, mtr_t* mtr)
{
const bool is_temp = rseg == trx->rsegs.m_noredo.rseg;
- mtr_t mtr;
- dberr_t err = DB_SUCCESS;
ut_ad(mutex_own(&trx->undo_mutex));
ut_ad(rseg == trx->rsegs.m_redo.rseg
@@ -1415,41 +1453,42 @@ trx_undo_assign_undo(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo)
ut_ad(undo == (is_temp
? &trx->rsegs.m_noredo.undo
: &trx->rsegs.m_redo.undo));
-
- mtr.start(trx);
-
- if (is_temp) {
- mtr.set_log_mode(MTR_LOG_NO_REDO);
+ ut_ad(mtr->get_log_mode()
+ == (is_temp ? MTR_LOG_NO_REDO : MTR_LOG_ALL));
+
+ if (*undo) {
+ return buf_page_get_gen(
+ page_id_t((*undo)->space, (*undo)->last_page_no),
+ univ_page_size, RW_X_LATCH,
+ buf_pool_is_obsolete((*undo)->withdraw_clock)
+ ? NULL : (*undo)->guess_block,
+ BUF_GET, __FILE__, __LINE__, mtr, err);
}
- mutex_enter(&rseg->mutex);
-
DBUG_EXECUTE_IF(
"ib_create_table_fail_too_many_trx",
- err = DB_TOO_MANY_CONCURRENT_TRXS;
- goto func_exit;
+ *err = DB_TOO_MANY_CONCURRENT_TRXS; return NULL;
);
- *undo = trx_undo_reuse_cached(trx, rseg, trx->id, trx->xid, &mtr);
- if (*undo == NULL) {
- err = trx_undo_create(trx, rseg, trx->id, trx->xid,
- undo, &mtr);
- if (err != DB_SUCCESS) {
+ mutex_enter(&rseg->mutex);
+
+ buf_block_t* block = trx_undo_reuse_cached(trx, rseg, undo, mtr);
+
+ if (!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;
}
UT_LIST_ADD_FIRST(rseg->undo_list, *undo);
- if (!is_temp && trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
- trx_undo_mark_as_dict_operation(trx, *undo, &mtr);
- }
-
func_exit:
mutex_exit(&rseg->mutex);
- mtr.commit();
-
- return(err);
+ return block;
}
/******************************************************************//**
@@ -1575,21 +1614,16 @@ trx_undo_commit_cleanup(trx_undo_t* undo, bool is_temp)
ut_ad(rseg->curr_size > undo->size);
rseg->curr_size -= undo->size;
- trx_undo_mem_free(undo);
+ ut_free(undo);
}
mutex_exit(&rseg->mutex);
}
-/********************************************************************//**
-At shutdown, frees the undo logs of a PREPARED transaction. */
+/** At shutdown, frees the undo logs of a transaction. */
void
-trx_undo_free_prepared(
-/*===================*/
- trx_t* trx) /*!< in/out: PREPARED transaction */
+trx_undo_free_at_shutdown(trx_t *trx)
{
- ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
-
if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
switch (undo->state) {
case TRX_UNDO_PREPARED:
@@ -1602,17 +1636,18 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
- trx->is_recovered=false */
+ trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
ut_a(!srv_was_started
|| srv_read_only_mode
- || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
+ || srv_fast_shutdown);
break;
default:
ut_error;
}
UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->undo_list, undo);
- trx_undo_mem_free(undo);
+ ut_free(undo);
undo = NULL;
}
@@ -1628,17 +1663,18 @@ trx_undo_free_prepared(
/* fall through */
case TRX_UNDO_ACTIVE:
/* lock_trx_release_locks() assigns
- trx->is_recovered=false */
+ trx->state = TRX_STATE_COMMITTED_IN_MEMORY. */
ut_a(!srv_was_started
|| srv_read_only_mode
- || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
+ || srv_fast_shutdown);
break;
default:
ut_error;
}
UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->old_insert_list, undo);
- trx_undo_mem_free(undo);
+ ut_free(undo);
undo = NULL;
}
@@ -1646,7 +1682,7 @@ trx_undo_free_prepared(
ut_a(undo->state == TRX_UNDO_PREPARED);
UT_LIST_REMOVE(trx->rsegs.m_noredo.rseg->undo_list, undo);
- trx_undo_mem_free(undo);
+ ut_free(undo);
undo = NULL;
}
}
@@ -1684,6 +1720,7 @@ trx_undo_truncate_tablespace(
mtr_start(&mtr);
mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
mtr_x_lock(fil_space_get_latch(space_id, NULL), &mtr);
+ buf_block_t* sys_header = trx_sysf_get(&mtr);
for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) {
trx_rsegf_t* rseg_header;
@@ -1691,7 +1728,7 @@ trx_undo_truncate_tablespace(
trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i);
rseg->page_no = trx_rseg_header_create(
- space_id, ULINT_MAX, rseg->id, &mtr);
+ space_id, rseg->id, sys_header, &mtr);
rseg_header = trx_rsegf_get_new(space_id, rseg->page_no, &mtr);
@@ -1708,15 +1745,12 @@ trx_undo_truncate_tablespace(
next_undo = UT_LIST_GET_NEXT(undo_list, undo);
UT_LIST_REMOVE(rseg->undo_cached, undo);
MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
- trx_undo_mem_free(undo);
+ 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);
- rseg->max_size = mtr_read_ulint(
- rseg_header + TRX_RSEG_MAX_SIZE, MLOG_4BYTES, &mtr);
-
/* Initialize the undo log lists according to the rseg header */
rseg->curr_size = mtr_read_ulint(
rseg_header + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, &mtr)
@@ -1727,7 +1761,7 @@ trx_undo_truncate_tablespace(
rseg->trx_ref_count = 0;
rseg->last_page_no = FIL_NULL;
rseg->last_offset = 0;
- rseg->last_trx_no = 0;
+ rseg->last_commit = 0;
rseg->needs_purge = false;
}
mtr_commit(&mtr);