1/*****************************************************************************
2Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
3Copyright (c) 2013, 2018, MariaDB Corporation.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free Software
7Foundation; version 2 of the License.
8
9This program is distributed in the hope that it will be useful, but WITHOUT
10ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License along with
14this program; if not, write to the Free Software Foundation, Inc.,
1551 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16
17*****************************************************************************/
18
19/**************************************************//**
20@file include/page0page.h
21Index page routines
22
23Created 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
51Index page header starts at the first offset left free by the FIL-module */
52
53typedef byte page_header_t;
54#endif /* !UNIV_INNOCHECKSUM */
55
56#define PAGE_HEADER 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
70ROW_FORMAT=REDUNDANT tables, this byte can contain garbage if the .ibd
71file was created in MySQL 4.1.0 or if the table resides in the system
72tablespace and was created before MySQL 4.1.1 or MySQL 4.0.14.
73In this case, the FIL_PAGE_TYPE would be FIL_PAGE_INDEX.
74
75In ROW_FORMAT=COMPRESSED tables, this field is always 0, because
76instant ADD COLUMN is not supported.
77
78In ROW_FORMAT=COMPACT and ROW_FORMAT=DYNAMIC tables, this field is
79always 0, except in the root page of the clustered index after instant
80ADD COLUMN.
81
82Instant ADD COLUMN will change FIL_PAGE_TYPE to FIL_PAGE_TYPE_INSTANT
83and initialize the PAGE_INSTANT field to the original number of
84fields in the clustered index (dict_index_t::n_core_fields). The most
85significant bits are in the first byte, and the least significant 5
86bits are stored in the most significant 5 bits of PAGE_DIRECTION_B.
87
88These FIL_PAGE_TYPE_INSTANT and PAGE_INSTANT may be assigned even if
89instant ADD COLUMN was not committed. Changes to these page header fields
90are not undo-logged, but changes to the 'default value record' are.
91If the server is killed and restarted, the page header fields could
92remain set even though no 'default value record' is present.
93
94When the table becomes empty, the PAGE_INSTANT field and the
95FIL_PAGE_TYPE can be reset and any 'default value record' be removed. */
96#define PAGE_INSTANT 12
97
98/** last insert direction: PAGE_LEFT, ....
99In ROW_FORMAT=REDUNDANT tables created before MySQL 4.1.1 or MySQL 4.0.14,
100this 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;
106Defined only in secondary index leaf pages and in change buffer leaf pages.
107Otherwise 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 PAGE_HEADER_PRIV_END 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
181typedef byte page_dir_slot_t;
182typedef page_dir_slot_t page_dir_t;
183
184/* Offset of the directory start down from the page end. We call the
185slot with the highest file address directory start, as it points to
186the 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
193page 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
197number may drop below the minimum in the first and the last slot in the
198directory. */
199#define PAGE_DIR_SLOT_MAX_N_OWNED 8
200#define PAGE_DIR_SLOT_MIN_N_OWNED 4
201
202extern 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 */
208MY_ATTRIBUTE((const))
209inline
210page_t*
211page_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 */
219MY_ATTRIBUTE((const))
220inline
221ulint
222page_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 */
231inline
232byte
233page_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) */
242inline
243bool
244page_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) */
254inline
255bool
256page_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) */
266inline
267bool
268page_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 */
280inline
281byte
282page_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
289in 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 */
292inline
293bool
294page_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 */
304inline
305unsigned
306page_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 */
315inline
316unsigned
317page_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 */
327inline
328bool
329page_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 */
349inline
350bool
351page_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 */
361inline
362bool
363page_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 */
373inline
374bool
375page_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 */
389inline
390bool
391page_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 */
396inline
397bool
398page_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 */
403inline
404bool
405page_rec_is_infimum(const rec_t* rec);
406
407/*************************************************************//**
408Returns the max trx id field value. */
409UNIV_INLINE
410trx_id_t
411page_get_max_trx_id(
412/*================*/
413 const page_t* page); /*!< in: page */
414/*************************************************************//**
415Sets the max trx id field value. */
416void
417page_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/*************************************************************//**
424Sets the max trx id field value if trx_id is bigger than the previous
425value. */
426UNIV_INLINE
427void
428page_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 */
444void
445page_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 */
456MY_ATTRIBUTE((nonnull, warn_unused_result))
457UNIV_INLINE
458ib_uint64_t
459page_get_autoinc(const page_t* page);
460
461/*************************************************************//**
462Returns the RTREE SPLIT SEQUENCE NUMBER (FIL_RTREE_SPLIT_SEQ_NUM).
463@return SPLIT SEQUENCE NUMBER */
464UNIV_INLINE
465node_seq_t
466page_get_ssn_id(
467/*============*/
468 const page_t* page); /*!< in: page */
469/*************************************************************//**
470Sets the RTREE SPLIT SEQUENCE NUMBER field value */
471UNIV_INLINE
472void
473page_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/*************************************************************//**
483Reads the given header field. */
484UNIV_INLINE
485uint16_t
486page_header_get_field(
487/*==================*/
488 const page_t* page, /*!< in: page */
489 ulint field); /*!< in: PAGE_N_DIR_SLOTS, ... */
490
491#ifndef UNIV_INNOCHECKSUM
492/*************************************************************//**
493Sets the given header field. */
494UNIV_INLINE
495void
496page_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/*************************************************************//**
504Returns the offset stored in the given header field.
505@return offset from the start of the page, or 0 */
506UNIV_INLINE
507uint16_t
508page_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/*************************************************************//**
515Returns 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/*************************************************************//**
520Sets the pointer stored in the given header field. */
521UNIV_INLINE
522void
523page_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/*************************************************************//**
532Resets the last insert info field in the page header. Writes to mlog
533about this operation. */
534UNIV_INLINE
535void
536page_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/************************************************************//**
546Returns the nth record of the record list.
547This is the inverse function of page_rec_get_n_recs_before().
548@return nth record */
549const rec_t*
550page_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/************************************************************//**
556Returns the nth record of the record list.
557This is the inverse function of page_rec_get_n_recs_before().
558@return nth record */
559UNIV_INLINE
560rec_t*
561page_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/************************************************************//**
568Returns the middle record of the records on the page. If there is an
569even number of records in the list, returns the first record of the
570upper half-list.
571@return middle record */
572UNIV_INLINE
573rec_t*
574page_get_middle_rec(
575/*================*/
576 page_t* page) /*!< in: page */
577 MY_ATTRIBUTE((nonnull, warn_unused_result));
578/*************************************************************//**
579Gets the page number.
580@return page number */
581UNIV_INLINE
582ulint
583page_get_page_no(
584/*=============*/
585 const page_t* page); /*!< in: page */
586
587/*************************************************************//**
588Gets the tablespace identifier.
589@return space id */
590UNIV_INLINE
591ulint
592page_get_space_id(
593/*==============*/
594 const page_t* page); /*!< in: page */
595
596/*************************************************************//**
597Gets the number of user records on page (the infimum and supremum records
598are not user records).
599@return number of user records */
600UNIV_INLINE
601uint16_t
602page_get_n_recs(
603/*============*/
604 const page_t* page); /*!< in: index page */
605
606/***************************************************************//**
607Returns the number of records before the given record in chain.
608The number includes infimum and supremum records.
609This is the inverse function of page_rec_get_nth().
610@return number of records */
611ulint
612page_rec_get_n_recs_before(
613/*=======================*/
614 const rec_t* rec); /*!< in: the physical record */
615/*************************************************************//**
616Gets the number of records in the heap.
617@return number of user records */
618UNIV_INLINE
619uint16_t
620page_dir_get_n_heap(
621/*================*/
622 const page_t* page); /*!< in: index page */
623/*************************************************************//**
624Sets the number of records in the heap. */
625UNIV_INLINE
626void
627page_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/*************************************************************//**
637Gets the number of dir slots in directory.
638@return number of slots */
639UNIV_INLINE
640uint16_t
641page_dir_get_n_slots(
642/*=================*/
643 const page_t* page); /*!< in: index page */
644/*************************************************************//**
645Sets the number of dir slots in directory. */
646UNIV_INLINE
647void
648page_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/*************************************************************//**
656Gets pointer to nth directory slot.
657@return pointer to dir slot */
658UNIV_INLINE
659page_dir_slot_t*
660page_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/**************************************************************//**
670Used to check the consistency of a record on a page.
671@return TRUE if succeed */
672UNIV_INLINE
673ibool
674page_rec_check(
675/*===========*/
676 const rec_t* rec); /*!< in: record */
677/***************************************************************//**
678Gets the record pointed to by a directory slot.
679@return pointer to record */
680UNIV_INLINE
681const rec_t*
682page_dir_slot_get_rec(
683/*==================*/
684 const page_dir_slot_t* slot); /*!< in: directory slot */
685/***************************************************************//**
686This is used to set the record offset in a directory slot. */
687UNIV_INLINE
688void
689page_dir_slot_set_rec(
690/*==================*/
691 page_dir_slot_t* slot, /*!< in: directory slot */
692 rec_t* rec); /*!< in: record on the page */
693/***************************************************************//**
694Gets the number of records owned by a directory slot.
695@return number of records */
696UNIV_INLINE
697ulint
698page_dir_slot_get_n_owned(
699/*======================*/
700 const page_dir_slot_t* slot); /*!< in: page directory slot */
701/***************************************************************//**
702This is used to set the owned records field of a directory slot. */
703UNIV_INLINE
704void
705page_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/************************************************************//**
711Calculates the space reserved for directory slots of a given
712number of records. The exact value is a fraction number
713n * PAGE_DIR_SLOT_SIZE / PAGE_DIR_SLOT_MIN_N_OWNED, and it is
714rounded upwards to an integer. */
715UNIV_INLINE
716ulint
717page_dir_calc_reserved_space(
718/*=========================*/
719 ulint n_recs); /*!< in: number of records */
720/***************************************************************//**
721Looks for the directory slot which owns the given record.
722@return the directory slot number */
723ulint
724page_dir_find_owner_slot(
725/*=====================*/
726 const rec_t* rec); /*!< in: the physical record */
727
728/***************************************************************//**
729Returns the heap number of a record.
730@return heap number */
731UNIV_INLINE
732ulint
733page_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 */
739inline
740bool
741page_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 */
753inline
754bool
755page_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 */
763inline
764bool
765page_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 */
774inline
775bool
776page_has_next(const page_t* page)
777{
778 return *reinterpret_cast<const uint32_t*>(page + FIL_PAGE_NEXT)
779 != FIL_NULL;
780}
781
782/************************************************************//**
783Gets the pointer to the next record on the page.
784@return pointer to next record */
785UNIV_INLINE
786const rec_t*
787page_rec_get_next_low(
788/*==================*/
789 const rec_t* rec, /*!< in: pointer to record */
790 ulint comp); /*!< in: nonzero=compact page layout */
791/************************************************************//**
792Gets the pointer to the next record on the page.
793@return pointer to next record */
794UNIV_INLINE
795rec_t*
796page_rec_get_next(
797/*==============*/
798 rec_t* rec); /*!< in: pointer to record */
799/************************************************************//**
800Gets the pointer to the next record on the page.
801@return pointer to next record */
802UNIV_INLINE
803const rec_t*
804page_rec_get_next_const(
805/*====================*/
806 const rec_t* rec); /*!< in: pointer to record */
807/************************************************************//**
808Gets the pointer to the next non delete-marked record on the page.
809If all subsequent records are delete-marked, then this function
810will return the supremum record.
811@return pointer to next non delete-marked record or pointer to supremum */
812UNIV_INLINE
813const rec_t*
814page_rec_get_next_non_del_marked(
815/*=============================*/
816 const rec_t* rec); /*!< in: pointer to record */
817/************************************************************//**
818Sets the pointer to the next record on the page. */
819UNIV_INLINE
820void
821page_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/************************************************************//**
828Gets the pointer to the previous record.
829@return pointer to previous record */
830UNIV_INLINE
831const rec_t*
832page_rec_get_prev_const(
833/*====================*/
834 const rec_t* rec); /*!< in: pointer to record, must not be page
835 infimum */
836/************************************************************//**
837Gets the pointer to the previous record.
838@return pointer to previous record */
839UNIV_INLINE
840rec_t*
841page_rec_get_prev(
842/*==============*/
843 rec_t* rec); /*!< in: pointer to record,
844 must not be page infimum */
845
846/************************************************************//**
847true if the record is the first user record on a page.
848@return true if the first user record */
849UNIV_INLINE
850bool
851page_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/************************************************************//**
858true if the record is the second user record on a page.
859@return true if the second user record */
860UNIV_INLINE
861bool
862page_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/************************************************************//**
869true if the record is the last user record on a page.
870@return true if the last user record */
871UNIV_INLINE
872bool
873page_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/************************************************************//**
880true if the record is the second last user record on a page.
881@return true if the second last user record */
882UNIV_INLINE
883bool
884page_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/***************************************************************//**
891Looks for the record which owns the given record.
892@return the owner record */
893UNIV_INLINE
894rec_t*
895page_rec_find_owner_rec(
896/*====================*/
897 rec_t* rec); /*!< in: the physical record */
898
899/***********************************************************************//**
900Write a 32-bit field in a data dictionary record. */
901UNIV_INLINE
902void
903page_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/************************************************************//**
911Returns the maximum combined size of records which can be inserted on top
912of record heap.
913@return maximum combined size for inserted records */
914UNIV_INLINE
915ulint
916page_get_max_insert_size(
917/*=====================*/
918 const page_t* page, /*!< in: index page */
919 ulint n_recs);/*!< in: number of records */
920/************************************************************//**
921Returns the maximum combined size of records which can be inserted on top
922of record heap if page is first reorganized.
923@return maximum combined size for inserted records */
924UNIV_INLINE
925ulint
926page_get_max_insert_size_after_reorganize(
927/*======================================*/
928 const page_t* page, /*!< in: index page */
929 ulint n_recs);/*!< in: number of records */
930/*************************************************************//**
931Calculates free space if a page is emptied.
932@return free space */
933UNIV_INLINE
934ulint
935page_get_free_space_of_empty(
936/*=========================*/
937 ulint comp) /*!< in: nonzero=compact page format */
938 MY_ATTRIBUTE((const));
939/**********************************************************//**
940Returns the base extra size of a physical record. This is the
941size of the fixed header, independent of the record size.
942@return REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */
943UNIV_INLINE
944ulint
945page_rec_get_base_extra_size(
946/*=========================*/
947 const rec_t* rec); /*!< in: physical record */
948/************************************************************//**
949Returns the sum of the sizes of the records in the record list
950excluding the infimum and supremum records.
951@return data in bytes */
952UNIV_INLINE
953uint16_t
954page_get_data_size(
955/*===============*/
956 const page_t* page); /*!< in: index page */
957/************************************************************//**
958Allocates a block of memory from the head of the free list
959of an index page. */
960UNIV_INLINE
961void
962page_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/************************************************************//**
972Allocates a block of memory from the heap of an index page.
973@return pointer to start of allocated buffer, or NULL if allocation fails */
974byte*
975page_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/************************************************************//**
986Puts a record to free list. */
987UNIV_INLINE
988void
989page_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 */
1003inline
1004byte
1005page_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 */
1010inline
1011void
1012page_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 */
1017inline
1018byte
1019page_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 */
1027inline
1028uint16_t
1029page_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 */
1034inline
1035void
1036page_set_instant(page_t* page, unsigned n, mtr_t* mtr);
1037
1038/**********************************************************//**
1039Create an uncompressed B-tree index page.
1040@return pointer to the page */
1041page_t*
1042page_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/**********************************************************//**
1050Create a compressed B-tree index page.
1051@return pointer to the page */
1052page_t*
1053page_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/**********************************************************//**
1071Empty a previously created B-tree index page. */
1072void
1073page_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/*************************************************************//**
1080Differs from page_copy_rec_list_end, because this function does not
1081touch the lock table and max trx id on page or compress the page.
1082
1083IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
1084if new_block is a compressed leaf page in a secondary index.
1085This has to be done either within the same mini-transaction,
1086or by invoking ibuf_reset_free_bits() before mtr_commit(). */
1087void
1088page_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/*************************************************************//**
1096Copies records from page to new_page, from the given record onward,
1097including that record. Infimum and supremum records are not copied.
1098The records are copied to the start of the record list on new_page.
1099
1100IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
1101if new_block is a compressed leaf page in a secondary index.
1102This has to be done either within the same mini-transaction,
1103or by invoking ibuf_reset_free_bits() before mtr_commit().
1104
1105@return pointer to the original successor of the infimum record on
1106new_page, or NULL on zip overflow (new_block will be decompressed) */
1107rec_t*
1108page_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/*************************************************************//**
1117Copies records from page to new_page, up to the given record, NOT
1118including that record. Infimum and supremum records are not copied.
1119The records are copied to the end of the record list on new_page.
1120
1121IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
1122if new_block is a compressed leaf page in a secondary index.
1123This has to be done either within the same mini-transaction,
1124or by invoking ibuf_reset_free_bits() before mtr_commit().
1125
1126@return pointer to the original predecessor of the supremum record on
1127new_page, or NULL on zip overflow (new_block will be decompressed) */
1128rec_t*
1129page_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/*************************************************************//**
1138Deletes records from a page from a given record onward, including that record.
1139The infimum and supremum records are not deleted. */
1140void
1141page_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/*************************************************************//**
1154Deletes records from page, up to the given record, NOT including
1155that record. Infimum and supremum records are not deleted. */
1156void
1157page_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/*************************************************************//**
1165Moves record list end to another page. Moved records include
1166split_rec.
1167
1168IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
1169if new_block is a compressed leaf page in a secondary index.
1170This has to be done either within the same mini-transaction,
1171or by invoking ibuf_reset_free_bits() before mtr_commit().
1172
1173@return TRUE on success; FALSE on compression failure (new_block will
1174be decompressed) */
1175ibool
1176page_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/*************************************************************//**
1185Moves record list start to another page. Moved records do not include
1186split_rec.
1187
1188IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
1189if new_block is a compressed leaf page in a secondary index.
1190This has to be done either within the same mini-transaction,
1191or by invoking ibuf_reset_free_bits() before mtr_commit().
1192
1193@return TRUE on success; FALSE on compression failure */
1194ibool
1195page_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/****************************************************************//**
1204Splits a directory slot which owns too many records. */
1205void
1206page_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/*************************************************************//**
1214Tries to balance the given directory slot with too few records
1215with the upper neighbor, so that there are at least the minimum number
1216of records owned by the slot; this may result in the merging of
1217two slots. */
1218void
1219page_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/**********************************************************//**
1226Parses a log record of a record list end or start deletion.
1227@return end of log record or NULL */
1228byte*
1229page_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 */
1244void
1245page_parse_create(
1246 buf_block_t* block,
1247 ulint comp,
1248 bool is_rtree);
1249
1250/************************************************************//**
1251Prints record contents including the data relevant only in
1252the index page context. */
1253void
1254page_rec_print(
1255/*===========*/
1256 const rec_t* rec, /*!< in: physical record */
1257 const ulint* offsets);/*!< in: record descriptor */
1258# ifdef UNIV_BTR_PRINT
1259/***************************************************************//**
1260This is used to print the contents of the directory for
1261debugging purposes. */
1262void
1263page_dir_print(
1264/*===========*/
1265 page_t* page, /*!< in: index page */
1266 ulint pr_n); /*!< in: print n first and n last entries */
1267/***************************************************************//**
1268This is used to print the contents of the page record list for
1269debugging purposes. */
1270void
1271page_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/***************************************************************//**
1277Prints the info in a page header. */
1278void
1279page_header_print(
1280/*==============*/
1281 const page_t* page); /*!< in: index page */
1282/***************************************************************//**
1283This is used to print the contents of the page for
1284debugging purposes. */
1285void
1286page_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/***************************************************************//**
1296The following is used to validate a record on a page. This function
1297differs from rec_validate as it can also check the n_owned field and
1298the heap_no field.
1299@return TRUE if ok */
1300ibool
1301page_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/***************************************************************//**
1307Checks that the first directory slot points to the infimum record and
1308the last to the supremum. This function is intended to track if the
1309bug fixed in 4.0.14 has caused corruption to users' databases. */
1310void
1311page_check_dir(
1312/*===========*/
1313 const page_t* page); /*!< in: index page */
1314#endif /* UNIV_DEBUG */
1315/***************************************************************//**
1316This function checks the consistency of an index page when we do not
1317know the index. This is also resilient so that this should never crash
1318even if the page is total garbage.
1319@return TRUE if ok */
1320ibool
1321page_simple_validate_old(
1322/*=====================*/
1323 const page_t* page); /*!< in: index page in ROW_FORMAT=REDUNDANT */
1324/***************************************************************//**
1325This function checks the consistency of an index page when we do not
1326know the index. This is also resilient so that this should never crash
1327even if the page is total garbage.
1328@return TRUE if ok */
1329ibool
1330page_simple_validate_new(
1331/*=====================*/
1332 const page_t* page); /*!< in: index page in ROW_FORMAT!=REDUNDANT */
1333/***************************************************************//**
1334This function checks the consistency of an index page.
1335@return TRUE if ok */
1336ibool
1337page_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/***************************************************************//**
1343Looks in the page record list for a record with the given heap number.
1344@return record, NULL if not found */
1345const rec_t*
1346page_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 */
1354const rec_t*
1355page_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,
1359but 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 */
1363void
1364page_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