/***************************************************************************** Copyright (c) 1996, 2018, 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/trx0rseg.ic Rollback segment Created 3/26/1996 Heikki Tuuri *******************************************************/ #include "mtr0log.h" #include "srv0srv.h" #include "trx0purge.h" #include "trx0sys.h" /** Gets a rollback segment header. @param[in] space space where placed @param[in] page_no page number of the header @param[in] page_size page size @param[in,out] mtr mini-transaction @return rollback segment header, page x-latched */ UNIV_INLINE trx_rsegf_t *trx_rsegf_get(space_id_t space, page_no_t page_no, const page_size_t &page_size, mtr_t *mtr) { buf_block_t *block; trx_rsegf_t *header; block = buf_page_get(page_id_t(space, page_no), page_size, RW_X_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_RSEG_HEADER); header = TRX_RSEG + buf_block_get_frame(block); return (header); } /** Gets a newly created rollback segment header. @param[in] space space where placed @param[in] page_no page number of the header @param[in] page_size page size @param[in,out] mtr mini-transaction @return rollback segment header, page x-latched */ UNIV_INLINE trx_rsegf_t *trx_rsegf_get_new(space_id_t space, page_no_t page_no, const page_size_t &page_size, mtr_t *mtr) { buf_block_t *block; trx_rsegf_t *header; block = buf_page_get(page_id_t(space, page_no), page_size, RW_X_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_RSEG_HEADER_NEW); header = TRX_RSEG + buf_block_get_frame(block); return (header); } /** Gets the file page number of the nth undo log slot. @return page number of the undo log segment */ UNIV_INLINE page_no_t trx_rsegf_get_nth_undo( trx_rsegf_t *rsegf, /*!< in: rollback segment header */ ulint n, /*!< in: index of slot */ mtr_t *mtr) /*!< in: mtr */ { ut_a(n < TRX_RSEG_N_SLOTS); return (mtr_read_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + n * TRX_RSEG_SLOT_SIZE, MLOG_4BYTES, mtr)); } /** Sets the file page number of the nth undo log slot. */ UNIV_INLINE void trx_rsegf_set_nth_undo( trx_rsegf_t *rsegf, /*!< in: rollback segment header */ ulint n, /*!< in: index of slot */ page_no_t page_no, /*!< in: page number of the undo log segment */ mtr_t *mtr) /*!< in: mtr */ { ut_a(n < TRX_RSEG_N_SLOTS); mlog_write_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + n * TRX_RSEG_SLOT_SIZE, page_no, MLOG_4BYTES, mtr); } /** Looks for a free slot for an undo log segment. @return slot index or ULINT_UNDEFINED if not found */ UNIV_INLINE ulint trx_rsegf_undo_find_free( trx_rsegf_t *rsegf, /*!< in: rollback segment header */ mtr_t *mtr) /*!< in: mtr */ { ulint i; page_no_t page_no; ulint max_slots = TRX_RSEG_N_SLOTS; #ifdef UNIV_DEBUG if (trx_rseg_n_slots_debug) { max_slots = ut_min(static_cast(trx_rseg_n_slots_debug), static_cast(TRX_RSEG_N_SLOTS)); } #endif for (i = 0; i < max_slots; i++) { page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr); if (page_no == FIL_NULL) { return (i); } } return (ULINT_UNDEFINED); } /** Convert a 7-bit ID stored in a rollback pointer to an undo space ID. Before 8.0, this ID is called an rseg_id and is a slot in the TRX_SYS page where the space_id can be read. After 8.0 this is an undo space number which can be converted directly to an undo space ID. @param[in] id a 7-bit ID from a rollback pointer @param[in] is_temp true if rseg from Temp Tablespace else false. @return undo tablespace ID containing the rollback segment */ inline space_id_t trx_rseg_id_to_space_id(ulint id, bool is_temp) { /* The rseg_id must be an undo_space_num between 0 and 127. */ ut_ad(id < TRX_SYS_N_RSEGS); /* MySQL versions before v5.7.2 used the first 32 slots in the TRX_SYS page for redo rollback segments. v5.7.2 uses these seg_ids for no-redo rollback segments in the temporary tablespace. v8 will once again use them for durable/redo rollback segments. */ if (is_temp) { return (srv_tmp_space.space_id()); } /* If the ID is 0 then use the system tablespace. */ if (id == 0) { return (TRX_SYS_SPACE); } if (srv_upgrade_old_undo_found) { /* Interpret the id as a slot in the TRX_SYS page. */ trx_rseg_t *rseg = trx_sys->rsegs.find(id); return (rseg->space_id); } /* We assume at this point that all undo tablespaces have reserved space_ids and RSEG_ARRAY pages. */ ut_ad(!undo::spaces->empty()); /* The space_id_bank for this slot cannot change since this call is done by purge or MVCC. This space_id can only change during truncate when there are no more undo logs in this undo tablespace. */ space_id_t space_id = undo::num2id(static_cast(id)); ut_ad(space_id != SPACE_UNKNOWN); return (space_id); } /** Get a pointer to the rollback segment directory header and x-latches its page. @param[in] space_id Undo Tablespace ID @param[in] mtr mtr @return pointer to rollback segment directory header with page x-latched. */ inline trx_rsegsf_t *trx_rsegsf_get(space_id_t space_id, mtr_t *mtr) { buf_block_t *block; trx_rsegsf_t *rsegs_header; ut_ad(mtr != nullptr); ut_ad(undo::is_reserved(space_id)); block = buf_page_get(page_id_t(space_id, FSP_RSEG_ARRAY_PAGE_NO), univ_page_size, RW_X_LATCH, mtr); buf_block_dbg_add_level(block, SYNC_RSEG_ARRAY_HEADER); rsegs_header = RSEG_ARRAY_HEADER + buf_block_get_frame(block); return (rsegs_header); } /** Get the page number of the nth rollback segment slot in the RSEG_ARRAY page for this undo tablespace. @param[in] rsegs_header rollback segment array page header @param[in] slot slot index == rseg id @param[in] mtr mtr @return page number, FIL_NULL if slot unused */ inline page_no_t trx_rsegsf_get_page_no(trx_rsegsf_t *rsegs_header, ulint slot, mtr_t *mtr) { ut_ad(rsegs_header != nullptr); ut_ad(mtr != nullptr); ut_ad(slot < FSP_MAX_ROLLBACK_SEGMENTS); return (mtr_read_ulint( rsegs_header + RSEG_ARRAY_PAGES_OFFSET + slot * RSEG_ARRAY_SLOT_SIZE, MLOG_4BYTES, mtr)); } /** Sets the page number of the nth rollback segment slot in the independent undo tablespace. @param[in] rsegs_header rollback segment array page header @param[in] slot slot number on page == rseg id @param[in] page_no rollback regment header page number @param[in] mtr mtr */ UNIV_INLINE void trx_rsegsf_set_page_no(trx_rsegsf_t *rsegs_header, ulint slot, page_no_t page_no, mtr_t *mtr) { ut_ad(rsegs_header); mlog_write_ulint( rsegs_header + RSEG_ARRAY_PAGES_OFFSET + slot * RSEG_ARRAY_SLOT_SIZE, page_no, MLOG_4BYTES, mtr); }