1 /*****************************************************************************
2 
3 Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8 
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation.  The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License, version 2.0, for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24 
25 *****************************************************************************/
26 
27 /**************************************************//**
28 @file include/page0page.h
29 Index page routines
30 
31 Created 2/2/1994 Heikki Tuuri
32 *******************************************************/
33 
34 #ifndef page0page_h
35 #define page0page_h
36 
37 #include "univ.i"
38 
39 #include "page0types.h"
40 #include "fil0fil.h"
41 #include "buf0buf.h"
42 #include "data0data.h"
43 #include "dict0dict.h"
44 #include "rem0rec.h"
45 #include "fsp0fsp.h"
46 #include "mtr0mtr.h"
47 
48 #ifdef UNIV_MATERIALIZE
49 #undef UNIV_INLINE
50 #define UNIV_INLINE
51 #endif
52 
53 /*			PAGE HEADER
54 			===========
55 
56 Index page header starts at the first offset left free by the FIL-module */
57 
58 typedef	byte		page_header_t;
59 
60 #define	PAGE_HEADER	FSEG_PAGE_DATA	/* index page header starts at this
61 				offset */
62 /*-----------------------------*/
63 #define PAGE_N_DIR_SLOTS 0	/* number of slots in page directory */
64 #define	PAGE_HEAP_TOP	 2	/* pointer to record heap top */
65 #define	PAGE_N_HEAP	 4	/* number of records in the heap,
66 				bit 15=flag: new-style compact page format */
67 #define	PAGE_FREE	 6	/* pointer to start of page free record list */
68 #define	PAGE_GARBAGE	 8	/* number of bytes in deleted records */
69 #define	PAGE_LAST_INSERT 10	/* pointer to the last inserted record, or
70 				NULL if this info has been reset by a delete,
71 				for example */
72 #define	PAGE_DIRECTION	 12	/* last insert direction: PAGE_LEFT, ... */
73 #define	PAGE_N_DIRECTION 14	/* number of consecutive inserts to the same
74 				direction */
75 #define	PAGE_N_RECS	 16	/* number of user records on the page */
76 #define PAGE_MAX_TRX_ID	 18	/* highest id of a trx which may have modified
77 				a record on the page; trx_id_t; defined only
78 				in secondary indexes and in the insert buffer
79 				tree */
80 #define PAGE_HEADER_PRIV_END 26	/* end of private data structure of the page
81 				header which are set in a page create */
82 /*----*/
83 #define	PAGE_LEVEL	 26	/* level of the node in an index tree; the
84 				leaf level is the level 0.  This field should
85 				not be written to after page creation. */
86 #define	PAGE_INDEX_ID	 28	/* index id where the page belongs.
87 				This field should not be written to after
88 				page creation. */
89 #define PAGE_BTR_SEG_LEAF 36	/* file segment header for the leaf pages in
90 				a B-tree: defined only on the root page of a
91 				B-tree, but not in the root of an ibuf tree */
92 #define PAGE_BTR_IBUF_FREE_LIST	PAGE_BTR_SEG_LEAF
93 #define PAGE_BTR_IBUF_FREE_LIST_NODE PAGE_BTR_SEG_LEAF
94 				/* in the place of PAGE_BTR_SEG_LEAF and _TOP
95 				there is a free list base node if the page is
96 				the root page of an ibuf tree, and at the same
97 				place is the free list node if the page is in
98 				a free list */
99 #define PAGE_BTR_SEG_TOP (36 + FSEG_HEADER_SIZE)
100 				/* file segment header for the non-leaf pages
101 				in a B-tree: defined only on the root page of
102 				a B-tree, but not in the root of an ibuf
103 				tree */
104 /*----*/
105 #define PAGE_DATA	(PAGE_HEADER + 36 + 2 * FSEG_HEADER_SIZE)
106 				/* start of data on the page */
107 
108 #define PAGE_OLD_INFIMUM	(PAGE_DATA + 1 + REC_N_OLD_EXTRA_BYTES)
109 				/* offset of the page infimum record on an
110 				old-style page */
111 #define PAGE_OLD_SUPREMUM	(PAGE_DATA + 2 + 2 * REC_N_OLD_EXTRA_BYTES + 8)
112 				/* offset of the page supremum record on an
113 				old-style page */
114 #define PAGE_OLD_SUPREMUM_END (PAGE_OLD_SUPREMUM + 9)
115 				/* offset of the page supremum record end on
116 				an old-style page */
117 #define PAGE_NEW_INFIMUM	(PAGE_DATA + REC_N_NEW_EXTRA_BYTES)
118 				/* offset of the page infimum record on a
119 				new-style compact page */
120 #define PAGE_NEW_SUPREMUM	(PAGE_DATA + 2 * REC_N_NEW_EXTRA_BYTES + 8)
121 				/* offset of the page supremum record on a
122 				new-style compact page */
123 #define PAGE_NEW_SUPREMUM_END (PAGE_NEW_SUPREMUM + 8)
124 				/* offset of the page supremum record end on
125 				a new-style compact page */
126 /*-----------------------------*/
127 
128 /* Heap numbers */
129 #define PAGE_HEAP_NO_INFIMUM	0	/* page infimum */
130 #define PAGE_HEAP_NO_SUPREMUM	1	/* page supremum */
131 #define PAGE_HEAP_NO_USER_LOW	2	/* first user record in
132 					creation (insertion) order,
133 					not necessarily collation order;
134 					this record may have been deleted */
135 
136 /* Directions of cursor movement */
137 #define	PAGE_LEFT		1
138 #define	PAGE_RIGHT		2
139 #define	PAGE_SAME_REC		3
140 #define	PAGE_SAME_PAGE		4
141 #define	PAGE_NO_DIRECTION	5
142 
143 /*			PAGE DIRECTORY
144 			==============
145 */
146 
147 typedef	byte			page_dir_slot_t;
148 typedef page_dir_slot_t		page_dir_t;
149 
150 /* Offset of the directory start down from the page end. We call the
151 slot with the highest file address directory start, as it points to
152 the first record in the list of records. */
153 #define	PAGE_DIR		FIL_PAGE_DATA_END
154 
155 /* We define a slot in the page directory as two bytes */
156 #define	PAGE_DIR_SLOT_SIZE	2
157 
158 /* The offset of the physically lower end of the directory, counted from
159 page end, when the page is empty */
160 #define PAGE_EMPTY_DIR_START	(PAGE_DIR + 2 * PAGE_DIR_SLOT_SIZE)
161 
162 /* The maximum and minimum number of records owned by a directory slot. The
163 number may drop below the minimum in the first and the last slot in the
164 directory. */
165 #define PAGE_DIR_SLOT_MAX_N_OWNED	8
166 #define	PAGE_DIR_SLOT_MIN_N_OWNED	4
167 
168 /************************************************************//**
169 Gets the start of a page.
170 @return	start of the page */
171 UNIV_INLINE
172 page_t*
173 page_align(
174 /*=======*/
175 	const void*	ptr)	/*!< in: pointer to page frame */
176 		MY_ATTRIBUTE((const));
177 /************************************************************//**
178 Gets the offset within a page.
179 @return	offset from the start of the page */
180 UNIV_INLINE
181 ulint
182 page_offset(
183 /*========*/
184 	const void*	ptr)	/*!< in: pointer to page frame */
185 		MY_ATTRIBUTE((const));
186 /*************************************************************//**
187 Returns the max trx id field value. */
188 UNIV_INLINE
189 trx_id_t
190 page_get_max_trx_id(
191 /*================*/
192 	const page_t*	page);	/*!< in: page */
193 /*************************************************************//**
194 Sets the max trx id field value. */
195 UNIV_INTERN
196 void
197 page_set_max_trx_id(
198 /*================*/
199 	buf_block_t*	block,	/*!< in/out: page */
200 	page_zip_des_t*	page_zip,/*!< in/out: compressed page, or NULL */
201 	trx_id_t	trx_id,	/*!< in: transaction id */
202 	mtr_t*		mtr);	/*!< in/out: mini-transaction, or NULL */
203 /*************************************************************//**
204 Sets the max trx id field value if trx_id is bigger than the previous
205 value. */
206 UNIV_INLINE
207 void
208 page_update_max_trx_id(
209 /*===================*/
210 	buf_block_t*	block,	/*!< in/out: page */
211 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose
212 				uncompressed part will be updated, or NULL */
213 	trx_id_t	trx_id,	/*!< in: transaction id */
214 	mtr_t*		mtr);	/*!< in/out: mini-transaction */
215 /*************************************************************//**
216 Reads the given header field. */
217 UNIV_INLINE
218 ulint
219 page_header_get_field(
220 /*==================*/
221 	const page_t*	page,	/*!< in: page */
222 	ulint		field);	/*!< in: PAGE_N_DIR_SLOTS, ... */
223 /*************************************************************//**
224 Sets the given header field. */
225 UNIV_INLINE
226 void
227 page_header_set_field(
228 /*==================*/
229 	page_t*		page,	/*!< in/out: page */
230 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose
231 				uncompressed part will be updated, or NULL */
232 	ulint		field,	/*!< in: PAGE_N_DIR_SLOTS, ... */
233 	ulint		val);	/*!< in: value */
234 /*************************************************************//**
235 Returns the offset stored in the given header field.
236 @return	offset from the start of the page, or 0 */
237 UNIV_INLINE
238 ulint
239 page_header_get_offs(
240 /*=================*/
241 	const page_t*	page,	/*!< in: page */
242 	ulint		field)	/*!< in: PAGE_FREE, ... */
243 	MY_ATTRIBUTE((nonnull, pure));
244 
245 /*************************************************************//**
246 Returns the pointer stored in the given header field, or NULL. */
247 #define page_header_get_ptr(page, field)			\
248 	(page_header_get_offs(page, field)			\
249 	 ? page + page_header_get_offs(page, field) : NULL)
250 /*************************************************************//**
251 Sets the pointer stored in the given header field. */
252 UNIV_INLINE
253 void
254 page_header_set_ptr(
255 /*================*/
256 	page_t*		page,	/*!< in/out: page */
257 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose
258 				uncompressed part will be updated, or NULL */
259 	ulint		field,	/*!< in/out: PAGE_FREE, ... */
260 	const byte*	ptr);	/*!< in: pointer or NULL*/
261 #ifndef UNIV_HOTBACKUP
262 /*************************************************************//**
263 Resets the last insert info field in the page header. Writes to mlog
264 about this operation. */
265 UNIV_INLINE
266 void
267 page_header_reset_last_insert(
268 /*==========================*/
269 	page_t*		page,	/*!< in: page */
270 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose
271 				uncompressed part will be updated, or NULL */
272 	mtr_t*		mtr);	/*!< in: mtr */
273 #endif /* !UNIV_HOTBACKUP */
274 /************************************************************//**
275 Gets the offset of the first record on the page.
276 @return	offset of the first record in record list, relative from page */
277 UNIV_INLINE
278 ulint
279 page_get_infimum_offset(
280 /*====================*/
281 	const page_t*	page);	/*!< in: page which must have record(s) */
282 /************************************************************//**
283 Gets the offset of the last record on the page.
284 @return	offset of the last record in record list, relative from page */
285 UNIV_INLINE
286 ulint
287 page_get_supremum_offset(
288 /*=====================*/
289 	const page_t*	page);	/*!< in: page which must have record(s) */
290 #define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page))
291 #define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page))
292 
293 /************************************************************//**
294 Returns the nth record of the record list.
295 This is the inverse function of page_rec_get_n_recs_before().
296 @return	nth record */
297 UNIV_INTERN
298 const rec_t*
299 page_rec_get_nth_const(
300 /*===================*/
301 	const page_t*	page,	/*!< in: page */
302 	ulint		nth)	/*!< in: nth record */
303 	MY_ATTRIBUTE((nonnull, warn_unused_result));
304 /************************************************************//**
305 Returns the nth record of the record list.
306 This is the inverse function of page_rec_get_n_recs_before().
307 @return	nth record */
308 UNIV_INLINE
309 rec_t*
310 page_rec_get_nth(
311 /*=============*/
312 	page_t*	page,	/*< in: page */
313 	ulint	nth)	/*!< in: nth record */
314 	MY_ATTRIBUTE((nonnull, warn_unused_result));
315 
316 #ifndef UNIV_HOTBACKUP
317 /************************************************************//**
318 Returns the middle record of the records on the page. If there is an
319 even number of records in the list, returns the first record of the
320 upper half-list.
321 @return	middle record */
322 UNIV_INLINE
323 rec_t*
324 page_get_middle_rec(
325 /*================*/
326 	page_t*	page)	/*!< in: page */
327 	MY_ATTRIBUTE((nonnull, warn_unused_result));
328 /*************************************************************//**
329 Compares a data tuple to a physical record. Differs from the function
330 cmp_dtuple_rec_with_match in the way that the record must reside on an
331 index page, and also page infimum and supremum records can be given in
332 the parameter rec. These are considered as the negative infinity and
333 the positive infinity in the alphabetical order.
334 @return 1, 0, -1, if dtuple is greater, equal, less than rec,
335 respectively, when only the common first fields are compared */
336 UNIV_INLINE
337 int
338 page_cmp_dtuple_rec_with_match(
339 /*===========================*/
340 	const dtuple_t*	dtuple,	/*!< in: data tuple */
341 	const rec_t*	rec,	/*!< in: physical record on a page; may also
342 				be page infimum or supremum, in which case
343 				matched-parameter values below are not
344 				affected */
345 	const ulint*	offsets,/*!< in: array returned by rec_get_offsets() */
346 	ulint*		matched_fields, /*!< in/out: number of already completely
347 				matched fields; when function returns
348 				contains the value for current comparison */
349 	ulint*		matched_bytes); /*!< in/out: number of already matched
350 				bytes within the first field not completely
351 				matched; when function returns contains the
352 				value for current comparison */
353 #endif /* !UNIV_HOTBACKUP */
354 /*************************************************************//**
355 Gets the page number.
356 @return	page number */
357 UNIV_INLINE
358 ulint
359 page_get_page_no(
360 /*=============*/
361 	const page_t*	page);	/*!< in: page */
362 /*************************************************************//**
363 Gets the tablespace identifier.
364 @return	space id */
365 UNIV_INLINE
366 ulint
367 page_get_space_id(
368 /*==============*/
369 	const page_t*	page);	/*!< in: page */
370 /*************************************************************//**
371 Gets the number of user records on page (the infimum and supremum records
372 are not user records).
373 @return	number of user records */
374 UNIV_INLINE
375 ulint
376 page_get_n_recs(
377 /*============*/
378 	const page_t*	page);	/*!< in: index page */
379 /***************************************************************//**
380 Returns the number of records before the given record in chain.
381 The number includes infimum and supremum records.
382 This is the inverse function of page_rec_get_nth().
383 @return	number of records */
384 UNIV_INTERN
385 ulint
386 page_rec_get_n_recs_before(
387 /*=======================*/
388 	const rec_t*	rec);	/*!< in: the physical record */
389 /*************************************************************//**
390 Gets the number of records in the heap.
391 @return	number of user records */
392 UNIV_INLINE
393 ulint
394 page_dir_get_n_heap(
395 /*================*/
396 	const page_t*	page);	/*!< in: index page */
397 /*************************************************************//**
398 Sets the number of records in the heap. */
399 UNIV_INLINE
400 void
401 page_dir_set_n_heap(
402 /*================*/
403 	page_t*		page,	/*!< in/out: index page */
404 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose
405 				uncompressed part will be updated, or NULL.
406 				Note that the size of the dense page directory
407 				in the compressed page trailer is
408 				n_heap * PAGE_ZIP_DIR_SLOT_SIZE. */
409 	ulint		n_heap);/*!< in: number of records */
410 /*************************************************************//**
411 Gets the number of dir slots in directory.
412 @return	number of slots */
413 UNIV_INLINE
414 ulint
415 page_dir_get_n_slots(
416 /*=================*/
417 	const page_t*	page);	/*!< in: index page */
418 /*************************************************************//**
419 Sets the number of dir slots in directory. */
420 UNIV_INLINE
421 void
422 page_dir_set_n_slots(
423 /*=================*/
424 	page_t*		page,	/*!< in/out: page */
425 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose
426 				uncompressed part will be updated, or NULL */
427 	ulint		n_slots);/*!< in: number of slots */
428 #ifdef UNIV_DEBUG
429 /*************************************************************//**
430 Gets pointer to nth directory slot.
431 @return	pointer to dir slot */
432 UNIV_INLINE
433 page_dir_slot_t*
434 page_dir_get_nth_slot(
435 /*==================*/
436 	const page_t*	page,	/*!< in: index page */
437 	ulint		n);	/*!< in: position */
438 #else /* UNIV_DEBUG */
439 # define page_dir_get_nth_slot(page, n)		\
440 	((page) + UNIV_PAGE_SIZE - PAGE_DIR	\
441 	 - (n + 1) * PAGE_DIR_SLOT_SIZE)
442 #endif /* UNIV_DEBUG */
443 /**************************************************************//**
444 Used to check the consistency of a record on a page.
445 @return	TRUE if succeed */
446 UNIV_INLINE
447 ibool
448 page_rec_check(
449 /*===========*/
450 	const rec_t*	rec);	/*!< in: record */
451 /***************************************************************//**
452 Gets the record pointed to by a directory slot.
453 @return	pointer to record */
454 UNIV_INLINE
455 const rec_t*
456 page_dir_slot_get_rec(
457 /*==================*/
458 	const page_dir_slot_t*	slot);	/*!< in: directory slot */
459 /***************************************************************//**
460 This is used to set the record offset in a directory slot. */
461 UNIV_INLINE
462 void
463 page_dir_slot_set_rec(
464 /*==================*/
465 	page_dir_slot_t* slot,	/*!< in: directory slot */
466 	rec_t*		 rec);	/*!< in: record on the page */
467 /***************************************************************//**
468 Gets the number of records owned by a directory slot.
469 @return	number of records */
470 UNIV_INLINE
471 ulint
472 page_dir_slot_get_n_owned(
473 /*======================*/
474 	const page_dir_slot_t*	slot);	/*!< in: page directory slot */
475 /***************************************************************//**
476 This is used to set the owned records field of a directory slot. */
477 UNIV_INLINE
478 void
479 page_dir_slot_set_n_owned(
480 /*======================*/
481 	page_dir_slot_t*slot,	/*!< in/out: directory slot */
482 	page_zip_des_t*	page_zip,/*!< in/out: compressed page, or NULL */
483 	ulint		n);	/*!< in: number of records owned by the slot */
484 /************************************************************//**
485 Calculates the space reserved for directory slots of a given
486 number of records. The exact value is a fraction number
487 n * PAGE_DIR_SLOT_SIZE / PAGE_DIR_SLOT_MIN_N_OWNED, and it is
488 rounded upwards to an integer. */
489 UNIV_INLINE
490 ulint
491 page_dir_calc_reserved_space(
492 /*=========================*/
493 	ulint	n_recs);	/*!< in: number of records */
494 /***************************************************************//**
495 Looks for the directory slot which owns the given record.
496 @return	the directory slot number */
497 UNIV_INTERN
498 ulint
499 page_dir_find_owner_slot(
500 /*=====================*/
501 	const rec_t*	rec);	/*!< in: the physical record */
502 /************************************************************//**
503 Determine whether the page is in new-style compact format.
504 @return nonzero if the page is in compact format, zero if it is in
505 old-style format */
506 UNIV_INLINE
507 ulint
508 page_is_comp(
509 /*=========*/
510 	const page_t*	page);	/*!< in: index page */
511 /************************************************************//**
512 TRUE if the record is on a page in compact format.
513 @return	nonzero if in compact format */
514 UNIV_INLINE
515 ulint
516 page_rec_is_comp(
517 /*=============*/
518 	const rec_t*	rec);	/*!< in: record */
519 /***************************************************************//**
520 Returns the heap number of a record.
521 @return	heap number */
522 UNIV_INLINE
523 ulint
524 page_rec_get_heap_no(
525 /*=================*/
526 	const rec_t*	rec);	/*!< in: the physical record */
527 /************************************************************//**
528 Determine whether the page is a B-tree leaf.
529 @return	true if the page is a B-tree leaf (PAGE_LEVEL = 0) */
530 UNIV_INLINE
531 bool
532 page_is_leaf(
533 /*=========*/
534 	const page_t*	page)	/*!< in: page */
535 	MY_ATTRIBUTE((nonnull, pure));
536 /************************************************************//**
537 Determine whether the page is empty.
538 @return	true if the page is empty (PAGE_N_RECS = 0) */
539 UNIV_INLINE
540 bool
541 page_is_empty(
542 /*==========*/
543 	const page_t*	page)	/*!< in: page */
544 	MY_ATTRIBUTE((nonnull, pure));
545 /************************************************************//**
546 Determine whether the page contains garbage.
547 @return	true if the page contains garbage (PAGE_GARBAGE is not 0) */
548 UNIV_INLINE
549 bool
550 page_has_garbage(
551 /*=============*/
552 	const page_t*	page)	/*!< in: page */
553 	MY_ATTRIBUTE((nonnull, pure));
554 /************************************************************//**
555 Gets the pointer to the next record on the page.
556 @return	pointer to next record */
557 UNIV_INLINE
558 const rec_t*
559 page_rec_get_next_low(
560 /*==================*/
561 	const rec_t*	rec,	/*!< in: pointer to record */
562 	ulint		comp);	/*!< in: nonzero=compact page layout */
563 /************************************************************//**
564 Gets the pointer to the next record on the page.
565 @return	pointer to next record */
566 UNIV_INLINE
567 rec_t*
568 page_rec_get_next(
569 /*==============*/
570 	rec_t*	rec);	/*!< in: pointer to record */
571 /************************************************************//**
572 Gets the pointer to the next record on the page.
573 @return	pointer to next record */
574 UNIV_INLINE
575 const rec_t*
576 page_rec_get_next_const(
577 /*====================*/
578 	const rec_t*	rec);	/*!< in: pointer to record */
579 /************************************************************//**
580 Gets the pointer to the next non delete-marked record on the page.
581 If all subsequent records are delete-marked, then this function
582 will return the supremum record.
583 @return	pointer to next non delete-marked record or pointer to supremum */
584 UNIV_INLINE
585 const rec_t*
586 page_rec_get_next_non_del_marked(
587 /*=============================*/
588 	const rec_t*	rec);	/*!< in: pointer to record */
589 /************************************************************//**
590 Sets the pointer to the next record on the page. */
591 UNIV_INLINE
592 void
593 page_rec_set_next(
594 /*==============*/
595 	rec_t*		rec,	/*!< in: pointer to record,
596 				must not be page supremum */
597 	const rec_t*	next);	/*!< in: pointer to next record,
598 				must not be page infimum */
599 /************************************************************//**
600 Gets the pointer to the previous record.
601 @return	pointer to previous record */
602 UNIV_INLINE
603 const rec_t*
604 page_rec_get_prev_const(
605 /*====================*/
606 	const rec_t*	rec);	/*!< in: pointer to record, must not be page
607 				infimum */
608 /************************************************************//**
609 Gets the pointer to the previous record.
610 @return	pointer to previous record */
611 UNIV_INLINE
612 rec_t*
613 page_rec_get_prev(
614 /*==============*/
615 	rec_t*		rec);	/*!< in: pointer to record,
616 				must not be page infimum */
617 /************************************************************//**
618 TRUE if the record is a user record on the page.
619 @return	TRUE if a user record */
620 UNIV_INLINE
621 ibool
622 page_rec_is_user_rec_low(
623 /*=====================*/
624 	ulint	offset)	/*!< in: record offset on page */
625 	MY_ATTRIBUTE((const));
626 /************************************************************//**
627 TRUE if the record is the supremum record on a page.
628 @return	TRUE if the supremum record */
629 UNIV_INLINE
630 ibool
631 page_rec_is_supremum_low(
632 /*=====================*/
633 	ulint	offset)	/*!< in: record offset on page */
634 	MY_ATTRIBUTE((const));
635 /************************************************************//**
636 TRUE if the record is the infimum record on a page.
637 @return	TRUE if the infimum record */
638 UNIV_INLINE
639 ibool
640 page_rec_is_infimum_low(
641 /*====================*/
642 	ulint	offset)	/*!< in: record offset on page */
643 	MY_ATTRIBUTE((const));
644 
645 /************************************************************//**
646 TRUE if the record is a user record on the page.
647 @return	TRUE if a user record */
648 UNIV_INLINE
649 ibool
650 page_rec_is_user_rec(
651 /*=================*/
652 	const rec_t*	rec)	/*!< in: record */
653 	MY_ATTRIBUTE((const));
654 /************************************************************//**
655 TRUE if the record is the supremum record on a page.
656 @return	TRUE if the supremum record */
657 UNIV_INLINE
658 ibool
659 page_rec_is_supremum(
660 /*=================*/
661 	const rec_t*	rec)	/*!< in: record */
662 	MY_ATTRIBUTE((const));
663 
664 /************************************************************//**
665 TRUE if the record is the infimum record on a page.
666 @return	TRUE if the infimum record */
667 UNIV_INLINE
668 ibool
669 page_rec_is_infimum(
670 /*================*/
671 	const rec_t*	rec)	/*!< in: record */
672 	MY_ATTRIBUTE((const));
673 /***************************************************************//**
674 Looks for the record which owns the given record.
675 @return	the owner record */
676 UNIV_INLINE
677 rec_t*
678 page_rec_find_owner_rec(
679 /*====================*/
680 	rec_t*	rec);	/*!< in: the physical record */
681 #ifndef UNIV_HOTBACKUP
682 /***********************************************************************//**
683 Write a 32-bit field in a data dictionary record. */
684 UNIV_INLINE
685 void
686 page_rec_write_field(
687 /*=================*/
688 	rec_t*	rec,	/*!< in/out: record to update */
689 	ulint	i,	/*!< in: index of the field to update */
690 	ulint	val,	/*!< in: value to write */
691 	mtr_t*	mtr)	/*!< in/out: mini-transaction */
692 	MY_ATTRIBUTE((nonnull));
693 #endif /* !UNIV_HOTBACKUP */
694 /************************************************************//**
695 Returns the maximum combined size of records which can be inserted on top
696 of record heap.
697 @return	maximum combined size for inserted records */
698 UNIV_INLINE
699 ulint
700 page_get_max_insert_size(
701 /*=====================*/
702 	const page_t*	page,	/*!< in: index page */
703 	ulint		n_recs);/*!< in: number of records */
704 /************************************************************//**
705 Returns the maximum combined size of records which can be inserted on top
706 of record heap if page is first reorganized.
707 @return	maximum combined size for inserted records */
708 UNIV_INLINE
709 ulint
710 page_get_max_insert_size_after_reorganize(
711 /*======================================*/
712 	const page_t*	page,	/*!< in: index page */
713 	ulint		n_recs);/*!< in: number of records */
714 /*************************************************************//**
715 Calculates free space if a page is emptied.
716 @return	free space */
717 UNIV_INLINE
718 ulint
719 page_get_free_space_of_empty(
720 /*=========================*/
721 	ulint	comp)	/*!< in: nonzero=compact page format */
722 		MY_ATTRIBUTE((const));
723 /**********************************************************//**
724 Returns the base extra size of a physical record.  This is the
725 size of the fixed header, independent of the record size.
726 @return	REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */
727 UNIV_INLINE
728 ulint
729 page_rec_get_base_extra_size(
730 /*=========================*/
731 	const rec_t*	rec);	/*!< in: physical record */
732 /************************************************************//**
733 Returns the sum of the sizes of the records in the record list
734 excluding the infimum and supremum records.
735 @return	data in bytes */
736 UNIV_INLINE
737 ulint
738 page_get_data_size(
739 /*===============*/
740 	const page_t*	page);	/*!< in: index page */
741 /************************************************************//**
742 Allocates a block of memory from the head of the free list
743 of an index page. */
744 UNIV_INLINE
745 void
746 page_mem_alloc_free(
747 /*================*/
748 	page_t*		page,	/*!< in/out: index page */
749 	page_zip_des_t*	page_zip,/*!< in/out: compressed page with enough
750 				space available for inserting the record,
751 				or NULL */
752 	rec_t*		next_rec,/*!< in: pointer to the new head of the
753 				free record list */
754 	ulint		need);	/*!< in: number of bytes allocated */
755 /************************************************************//**
756 Allocates a block of memory from the heap of an index page.
757 @return	pointer to start of allocated buffer, or NULL if allocation fails */
758 UNIV_INTERN
759 byte*
760 page_mem_alloc_heap(
761 /*================*/
762 	page_t*		page,	/*!< in/out: index page */
763 	page_zip_des_t*	page_zip,/*!< in/out: compressed page with enough
764 				space available for inserting the record,
765 				or NULL */
766 	ulint		need,	/*!< in: total number of bytes needed */
767 	ulint*		heap_no);/*!< out: this contains the heap number
768 				of the allocated record
769 				if allocation succeeds */
770 /************************************************************//**
771 Puts a record to free list. */
772 UNIV_INLINE
773 void
774 page_mem_free(
775 /*==========*/
776 	page_t*			page,	/*!< in/out: index page */
777 	page_zip_des_t*		page_zip,/*!< in/out: compressed page,
778 					 or NULL */
779 	rec_t*			rec,	/*!< in: pointer to the (origin of)
780 					record */
781 	const dict_index_t*	index,	/*!< in: index of rec */
782 	const ulint*		offsets);/*!< in: array returned by
783 					 rec_get_offsets() */
784 /**********************************************************//**
785 Create an uncompressed B-tree index page.
786 @return	pointer to the page */
787 UNIV_INTERN
788 page_t*
789 page_create(
790 /*========*/
791 	buf_block_t*	block,		/*!< in: a buffer block where the
792 					page is created */
793 	mtr_t*		mtr,		/*!< in: mini-transaction handle */
794 	ulint		comp);		/*!< in: nonzero=compact page format */
795 /**********************************************************//**
796 Create a compressed B-tree index page.
797 @return	pointer to the page */
798 UNIV_INTERN
799 page_t*
800 page_create_zip(
801 /*============*/
802 	buf_block_t*	block,		/*!< in/out: a buffer frame where the
803 					page is created */
804 	dict_index_t*	index,		/*!< in: the index of the page */
805 	ulint		level,		/*!< in: the B-tree level of the page */
806 	trx_id_t	max_trx_id,	/*!< in: PAGE_MAX_TRX_ID */
807 	mtr_t*		mtr)		/*!< in/out: mini-transaction */
808 	MY_ATTRIBUTE((nonnull));
809 /**********************************************************//**
810 Empty a previously created B-tree index page. */
811 UNIV_INTERN
812 void
813 page_create_empty(
814 /*==============*/
815 	buf_block_t*	block,	/*!< in/out: B-tree block */
816 	dict_index_t*	index,	/*!< in: the index of the page */
817 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
818 	MY_ATTRIBUTE((nonnull(1,2)));
819 /*************************************************************//**
820 Differs from page_copy_rec_list_end, because this function does not
821 touch the lock table and max trx id on page or compress the page.
822 
823 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
824 if new_block is a compressed leaf page in a secondary index.
825 This has to be done either within the same mini-transaction,
826 or by invoking ibuf_reset_free_bits() before mtr_commit(). */
827 UNIV_INTERN
828 void
829 page_copy_rec_list_end_no_locks(
830 /*============================*/
831 	buf_block_t*	new_block,	/*!< in: index page to copy to */
832 	buf_block_t*	block,		/*!< in: index page of rec */
833 	rec_t*		rec,		/*!< in: record on page */
834 	dict_index_t*	index,		/*!< in: record descriptor */
835 	mtr_t*		mtr);		/*!< in: mtr */
836 /*************************************************************//**
837 Copies records from page to new_page, from the given record onward,
838 including that record. Infimum and supremum records are not copied.
839 The records are copied to the start of the record list on new_page.
840 
841 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
842 if new_block is a compressed leaf page in a secondary index.
843 This has to be done either within the same mini-transaction,
844 or by invoking ibuf_reset_free_bits() before mtr_commit().
845 
846 @return pointer to the original successor of the infimum record on
847 new_page, or NULL on zip overflow (new_block will be decompressed) */
848 UNIV_INTERN
849 rec_t*
850 page_copy_rec_list_end(
851 /*===================*/
852 	buf_block_t*	new_block,	/*!< in/out: index page to copy to */
853 	buf_block_t*	block,		/*!< in: index page containing rec */
854 	rec_t*		rec,		/*!< in: record on page */
855 	dict_index_t*	index,		/*!< in: record descriptor */
856 	mtr_t*		mtr)		/*!< in: mtr */
857 	MY_ATTRIBUTE((nonnull));
858 /*************************************************************//**
859 Copies records from page to new_page, up to the given record, NOT
860 including that record. Infimum and supremum records are not copied.
861 The records are copied to the end of the record list on new_page.
862 
863 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
864 if new_block is a compressed leaf page in a secondary index.
865 This has to be done either within the same mini-transaction,
866 or by invoking ibuf_reset_free_bits() before mtr_commit().
867 
868 @return pointer to the original predecessor of the supremum record on
869 new_page, or NULL on zip overflow (new_block will be decompressed) */
870 UNIV_INTERN
871 rec_t*
872 page_copy_rec_list_start(
873 /*=====================*/
874 	buf_block_t*	new_block,	/*!< in/out: index page to copy to */
875 	buf_block_t*	block,		/*!< in: index page containing rec */
876 	rec_t*		rec,		/*!< in: record on page */
877 	dict_index_t*	index,		/*!< in: record descriptor */
878 	mtr_t*		mtr)		/*!< in: mtr */
879 	MY_ATTRIBUTE((nonnull));
880 /*************************************************************//**
881 Deletes records from a page from a given record onward, including that record.
882 The infimum and supremum records are not deleted. */
883 UNIV_INTERN
884 void
885 page_delete_rec_list_end(
886 /*=====================*/
887 	rec_t*		rec,	/*!< in: pointer to record on page */
888 	buf_block_t*	block,	/*!< in: buffer block of the page */
889 	dict_index_t*	index,	/*!< in: record descriptor */
890 	ulint		n_recs,	/*!< in: number of records to delete,
891 				or ULINT_UNDEFINED if not known */
892 	ulint		size,	/*!< in: the sum of the sizes of the
893 				records in the end of the chain to
894 				delete, or ULINT_UNDEFINED if not known */
895 	mtr_t*		mtr)	/*!< in: mtr */
896 	MY_ATTRIBUTE((nonnull));
897 /*************************************************************//**
898 Deletes records from page, up to the given record, NOT including
899 that record. Infimum and supremum records are not deleted. */
900 UNIV_INTERN
901 void
902 page_delete_rec_list_start(
903 /*=======================*/
904 	rec_t*		rec,	/*!< in: record on page */
905 	buf_block_t*	block,	/*!< in: buffer block of the page */
906 	dict_index_t*	index,	/*!< in: record descriptor */
907 	mtr_t*		mtr)	/*!< in: mtr */
908 	MY_ATTRIBUTE((nonnull));
909 /*************************************************************//**
910 Moves record list end to another page. Moved records include
911 split_rec.
912 
913 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
914 if new_block is a compressed leaf page in a secondary index.
915 This has to be done either within the same mini-transaction,
916 or by invoking ibuf_reset_free_bits() before mtr_commit().
917 
918 @return TRUE on success; FALSE on compression failure (new_block will
919 be decompressed) */
920 UNIV_INTERN
921 ibool
922 page_move_rec_list_end(
923 /*===================*/
924 	buf_block_t*	new_block,	/*!< in/out: index page where to move */
925 	buf_block_t*	block,		/*!< in: index page from where to move */
926 	rec_t*		split_rec,	/*!< in: first record to move */
927 	dict_index_t*	index,		/*!< in: record descriptor */
928 	mtr_t*		mtr)		/*!< in: mtr */
929 	MY_ATTRIBUTE((nonnull(1, 2, 4, 5)));
930 /*************************************************************//**
931 Moves record list start to another page. Moved records do not include
932 split_rec.
933 
934 IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
935 if new_block is a compressed leaf page in a secondary index.
936 This has to be done either within the same mini-transaction,
937 or by invoking ibuf_reset_free_bits() before mtr_commit().
938 
939 @return	TRUE on success; FALSE on compression failure */
940 UNIV_INTERN
941 ibool
942 page_move_rec_list_start(
943 /*=====================*/
944 	buf_block_t*	new_block,	/*!< in/out: index page where to move */
945 	buf_block_t*	block,		/*!< in/out: page containing split_rec */
946 	rec_t*		split_rec,	/*!< in: first record not to move */
947 	dict_index_t*	index,		/*!< in: record descriptor */
948 	mtr_t*		mtr)		/*!< in: mtr */
949 	MY_ATTRIBUTE((nonnull(1, 2, 4, 5)));
950 /****************************************************************//**
951 Splits a directory slot which owns too many records. */
952 UNIV_INTERN
953 void
954 page_dir_split_slot(
955 /*================*/
956 	page_t*		page,	/*!< in: index page */
957 	page_zip_des_t*	page_zip,/*!< in/out: compressed page whose
958 				uncompressed part will be written, or NULL */
959 	ulint		slot_no)/*!< in: the directory slot */
960 	MY_ATTRIBUTE((nonnull(1)));
961 /*************************************************************//**
962 Tries to balance the given directory slot with too few records
963 with the upper neighbor, so that there are at least the minimum number
964 of records owned by the slot; this may result in the merging of
965 two slots. */
966 UNIV_INTERN
967 void
968 page_dir_balance_slot(
969 /*==================*/
970 	page_t*		page,	/*!< in/out: index page */
971 	page_zip_des_t*	page_zip,/*!< in/out: compressed page, or NULL */
972 	ulint		slot_no)/*!< in: the directory slot */
973 	MY_ATTRIBUTE((nonnull(1)));
974 /**********************************************************//**
975 Parses a log record of a record list end or start deletion.
976 @return	end of log record or NULL */
977 UNIV_INTERN
978 byte*
979 page_parse_delete_rec_list(
980 /*=======================*/
981 	byte		type,	/*!< in: MLOG_LIST_END_DELETE,
982 				MLOG_LIST_START_DELETE,
983 				MLOG_COMP_LIST_END_DELETE or
984 				MLOG_COMP_LIST_START_DELETE */
985 	byte*		ptr,	/*!< in: buffer */
986 	byte*		end_ptr,/*!< in: buffer end */
987 	buf_block_t*	block,	/*!< in/out: buffer block or NULL */
988 	dict_index_t*	index,	/*!< in: record descriptor */
989 	mtr_t*		mtr);	/*!< in: mtr or NULL */
990 /***********************************************************//**
991 Parses a redo log record of creating a page.
992 @return	end of log record or NULL */
993 UNIV_INTERN
994 byte*
995 page_parse_create(
996 /*==============*/
997 	byte*		ptr,	/*!< in: buffer */
998 	byte*		end_ptr,/*!< in: buffer end */
999 	ulint		comp,	/*!< in: nonzero=compact page format */
1000 	buf_block_t*	block,	/*!< in: block or NULL */
1001 	mtr_t*		mtr);	/*!< in: mtr or NULL */
1002 #ifndef UNIV_HOTBACKUP
1003 /************************************************************//**
1004 Prints record contents including the data relevant only in
1005 the index page context. */
1006 UNIV_INTERN
1007 void
1008 page_rec_print(
1009 /*===========*/
1010 	const rec_t*	rec,	/*!< in: physical record */
1011 	const ulint*	offsets);/*!< in: record descriptor */
1012 # ifdef UNIV_BTR_PRINT
1013 /***************************************************************//**
1014 This is used to print the contents of the directory for
1015 debugging purposes. */
1016 UNIV_INTERN
1017 void
1018 page_dir_print(
1019 /*===========*/
1020 	page_t*	page,	/*!< in: index page */
1021 	ulint	pr_n);	/*!< in: print n first and n last entries */
1022 /***************************************************************//**
1023 This is used to print the contents of the page record list for
1024 debugging purposes. */
1025 UNIV_INTERN
1026 void
1027 page_print_list(
1028 /*============*/
1029 	buf_block_t*	block,	/*!< in: index page */
1030 	dict_index_t*	index,	/*!< in: dictionary index of the page */
1031 	ulint		pr_n);	/*!< in: print n first and n last entries */
1032 /***************************************************************//**
1033 Prints the info in a page header. */
1034 UNIV_INTERN
1035 void
1036 page_header_print(
1037 /*==============*/
1038 	const page_t*	page);	/*!< in: index page */
1039 /***************************************************************//**
1040 This is used to print the contents of the page for
1041 debugging purposes. */
1042 UNIV_INTERN
1043 void
1044 page_print(
1045 /*=======*/
1046 	buf_block_t*	block,	/*!< in: index page */
1047 	dict_index_t*	index,	/*!< in: dictionary index of the page */
1048 	ulint		dn,	/*!< in: print dn first and last entries
1049 				in directory */
1050 	ulint		rn);	/*!< in: print rn first and last records
1051 				in directory */
1052 # endif /* UNIV_BTR_PRINT */
1053 #endif /* !UNIV_HOTBACKUP */
1054 /***************************************************************//**
1055 The following is used to validate a record on a page. This function
1056 differs from rec_validate as it can also check the n_owned field and
1057 the heap_no field.
1058 @return	TRUE if ok */
1059 UNIV_INTERN
1060 ibool
1061 page_rec_validate(
1062 /*==============*/
1063 	const rec_t*	rec,	/*!< in: physical record */
1064 	const ulint*	offsets);/*!< in: array returned by rec_get_offsets() */
1065 /***************************************************************//**
1066 Checks that the first directory slot points to the infimum record and
1067 the last to the supremum. This function is intended to track if the
1068 bug fixed in 4.0.14 has caused corruption to users' databases. */
1069 UNIV_INTERN
1070 void
1071 page_check_dir(
1072 /*===========*/
1073 	const page_t*	page);	/*!< in: index page */
1074 /***************************************************************//**
1075 This function checks the consistency of an index page when we do not
1076 know the index. This is also resilient so that this should never crash
1077 even if the page is total garbage.
1078 @return	TRUE if ok */
1079 UNIV_INTERN
1080 ibool
1081 page_simple_validate_old(
1082 /*=====================*/
1083 	const page_t*	page);	/*!< in: index page in ROW_FORMAT=REDUNDANT */
1084 /***************************************************************//**
1085 This function checks the consistency of an index page when we do not
1086 know the index. This is also resilient so that this should never crash
1087 even if the page is total garbage.
1088 @return	TRUE if ok */
1089 UNIV_INTERN
1090 ibool
1091 page_simple_validate_new(
1092 /*=====================*/
1093 	const page_t*	page);	/*!< in: index page in ROW_FORMAT!=REDUNDANT */
1094 /***************************************************************//**
1095 This function checks the consistency of an index page.
1096 @return	TRUE if ok */
1097 UNIV_INTERN
1098 ibool
1099 page_validate(
1100 /*==========*/
1101 	const page_t*	page,	/*!< in: index page */
1102 	dict_index_t*	index);	/*!< in: data dictionary index containing
1103 				the page record type definition */
1104 /***************************************************************//**
1105 Looks in the page record list for a record with the given heap number.
1106 @return	record, NULL if not found */
1107 
1108 const rec_t*
1109 page_find_rec_with_heap_no(
1110 /*=======================*/
1111 	const page_t*	page,	/*!< in: index page */
1112 	ulint		heap_no);/*!< in: heap number */
1113 /** Get the last non-delete-marked record on a page.
1114 @param[in]	page	index tree leaf page
1115 @return the last record, not delete-marked
1116 @retval infimum record if all records are delete-marked */
1117 
1118 const rec_t*
1119 page_find_rec_max_not_deleted(
1120 	const page_t*	page);
1121 
1122 /** Issue a warning when the checksum that is stored in the page is valid,
1123 but different than the global setting innodb_checksum_algorithm.
1124 @param[in]	current_algo	current checksum algorithm
1125 @param[in]	page_checksum	page valid checksum
1126 @param[in]	space_id	tablespace id
1127 @param[in]	page_no		page number */
1128 void
1129 page_warn_strict_checksum(
1130 	srv_checksum_algorithm_t	curr_algo,
1131 	srv_checksum_algorithm_t	page_checksum,
1132 	ulint				space_id,
1133 	ulint				page_no);
1134 
1135 #ifdef UNIV_MATERIALIZE
1136 #undef UNIV_INLINE
1137 #define UNIV_INLINE  UNIV_INLINE_ORIGINAL
1138 #endif
1139 
1140 #ifndef UNIV_NONINL
1141 #include "page0page.ic"
1142 #endif
1143 
1144 #endif
1145