| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /**************************************************//** |
| 21 | @file include/trx0undo.ic |
| 22 | Transaction undo log |
| 23 | |
| 24 | Created 3/26/1996 Heikki Tuuri |
| 25 | *******************************************************/ |
| 26 | |
| 27 | #include "data0type.h" |
| 28 | #include "page0page.h" |
| 29 | |
| 30 | /***********************************************************************//** |
| 31 | Builds a roll pointer. |
| 32 | @return roll pointer */ |
| 33 | UNIV_INLINE |
| 34 | roll_ptr_t |
| 35 | trx_undo_build_roll_ptr( |
| 36 | /*====================*/ |
| 37 | ibool is_insert, /*!< in: TRUE if insert undo log */ |
| 38 | ulint rseg_id, /*!< in: rollback segment id */ |
| 39 | ulint page_no, /*!< in: page number */ |
| 40 | ulint offset) /*!< in: offset of the undo entry within page */ |
| 41 | { |
| 42 | roll_ptr_t roll_ptr; |
| 43 | compile_time_assert(DATA_ROLL_PTR_LEN == 7); |
| 44 | ut_ad(is_insert == 0 || is_insert == 1); |
| 45 | ut_ad(rseg_id < TRX_SYS_N_RSEGS); |
| 46 | ut_ad(offset < 65536); |
| 47 | |
| 48 | roll_ptr = (roll_ptr_t) is_insert << ROLL_PTR_INSERT_FLAG_POS |
| 49 | | (roll_ptr_t) rseg_id << ROLL_PTR_RSEG_ID_POS |
| 50 | | (roll_ptr_t) page_no << ROLL_PTR_PAGE_POS |
| 51 | | offset; |
| 52 | return(roll_ptr); |
| 53 | } |
| 54 | |
| 55 | /***********************************************************************//** |
| 56 | Decodes a roll pointer. */ |
| 57 | UNIV_INLINE |
| 58 | void |
| 59 | trx_undo_decode_roll_ptr( |
| 60 | /*=====================*/ |
| 61 | roll_ptr_t roll_ptr, /*!< in: roll pointer */ |
| 62 | ibool* is_insert, /*!< out: TRUE if insert undo log */ |
| 63 | ulint* rseg_id, /*!< out: rollback segment id */ |
| 64 | ulint* page_no, /*!< out: page number */ |
| 65 | ulint* offset) /*!< out: offset of the undo |
| 66 | entry within page */ |
| 67 | { |
| 68 | compile_time_assert(DATA_ROLL_PTR_LEN == 7); |
| 69 | ut_ad(roll_ptr < (1ULL << 56)); |
| 70 | *offset = (ulint) roll_ptr & 0xFFFF; |
| 71 | roll_ptr >>= 16; |
| 72 | *page_no = (ulint) roll_ptr & 0xFFFFFFFF; |
| 73 | roll_ptr >>= 32; |
| 74 | *rseg_id = (ulint) roll_ptr & 0x7F; |
| 75 | roll_ptr >>= 7; |
| 76 | *is_insert = (ibool) roll_ptr; /* TRUE==1 */ |
| 77 | } |
| 78 | |
| 79 | /***********************************************************************//** |
| 80 | Returns TRUE if the roll pointer is of the insert type. |
| 81 | @return TRUE if insert undo log */ |
| 82 | UNIV_INLINE |
| 83 | ibool |
| 84 | trx_undo_roll_ptr_is_insert( |
| 85 | /*========================*/ |
| 86 | roll_ptr_t roll_ptr) /*!< in: roll pointer */ |
| 87 | { |
| 88 | compile_time_assert(DATA_ROLL_PTR_LEN == 7); |
| 89 | ut_ad(roll_ptr < (1ULL << (ROLL_PTR_INSERT_FLAG_POS + 1))); |
| 90 | return((ibool) (roll_ptr >> ROLL_PTR_INSERT_FLAG_POS)); |
| 91 | } |
| 92 | |
| 93 | /***********************************************************************//** |
| 94 | Returns true if the record is of the insert type. |
| 95 | @return true if the record was freshly inserted (not updated). */ |
| 96 | UNIV_INLINE |
| 97 | bool |
| 98 | trx_undo_trx_id_is_insert( |
| 99 | /*======================*/ |
| 100 | const byte* trx_id) /*!< in: DB_TRX_ID, followed by DB_ROLL_PTR */ |
| 101 | { |
| 102 | compile_time_assert(DATA_TRX_ID + 1 == DATA_ROLL_PTR); |
| 103 | return bool(trx_id[DATA_TRX_ID_LEN] >> 7); |
| 104 | } |
| 105 | |
| 106 | /*****************************************************************//** |
| 107 | Writes a roll ptr to an index page. In case that the size changes in |
| 108 | some future version, this function should be used instead of |
| 109 | mach_write_... */ |
| 110 | UNIV_INLINE |
| 111 | void |
| 112 | trx_write_roll_ptr( |
| 113 | /*===============*/ |
| 114 | byte* ptr, /*!< in: pointer to memory where |
| 115 | written */ |
| 116 | roll_ptr_t roll_ptr) /*!< in: roll ptr */ |
| 117 | { |
| 118 | compile_time_assert(DATA_ROLL_PTR_LEN == 7); |
| 119 | mach_write_to_7(ptr, roll_ptr); |
| 120 | } |
| 121 | |
| 122 | /*****************************************************************//** |
| 123 | Reads a roll ptr from an index page. In case that the roll ptr size |
| 124 | changes in some future version, this function should be used instead of |
| 125 | mach_read_... |
| 126 | @return roll ptr */ |
| 127 | UNIV_INLINE |
| 128 | roll_ptr_t |
| 129 | trx_read_roll_ptr( |
| 130 | /*==============*/ |
| 131 | const byte* ptr) /*!< in: pointer to memory from where to read */ |
| 132 | { |
| 133 | compile_time_assert(DATA_ROLL_PTR_LEN == 7); |
| 134 | return(mach_read_from_7(ptr)); |
| 135 | } |
| 136 | |
| 137 | /** Gets an undo log page and x-latches it. |
| 138 | @param[in] page_id page id |
| 139 | @param[in,out] mtr mini-transaction |
| 140 | @return pointer to page x-latched */ |
| 141 | UNIV_INLINE |
| 142 | page_t* |
| 143 | trx_undo_page_get(const page_id_t& page_id, mtr_t* mtr) |
| 144 | { |
| 145 | buf_block_t* block = buf_page_get(page_id, univ_page_size, |
| 146 | RW_X_LATCH, mtr); |
| 147 | |
| 148 | buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE); |
| 149 | |
| 150 | return(buf_block_get_frame(block)); |
| 151 | } |
| 152 | |
| 153 | /** Gets an undo log page and s-latches it. |
| 154 | @param[in] page_id page id |
| 155 | @param[in,out] mtr mini-transaction |
| 156 | @return pointer to page s-latched */ |
| 157 | UNIV_INLINE |
| 158 | page_t* |
| 159 | trx_undo_page_get_s_latched(const page_id_t& page_id, mtr_t* mtr) |
| 160 | { |
| 161 | buf_block_t* block = buf_page_get(page_id, univ_page_size, |
| 162 | RW_S_LATCH, mtr); |
| 163 | |
| 164 | buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE); |
| 165 | |
| 166 | return(buf_block_get_frame(block)); |
| 167 | } |
| 168 | |
| 169 | /** Determine the end offset of undo log records of an undo log page. |
| 170 | @param[in] undo_page undo log page |
| 171 | @param[in] page_no undo log header page number |
| 172 | @param[in] offset undo log header offset |
| 173 | @return end offset */ |
| 174 | inline |
| 175 | uint16_t |
| 176 | trx_undo_page_get_end(const page_t* undo_page, ulint page_no, ulint offset) |
| 177 | { |
| 178 | if (page_no == page_get_page_no(undo_page)) { |
| 179 | if (uint16_t end = mach_read_from_2(TRX_UNDO_NEXT_LOG |
| 180 | + offset + undo_page)) { |
| 181 | return end; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | return mach_read_from_2(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE |
| 186 | + undo_page); |
| 187 | } |
| 188 | |
| 189 | /******************************************************************//** |
| 190 | Returns the next undo log record on the page in the specified log, or |
| 191 | NULL if none exists. |
| 192 | @return pointer to record, NULL if none */ |
| 193 | UNIV_INLINE |
| 194 | trx_undo_rec_t* |
| 195 | trx_undo_page_get_next_rec( |
| 196 | /*=======================*/ |
| 197 | trx_undo_rec_t* rec, /*!< in: undo log record */ |
| 198 | ulint page_no,/*!< in: undo log header page number */ |
| 199 | ulint offset) /*!< in: undo log header offset on page */ |
| 200 | { |
| 201 | page_t* undo_page; |
| 202 | ulint end; |
| 203 | ulint next; |
| 204 | |
| 205 | undo_page = (page_t*) ut_align_down(rec, srv_page_size); |
| 206 | |
| 207 | end = trx_undo_page_get_end(undo_page, page_no, offset); |
| 208 | |
| 209 | next = mach_read_from_2(rec); |
| 210 | |
| 211 | if (next == end) { |
| 212 | |
| 213 | return(NULL); |
| 214 | } |
| 215 | |
| 216 | return(undo_page + next); |
| 217 | } |
| 218 | |