diff options
Diffstat (limited to 'storage/innobase/include/trx0rseg.h')
-rw-r--r-- | storage/innobase/include/trx0rseg.h | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h new file mode 100644 index 00000000..43e0c290 --- /dev/null +++ b/storage/innobase/include/trx0rseg.h @@ -0,0 +1,301 @@ +/***************************************************************************** + +Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 2022, 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, Fifth Floor, Boston, MA 02110-1335 USA + +*****************************************************************************/ + +/**************************************************//** +@file include/trx0rseg.h +Rollback segment + +Created 3/26/1996 Heikki Tuuri +*******************************************************/ + +#pragma once +#include "trx0types.h" +#include "fut0lst.h" + +/** Create a rollback segment header. +@param[in,out] space system, undo, or temporary tablespace +@param[in] rseg_id rollback segment identifier +@param[in] max_trx_id new value of TRX_RSEG_MAX_TRX_ID +@param[in,out] mtr mini-transaction +@param[out] err error code +@return the created rollback segment +@retval nullptr on failure */ +buf_block_t *trx_rseg_header_create(fil_space_t *space, ulint rseg_id, + trx_id_t max_trx_id, mtr_t *mtr, + dberr_t *err) + MY_ATTRIBUTE((nonnull, warn_unused_result)); + +/** Initialize or recover the rollback segments at startup. */ +dberr_t trx_rseg_array_init(); + +/** Create the temporary rollback segments. */ +dberr_t trx_temp_rseg_create(mtr_t *mtr); + +/* Number of undo log slots in a rollback segment file copy */ +#define TRX_RSEG_N_SLOTS (srv_page_size / 16) + +/* Maximum number of transactions supported by a single rollback segment */ +#define TRX_RSEG_MAX_N_TRXS (TRX_RSEG_N_SLOTS / 2) + +/** The rollback segment memory object */ +struct alignas(CPU_LEVEL1_DCACHE_LINESIZE) trx_rseg_t +{ + /** tablespace containing the rollback segment; constant after init() */ + fil_space_t *space; + /** latch protecting everything except page_no, space */ + srw_spin_lock latch; + /** rollback segment header page number; constant after init() */ + uint32_t page_no; + /** length of the TRX_RSEG_HISTORY list (number of transactions) */ + uint32_t history_size; + + /** Last known transaction that has not been purged yet, + or 0 if everything has been purged. */ + trx_id_t needs_purge; + +private: + /** Reference counter to track is_persistent() transactions, + with SKIP flag. */ + std::atomic<uint32_t> ref; + + /** Whether undo tablespace truncation is pending */ + static constexpr uint32_t SKIP= 1; + /** Transaction reference count multiplier */ + static constexpr uint32_t REF= 2; + + uint32_t ref_load() const { return ref.load(std::memory_order_relaxed); } + + /** Set the SKIP bit */ + void ref_set_skip() + { + static_assert(SKIP == 1U, "compatibility"); +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + __asm__ __volatile__("lock btsl $0, %0" : "+m" (ref)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64) + _interlockedbittestandset(reinterpret_cast<volatile long*>(&ref), 0); +#else + ref.fetch_or(SKIP, std::memory_order_relaxed); +#endif + } + /** Clear a bit in ref */ + void ref_reset_skip() + { + static_assert(SKIP == 1U, "compatibility"); +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + __asm__ __volatile__("lock btrl $0, %0" : "+m" (ref)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64) + _interlockedbittestandreset(reinterpret_cast<volatile long*>(&ref), 0); +#else + ref.fetch_and(~SKIP, std::memory_order_relaxed); +#endif + } + +public: + + /** Initialize the fields that are not zero-initialized. */ + void init(fil_space_t *space, uint32_t page); + /** Reinitialize the fields on undo tablespace truncation. */ + void reinit(uint32_t page); + /** Clean up. */ + void destroy(); + + /** Note that undo tablespace truncation was started. */ + void set_skip_allocation() { ut_ad(is_persistent()); ref_set_skip(); } + /** Note that undo tablespace truncation was completed. */ + void clear_skip_allocation() + { + ut_ad(is_persistent()); +#if defined DBUG_OFF + ref_reset_skip(); +#else + ut_d(auto r=) ref.fetch_and(~SKIP, std::memory_order_relaxed); + ut_ad(r == SKIP); +#endif + } + /** @return whether the segment is marked for undo truncation */ + bool skip_allocation() const + { return ref.load(std::memory_order_acquire) & SKIP; } + /** Increment the reference count */ + void acquire() + { ut_d(auto r=) ref.fetch_add(REF); ut_ad(!(r & SKIP)); } + /** Increment the reference count if possible + @retval true if the reference count was incremented + @retval false if skip_allocation() holds */ + bool acquire_if_available() + { + uint32_t r= 0; + while (!ref.compare_exchange_weak(r, r + REF, + std::memory_order_relaxed, + std::memory_order_relaxed)) + if (r & SKIP) + return false; + return true; + } + + /** Decrement the reference count */ + void release() + { + ut_d(const auto r=) + ref.fetch_sub(REF, std::memory_order_relaxed); + ut_ad(r >= REF); + } + /** @return whether references exist */ + bool is_referenced() const { return ref_load() >= REF; } + + /** current size in pages */ + uint32_t curr_size; + + /** List of undo logs (transactions) */ + UT_LIST_BASE_NODE_T(trx_undo_t) undo_list; + /** List of undo log segments cached for fast reuse */ + UT_LIST_BASE_NODE_T(trx_undo_t) undo_cached; + + /** Last not yet purged undo log header; FIL_NULL if all purged */ + uint32_t last_page_no; + + /** trx_t::no | last_offset << 48 */ + uint64_t last_commit_and_offset; + + /** @return the commit ID of the last committed transaction */ + trx_id_t last_trx_no() const + { return last_commit_and_offset & ((1ULL << 48) - 1); } + /** @return header offset of the last committed transaction */ + uint16_t last_offset() const + { return static_cast<uint16_t>(last_commit_and_offset >> 48); } + + void set_last_commit(uint16_t last_offset, trx_id_t trx_no) + { + last_commit_and_offset= static_cast<uint64_t>(last_offset) << 48 | trx_no; + } + + /** @return the page identifier */ + page_id_t page_id() const { return page_id_t{space->id, page_no}; } + + /** @return the rollback segment header page, exclusively latched */ + buf_block_t *get(mtr_t *mtr, dberr_t *err) const; + + /** @return whether the rollback segment is persistent */ + bool is_persistent() const + { + ut_ad(space == fil_system.temp_space || space == fil_system.sys_space || + (srv_undo_space_id_start > 0 && + space->id >= srv_undo_space_id_start && + space->id <= srv_undo_space_id_start + TRX_SYS_MAX_UNDO_SPACES)); + ut_ad(space == fil_system.temp_space || space == fil_system.sys_space || + !srv_was_started || + (srv_undo_space_id_start > 0 && + space->id >= srv_undo_space_id_start + && space->id <= srv_undo_space_id_start + + srv_undo_tablespaces_open)); + return space->id != SRV_TMP_SPACE_ID; + } +}; + +/* Undo log segment slot in a rollback segment header */ +/*-------------------------------------------------------------*/ +#define TRX_RSEG_SLOT_PAGE_NO 0 /* Page number of the header page of + an undo log segment */ +/*-------------------------------------------------------------*/ +/* Slot size */ +#define TRX_RSEG_SLOT_SIZE 4 + +/* The offset of the rollback segment header on its page */ +#define TRX_RSEG FSEG_PAGE_DATA + +/* Transaction rollback segment header */ +/*-------------------------------------------------------------*/ +/** 0xfffffffe = pre-MariaDB 10.3.5 format; 0=MariaDB 10.3.5 or later */ +#define TRX_RSEG_FORMAT 0 +/** Number of pages in the TRX_RSEG_HISTORY list */ +#define TRX_RSEG_HISTORY_SIZE 4 +/** Committed transaction logs that have not been purged yet */ +#define TRX_RSEG_HISTORY 8 +#define TRX_RSEG_FSEG_HEADER (8 + FLST_BASE_NODE_SIZE) + /* Header for the file segment where + this page is placed */ +#define TRX_RSEG_UNDO_SLOTS (8 + FLST_BASE_NODE_SIZE + FSEG_HEADER_SIZE) + /* Undo log segment slots */ +/** Maximum transaction ID (valid only if TRX_RSEG_FORMAT is 0) */ +#define TRX_RSEG_MAX_TRX_ID (TRX_RSEG_UNDO_SLOTS + TRX_RSEG_N_SLOTS \ + * TRX_RSEG_SLOT_SIZE) + +/** 8 bytes offset within the binlog file */ +#define TRX_RSEG_BINLOG_OFFSET TRX_RSEG_MAX_TRX_ID + 8 +/** MySQL log file name, 512 bytes, including terminating NUL +(valid only if TRX_RSEG_FORMAT is 0). +If no binlog information is present, the first byte is NUL. */ +#define TRX_RSEG_BINLOG_NAME TRX_RSEG_MAX_TRX_ID + 16 +/** Maximum length of binlog file name, including terminating NUL, in bytes */ +#define TRX_RSEG_BINLOG_NAME_LEN 512 + +#ifdef WITH_WSREP +# include "trx0xa.h" + +/** Update the WSREP XID information in rollback segment header. +@param[in,out] rseg_header rollback segment header +@param[in] xid WSREP XID +@param[in,out] mtr mini-transaction */ +void +trx_rseg_update_wsrep_checkpoint( + buf_block_t* rseg_header, + const XID* xid, + mtr_t* mtr); + +/** Update WSREP checkpoint XID in first rollback segment header +as part of wsrep_set_SE_checkpoint() when it is guaranteed that there +are no wsrep transactions committing. +If the UUID part of the WSREP XID does not match to the UUIDs of XIDs already +stored into rollback segments, the WSREP XID in all the remaining rollback +segments will be reset. +@param[in] xid WSREP XID */ +void trx_rseg_update_wsrep_checkpoint(const XID* xid); + +/** Recover the latest WSREP checkpoint XID. +@param[out] xid WSREP XID +@return whether the WSREP XID was found */ +bool trx_rseg_read_wsrep_checkpoint(XID& xid); +#endif /* WITH_WSREP */ + +/** Read the page number of an undo log slot. +@param[in] rseg_header rollback segment header +@param[in] n slot number */ +inline uint32_t trx_rsegf_get_nth_undo(const buf_block_t *rseg_header, ulint n) +{ + ut_ad(n < TRX_RSEG_N_SLOTS); + return mach_read_from_4(TRX_RSEG + TRX_RSEG_UNDO_SLOTS + + n * TRX_RSEG_SLOT_SIZE + rseg_header->page.frame); +} + +/** Upgrade a rollback segment header page to MariaDB 10.3 format. +@param[in,out] rseg_header rollback segment header page +@param[in,out] mtr mini-transaction */ +void trx_rseg_format_upgrade(buf_block_t *rseg_header, mtr_t *mtr); + +/** Update the offset information about the end of the binlog entry +which corresponds to the transaction just being committed. +In a replication slave, this updates the master binlog position +up to which replication has proceeded. +@param[in,out] rseg_header rollback segment header +@param[in] log_file_name binlog file name +@param[in] log_offset binlog offset value +@param[in,out] mtr mini-transaction */ +void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, + const char *log_file_name, + ulonglong log_offset, + mtr_t *mtr); |