1 | /***************************************************************************** |
2 | Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. |
3 | Copyright (c) 2013, 2018, MariaDB Corporation. |
4 | |
5 | This program is free software; you can redistribute it and/or modify it under |
6 | the terms of the GNU General Public License as published by the Free Software |
7 | Foundation; version 2 of the License. |
8 | |
9 | This program is distributed in the hope that it will be useful, but WITHOUT |
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
11 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License along with |
14 | this program; if not, write to the Free Software Foundation, Inc., |
15 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
16 | |
17 | *****************************************************************************/ |
18 | |
19 | /**************************************************//** |
20 | @file include/page0page.h |
21 | Index page routines |
22 | |
23 | Created 2/2/1994 Heikki Tuuri |
24 | *******************************************************/ |
25 | |
26 | #ifndef page0page_h |
27 | #define page0page_h |
28 | |
29 | #include "univ.i" |
30 | |
31 | #include "page0types.h" |
32 | #ifndef UNIV_INNOCHECKSUM |
33 | #include "fil0fil.h" |
34 | #include "buf0buf.h" |
35 | #include "data0data.h" |
36 | #include "dict0dict.h" |
37 | #include "rem0rec.h" |
38 | #endif /* !UNIV_INNOCHECKSUM*/ |
39 | #include "fsp0fsp.h" |
40 | #ifndef UNIV_INNOCHECKSUM |
41 | #include "mtr0mtr.h" |
42 | |
43 | #ifdef UNIV_MATERIALIZE |
44 | #undef UNIV_INLINE |
45 | #define UNIV_INLINE |
46 | #endif |
47 | |
48 | /* PAGE HEADER |
49 | =========== |
50 | |
51 | Index page header starts at the first offset left free by the FIL-module */ |
52 | |
53 | typedef byte page_header_t; |
54 | #endif /* !UNIV_INNOCHECKSUM */ |
55 | |
56 | #define FSEG_PAGE_DATA /* index page header starts at this |
57 | offset */ |
58 | /*-----------------------------*/ |
59 | #define PAGE_N_DIR_SLOTS 0 /* number of slots in page directory */ |
60 | #define PAGE_HEAP_TOP 2 /* pointer to record heap top */ |
61 | #define PAGE_N_HEAP 4 /* number of records in the heap, |
62 | bit 15=flag: new-style compact page format */ |
63 | #define PAGE_FREE 6 /* pointer to start of page free record list */ |
64 | #define PAGE_GARBAGE 8 /* number of bytes in deleted records */ |
65 | #define PAGE_LAST_INSERT 10 /* pointer to the last inserted record, or |
66 | 0 if this info has been reset by a delete, |
67 | for example */ |
68 | |
69 | /** This 10-bit field is usually 0. In B-tree index pages of |
70 | ROW_FORMAT=REDUNDANT tables, this byte can contain garbage if the .ibd |
71 | file was created in MySQL 4.1.0 or if the table resides in the system |
72 | tablespace and was created before MySQL 4.1.1 or MySQL 4.0.14. |
73 | In this case, the FIL_PAGE_TYPE would be FIL_PAGE_INDEX. |
74 | |
75 | In ROW_FORMAT=COMPRESSED tables, this field is always 0, because |
76 | instant ADD COLUMN is not supported. |
77 | |
78 | In ROW_FORMAT=COMPACT and ROW_FORMAT=DYNAMIC tables, this field is |
79 | always 0, except in the root page of the clustered index after instant |
80 | ADD COLUMN. |
81 | |
82 | Instant ADD COLUMN will change FIL_PAGE_TYPE to FIL_PAGE_TYPE_INSTANT |
83 | and initialize the PAGE_INSTANT field to the original number of |
84 | fields in the clustered index (dict_index_t::n_core_fields). The most |
85 | significant bits are in the first byte, and the least significant 5 |
86 | bits are stored in the most significant 5 bits of PAGE_DIRECTION_B. |
87 | |
88 | These FIL_PAGE_TYPE_INSTANT and PAGE_INSTANT may be assigned even if |
89 | instant ADD COLUMN was not committed. Changes to these page header fields |
90 | are not undo-logged, but changes to the 'default value record' are. |
91 | If the server is killed and restarted, the page header fields could |
92 | remain set even though no 'default value record' is present. |
93 | |
94 | When the table becomes empty, the PAGE_INSTANT field and the |
95 | FIL_PAGE_TYPE can be reset and any 'default value record' be removed. */ |
96 | #define PAGE_INSTANT 12 |
97 | |
98 | /** last insert direction: PAGE_LEFT, .... |
99 | In ROW_FORMAT=REDUNDANT tables created before MySQL 4.1.1 or MySQL 4.0.14, |
100 | this byte can be garbage. */ |
101 | #define PAGE_DIRECTION_B 13 |
102 | #define PAGE_N_DIRECTION 14 /* number of consecutive inserts to the same |
103 | direction */ |
104 | #define PAGE_N_RECS 16 /* number of user records on the page */ |
105 | /** The largest DB_TRX_ID that may have modified a record on the page; |
106 | Defined only in secondary index leaf pages and in change buffer leaf pages. |
107 | Otherwise written as 0. @see PAGE_ROOT_AUTO_INC */ |
108 | #define PAGE_MAX_TRX_ID 18 |
109 | /** The AUTO_INCREMENT value (on persistent clustered index root pages). */ |
110 | #define PAGE_ROOT_AUTO_INC PAGE_MAX_TRX_ID |
111 | #define 26 /* end of private data structure of the page |
112 | header which are set in a page create */ |
113 | /*----*/ |
114 | #define PAGE_LEVEL 26 /* level of the node in an index tree; the |
115 | leaf level is the level 0. This field should |
116 | not be written to after page creation. */ |
117 | #define PAGE_INDEX_ID 28 /* index id where the page belongs. |
118 | This field should not be written to after |
119 | page creation. */ |
120 | |
121 | #define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in |
122 | a B-tree: defined only on the root page of a |
123 | B-tree, but not in the root of an ibuf tree */ |
124 | #define PAGE_BTR_IBUF_FREE_LIST PAGE_BTR_SEG_LEAF |
125 | #define PAGE_BTR_IBUF_FREE_LIST_NODE PAGE_BTR_SEG_LEAF |
126 | /* in the place of PAGE_BTR_SEG_LEAF and _TOP |
127 | there is a free list base node if the page is |
128 | the root page of an ibuf tree, and at the same |
129 | place is the free list node if the page is in |
130 | a free list */ |
131 | #define PAGE_BTR_SEG_TOP (36 + FSEG_HEADER_SIZE) |
132 | /* file segment header for the non-leaf pages |
133 | in a B-tree: defined only on the root page of |
134 | a B-tree, but not in the root of an ibuf |
135 | tree */ |
136 | /*----*/ |
137 | #define PAGE_DATA (PAGE_HEADER + 36 + 2 * FSEG_HEADER_SIZE) |
138 | /* start of data on the page */ |
139 | |
140 | #define PAGE_OLD_INFIMUM (PAGE_DATA + 1 + REC_N_OLD_EXTRA_BYTES) |
141 | /* offset of the page infimum record on an |
142 | old-style page */ |
143 | #define PAGE_OLD_SUPREMUM (PAGE_DATA + 2 + 2 * REC_N_OLD_EXTRA_BYTES + 8) |
144 | /* offset of the page supremum record on an |
145 | old-style page */ |
146 | #define PAGE_OLD_SUPREMUM_END (PAGE_OLD_SUPREMUM + 9) |
147 | /* offset of the page supremum record end on |
148 | an old-style page */ |
149 | #define PAGE_NEW_INFIMUM (PAGE_DATA + REC_N_NEW_EXTRA_BYTES) |
150 | /* offset of the page infimum record on a |
151 | new-style compact page */ |
152 | #define PAGE_NEW_SUPREMUM (PAGE_DATA + 2 * REC_N_NEW_EXTRA_BYTES + 8) |
153 | /* offset of the page supremum record on a |
154 | new-style compact page */ |
155 | #define PAGE_NEW_SUPREMUM_END (PAGE_NEW_SUPREMUM + 8) |
156 | /* offset of the page supremum record end on |
157 | a new-style compact page */ |
158 | /*-----------------------------*/ |
159 | |
160 | /* Heap numbers */ |
161 | #define PAGE_HEAP_NO_INFIMUM 0U /* page infimum */ |
162 | #define PAGE_HEAP_NO_SUPREMUM 1U /* page supremum */ |
163 | #define PAGE_HEAP_NO_USER_LOW 2U /* first user record in |
164 | creation (insertion) order, |
165 | not necessarily collation order; |
166 | this record may have been deleted */ |
167 | |
168 | /* Directions of cursor movement */ |
169 | #define PAGE_LEFT 1 |
170 | #define PAGE_RIGHT 2 |
171 | #define PAGE_SAME_REC 3 |
172 | #define PAGE_SAME_PAGE 4 |
173 | #define PAGE_NO_DIRECTION 5 |
174 | |
175 | #ifndef UNIV_INNOCHECKSUM |
176 | |
177 | /* PAGE DIRECTORY |
178 | ============== |
179 | */ |
180 | |
181 | typedef byte page_dir_slot_t; |
182 | typedef page_dir_slot_t page_dir_t; |
183 | |
184 | /* Offset of the directory start down from the page end. We call the |
185 | slot with the highest file address directory start, as it points to |
186 | the first record in the list of records. */ |
187 | #define PAGE_DIR FIL_PAGE_DATA_END |
188 | |
189 | /* We define a slot in the page directory as two bytes */ |
190 | #define PAGE_DIR_SLOT_SIZE 2 |
191 | |
192 | /* The offset of the physically lower end of the directory, counted from |
193 | page end, when the page is empty */ |
194 | #define PAGE_EMPTY_DIR_START (PAGE_DIR + 2 * PAGE_DIR_SLOT_SIZE) |
195 | |
196 | /* The maximum and minimum number of records owned by a directory slot. The |
197 | number may drop below the minimum in the first and the last slot in the |
198 | directory. */ |
199 | #define PAGE_DIR_SLOT_MAX_N_OWNED 8 |
200 | #define PAGE_DIR_SLOT_MIN_N_OWNED 4 |
201 | |
202 | extern my_bool srv_immediate_scrub_data_uncompressed; |
203 | #endif /* UNIV_INNOCHECKSUM */ |
204 | |
205 | /** Get the start of a page frame. |
206 | @param[in] ptr pointer within a page frame |
207 | @return start of the page frame */ |
208 | MY_ATTRIBUTE((const)) |
209 | inline |
210 | page_t* |
211 | page_align(const void* ptr) |
212 | { |
213 | return(static_cast<page_t*>(ut_align_down(ptr, srv_page_size))); |
214 | } |
215 | |
216 | /** Gets the byte offset within a page frame. |
217 | @param[in] ptr pointer within a page frame |
218 | @return offset from the start of the page */ |
219 | MY_ATTRIBUTE((const)) |
220 | inline |
221 | ulint |
222 | page_offset(const void* ptr) |
223 | { |
224 | return(ut_align_offset(ptr, srv_page_size)); |
225 | } |
226 | |
227 | /** Determine whether an index page is not in ROW_FORMAT=REDUNDANT. |
228 | @param[in] page index page |
229 | @return nonzero if ROW_FORMAT is one of COMPACT,DYNAMIC,COMPRESSED |
230 | @retval 0 if ROW_FORMAT=REDUNDANT */ |
231 | inline |
232 | byte |
233 | page_is_comp(const page_t* page) |
234 | { |
235 | ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN)); |
236 | return(page[PAGE_HEADER + PAGE_N_HEAP] & 0x80); |
237 | } |
238 | |
239 | /** Determine whether an index page is empty. |
240 | @param[in] page index page |
241 | @return whether the page is empty (PAGE_N_RECS = 0) */ |
242 | inline |
243 | bool |
244 | page_is_empty(const page_t* page) |
245 | { |
246 | ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN)); |
247 | return !*reinterpret_cast<const uint16_t*>(PAGE_HEADER + PAGE_N_RECS |
248 | + page); |
249 | } |
250 | |
251 | /** Determine whether an index page contains garbage. |
252 | @param[in] page index page |
253 | @return whether the page contains garbage (PAGE_GARBAGE is not 0) */ |
254 | inline |
255 | bool |
256 | page_has_garbage(const page_t* page) |
257 | { |
258 | ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN)); |
259 | return *reinterpret_cast<const uint16_t*>(PAGE_HEADER + PAGE_GARBAGE |
260 | + page); |
261 | } |
262 | |
263 | /** Determine whether an B-tree or R-tree index page is a leaf page. |
264 | @param[in] page index page |
265 | @return true if the page is a leaf (PAGE_LEVEL = 0) */ |
266 | inline |
267 | bool |
268 | page_is_leaf(const page_t* page) |
269 | { |
270 | ut_ad(!ut_align_offset(page, UNIV_ZIP_SIZE_MIN)); |
271 | return !*reinterpret_cast<const uint16_t*>(PAGE_HEADER + PAGE_LEVEL |
272 | + page); |
273 | } |
274 | |
275 | #ifndef UNIV_INNOCHECKSUM |
276 | /** Determine whether an index page record is not in ROW_FORMAT=REDUNDANT. |
277 | @param[in] rec record in an index page frame (not a copy) |
278 | @return nonzero if ROW_FORMAT is one of COMPACT,DYNAMIC,COMPRESSED |
279 | @retval 0 if ROW_FORMAT=REDUNDANT */ |
280 | inline |
281 | byte |
282 | page_rec_is_comp(const byte* rec) |
283 | { |
284 | return(page_is_comp(page_align(rec))); |
285 | } |
286 | |
287 | # ifdef UNIV_DEBUG |
288 | /** Determine if the record is the 'default row' pseudo-record |
289 | in the clustered index. |
290 | @param[in] rec leaf page record on an index page |
291 | @return whether the record is the 'default row' pseudo-record */ |
292 | inline |
293 | bool |
294 | page_rec_is_default_row(const rec_t* rec) |
295 | { |
296 | return rec_get_info_bits(rec, page_rec_is_comp(rec)) |
297 | & REC_INFO_MIN_REC_FLAG; |
298 | } |
299 | # endif /* UNIV_DEBUG */ |
300 | |
301 | /** Determine the offset of the infimum record on the page. |
302 | @param[in] page index page |
303 | @return offset of the infimum record in record list, relative from page */ |
304 | inline |
305 | unsigned |
306 | page_get_infimum_offset(const page_t* page) |
307 | { |
308 | ut_ad(!page_offset(page)); |
309 | return page_is_comp(page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM; |
310 | } |
311 | |
312 | /** Determine the offset of the supremum record on the page. |
313 | @param[in] page index page |
314 | @return offset of the supremum record in record list, relative from page */ |
315 | inline |
316 | unsigned |
317 | page_get_supremum_offset(const page_t* page) |
318 | { |
319 | ut_ad(!page_offset(page)); |
320 | return page_is_comp(page) ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM; |
321 | } |
322 | |
323 | /** Determine whether an index page record is a user record. |
324 | @param[in] offset record offset in the page |
325 | @retval true if a user record |
326 | @retval false if the infimum or supremum pseudo-record */ |
327 | inline |
328 | bool |
329 | page_rec_is_user_rec_low(ulint offset) |
330 | { |
331 | compile_time_assert(PAGE_OLD_INFIMUM >= PAGE_NEW_INFIMUM); |
332 | compile_time_assert(PAGE_OLD_SUPREMUM >= PAGE_NEW_SUPREMUM); |
333 | compile_time_assert(PAGE_NEW_INFIMUM < PAGE_OLD_SUPREMUM); |
334 | compile_time_assert(PAGE_OLD_INFIMUM < PAGE_NEW_SUPREMUM); |
335 | compile_time_assert(PAGE_NEW_SUPREMUM < PAGE_OLD_SUPREMUM_END); |
336 | compile_time_assert(PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM_END); |
337 | ut_ad(offset >= PAGE_NEW_INFIMUM); |
338 | ut_ad(offset <= srv_page_size - PAGE_EMPTY_DIR_START); |
339 | |
340 | return(offset != PAGE_NEW_SUPREMUM |
341 | && offset != PAGE_NEW_INFIMUM |
342 | && offset != PAGE_OLD_INFIMUM |
343 | && offset != PAGE_OLD_SUPREMUM); |
344 | } |
345 | |
346 | /** Determine if a record is the supremum record on an index page. |
347 | @param[in] offset record offset in an index page |
348 | @return true if the supremum record */ |
349 | inline |
350 | bool |
351 | page_rec_is_supremum_low(ulint offset) |
352 | { |
353 | ut_ad(offset >= PAGE_NEW_INFIMUM); |
354 | ut_ad(offset <= srv_page_size - PAGE_EMPTY_DIR_START); |
355 | return(offset == PAGE_NEW_SUPREMUM || offset == PAGE_OLD_SUPREMUM); |
356 | } |
357 | |
358 | /** Determine if a record is the infimum record on an index page. |
359 | @param[in] offset record offset in an index page |
360 | @return true if the infimum record */ |
361 | inline |
362 | bool |
363 | page_rec_is_infimum_low(ulint offset) |
364 | { |
365 | ut_ad(offset >= PAGE_NEW_INFIMUM); |
366 | ut_ad(offset <= srv_page_size - PAGE_EMPTY_DIR_START); |
367 | return(offset == PAGE_NEW_INFIMUM || offset == PAGE_OLD_INFIMUM); |
368 | } |
369 | |
370 | /** Determine whether an B-tree or R-tree index record is in a leaf page. |
371 | @param[in] rec index record in an index page |
372 | @return true if the record is in a leaf page */ |
373 | inline |
374 | bool |
375 | page_rec_is_leaf(const page_t* rec) |
376 | { |
377 | const page_t* page = page_align(rec); |
378 | ut_ad(ulint(rec - page) >= page_get_infimum_offset(page)); |
379 | bool leaf = page_is_leaf(page); |
380 | ut_ad(!page_rec_is_comp(rec) |
381 | || !page_rec_is_user_rec_low(ulint(rec - page)) |
382 | || leaf == !rec_get_node_ptr_flag(rec)); |
383 | return leaf; |
384 | } |
385 | |
386 | /** Determine whether an index page record is a user record. |
387 | @param[in] rec record in an index page |
388 | @return true if a user record */ |
389 | inline |
390 | bool |
391 | page_rec_is_user_rec(const rec_t* rec); |
392 | |
393 | /** Determine whether an index page record is the supremum record. |
394 | @param[in] rec record in an index page |
395 | @return true if the supremum record */ |
396 | inline |
397 | bool |
398 | page_rec_is_supremum(const rec_t* rec); |
399 | |
400 | /** Determine whether an index page record is the infimum record. |
401 | @param[in] rec record in an index page |
402 | @return true if the infimum record */ |
403 | inline |
404 | bool |
405 | page_rec_is_infimum(const rec_t* rec); |
406 | |
407 | /*************************************************************//** |
408 | Returns the max trx id field value. */ |
409 | UNIV_INLINE |
410 | trx_id_t |
411 | page_get_max_trx_id( |
412 | /*================*/ |
413 | const page_t* page); /*!< in: page */ |
414 | /*************************************************************//** |
415 | Sets the max trx id field value. */ |
416 | void |
417 | page_set_max_trx_id( |
418 | /*================*/ |
419 | buf_block_t* block, /*!< in/out: page */ |
420 | page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ |
421 | trx_id_t trx_id, /*!< in: transaction id */ |
422 | mtr_t* mtr); /*!< in/out: mini-transaction, or NULL */ |
423 | /*************************************************************//** |
424 | Sets the max trx id field value if trx_id is bigger than the previous |
425 | value. */ |
426 | UNIV_INLINE |
427 | void |
428 | page_update_max_trx_id( |
429 | /*===================*/ |
430 | buf_block_t* block, /*!< in/out: page */ |
431 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
432 | uncompressed part will be updated, or NULL */ |
433 | trx_id_t trx_id, /*!< in: transaction id */ |
434 | mtr_t* mtr); /*!< in/out: mini-transaction */ |
435 | |
436 | /** Persist the AUTO_INCREMENT value on a clustered index root page. |
437 | @param[in,out] block clustered index root page |
438 | @param[in] index clustered index |
439 | @param[in] autoinc next available AUTO_INCREMENT value |
440 | @param[in,out] mtr mini-transaction |
441 | @param[in] reset whether to reset the AUTO_INCREMENT |
442 | to a possibly smaller value than currently |
443 | exists in the page */ |
444 | void |
445 | page_set_autoinc( |
446 | buf_block_t* block, |
447 | const dict_index_t* index MY_ATTRIBUTE((unused)), |
448 | ib_uint64_t autoinc, |
449 | mtr_t* mtr, |
450 | bool reset) |
451 | MY_ATTRIBUTE((nonnull)); |
452 | |
453 | /** Read the AUTO_INCREMENT value from a clustered index root page. |
454 | @param[in] page clustered index root page |
455 | @return the persisted AUTO_INCREMENT value */ |
456 | MY_ATTRIBUTE((nonnull, warn_unused_result)) |
457 | UNIV_INLINE |
458 | ib_uint64_t |
459 | page_get_autoinc(const page_t* page); |
460 | |
461 | /*************************************************************//** |
462 | Returns the RTREE SPLIT SEQUENCE NUMBER (FIL_RTREE_SPLIT_SEQ_NUM). |
463 | @return SPLIT SEQUENCE NUMBER */ |
464 | UNIV_INLINE |
465 | node_seq_t |
466 | page_get_ssn_id( |
467 | /*============*/ |
468 | const page_t* page); /*!< in: page */ |
469 | /*************************************************************//** |
470 | Sets the RTREE SPLIT SEQUENCE NUMBER field value */ |
471 | UNIV_INLINE |
472 | void |
473 | page_set_ssn_id( |
474 | /*============*/ |
475 | buf_block_t* block, /*!< in/out: page */ |
476 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
477 | uncompressed part will be updated, or NULL */ |
478 | node_seq_t ssn_id, /*!< in: split sequence id */ |
479 | mtr_t* mtr); /*!< in/out: mini-transaction */ |
480 | |
481 | #endif /* !UNIV_INNOCHECKSUM */ |
482 | /*************************************************************//** |
483 | Reads the given header field. */ |
484 | UNIV_INLINE |
485 | uint16_t |
486 | ( |
487 | /*==================*/ |
488 | const page_t* page, /*!< in: page */ |
489 | ulint field); /*!< in: PAGE_N_DIR_SLOTS, ... */ |
490 | |
491 | #ifndef UNIV_INNOCHECKSUM |
492 | /*************************************************************//** |
493 | Sets the given header field. */ |
494 | UNIV_INLINE |
495 | void |
496 | page_header_set_field( |
497 | /*==================*/ |
498 | page_t* page, /*!< in/out: page */ |
499 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
500 | uncompressed part will be updated, or NULL */ |
501 | ulint field, /*!< in: PAGE_N_DIR_SLOTS, ... */ |
502 | ulint val); /*!< in: value */ |
503 | /*************************************************************//** |
504 | Returns the offset stored in the given header field. |
505 | @return offset from the start of the page, or 0 */ |
506 | UNIV_INLINE |
507 | uint16_t |
508 | page_header_get_offs( |
509 | /*=================*/ |
510 | const page_t* page, /*!< in: page */ |
511 | ulint field) /*!< in: PAGE_FREE, ... */ |
512 | MY_ATTRIBUTE((warn_unused_result)); |
513 | |
514 | /*************************************************************//** |
515 | Returns the pointer stored in the given header field, or NULL. */ |
516 | #define page_header_get_ptr(page, field) \ |
517 | (page_header_get_offs(page, field) \ |
518 | ? page + page_header_get_offs(page, field) : NULL) |
519 | /*************************************************************//** |
520 | Sets the pointer stored in the given header field. */ |
521 | UNIV_INLINE |
522 | void |
523 | page_header_set_ptr( |
524 | /*================*/ |
525 | page_t* page, /*!< in/out: page */ |
526 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
527 | uncompressed part will be updated, or NULL */ |
528 | ulint field, /*!< in/out: PAGE_FREE, ... */ |
529 | const byte* ptr); /*!< in: pointer or NULL*/ |
530 | |
531 | /*************************************************************//** |
532 | Resets the last insert info field in the page header. Writes to mlog |
533 | about this operation. */ |
534 | UNIV_INLINE |
535 | void |
536 | page_header_reset_last_insert( |
537 | /*==========================*/ |
538 | page_t* page, /*!< in: page */ |
539 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
540 | uncompressed part will be updated, or NULL */ |
541 | mtr_t* mtr); /*!< in: mtr */ |
542 | #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page)) |
543 | #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page)) |
544 | |
545 | /************************************************************//** |
546 | Returns the nth record of the record list. |
547 | This is the inverse function of page_rec_get_n_recs_before(). |
548 | @return nth record */ |
549 | const rec_t* |
550 | page_rec_get_nth_const( |
551 | /*===================*/ |
552 | const page_t* page, /*!< in: page */ |
553 | ulint nth) /*!< in: nth record */ |
554 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
555 | /************************************************************//** |
556 | Returns the nth record of the record list. |
557 | This is the inverse function of page_rec_get_n_recs_before(). |
558 | @return nth record */ |
559 | UNIV_INLINE |
560 | rec_t* |
561 | page_rec_get_nth( |
562 | /*=============*/ |
563 | page_t* page, /*< in: page */ |
564 | ulint nth) /*!< in: nth record */ |
565 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
566 | |
567 | /************************************************************//** |
568 | Returns the middle record of the records on the page. If there is an |
569 | even number of records in the list, returns the first record of the |
570 | upper half-list. |
571 | @return middle record */ |
572 | UNIV_INLINE |
573 | rec_t* |
574 | page_get_middle_rec( |
575 | /*================*/ |
576 | page_t* page) /*!< in: page */ |
577 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
578 | /*************************************************************//** |
579 | Gets the page number. |
580 | @return page number */ |
581 | UNIV_INLINE |
582 | ulint |
583 | page_get_page_no( |
584 | /*=============*/ |
585 | const page_t* page); /*!< in: page */ |
586 | |
587 | /*************************************************************//** |
588 | Gets the tablespace identifier. |
589 | @return space id */ |
590 | UNIV_INLINE |
591 | ulint |
592 | page_get_space_id( |
593 | /*==============*/ |
594 | const page_t* page); /*!< in: page */ |
595 | |
596 | /*************************************************************//** |
597 | Gets the number of user records on page (the infimum and supremum records |
598 | are not user records). |
599 | @return number of user records */ |
600 | UNIV_INLINE |
601 | uint16_t |
602 | page_get_n_recs( |
603 | /*============*/ |
604 | const page_t* page); /*!< in: index page */ |
605 | |
606 | /***************************************************************//** |
607 | Returns the number of records before the given record in chain. |
608 | The number includes infimum and supremum records. |
609 | This is the inverse function of page_rec_get_nth(). |
610 | @return number of records */ |
611 | ulint |
612 | page_rec_get_n_recs_before( |
613 | /*=======================*/ |
614 | const rec_t* rec); /*!< in: the physical record */ |
615 | /*************************************************************//** |
616 | Gets the number of records in the heap. |
617 | @return number of user records */ |
618 | UNIV_INLINE |
619 | uint16_t |
620 | page_dir_get_n_heap( |
621 | /*================*/ |
622 | const page_t* page); /*!< in: index page */ |
623 | /*************************************************************//** |
624 | Sets the number of records in the heap. */ |
625 | UNIV_INLINE |
626 | void |
627 | page_dir_set_n_heap( |
628 | /*================*/ |
629 | page_t* page, /*!< in/out: index page */ |
630 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
631 | uncompressed part will be updated, or NULL. |
632 | Note that the size of the dense page directory |
633 | in the compressed page trailer is |
634 | n_heap * PAGE_ZIP_DIR_SLOT_SIZE. */ |
635 | ulint n_heap);/*!< in: number of records */ |
636 | /*************************************************************//** |
637 | Gets the number of dir slots in directory. |
638 | @return number of slots */ |
639 | UNIV_INLINE |
640 | uint16_t |
641 | page_dir_get_n_slots( |
642 | /*=================*/ |
643 | const page_t* page); /*!< in: index page */ |
644 | /*************************************************************//** |
645 | Sets the number of dir slots in directory. */ |
646 | UNIV_INLINE |
647 | void |
648 | page_dir_set_n_slots( |
649 | /*=================*/ |
650 | page_t* page, /*!< in/out: page */ |
651 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
652 | uncompressed part will be updated, or NULL */ |
653 | ulint n_slots);/*!< in: number of slots */ |
654 | #ifdef UNIV_DEBUG |
655 | /*************************************************************//** |
656 | Gets pointer to nth directory slot. |
657 | @return pointer to dir slot */ |
658 | UNIV_INLINE |
659 | page_dir_slot_t* |
660 | page_dir_get_nth_slot( |
661 | /*==================*/ |
662 | const page_t* page, /*!< in: index page */ |
663 | ulint n); /*!< in: position */ |
664 | #else /* UNIV_DEBUG */ |
665 | # define page_dir_get_nth_slot(page, n) \ |
666 | ((page) + (srv_page_size - PAGE_DIR \ |
667 | - (n + 1) * PAGE_DIR_SLOT_SIZE)) |
668 | #endif /* UNIV_DEBUG */ |
669 | /**************************************************************//** |
670 | Used to check the consistency of a record on a page. |
671 | @return TRUE if succeed */ |
672 | UNIV_INLINE |
673 | ibool |
674 | page_rec_check( |
675 | /*===========*/ |
676 | const rec_t* rec); /*!< in: record */ |
677 | /***************************************************************//** |
678 | Gets the record pointed to by a directory slot. |
679 | @return pointer to record */ |
680 | UNIV_INLINE |
681 | const rec_t* |
682 | page_dir_slot_get_rec( |
683 | /*==================*/ |
684 | const page_dir_slot_t* slot); /*!< in: directory slot */ |
685 | /***************************************************************//** |
686 | This is used to set the record offset in a directory slot. */ |
687 | UNIV_INLINE |
688 | void |
689 | page_dir_slot_set_rec( |
690 | /*==================*/ |
691 | page_dir_slot_t* slot, /*!< in: directory slot */ |
692 | rec_t* rec); /*!< in: record on the page */ |
693 | /***************************************************************//** |
694 | Gets the number of records owned by a directory slot. |
695 | @return number of records */ |
696 | UNIV_INLINE |
697 | ulint |
698 | page_dir_slot_get_n_owned( |
699 | /*======================*/ |
700 | const page_dir_slot_t* slot); /*!< in: page directory slot */ |
701 | /***************************************************************//** |
702 | This is used to set the owned records field of a directory slot. */ |
703 | UNIV_INLINE |
704 | void |
705 | page_dir_slot_set_n_owned( |
706 | /*======================*/ |
707 | page_dir_slot_t*slot, /*!< in/out: directory slot */ |
708 | page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ |
709 | ulint n); /*!< in: number of records owned by the slot */ |
710 | /************************************************************//** |
711 | Calculates the space reserved for directory slots of a given |
712 | number of records. The exact value is a fraction number |
713 | n * PAGE_DIR_SLOT_SIZE / PAGE_DIR_SLOT_MIN_N_OWNED, and it is |
714 | rounded upwards to an integer. */ |
715 | UNIV_INLINE |
716 | ulint |
717 | page_dir_calc_reserved_space( |
718 | /*=========================*/ |
719 | ulint n_recs); /*!< in: number of records */ |
720 | /***************************************************************//** |
721 | Looks for the directory slot which owns the given record. |
722 | @return the directory slot number */ |
723 | ulint |
724 | page_dir_find_owner_slot( |
725 | /*=====================*/ |
726 | const rec_t* rec); /*!< in: the physical record */ |
727 | |
728 | /***************************************************************//** |
729 | Returns the heap number of a record. |
730 | @return heap number */ |
731 | UNIV_INLINE |
732 | ulint |
733 | page_rec_get_heap_no( |
734 | /*=================*/ |
735 | const rec_t* rec); /*!< in: the physical record */ |
736 | /** Determine whether a page has any siblings. |
737 | @param[in] page page frame |
738 | @return true if the page has any siblings */ |
739 | inline |
740 | bool |
741 | page_has_siblings(const page_t* page) |
742 | { |
743 | compile_time_assert(!(FIL_PAGE_PREV % 8)); |
744 | compile_time_assert(FIL_PAGE_NEXT == FIL_PAGE_PREV + 4); |
745 | compile_time_assert(FIL_NULL == 0xffffffff); |
746 | return *reinterpret_cast<const uint64_t*>(page + FIL_PAGE_PREV) |
747 | != ~uint64_t(0); |
748 | } |
749 | |
750 | /** Determine whether a page is an index root page. |
751 | @param[in] page page frame |
752 | @return true if the page is a root page of an index */ |
753 | inline |
754 | bool |
755 | page_is_root(const page_t* page) |
756 | { |
757 | return fil_page_index_page_check(page) && !page_has_siblings(page); |
758 | } |
759 | |
760 | /** Determine whether a page has a predecessor. |
761 | @param[in] page page frame |
762 | @return true if the page has a predecessor */ |
763 | inline |
764 | bool |
765 | page_has_prev(const page_t* page) |
766 | { |
767 | return *reinterpret_cast<const uint32_t*>(page + FIL_PAGE_PREV) |
768 | != FIL_NULL; |
769 | } |
770 | |
771 | /** Determine whether a page has a successor. |
772 | @param[in] page page frame |
773 | @return true if the page has a successor */ |
774 | inline |
775 | bool |
776 | page_has_next(const page_t* page) |
777 | { |
778 | return *reinterpret_cast<const uint32_t*>(page + FIL_PAGE_NEXT) |
779 | != FIL_NULL; |
780 | } |
781 | |
782 | /************************************************************//** |
783 | Gets the pointer to the next record on the page. |
784 | @return pointer to next record */ |
785 | UNIV_INLINE |
786 | const rec_t* |
787 | page_rec_get_next_low( |
788 | /*==================*/ |
789 | const rec_t* rec, /*!< in: pointer to record */ |
790 | ulint comp); /*!< in: nonzero=compact page layout */ |
791 | /************************************************************//** |
792 | Gets the pointer to the next record on the page. |
793 | @return pointer to next record */ |
794 | UNIV_INLINE |
795 | rec_t* |
796 | page_rec_get_next( |
797 | /*==============*/ |
798 | rec_t* rec); /*!< in: pointer to record */ |
799 | /************************************************************//** |
800 | Gets the pointer to the next record on the page. |
801 | @return pointer to next record */ |
802 | UNIV_INLINE |
803 | const rec_t* |
804 | page_rec_get_next_const( |
805 | /*====================*/ |
806 | const rec_t* rec); /*!< in: pointer to record */ |
807 | /************************************************************//** |
808 | Gets the pointer to the next non delete-marked record on the page. |
809 | If all subsequent records are delete-marked, then this function |
810 | will return the supremum record. |
811 | @return pointer to next non delete-marked record or pointer to supremum */ |
812 | UNIV_INLINE |
813 | const rec_t* |
814 | page_rec_get_next_non_del_marked( |
815 | /*=============================*/ |
816 | const rec_t* rec); /*!< in: pointer to record */ |
817 | /************************************************************//** |
818 | Sets the pointer to the next record on the page. */ |
819 | UNIV_INLINE |
820 | void |
821 | page_rec_set_next( |
822 | /*==============*/ |
823 | rec_t* rec, /*!< in: pointer to record, |
824 | must not be page supremum */ |
825 | const rec_t* next); /*!< in: pointer to next record, |
826 | must not be page infimum */ |
827 | /************************************************************//** |
828 | Gets the pointer to the previous record. |
829 | @return pointer to previous record */ |
830 | UNIV_INLINE |
831 | const rec_t* |
832 | page_rec_get_prev_const( |
833 | /*====================*/ |
834 | const rec_t* rec); /*!< in: pointer to record, must not be page |
835 | infimum */ |
836 | /************************************************************//** |
837 | Gets the pointer to the previous record. |
838 | @return pointer to previous record */ |
839 | UNIV_INLINE |
840 | rec_t* |
841 | page_rec_get_prev( |
842 | /*==============*/ |
843 | rec_t* rec); /*!< in: pointer to record, |
844 | must not be page infimum */ |
845 | |
846 | /************************************************************//** |
847 | true if the record is the first user record on a page. |
848 | @return true if the first user record */ |
849 | UNIV_INLINE |
850 | bool |
851 | page_rec_is_first( |
852 | /*==============*/ |
853 | const rec_t* rec, /*!< in: record */ |
854 | const page_t* page) /*!< in: page */ |
855 | MY_ATTRIBUTE((warn_unused_result)); |
856 | |
857 | /************************************************************//** |
858 | true if the record is the second user record on a page. |
859 | @return true if the second user record */ |
860 | UNIV_INLINE |
861 | bool |
862 | page_rec_is_second( |
863 | /*===============*/ |
864 | const rec_t* rec, /*!< in: record */ |
865 | const page_t* page) /*!< in: page */ |
866 | MY_ATTRIBUTE((warn_unused_result)); |
867 | |
868 | /************************************************************//** |
869 | true if the record is the last user record on a page. |
870 | @return true if the last user record */ |
871 | UNIV_INLINE |
872 | bool |
873 | page_rec_is_last( |
874 | /*=============*/ |
875 | const rec_t* rec, /*!< in: record */ |
876 | const page_t* page) /*!< in: page */ |
877 | MY_ATTRIBUTE((warn_unused_result)); |
878 | |
879 | /************************************************************//** |
880 | true if the record is the second last user record on a page. |
881 | @return true if the second last user record */ |
882 | UNIV_INLINE |
883 | bool |
884 | page_rec_is_second_last( |
885 | /*====================*/ |
886 | const rec_t* rec, /*!< in: record */ |
887 | const page_t* page) /*!< in: page */ |
888 | MY_ATTRIBUTE((warn_unused_result)); |
889 | |
890 | /***************************************************************//** |
891 | Looks for the record which owns the given record. |
892 | @return the owner record */ |
893 | UNIV_INLINE |
894 | rec_t* |
895 | page_rec_find_owner_rec( |
896 | /*====================*/ |
897 | rec_t* rec); /*!< in: the physical record */ |
898 | |
899 | /***********************************************************************//** |
900 | Write a 32-bit field in a data dictionary record. */ |
901 | UNIV_INLINE |
902 | void |
903 | page_rec_write_field( |
904 | /*=================*/ |
905 | rec_t* rec, /*!< in/out: record to update */ |
906 | ulint i, /*!< in: index of the field to update */ |
907 | ulint val, /*!< in: value to write */ |
908 | mtr_t* mtr) /*!< in/out: mini-transaction */ |
909 | MY_ATTRIBUTE((nonnull)); |
910 | /************************************************************//** |
911 | Returns the maximum combined size of records which can be inserted on top |
912 | of record heap. |
913 | @return maximum combined size for inserted records */ |
914 | UNIV_INLINE |
915 | ulint |
916 | page_get_max_insert_size( |
917 | /*=====================*/ |
918 | const page_t* page, /*!< in: index page */ |
919 | ulint n_recs);/*!< in: number of records */ |
920 | /************************************************************//** |
921 | Returns the maximum combined size of records which can be inserted on top |
922 | of record heap if page is first reorganized. |
923 | @return maximum combined size for inserted records */ |
924 | UNIV_INLINE |
925 | ulint |
926 | page_get_max_insert_size_after_reorganize( |
927 | /*======================================*/ |
928 | const page_t* page, /*!< in: index page */ |
929 | ulint n_recs);/*!< in: number of records */ |
930 | /*************************************************************//** |
931 | Calculates free space if a page is emptied. |
932 | @return free space */ |
933 | UNIV_INLINE |
934 | ulint |
935 | page_get_free_space_of_empty( |
936 | /*=========================*/ |
937 | ulint comp) /*!< in: nonzero=compact page format */ |
938 | MY_ATTRIBUTE((const)); |
939 | /**********************************************************//** |
940 | Returns the base extra size of a physical record. This is the |
941 | size of the fixed header, independent of the record size. |
942 | @return REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */ |
943 | UNIV_INLINE |
944 | ulint |
945 | page_rec_get_base_extra_size( |
946 | /*=========================*/ |
947 | const rec_t* rec); /*!< in: physical record */ |
948 | /************************************************************//** |
949 | Returns the sum of the sizes of the records in the record list |
950 | excluding the infimum and supremum records. |
951 | @return data in bytes */ |
952 | UNIV_INLINE |
953 | uint16_t |
954 | page_get_data_size( |
955 | /*===============*/ |
956 | const page_t* page); /*!< in: index page */ |
957 | /************************************************************//** |
958 | Allocates a block of memory from the head of the free list |
959 | of an index page. */ |
960 | UNIV_INLINE |
961 | void |
962 | page_mem_alloc_free( |
963 | /*================*/ |
964 | page_t* page, /*!< in/out: index page */ |
965 | page_zip_des_t* page_zip,/*!< in/out: compressed page with enough |
966 | space available for inserting the record, |
967 | or NULL */ |
968 | rec_t* next_rec,/*!< in: pointer to the new head of the |
969 | free record list */ |
970 | ulint need); /*!< in: number of bytes allocated */ |
971 | /************************************************************//** |
972 | Allocates a block of memory from the heap of an index page. |
973 | @return pointer to start of allocated buffer, or NULL if allocation fails */ |
974 | byte* |
975 | page_mem_alloc_heap( |
976 | /*================*/ |
977 | page_t* page, /*!< in/out: index page */ |
978 | page_zip_des_t* page_zip,/*!< in/out: compressed page with enough |
979 | space available for inserting the record, |
980 | or NULL */ |
981 | ulint need, /*!< in: total number of bytes needed */ |
982 | ulint* heap_no);/*!< out: this contains the heap number |
983 | of the allocated record |
984 | if allocation succeeds */ |
985 | /************************************************************//** |
986 | Puts a record to free list. */ |
987 | UNIV_INLINE |
988 | void |
989 | page_mem_free( |
990 | /*==========*/ |
991 | page_t* page, /*!< in/out: index page */ |
992 | page_zip_des_t* page_zip,/*!< in/out: compressed page, |
993 | or NULL */ |
994 | rec_t* rec, /*!< in: pointer to the (origin of) |
995 | record */ |
996 | const dict_index_t* index, /*!< in: index of rec */ |
997 | const ulint* offsets);/*!< in: array returned by |
998 | rec_get_offsets() */ |
999 | |
1000 | /** Read the PAGE_DIRECTION field from a byte. |
1001 | @param[in] ptr pointer to PAGE_DIRECTION_B |
1002 | @return the value of the PAGE_DIRECTION field */ |
1003 | inline |
1004 | byte |
1005 | page_ptr_get_direction(const byte* ptr); |
1006 | |
1007 | /** Set the PAGE_DIRECTION field. |
1008 | @param[in] ptr pointer to PAGE_DIRECTION_B |
1009 | @param[in] dir the value of the PAGE_DIRECTION field */ |
1010 | inline |
1011 | void |
1012 | page_ptr_set_direction(byte* ptr, byte dir); |
1013 | |
1014 | /** Read the PAGE_DIRECTION field. |
1015 | @param[in] page index page |
1016 | @return the value of the PAGE_DIRECTION field */ |
1017 | inline |
1018 | byte |
1019 | page_get_direction(const page_t* page) |
1020 | { |
1021 | return page_ptr_get_direction(PAGE_HEADER + PAGE_DIRECTION_B + page); |
1022 | } |
1023 | |
1024 | /** Read the PAGE_INSTANT field. |
1025 | @param[in] page index page |
1026 | @return the value of the PAGE_INSTANT field */ |
1027 | inline |
1028 | uint16_t |
1029 | page_get_instant(const page_t* page); |
1030 | /** Assign the PAGE_INSTANT field. |
1031 | @param[in,out] page clustered index root page |
1032 | @param[in] n original number of clustered index fields |
1033 | @param[in,out] mtr mini-transaction */ |
1034 | inline |
1035 | void |
1036 | page_set_instant(page_t* page, unsigned n, mtr_t* mtr); |
1037 | |
1038 | /**********************************************************//** |
1039 | Create an uncompressed B-tree index page. |
1040 | @return pointer to the page */ |
1041 | page_t* |
1042 | page_create( |
1043 | /*========*/ |
1044 | buf_block_t* block, /*!< in: a buffer block where the |
1045 | page is created */ |
1046 | mtr_t* mtr, /*!< in: mini-transaction handle */ |
1047 | ulint comp, /*!< in: nonzero=compact page format */ |
1048 | bool is_rtree); /*!< in: if creating R-tree page */ |
1049 | /**********************************************************//** |
1050 | Create a compressed B-tree index page. |
1051 | @return pointer to the page */ |
1052 | page_t* |
1053 | page_create_zip( |
1054 | /*============*/ |
1055 | buf_block_t* block, /*!< in/out: a buffer frame |
1056 | where the page is created */ |
1057 | dict_index_t* index, /*!< in: the index of the |
1058 | page, or NULL when applying |
1059 | TRUNCATE log |
1060 | record during recovery */ |
1061 | ulint level, /*!< in: the B-tree level of |
1062 | the page */ |
1063 | trx_id_t max_trx_id, /*!< in: PAGE_MAX_TRX_ID */ |
1064 | const redo_page_compress_t* page_comp_info, |
1065 | /*!< in: used for applying |
1066 | TRUNCATE log |
1067 | record during recovery */ |
1068 | mtr_t* mtr); /*!< in/out: mini-transaction |
1069 | handle */ |
1070 | /**********************************************************//** |
1071 | Empty a previously created B-tree index page. */ |
1072 | void |
1073 | page_create_empty( |
1074 | /*==============*/ |
1075 | buf_block_t* block, /*!< in/out: B-tree block */ |
1076 | dict_index_t* index, /*!< in: the index of the page */ |
1077 | mtr_t* mtr) /*!< in/out: mini-transaction */ |
1078 | MY_ATTRIBUTE((nonnull(1,2))); |
1079 | /*************************************************************//** |
1080 | Differs from page_copy_rec_list_end, because this function does not |
1081 | touch the lock table and max trx id on page or compress the page. |
1082 | |
1083 | IMPORTANT: The caller will have to update IBUF_BITMAP_FREE |
1084 | if new_block is a compressed leaf page in a secondary index. |
1085 | This has to be done either within the same mini-transaction, |
1086 | or by invoking ibuf_reset_free_bits() before mtr_commit(). */ |
1087 | void |
1088 | page_copy_rec_list_end_no_locks( |
1089 | /*============================*/ |
1090 | buf_block_t* new_block, /*!< in: index page to copy to */ |
1091 | buf_block_t* block, /*!< in: index page of rec */ |
1092 | rec_t* rec, /*!< in: record on page */ |
1093 | dict_index_t* index, /*!< in: record descriptor */ |
1094 | mtr_t* mtr); /*!< in: mtr */ |
1095 | /*************************************************************//** |
1096 | Copies records from page to new_page, from the given record onward, |
1097 | including that record. Infimum and supremum records are not copied. |
1098 | The records are copied to the start of the record list on new_page. |
1099 | |
1100 | IMPORTANT: The caller will have to update IBUF_BITMAP_FREE |
1101 | if new_block is a compressed leaf page in a secondary index. |
1102 | This has to be done either within the same mini-transaction, |
1103 | or by invoking ibuf_reset_free_bits() before mtr_commit(). |
1104 | |
1105 | @return pointer to the original successor of the infimum record on |
1106 | new_page, or NULL on zip overflow (new_block will be decompressed) */ |
1107 | rec_t* |
1108 | page_copy_rec_list_end( |
1109 | /*===================*/ |
1110 | buf_block_t* new_block, /*!< in/out: index page to copy to */ |
1111 | buf_block_t* block, /*!< in: index page containing rec */ |
1112 | rec_t* rec, /*!< in: record on page */ |
1113 | dict_index_t* index, /*!< in: record descriptor */ |
1114 | mtr_t* mtr) /*!< in: mtr */ |
1115 | MY_ATTRIBUTE((nonnull)); |
1116 | /*************************************************************//** |
1117 | Copies records from page to new_page, up to the given record, NOT |
1118 | including that record. Infimum and supremum records are not copied. |
1119 | The records are copied to the end of the record list on new_page. |
1120 | |
1121 | IMPORTANT: The caller will have to update IBUF_BITMAP_FREE |
1122 | if new_block is a compressed leaf page in a secondary index. |
1123 | This has to be done either within the same mini-transaction, |
1124 | or by invoking ibuf_reset_free_bits() before mtr_commit(). |
1125 | |
1126 | @return pointer to the original predecessor of the supremum record on |
1127 | new_page, or NULL on zip overflow (new_block will be decompressed) */ |
1128 | rec_t* |
1129 | page_copy_rec_list_start( |
1130 | /*=====================*/ |
1131 | buf_block_t* new_block, /*!< in/out: index page to copy to */ |
1132 | buf_block_t* block, /*!< in: index page containing rec */ |
1133 | rec_t* rec, /*!< in: record on page */ |
1134 | dict_index_t* index, /*!< in: record descriptor */ |
1135 | mtr_t* mtr) /*!< in: mtr */ |
1136 | MY_ATTRIBUTE((nonnull)); |
1137 | /*************************************************************//** |
1138 | Deletes records from a page from a given record onward, including that record. |
1139 | The infimum and supremum records are not deleted. */ |
1140 | void |
1141 | page_delete_rec_list_end( |
1142 | /*=====================*/ |
1143 | rec_t* rec, /*!< in: pointer to record on page */ |
1144 | buf_block_t* block, /*!< in: buffer block of the page */ |
1145 | dict_index_t* index, /*!< in: record descriptor */ |
1146 | ulint n_recs, /*!< in: number of records to delete, |
1147 | or ULINT_UNDEFINED if not known */ |
1148 | ulint size, /*!< in: the sum of the sizes of the |
1149 | records in the end of the chain to |
1150 | delete, or ULINT_UNDEFINED if not known */ |
1151 | mtr_t* mtr) /*!< in: mtr */ |
1152 | MY_ATTRIBUTE((nonnull)); |
1153 | /*************************************************************//** |
1154 | Deletes records from page, up to the given record, NOT including |
1155 | that record. Infimum and supremum records are not deleted. */ |
1156 | void |
1157 | page_delete_rec_list_start( |
1158 | /*=======================*/ |
1159 | rec_t* rec, /*!< in: record on page */ |
1160 | buf_block_t* block, /*!< in: buffer block of the page */ |
1161 | dict_index_t* index, /*!< in: record descriptor */ |
1162 | mtr_t* mtr) /*!< in: mtr */ |
1163 | MY_ATTRIBUTE((nonnull)); |
1164 | /*************************************************************//** |
1165 | Moves record list end to another page. Moved records include |
1166 | split_rec. |
1167 | |
1168 | IMPORTANT: The caller will have to update IBUF_BITMAP_FREE |
1169 | if new_block is a compressed leaf page in a secondary index. |
1170 | This has to be done either within the same mini-transaction, |
1171 | or by invoking ibuf_reset_free_bits() before mtr_commit(). |
1172 | |
1173 | @return TRUE on success; FALSE on compression failure (new_block will |
1174 | be decompressed) */ |
1175 | ibool |
1176 | page_move_rec_list_end( |
1177 | /*===================*/ |
1178 | buf_block_t* new_block, /*!< in/out: index page where to move */ |
1179 | buf_block_t* block, /*!< in: index page from where to move */ |
1180 | rec_t* split_rec, /*!< in: first record to move */ |
1181 | dict_index_t* index, /*!< in: record descriptor */ |
1182 | mtr_t* mtr) /*!< in: mtr */ |
1183 | MY_ATTRIBUTE((nonnull(1, 2, 4, 5))); |
1184 | /*************************************************************//** |
1185 | Moves record list start to another page. Moved records do not include |
1186 | split_rec. |
1187 | |
1188 | IMPORTANT: The caller will have to update IBUF_BITMAP_FREE |
1189 | if new_block is a compressed leaf page in a secondary index. |
1190 | This has to be done either within the same mini-transaction, |
1191 | or by invoking ibuf_reset_free_bits() before mtr_commit(). |
1192 | |
1193 | @return TRUE on success; FALSE on compression failure */ |
1194 | ibool |
1195 | page_move_rec_list_start( |
1196 | /*=====================*/ |
1197 | buf_block_t* new_block, /*!< in/out: index page where to move */ |
1198 | buf_block_t* block, /*!< in/out: page containing split_rec */ |
1199 | rec_t* split_rec, /*!< in: first record not to move */ |
1200 | dict_index_t* index, /*!< in: record descriptor */ |
1201 | mtr_t* mtr) /*!< in: mtr */ |
1202 | MY_ATTRIBUTE((nonnull(1, 2, 4, 5))); |
1203 | /****************************************************************//** |
1204 | Splits a directory slot which owns too many records. */ |
1205 | void |
1206 | page_dir_split_slot( |
1207 | /*================*/ |
1208 | page_t* page, /*!< in: index page */ |
1209 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
1210 | uncompressed part will be written, or NULL */ |
1211 | ulint slot_no)/*!< in: the directory slot */ |
1212 | MY_ATTRIBUTE((nonnull(1))); |
1213 | /*************************************************************//** |
1214 | Tries to balance the given directory slot with too few records |
1215 | with the upper neighbor, so that there are at least the minimum number |
1216 | of records owned by the slot; this may result in the merging of |
1217 | two slots. */ |
1218 | void |
1219 | page_dir_balance_slot( |
1220 | /*==================*/ |
1221 | page_t* page, /*!< in/out: index page */ |
1222 | page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ |
1223 | ulint slot_no)/*!< in: the directory slot */ |
1224 | MY_ATTRIBUTE((nonnull(1))); |
1225 | /**********************************************************//** |
1226 | Parses a log record of a record list end or start deletion. |
1227 | @return end of log record or NULL */ |
1228 | byte* |
1229 | page_parse_delete_rec_list( |
1230 | /*=======================*/ |
1231 | mlog_id_t type, /*!< in: MLOG_LIST_END_DELETE, |
1232 | MLOG_LIST_START_DELETE, |
1233 | MLOG_COMP_LIST_END_DELETE or |
1234 | MLOG_COMP_LIST_START_DELETE */ |
1235 | byte* ptr, /*!< in: buffer */ |
1236 | byte* end_ptr,/*!< in: buffer end */ |
1237 | buf_block_t* block, /*!< in/out: buffer block or NULL */ |
1238 | dict_index_t* index, /*!< in: record descriptor */ |
1239 | mtr_t* mtr); /*!< in: mtr or NULL */ |
1240 | /** Parses a redo log record of creating a page. |
1241 | @param[in,out] block buffer block, or NULL |
1242 | @param[in] comp nonzero=compact page format |
1243 | @param[in] is_rtree whether it is rtree page */ |
1244 | void |
1245 | page_parse_create( |
1246 | buf_block_t* block, |
1247 | ulint comp, |
1248 | bool is_rtree); |
1249 | |
1250 | /************************************************************//** |
1251 | Prints record contents including the data relevant only in |
1252 | the index page context. */ |
1253 | void |
1254 | page_rec_print( |
1255 | /*===========*/ |
1256 | const rec_t* rec, /*!< in: physical record */ |
1257 | const ulint* offsets);/*!< in: record descriptor */ |
1258 | # ifdef UNIV_BTR_PRINT |
1259 | /***************************************************************//** |
1260 | This is used to print the contents of the directory for |
1261 | debugging purposes. */ |
1262 | void |
1263 | page_dir_print( |
1264 | /*===========*/ |
1265 | page_t* page, /*!< in: index page */ |
1266 | ulint pr_n); /*!< in: print n first and n last entries */ |
1267 | /***************************************************************//** |
1268 | This is used to print the contents of the page record list for |
1269 | debugging purposes. */ |
1270 | void |
1271 | page_print_list( |
1272 | /*============*/ |
1273 | buf_block_t* block, /*!< in: index page */ |
1274 | dict_index_t* index, /*!< in: dictionary index of the page */ |
1275 | ulint pr_n); /*!< in: print n first and n last entries */ |
1276 | /***************************************************************//** |
1277 | Prints the info in a page header. */ |
1278 | void |
1279 | page_header_print( |
1280 | /*==============*/ |
1281 | const page_t* page); /*!< in: index page */ |
1282 | /***************************************************************//** |
1283 | This is used to print the contents of the page for |
1284 | debugging purposes. */ |
1285 | void |
1286 | page_print( |
1287 | /*=======*/ |
1288 | buf_block_t* block, /*!< in: index page */ |
1289 | dict_index_t* index, /*!< in: dictionary index of the page */ |
1290 | ulint dn, /*!< in: print dn first and last entries |
1291 | in directory */ |
1292 | ulint rn); /*!< in: print rn first and last records |
1293 | in directory */ |
1294 | # endif /* UNIV_BTR_PRINT */ |
1295 | /***************************************************************//** |
1296 | The following is used to validate a record on a page. This function |
1297 | differs from rec_validate as it can also check the n_owned field and |
1298 | the heap_no field. |
1299 | @return TRUE if ok */ |
1300 | ibool |
1301 | page_rec_validate( |
1302 | /*==============*/ |
1303 | const rec_t* rec, /*!< in: physical record */ |
1304 | const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ |
1305 | #ifdef UNIV_DEBUG |
1306 | /***************************************************************//** |
1307 | Checks that the first directory slot points to the infimum record and |
1308 | the last to the supremum. This function is intended to track if the |
1309 | bug fixed in 4.0.14 has caused corruption to users' databases. */ |
1310 | void |
1311 | page_check_dir( |
1312 | /*===========*/ |
1313 | const page_t* page); /*!< in: index page */ |
1314 | #endif /* UNIV_DEBUG */ |
1315 | /***************************************************************//** |
1316 | This function checks the consistency of an index page when we do not |
1317 | know the index. This is also resilient so that this should never crash |
1318 | even if the page is total garbage. |
1319 | @return TRUE if ok */ |
1320 | ibool |
1321 | page_simple_validate_old( |
1322 | /*=====================*/ |
1323 | const page_t* page); /*!< in: index page in ROW_FORMAT=REDUNDANT */ |
1324 | /***************************************************************//** |
1325 | This function checks the consistency of an index page when we do not |
1326 | know the index. This is also resilient so that this should never crash |
1327 | even if the page is total garbage. |
1328 | @return TRUE if ok */ |
1329 | ibool |
1330 | page_simple_validate_new( |
1331 | /*=====================*/ |
1332 | const page_t* page); /*!< in: index page in ROW_FORMAT!=REDUNDANT */ |
1333 | /***************************************************************//** |
1334 | This function checks the consistency of an index page. |
1335 | @return TRUE if ok */ |
1336 | ibool |
1337 | page_validate( |
1338 | /*==========*/ |
1339 | const page_t* page, /*!< in: index page */ |
1340 | dict_index_t* index); /*!< in: data dictionary index containing |
1341 | the page record type definition */ |
1342 | /***************************************************************//** |
1343 | Looks in the page record list for a record with the given heap number. |
1344 | @return record, NULL if not found */ |
1345 | const rec_t* |
1346 | page_find_rec_with_heap_no( |
1347 | /*=======================*/ |
1348 | const page_t* page, /*!< in: index page */ |
1349 | ulint heap_no);/*!< in: heap number */ |
1350 | /** Get the last non-delete-marked record on a page. |
1351 | @param[in] page index tree leaf page |
1352 | @return the last record, not delete-marked |
1353 | @retval infimum record if all records are delete-marked */ |
1354 | const rec_t* |
1355 | page_find_rec_max_not_deleted( |
1356 | const page_t* page); |
1357 | |
1358 | /** Issue a warning when the checksum that is stored in the page is valid, |
1359 | but different than the global setting innodb_checksum_algorithm. |
1360 | @param[in] current_algo current checksum algorithm |
1361 | @param[in] page_checksum page valid checksum |
1362 | @param[in] page_id page identifier */ |
1363 | void |
1364 | page_warn_strict_checksum( |
1365 | srv_checksum_algorithm_t curr_algo, |
1366 | srv_checksum_algorithm_t page_checksum, |
1367 | const page_id_t& page_id); |
1368 | |
1369 | #ifdef UNIV_MATERIALIZE |
1370 | #undef UNIV_INLINE |
1371 | #define UNIV_INLINE UNIV_INLINE_ORIGINAL |
1372 | #endif |
1373 | |
1374 | #endif /* !UNIV_INNOCHECKSUM */ |
1375 | |
1376 | #include "page0page.ic" |
1377 | |
1378 | #endif |
1379 | |