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 | |