/***************************************************************************** Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. 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, version 2.0, 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 St, Fifth Floor, Boston, MA 02110-1301 USA *****************************************************************************/ /** @file include/trx0undo.ic Transaction undo log Created 3/26/1996 Heikki Tuuri *******************************************************/ #include "data0type.h" #include "page0page.h" #include "trx0purge.h" #ifndef UNIV_HOTBACKUP /** Build a roll pointer. @param[in] is_insert TRUE if insert undo log @param[in] space_id space ID of the rollback segment @param[in] page_no page number @param[in] offset offset of the undo entry within page @return roll pointer */ inline roll_ptr_t trx_undo_build_roll_ptr(ibool is_insert, space_id_t space_id, page_no_t page_no, ulint offset) { roll_ptr_t roll_ptr; ulint id; ut_ad(is_insert == 0 || is_insert == 1); ut_ad(offset < 65536); id = (fsp_is_undo_tablespace(space_id) ? undo::id2num(space_id) : 0); roll_ptr = (roll_ptr_t)is_insert << 55 | (roll_ptr_t)id << 48 | (roll_ptr_t)page_no << 16 | offset; return (roll_ptr); } /** Decodes a roll pointer. */ 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 */ page_no_t *page_no, /*!< out: page number */ ulint *offset) /*!< out: offset of the undo entry within page */ { 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 */ { 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 */ { return (static_cast(trx_id[DATA_TRX_ID_LEN] >> 7)); } #endif /* !UNIV_HOTBACKUP */ /** 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 */ { 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 */ { return (mach_read_from_7(ptr)); } #ifndef UNIV_HOTBACKUP /** Gets an undo log page and x-latches it. @param[in] page_id page id @param[in] page_size page size @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, const page_size_t &page_size, mtr_t *mtr) { buf_block_t *block = buf_page_get(page_id, 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] page_size page size @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, const page_size_t &page_size, mtr_t *mtr) { buf_block_t *block = buf_page_get(page_id, 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 */ page_no_t 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 */ page_no_t 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 */ page_no_t 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 */ page_no_t 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 */ page_no_t 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 */ page_no_t 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); } /* Set undo segment to prepared state and set XID @param[in] in_xid transaction XID. */ inline void trx_undo_t::set_prepared(const XID *in_xid) { state = TRX_UNDO_PREPARED; xid = *in_xid; flag |= TRX_UNDO_FLAG_XID; } #endif /* !UNIV_HOTBACKUP */