1
/******************************************************
4
(c) 1994-1996 Innobase Oy
6
Created 2/2/1994 Heikki Tuuri
7
*******************************************************/
14
#include "page0types.h"
17
#include "data0data.h"
18
#include "dict0dict.h"
23
#ifdef UNIV_MATERIALIZE
31
Index page header starts at the first offset left free by the FIL-module */
33
typedef byte page_header_t;
35
#define PAGE_HEADER FSEG_PAGE_DATA /* index page header starts at this
37
/*-----------------------------*/
38
#define PAGE_N_DIR_SLOTS 0 /* number of slots in page directory */
39
#define PAGE_HEAP_TOP 2 /* pointer to record heap top */
40
#define PAGE_N_HEAP 4 /* number of records in the heap,
41
bit 15=flag: new-style compact page format */
42
#define PAGE_FREE 6 /* pointer to start of page free record list */
43
#define PAGE_GARBAGE 8 /* number of bytes in deleted records */
44
#define PAGE_LAST_INSERT 10 /* pointer to the last inserted record, or
45
NULL if this info has been reset by a delete,
47
#define PAGE_DIRECTION 12 /* last insert direction: PAGE_LEFT, ... */
48
#define PAGE_N_DIRECTION 14 /* number of consecutive inserts to the same
50
#define PAGE_N_RECS 16 /* number of user records on the page */
51
#define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified
52
a record on the page; a dulint; defined only
53
in secondary indexes; specifically, not in an
54
ibuf tree; NOTE: this may be modified only
55
when the thread has an x-latch to the page,
56
and ALSO an x-latch to btr_search_latch
57
if there is a hash index to the page! */
58
#define PAGE_HEADER_PRIV_END 26 /* end of private data structure of the page
59
header which are set in a page create */
61
#define PAGE_LEVEL 26 /* level of the node in an index tree; the
62
leaf level is the level 0 */
63
#define PAGE_INDEX_ID 28 /* index id where the page belongs */
64
#define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in
65
a B-tree: defined only on the root page of a
66
B-tree, but not in the root of an ibuf tree */
67
#define PAGE_BTR_IBUF_FREE_LIST PAGE_BTR_SEG_LEAF
68
#define PAGE_BTR_IBUF_FREE_LIST_NODE PAGE_BTR_SEG_LEAF
69
/* in the place of PAGE_BTR_SEG_LEAF and _TOP
70
there is a free list base node if the page is
71
the root page of an ibuf tree, and at the same
72
place is the free list node if the page is in
74
#define PAGE_BTR_SEG_TOP (36 + FSEG_HEADER_SIZE)
75
/* file segment header for the non-leaf pages
76
in a B-tree: defined only on the root page of
77
a B-tree, but not in the root of an ibuf
80
#define PAGE_DATA (PAGE_HEADER + 36 + 2 * FSEG_HEADER_SIZE)
81
/* start of data on the page */
83
#define PAGE_OLD_INFIMUM (PAGE_DATA + 1 + REC_N_OLD_EXTRA_BYTES)
84
/* offset of the page infimum record on an
86
#define PAGE_OLD_SUPREMUM (PAGE_DATA + 2 + 2 * REC_N_OLD_EXTRA_BYTES + 8)
87
/* offset of the page supremum record on an
89
#define PAGE_OLD_SUPREMUM_END (PAGE_OLD_SUPREMUM + 9)
90
/* offset of the page supremum record end on
92
#define PAGE_NEW_INFIMUM (PAGE_DATA + REC_N_NEW_EXTRA_BYTES)
93
/* offset of the page infimum record on a
94
new-style compact page */
95
#define PAGE_NEW_SUPREMUM (PAGE_DATA + 2 * REC_N_NEW_EXTRA_BYTES + 8)
96
/* offset of the page supremum record on a
97
new-style compact page */
98
#define PAGE_NEW_SUPREMUM_END (PAGE_NEW_SUPREMUM + 8)
99
/* offset of the page supremum record end on
100
a new-style compact page */
101
/*-----------------------------*/
103
/* Directions of cursor movement */
106
#define PAGE_SAME_REC 3
107
#define PAGE_SAME_PAGE 4
108
#define PAGE_NO_DIRECTION 5
114
typedef byte page_dir_slot_t;
115
typedef page_dir_slot_t page_dir_t;
117
/* Offset of the directory start down from the page end. We call the
118
slot with the highest file address directory start, as it points to
119
the first record in the list of records. */
120
#define PAGE_DIR FIL_PAGE_DATA_END
122
/* We define a slot in the page directory as two bytes */
123
#define PAGE_DIR_SLOT_SIZE 2
125
/* The offset of the physically lower end of the directory, counted from
126
page end, when the page is empty */
127
#define PAGE_EMPTY_DIR_START (PAGE_DIR + 2 * PAGE_DIR_SLOT_SIZE)
129
/* The maximum and minimum number of records owned by a directory slot. The
130
number may drop below the minimum in the first and the last slot in the
132
#define PAGE_DIR_SLOT_MAX_N_OWNED 8
133
#define PAGE_DIR_SLOT_MIN_N_OWNED 4
135
/****************************************************************
136
Gets the start of a page. */
141
/* out: start of the page */
142
const void* ptr) /* in: pointer to page frame */
143
__attribute__((const));
144
/****************************************************************
145
Gets the offset within a page. */
150
/* out: offset from the start of the page */
151
const void* ptr) /* in: pointer to page frame */
152
__attribute__((const));
153
/*****************************************************************
154
Returns the max trx id field value. */
159
page_t* page); /* in: page */
160
/*****************************************************************
161
Sets the max trx id field value. */
166
page_t* page, /* in: page */
167
dulint trx_id);/* in: transaction id */
168
/*****************************************************************
169
Sets the max trx id field value if trx_id is bigger than the previous
173
page_update_max_trx_id(
174
/*===================*/
175
page_t* page, /* in: page */
176
dulint trx_id); /* in: transaction id */
177
/*****************************************************************
178
Reads the given header field. */
181
page_header_get_field(
182
/*==================*/
183
page_t* page, /* in: page */
184
ulint field); /* in: PAGE_N_DIR_SLOTS, ... */
185
/*****************************************************************
186
Sets the given header field. */
189
page_header_set_field(
190
/*==================*/
191
page_t* page, /* in: page */
192
ulint field, /* in: PAGE_N_DIR_SLOTS, ... */
193
ulint val); /* in: value */
194
/*****************************************************************
195
Returns the pointer stored in the given header field. */
200
/* out: pointer or NULL */
201
page_t* page, /* in: page */
202
ulint field); /* in: PAGE_FREE, ... */
203
/*****************************************************************
204
Sets the pointer stored in the given header field. */
209
page_t* page, /* in: page */
210
ulint field, /* in: PAGE_FREE, ... */
211
byte* ptr); /* in: pointer or NULL*/
212
/*****************************************************************
213
Resets the last insert info field in the page header. Writes to mlog
214
about this operation. */
217
page_header_reset_last_insert(
218
/*==========================*/
219
page_t* page, /* in: page */
220
mtr_t* mtr); /* in: mtr */
221
/****************************************************************
222
Gets the first record on the page. */
225
page_get_infimum_rec(
226
/*=================*/
227
/* out: the first record in record list */
228
page_t* page); /* in: page which must have record(s) */
229
/****************************************************************
230
Gets the last record on the page. */
233
page_get_supremum_rec(
234
/*==================*/
235
/* out: the last record in record list */
236
page_t* page); /* in: page which must have record(s) */
237
/****************************************************************
238
Returns the middle record of record list. If there are an even number
239
of records in the list, returns the first record of upper half-list. */
244
/* out: middle record */
245
page_t* page); /* in: page */
246
/*****************************************************************
247
Compares a data tuple to a physical record. Differs from the function
248
cmp_dtuple_rec_with_match in the way that the record must reside on an
249
index page, and also page infimum and supremum records can be given in
250
the parameter rec. These are considered as the negative infinity and
251
the positive infinity in the alphabetical order. */
254
page_cmp_dtuple_rec_with_match(
255
/*===========================*/
256
/* out: 1, 0, -1, if dtuple is greater, equal,
257
less than rec, respectively, when only the
258
common first fields are compared */
259
dtuple_t* dtuple, /* in: data tuple */
260
rec_t* rec, /* in: physical record on a page; may also
261
be page infimum or supremum, in which case
262
matched-parameter values below are not
264
const ulint* offsets,/* in: array returned by rec_get_offsets() */
265
ulint* matched_fields, /* in/out: number of already completely
266
matched fields; when function returns
267
contains the value for current comparison */
268
ulint* matched_bytes); /* in/out: number of already matched
269
bytes within the first field not completely
270
matched; when function returns contains the
271
value for current comparison */
272
/*****************************************************************
273
Gets the number of user records on page (the infimum and supremum records
274
are not user records). */
279
/* out: number of user records */
280
page_t* page); /* in: index page */
281
/*******************************************************************
282
Returns the number of records before the given record in chain.
283
The number includes infimum and supremum records. */
286
page_rec_get_n_recs_before(
287
/*=======================*/
288
/* out: number of records */
289
rec_t* rec); /* in: the physical record */
290
/*****************************************************************
291
Gets the number of records in the heap. */
296
/* out: number of user records */
297
page_t* page); /* in: index page */
298
/*****************************************************************
299
Sets the number of records in the heap. */
304
page_t* page, /* in: index page */
305
ulint n_heap);/* in: number of records */
306
/*****************************************************************
307
Gets the number of dir slots in directory. */
310
page_dir_get_n_slots(
311
/*=================*/
312
/* out: number of slots */
313
page_t* page); /* in: index page */
314
/*****************************************************************
315
Sets the number of dir slots in directory. */
318
page_dir_set_n_slots(
319
/*=================*/
320
/* out: number of slots */
321
page_t* page, /* in: index page */
322
ulint n_slots);/* in: number of slots */
323
/*****************************************************************
324
Gets pointer to nth directory slot. */
327
page_dir_get_nth_slot(
328
/*==================*/
329
/* out: pointer to dir slot */
330
page_t* page, /* in: index page */
331
ulint n); /* in: position */
332
/******************************************************************
333
Used to check the consistency of a record on a page. */
338
/* out: TRUE if succeed */
339
rec_t* rec); /* in: record */
340
/*******************************************************************
341
Gets the record pointed to by a directory slot. */
344
page_dir_slot_get_rec(
345
/*==================*/
346
/* out: pointer to record */
347
page_dir_slot_t* slot); /* in: directory slot */
348
/*******************************************************************
349
This is used to set the record offset in a directory slot. */
352
page_dir_slot_set_rec(
353
/*==================*/
354
page_dir_slot_t* slot, /* in: directory slot */
355
rec_t* rec); /* in: record on the page */
356
/*******************************************************************
357
Gets the number of records owned by a directory slot. */
360
page_dir_slot_get_n_owned(
361
/*======================*/
362
/* out: number of records */
363
page_dir_slot_t* slot); /* in: page directory slot */
364
/*******************************************************************
365
This is used to set the owned records field of a directory slot. */
368
page_dir_slot_set_n_owned(
369
/*======================*/
370
page_dir_slot_t* slot, /* in: directory slot */
371
ulint n); /* in: number of records owned
373
/****************************************************************
374
Calculates the space reserved for directory slots of a given
375
number of records. The exact value is a fraction number
376
n * PAGE_DIR_SLOT_SIZE / PAGE_DIR_SLOT_MIN_N_OWNED, and it is
377
rounded upwards to an integer. */
380
page_dir_calc_reserved_space(
381
/*=========================*/
382
ulint n_recs); /* in: number of records */
383
/*******************************************************************
384
Looks for the directory slot which owns the given record. */
387
page_dir_find_owner_slot(
388
/*=====================*/
389
/* out: the directory slot number */
390
rec_t* rec); /* in: the physical record */
391
/****************************************************************
392
Determine whether the page is in new-style compact format. */
397
/* out: nonzero if the page is in compact
398
format, zero if it is in old-style format */
399
page_t* page); /* in: index page */
400
/****************************************************************
401
TRUE if the record is on a page in compact format. */
406
/* out: nonzero if in compact format */
407
const rec_t* rec); /* in: record */
408
/****************************************************************
409
Gets the pointer to the next record on the page. */
414
/* out: pointer to next record */
415
rec_t* rec); /* in: pointer to record, must not be page
417
/****************************************************************
418
Sets the pointer to the next record on the page. */
423
rec_t* rec, /* in: pointer to record, must not be
425
rec_t* next); /* in: pointer to next record, must not
427
/****************************************************************
428
Gets the pointer to the previous record. */
433
/* out: pointer to previous record */
434
rec_t* rec); /* in: pointer to record,
435
must not be page infimum */
436
/****************************************************************
437
TRUE if the record is a user record on the page. */
440
page_rec_is_user_rec_low(
441
/*=====================*/
442
/* out: TRUE if a user record */
443
ulint offset);/* in: record offset on page */
444
/****************************************************************
445
TRUE if the record is the supremum record on a page. */
448
page_rec_is_supremum_low(
449
/*=====================*/
450
/* out: TRUE if the supremum record */
451
ulint offset);/* in: record offset on page */
452
/****************************************************************
453
TRUE if the record is the infimum record on a page. */
456
page_rec_is_infimum_low(
457
/*====================*/
458
/* out: TRUE if the infimum record */
459
ulint offset);/* in: record offset on page */
461
/****************************************************************
462
TRUE if the record is a user record on the page. */
465
page_rec_is_user_rec(
466
/*=================*/
467
/* out: TRUE if a user record */
468
const rec_t* rec); /* in: record */
469
/****************************************************************
470
TRUE if the record is the supremum record on a page. */
473
page_rec_is_supremum(
474
/*=================*/
475
/* out: TRUE if the supremum record */
476
const rec_t* rec); /* in: record */
477
/****************************************************************
478
TRUE if the record is the infimum record on a page. */
483
/* out: TRUE if the infimum record */
484
const rec_t* rec); /* in: record */
485
/*******************************************************************
486
Looks for the record which owns the given record. */
489
page_rec_find_owner_rec(
490
/*====================*/
491
/* out: the owner record */
492
rec_t* rec); /* in: the physical record */
493
/***************************************************************************
494
This is a low-level operation which is used in a database index creation
495
to update the page number of a created B-tree to a data dictionary
499
page_rec_write_index_page_no(
500
/*=========================*/
501
rec_t* rec, /* in: record to update */
502
ulint i, /* in: index of the field to update */
503
ulint page_no,/* in: value to write */
504
mtr_t* mtr); /* in: mtr */
505
/****************************************************************
506
Returns the maximum combined size of records which can be inserted on top
510
page_get_max_insert_size(
511
/*=====================*/
512
/* out: maximum combined size for inserted records */
513
page_t* page, /* in: index page */
514
ulint n_recs); /* in: number of records */
515
/****************************************************************
516
Returns the maximum combined size of records which can be inserted on top
517
of record heap if page is first reorganized. */
520
page_get_max_insert_size_after_reorganize(
521
/*======================================*/
522
/* out: maximum combined size for inserted records */
523
page_t* page, /* in: index page */
524
ulint n_recs);/* in: number of records */
525
/*****************************************************************
526
Calculates free space if a page is emptied. */
529
page_get_free_space_of_empty(
530
/*=========================*/
531
/* out: free space */
532
ulint comp) /* in: nonzero=compact page format */
533
__attribute__((const));
534
/*****************************************************************
535
Calculates free space if a page is emptied. */
538
page_get_free_space_of_empty_noninline(
539
/*===================================*/
540
/* out: free space */
541
ulint comp) /* in: nonzero=compact page format */
542
__attribute__((const));
543
/****************************************************************
544
Returns the sum of the sizes of the records in the record list
545
excluding the infimum and supremum records. */
550
/* out: data in bytes */
551
page_t* page); /* in: index page */
552
/****************************************************************
553
Allocates a block of memory from an index page. */
558
/* out: pointer to start of allocated
559
buffer, or NULL if allocation fails */
560
page_t* page, /* in: index page */
561
ulint need, /* in: number of bytes needed */
562
dict_index_t* index, /* in: record descriptor */
563
ulint* heap_no);/* out: this contains the heap number
564
of the allocated record
565
if allocation succeeds */
566
/****************************************************************
567
Puts a record to free list. */
572
page_t* page, /* in: index page */
573
rec_t* rec, /* in: pointer to the (origin of) record */
574
const ulint* offsets);/* in: array returned by rec_get_offsets() */
575
/**************************************************************
576
The index page creation function. */
581
/* out: pointer to the page */
582
buf_frame_t* frame, /* in: a buffer frame where the page is
584
mtr_t* mtr, /* in: mini-transaction handle */
585
ulint comp); /* in: nonzero=compact page format */
586
/*****************************************************************
587
Differs from page_copy_rec_list_end, because this function does not
588
touch the lock table and max trx id on page. */
591
page_copy_rec_list_end_no_locks(
592
/*============================*/
593
page_t* new_page, /* in: index page to copy to */
594
page_t* page, /* in: index page */
595
rec_t* rec, /* in: record on page */
596
dict_index_t* index, /* in: record descriptor */
597
mtr_t* mtr); /* in: mtr */
598
/*****************************************************************
599
Copies records from page to new_page, from the given record onward,
600
including that record. Infimum and supremum records are not copied.
601
The records are copied to the start of the record list on new_page. */
604
page_copy_rec_list_end(
605
/*===================*/
606
page_t* new_page, /* in: index page to copy to */
607
page_t* page, /* in: index page */
608
rec_t* rec, /* in: record on page */
609
dict_index_t* index, /* in: record descriptor */
610
mtr_t* mtr); /* in: mtr */
611
/*****************************************************************
612
Copies records from page to new_page, up to the given record, NOT
613
including that record. Infimum and supremum records are not copied.
614
The records are copied to the end of the record list on new_page. */
617
page_copy_rec_list_start(
618
/*=====================*/
619
page_t* new_page, /* in: index page to copy to */
620
page_t* page, /* in: index page */
621
rec_t* rec, /* in: record on page */
622
dict_index_t* index, /* in: record descriptor */
623
mtr_t* mtr); /* in: mtr */
624
/*****************************************************************
625
Deletes records from a page from a given record onward, including that record.
626
The infimum and supremum records are not deleted. */
629
page_delete_rec_list_end(
630
/*=====================*/
631
page_t* page, /* in: index page */
632
rec_t* rec, /* in: record on page */
633
dict_index_t* index, /* in: record descriptor */
634
ulint n_recs, /* in: number of records to delete,
635
or ULINT_UNDEFINED if not known */
636
ulint size, /* in: the sum of the sizes of the
637
records in the end of the chain to
638
delete, or ULINT_UNDEFINED if not known */
639
mtr_t* mtr); /* in: mtr */
640
/*****************************************************************
641
Deletes records from page, up to the given record, NOT including
642
that record. Infimum and supremum records are not deleted. */
645
page_delete_rec_list_start(
646
/*=======================*/
647
page_t* page, /* in: index page */
648
rec_t* rec, /* in: record on page */
649
dict_index_t* index, /* in: record descriptor */
650
mtr_t* mtr); /* in: mtr */
651
/*****************************************************************
652
Moves record list end to another page. Moved records include
656
page_move_rec_list_end(
657
/*===================*/
658
page_t* new_page, /* in: index page where to move */
659
page_t* page, /* in: index page */
660
rec_t* split_rec, /* in: first record to move */
661
dict_index_t* index, /* in: record descriptor */
662
mtr_t* mtr); /* in: mtr */
663
/*****************************************************************
664
Moves record list start to another page. Moved records do not include
668
page_move_rec_list_start(
669
/*=====================*/
670
page_t* new_page, /* in: index page where to move */
671
page_t* page, /* in: index page */
672
rec_t* split_rec, /* in: first record not to move */
673
dict_index_t* index, /* in: record descriptor */
674
mtr_t* mtr); /* in: mtr */
675
/********************************************************************
676
Splits a directory slot which owns too many records. */
681
page_t* page, /* in: the index page in question */
682
ulint slot_no); /* in: the directory slot */
683
/*****************************************************************
684
Tries to balance the given directory slot with too few records
685
with the upper neighbor, so that there are at least the minimum number
686
of records owned by the slot; this may result in the merging of
690
page_dir_balance_slot(
691
/*==================*/
692
page_t* page, /* in: index page */
693
ulint slot_no); /* in: the directory slot */
694
/**************************************************************
695
Parses a log record of a record list end or start deletion. */
698
page_parse_delete_rec_list(
699
/*=======================*/
700
/* out: end of log record or NULL */
701
byte type, /* in: MLOG_LIST_END_DELETE,
702
MLOG_LIST_START_DELETE,
703
MLOG_COMP_LIST_END_DELETE or
704
MLOG_COMP_LIST_START_DELETE */
705
byte* ptr, /* in: buffer */
706
byte* end_ptr,/* in: buffer end */
707
dict_index_t* index, /* in: record descriptor */
708
page_t* page, /* in: page or NULL */
709
mtr_t* mtr); /* in: mtr or NULL */
710
/***************************************************************
711
Parses a redo log record of creating a page. */
716
/* out: end of log record or NULL */
717
byte* ptr, /* in: buffer */
718
byte* end_ptr,/* in: buffer end */
719
ulint comp, /* in: nonzero=compact page format */
720
page_t* page, /* in: page or NULL */
721
mtr_t* mtr); /* in: mtr or NULL */
722
/****************************************************************
723
Prints record contents including the data relevant only in
724
the index page context. */
729
rec_t* rec, /* in: physical record */
730
const ulint* offsets);/* in: record descriptor */
731
/*******************************************************************
732
This is used to print the contents of the directory for
733
debugging purposes. */
738
page_t* page, /* in: index page */
739
ulint pr_n); /* in: print n first and n last entries */
740
/*******************************************************************
741
This is used to print the contents of the page record list for
742
debugging purposes. */
747
page_t* page, /* in: index page */
748
dict_index_t* index, /* in: dictionary index of the page */
749
ulint pr_n); /* in: print n first and n last entries */
750
/*******************************************************************
751
Prints the info in a page header. */
757
/*******************************************************************
758
This is used to print the contents of the page for
759
debugging purposes. */
764
page_t* page, /* in: index page */
765
dict_index_t* index, /* in: dictionary index of the page */
766
ulint dn, /* in: print dn first and last entries
768
ulint rn); /* in: print rn first and last records
770
/*******************************************************************
771
The following is used to validate a record on a page. This function
772
differs from rec_validate as it can also check the n_owned field and
773
the heap_no field. */
778
/* out: TRUE if ok */
779
rec_t* rec, /* in: physical record */
780
const ulint* offsets);/* in: array returned by rec_get_offsets() */
781
/*******************************************************************
782
Checks that the first directory slot points to the infimum record and
783
the last to the supremum. This function is intended to track if the
784
bug fixed in 4.0.14 has caused corruption to users' databases. */
789
page_t* page); /* in: index page */
790
/*******************************************************************
791
This function checks the consistency of an index page when we do not
792
know the index. This is also resilient so that this should never crash
793
even if the page is total garbage. */
796
page_simple_validate(
797
/*=================*/
798
/* out: TRUE if ok */
799
page_t* page); /* in: index page */
800
/*******************************************************************
801
This function checks the consistency of an index page. */
806
/* out: TRUE if ok */
807
page_t* page, /* in: index page */
808
dict_index_t* index); /* in: data dictionary index containing
809
the page record type definition */
810
/*******************************************************************
811
Looks in the page record list for a record with the given heap number. */
814
page_find_rec_with_heap_no(
815
/*=======================*/
816
/* out: record, NULL if not found */
817
page_t* page, /* in: index page */
818
ulint heap_no);/* in: heap number */
820
#ifdef UNIV_MATERIALIZE
822
#define UNIV_INLINE UNIV_INLINE_ORIGINAL
826
#include "page0page.ic"