1
/*****************************************************************************
3
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
5
This program is free software; you can redistribute it and/or modify it under
6
the terms of the GNU General Public License as published by the Free Software
7
Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License along with
14
this program; if not, write to the Free Software Foundation, Inc.,
15
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
*****************************************************************************/
19
/**************************************************//**
20
@file include/page0page.ic
23
Created 2/2/1994 Heikki Tuuri
24
*******************************************************/
26
#include "mach0data.h"
28
# include "log0recv.h"
29
#endif /* !UNIV_DEBUG */
30
#ifndef UNIV_HOTBACKUP
32
#endif /* !UNIV_HOTBACKUP */
36
#ifdef UNIV_MATERIALIZE
41
/************************************************************//**
42
Gets the start of a page.
43
@return start of the page */
48
const void* ptr) /*!< in: pointer to page frame */
50
return((page_t*) ut_align_down(ptr, UNIV_PAGE_SIZE));
52
/************************************************************//**
53
Gets the offset within a page.
54
@return offset from the start of the page */
59
const void* ptr) /*!< in: pointer to page frame */
61
return(ut_align_offset(ptr, UNIV_PAGE_SIZE));
63
/*************************************************************//**
64
Returns the max trx id field value. */
69
const page_t* page) /*!< in: page */
73
return(mach_read_from_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID));
76
/*************************************************************//**
77
Sets the max trx id field value if trx_id is bigger than the previous
81
page_update_max_trx_id(
82
/*===================*/
83
buf_block_t* block, /*!< in/out: page */
84
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
85
uncompressed part will be updated, or NULL */
86
trx_id_t trx_id, /*!< in: transaction id */
87
mtr_t* mtr) /*!< in/out: mini-transaction */
90
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
91
/* During crash recovery, this function may be called on
92
something else than a leaf page of a secondary index or the
93
insert buffer index tree (dict_index_is_sec_or_ibuf() returns
94
TRUE for the dummy indexes constructed during redo log
95
application). In that case, PAGE_MAX_TRX_ID is unused,
96
and trx_id is usually zero. */
97
ut_ad(trx_id || recv_recovery_is_on());
98
ut_ad(page_is_leaf(buf_block_get_frame(block)));
100
if (page_get_max_trx_id(buf_block_get_frame(block)) < trx_id) {
102
page_set_max_trx_id(block, page_zip, trx_id, mtr);
106
/*************************************************************//**
107
Reads the given header field. */
110
page_header_get_field(
111
/*==================*/
112
const page_t* page, /*!< in: page */
113
ulint field) /*!< in: PAGE_LEVEL, ... */
116
ut_ad(field <= PAGE_INDEX_ID);
118
return(mach_read_from_2(page + PAGE_HEADER + field));
121
/*************************************************************//**
122
Sets the given header field. */
125
page_header_set_field(
126
/*==================*/
127
page_t* page, /*!< in/out: page */
128
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
129
uncompressed part will be updated, or NULL */
130
ulint field, /*!< in: PAGE_N_DIR_SLOTS, ... */
131
ulint val) /*!< in: value */
134
ut_ad(field <= PAGE_N_RECS);
135
ut_ad(field == PAGE_N_HEAP || val < UNIV_PAGE_SIZE);
136
ut_ad(field != PAGE_N_HEAP || (val & 0x7fff) < UNIV_PAGE_SIZE);
138
mach_write_to_2(page + PAGE_HEADER + field, val);
140
page_zip_write_header(page_zip,
141
page + PAGE_HEADER + field, 2, NULL);
145
/*************************************************************//**
146
Returns the offset stored in the given header field.
147
@return offset from the start of the page, or 0 */
150
page_header_get_offs(
151
/*=================*/
152
const page_t* page, /*!< in: page */
153
ulint field) /*!< in: PAGE_FREE, ... */
158
ut_ad((field == PAGE_FREE)
159
|| (field == PAGE_LAST_INSERT)
160
|| (field == PAGE_HEAP_TOP));
162
offs = page_header_get_field(page, field);
164
ut_ad((field != PAGE_HEAP_TOP) || offs);
169
/*************************************************************//**
170
Sets the pointer stored in the given header field. */
175
page_t* page, /*!< in: page */
176
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
177
uncompressed part will be updated, or NULL */
178
ulint field, /*!< in: PAGE_FREE, ... */
179
const byte* ptr) /*!< in: pointer or NULL*/
184
ut_ad((field == PAGE_FREE)
185
|| (field == PAGE_LAST_INSERT)
186
|| (field == PAGE_HEAP_TOP));
194
ut_ad((field != PAGE_HEAP_TOP) || offs);
196
page_header_set_field(page, page_zip, field, offs);
199
#ifndef UNIV_HOTBACKUP
200
/*************************************************************//**
201
Resets the last insert info field in the page header. Writes to mlog
202
about this operation. */
205
page_header_reset_last_insert(
206
/*==========================*/
207
page_t* page, /*!< in/out: page */
208
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
209
uncompressed part will be updated, or NULL */
210
mtr_t* mtr) /*!< in: mtr */
215
mach_write_to_2(page + (PAGE_HEADER + PAGE_LAST_INSERT), 0);
216
page_zip_write_header(page_zip,
217
page + (PAGE_HEADER + PAGE_LAST_INSERT),
220
mlog_write_ulint(page + (PAGE_HEADER + PAGE_LAST_INSERT), 0,
224
#endif /* !UNIV_HOTBACKUP */
226
/************************************************************//**
227
Determine whether the page is in new-style compact format.
228
@return nonzero if the page is in compact format, zero if it is in
234
const page_t* page) /*!< in: index page */
236
return(page_header_get_field(page, PAGE_N_HEAP) & 0x8000);
239
/************************************************************//**
240
TRUE if the record is on a page in compact format.
241
@return nonzero if in compact format */
246
const rec_t* rec) /*!< in: record */
248
return(page_is_comp(page_align(rec)));
251
/***************************************************************//**
252
Returns the heap number of a record.
253
@return heap number */
256
page_rec_get_heap_no(
257
/*=================*/
258
const rec_t* rec) /*!< in: the physical record */
260
if (page_rec_is_comp(rec)) {
261
return(rec_get_heap_no_new(rec));
263
return(rec_get_heap_no_old(rec));
267
/************************************************************//**
268
Determine whether the page is a B-tree leaf.
269
@return true if the page is a B-tree leaf (PAGE_LEVEL = 0) */
274
const page_t* page) /*!< in: page */
276
return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
279
/************************************************************//**
280
Determine whether the page is empty.
281
@return true if the page is empty (PAGE_N_RECS = 0) */
286
const page_t* page) /*!< in: page */
288
return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_N_RECS)));
291
/************************************************************//**
292
Determine whether the page contains garbage.
293
@return true if the page contains garbage (PAGE_GARBAGE is not 0) */
298
const page_t* page) /*!< in: page */
300
return(!!*(const uint16*) (page + (PAGE_HEADER + PAGE_GARBAGE)));
303
/************************************************************//**
304
Gets the offset of the first record on the page.
305
@return offset of the first record in record list, relative from page */
308
page_get_infimum_offset(
309
/*====================*/
310
const page_t* page) /*!< in: page which must have record(s) */
313
ut_ad(!page_offset(page));
315
if (page_is_comp(page)) {
316
return(PAGE_NEW_INFIMUM);
318
return(PAGE_OLD_INFIMUM);
322
/************************************************************//**
323
Gets the offset of the last record on the page.
324
@return offset of the last record in record list, relative from page */
327
page_get_supremum_offset(
328
/*=====================*/
329
const page_t* page) /*!< in: page which must have record(s) */
332
ut_ad(!page_offset(page));
334
if (page_is_comp(page)) {
335
return(PAGE_NEW_SUPREMUM);
337
return(PAGE_OLD_SUPREMUM);
341
/************************************************************//**
342
TRUE if the record is a user record on the page.
343
@return TRUE if a user record */
346
page_rec_is_user_rec_low(
347
/*=====================*/
348
ulint offset) /*!< in: record offset on page */
350
ut_ad(offset >= PAGE_NEW_INFIMUM);
351
#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
352
# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
354
#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
355
# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
357
#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
358
# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
360
#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
361
# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
363
#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
364
# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
366
#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
367
# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
369
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
371
return(offset != PAGE_NEW_SUPREMUM
372
&& offset != PAGE_NEW_INFIMUM
373
&& offset != PAGE_OLD_INFIMUM
374
&& offset != PAGE_OLD_SUPREMUM);
377
/************************************************************//**
378
TRUE if the record is the supremum record on a page.
379
@return TRUE if the supremum record */
382
page_rec_is_supremum_low(
383
/*=====================*/
384
ulint offset) /*!< in: record offset on page */
386
ut_ad(offset >= PAGE_NEW_INFIMUM);
387
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
389
return(offset == PAGE_NEW_SUPREMUM
390
|| offset == PAGE_OLD_SUPREMUM);
393
/************************************************************//**
394
TRUE if the record is the infimum record on a page.
395
@return TRUE if the infimum record */
398
page_rec_is_infimum_low(
399
/*====================*/
400
ulint offset) /*!< in: record offset on page */
402
ut_ad(offset >= PAGE_NEW_INFIMUM);
403
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
405
return(offset == PAGE_NEW_INFIMUM || offset == PAGE_OLD_INFIMUM);
408
/************************************************************//**
409
TRUE if the record is a user record on the page.
410
@return TRUE if a user record */
413
page_rec_is_user_rec(
414
/*=================*/
415
const rec_t* rec) /*!< in: record */
417
return(page_rec_is_user_rec_low(page_offset(rec)));
420
/************************************************************//**
421
TRUE if the record is the supremum record on a page.
422
@return TRUE if the supremum record */
425
page_rec_is_supremum(
426
/*=================*/
427
const rec_t* rec) /*!< in: record */
429
return(page_rec_is_supremum_low(page_offset(rec)));
432
/************************************************************//**
433
TRUE if the record is the infimum record on a page.
434
@return TRUE if the infimum record */
439
const rec_t* rec) /*!< in: record */
441
return(page_rec_is_infimum_low(page_offset(rec)));
444
/************************************************************//**
445
Returns the nth record of the record list.
446
This is the inverse function of page_rec_get_n_recs_before().
447
@return nth record */
452
page_t* page, /*!< in: page */
453
ulint nth) /*!< in: nth record */
455
return((rec_t*) page_rec_get_nth_const(page, nth));
458
#ifndef UNIV_HOTBACKUP
459
/************************************************************//**
460
Returns the middle record of the records on the page. If there is an
461
even number of records in the list, returns the first record of the
463
@return middle record */
468
page_t* page) /*!< in: page */
470
ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2;
472
return(page_rec_get_nth(page, middle));
475
/*************************************************************//**
476
Compares a data tuple to a physical record. Differs from the function
477
cmp_dtuple_rec_with_match in the way that the record must reside on an
478
index page, and also page infimum and supremum records can be given in
479
the parameter rec. These are considered as the negative infinity and
480
the positive infinity in the alphabetical order.
481
@return 1, 0, -1, if dtuple is greater, equal, less than rec,
482
respectively, when only the common first fields are compared */
485
page_cmp_dtuple_rec_with_match(
486
/*===========================*/
487
const dtuple_t* dtuple, /*!< in: data tuple */
488
const rec_t* rec, /*!< in: physical record on a page; may also
489
be page infimum or supremum, in which case
490
matched-parameter values below are not
492
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
493
ulint* matched_fields, /*!< in/out: number of already completely
494
matched fields; when function returns
495
contains the value for current comparison */
496
ulint* matched_bytes) /*!< in/out: number of already matched
497
bytes within the first field not completely
498
matched; when function returns contains the
499
value for current comparison */
503
ut_ad(dtuple_check_typed(dtuple));
504
ut_ad(rec_offs_validate(rec, NULL, offsets));
505
ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
507
rec_offset = page_offset(rec);
509
if (rec_offset == PAGE_NEW_INFIMUM
510
|| rec_offset == PAGE_OLD_INFIMUM) {
514
} else if (rec_offset == PAGE_NEW_SUPREMUM
515
|| rec_offset == PAGE_OLD_SUPREMUM) {
520
return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
524
#endif /* !UNIV_HOTBACKUP */
526
/*************************************************************//**
527
Gets the page number.
528
@return page number */
533
const page_t* page) /*!< in: page */
535
ut_ad(page == page_align((page_t*) page));
536
return(mach_read_from_4(page + FIL_PAGE_OFFSET));
539
/*************************************************************//**
540
Gets the tablespace identifier.
546
const page_t* page) /*!< in: page */
548
ut_ad(page == page_align((page_t*) page));
549
return(mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
552
/*************************************************************//**
553
Gets the number of user records on page (infimum and supremum records
554
are not user records).
555
@return number of user records */
560
const page_t* page) /*!< in: index page */
562
return(page_header_get_field(page, PAGE_N_RECS));
565
/*************************************************************//**
566
Gets the number of dir slots in directory.
567
@return number of slots */
570
page_dir_get_n_slots(
571
/*=================*/
572
const page_t* page) /*!< in: index page */
574
return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
576
/*************************************************************//**
577
Sets the number of dir slots in directory. */
580
page_dir_set_n_slots(
581
/*=================*/
582
page_t* page, /*!< in/out: page */
583
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
584
uncompressed part will be updated, or NULL */
585
ulint n_slots)/*!< in: number of slots */
587
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots);
590
/*************************************************************//**
591
Gets the number of records in the heap.
592
@return number of user records */
597
const page_t* page) /*!< in: index page */
599
return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff);
602
/*************************************************************//**
603
Sets the number of records in the heap. */
608
page_t* page, /*!< in/out: index page */
609
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
610
uncompressed part will be updated, or NULL.
611
Note that the size of the dense page directory
612
in the compressed page trailer is
613
n_heap * PAGE_ZIP_DIR_SLOT_SIZE. */
614
ulint n_heap) /*!< in: number of records */
616
ut_ad(n_heap < 0x8000);
617
ut_ad(!page_zip || n_heap
618
== (page_header_get_field(page, PAGE_N_HEAP) & 0x7fff) + 1);
620
page_header_set_field(page, page_zip, PAGE_N_HEAP, n_heap
622
& page_header_get_field(page, PAGE_N_HEAP)));
626
/*************************************************************//**
627
Gets pointer to nth directory slot.
628
@return pointer to dir slot */
631
page_dir_get_nth_slot(
632
/*==================*/
633
const page_t* page, /*!< in: index page */
634
ulint n) /*!< in: position */
636
ut_ad(page_dir_get_n_slots(page) > n);
638
return((page_dir_slot_t*)
639
page + UNIV_PAGE_SIZE - PAGE_DIR
640
- (n + 1) * PAGE_DIR_SLOT_SIZE);
642
#endif /* UNIV_DEBUG */
644
/**************************************************************//**
645
Used to check the consistency of a record on a page.
646
@return TRUE if succeed */
651
const rec_t* rec) /*!< in: record */
653
const page_t* page = page_align(rec);
657
ut_a(page_offset(rec) <= page_header_get_field(page, PAGE_HEAP_TOP));
658
ut_a(page_offset(rec) >= PAGE_DATA);
663
/***************************************************************//**
664
Gets the record pointed to by a directory slot.
665
@return pointer to record */
668
page_dir_slot_get_rec(
669
/*==================*/
670
const page_dir_slot_t* slot) /*!< in: directory slot */
672
return(page_align(slot) + mach_read_from_2(slot));
675
/***************************************************************//**
676
This is used to set the record offset in a directory slot. */
679
page_dir_slot_set_rec(
680
/*==================*/
681
page_dir_slot_t* slot, /*!< in: directory slot */
682
rec_t* rec) /*!< in: record on the page */
684
ut_ad(page_rec_check(rec));
686
mach_write_to_2(slot, page_offset(rec));
689
/***************************************************************//**
690
Gets the number of records owned by a directory slot.
691
@return number of records */
694
page_dir_slot_get_n_owned(
695
/*======================*/
696
const page_dir_slot_t* slot) /*!< in: page directory slot */
698
const rec_t* rec = page_dir_slot_get_rec(slot);
699
if (page_rec_is_comp(slot)) {
700
return(rec_get_n_owned_new(rec));
702
return(rec_get_n_owned_old(rec));
706
/***************************************************************//**
707
This is used to set the owned records field of a directory slot. */
710
page_dir_slot_set_n_owned(
711
/*======================*/
712
page_dir_slot_t*slot, /*!< in/out: directory slot */
713
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
714
ulint n) /*!< in: number of records owned by the slot */
716
rec_t* rec = (rec_t*) page_dir_slot_get_rec(slot);
717
if (page_rec_is_comp(slot)) {
718
rec_set_n_owned_new(rec, page_zip, n);
721
rec_set_n_owned_old(rec, n);
725
/************************************************************//**
726
Calculates the space reserved for directory slots of a given number of
727
records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
728
PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
731
page_dir_calc_reserved_space(
732
/*=========================*/
733
ulint n_recs) /*!< in: number of records */
735
return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
736
/ PAGE_DIR_SLOT_MIN_N_OWNED);
739
/************************************************************//**
740
Gets the pointer to the next record on the page.
741
@return pointer to next record */
744
page_rec_get_next_low(
745
/*==================*/
746
const rec_t* rec, /*!< in: pointer to record */
747
ulint comp) /*!< in: nonzero=compact page layout */
752
ut_ad(page_rec_check(rec));
754
page = page_align(rec);
756
offs = rec_get_next_offs(rec, comp);
758
if (offs >= UNIV_PAGE_SIZE) {
760
"InnoDB: Next record offset is nonsensical %lu"
761
" in record at offset %lu\n"
762
"InnoDB: rec address %p, space id %lu, page %lu\n",
763
(ulong) offs, (ulong) page_offset(rec),
765
(ulong) page_get_space_id(page),
766
(ulong) page_get_page_no(page));
767
buf_page_print(page, 0, 0);
770
} else if (offs == 0) {
778
/************************************************************//**
779
Gets the pointer to the next record on the page.
780
@return pointer to next record */
785
rec_t* rec) /*!< in: pointer to record */
787
return((rec_t*) page_rec_get_next_low(rec, page_rec_is_comp(rec)));
790
/************************************************************//**
791
Gets the pointer to the next record on the page.
792
@return pointer to next record */
795
page_rec_get_next_const(
796
/*====================*/
797
const rec_t* rec) /*!< in: pointer to record */
799
return(page_rec_get_next_low(rec, page_rec_is_comp(rec)));
802
/************************************************************//**
803
Gets the pointer to the next non delete-marked record on the page.
804
If all subsequent records are delete-marked, then this function
805
will return the supremum record.
806
@return pointer to next non delete-marked record or pointer to supremum */
809
page_rec_get_next_non_del_marked(
810
/*=============================*/
811
const rec_t* rec) /*!< in: pointer to record */
814
ulint page_is_compact = page_rec_is_comp(rec);
816
for (r = page_rec_get_next_const(rec);
817
!page_rec_is_supremum(r)
818
&& rec_get_deleted_flag(r, page_is_compact);
819
r = page_rec_get_next_const(r)) {
826
/************************************************************//**
827
Sets the pointer to the next record on the page. */
832
rec_t* rec, /*!< in: pointer to record,
833
must not be page supremum */
834
const rec_t* next) /*!< in: pointer to next record,
835
must not be page infimum */
839
ut_ad(page_rec_check(rec));
840
ut_ad(!page_rec_is_supremum(rec));
843
ut_ad(!next || !page_rec_is_infimum(next));
844
ut_ad(!next || page_align(rec) == page_align(next));
846
offs = next != NULL ? page_offset(next) : 0;
848
if (page_rec_is_comp(rec)) {
849
rec_set_next_offs_new(rec, offs);
851
rec_set_next_offs_old(rec, offs);
855
/************************************************************//**
856
Gets the pointer to the previous record.
857
@return pointer to previous record */
860
page_rec_get_prev_const(
861
/*====================*/
862
const rec_t* rec) /*!< in: pointer to record, must not be page
865
const page_dir_slot_t* slot;
868
const rec_t* prev_rec = NULL;
871
ut_ad(page_rec_check(rec));
873
page = page_align(rec);
875
ut_ad(!page_rec_is_infimum(rec));
877
slot_no = page_dir_find_owner_slot(rec);
881
slot = page_dir_get_nth_slot(page, slot_no - 1);
883
rec2 = page_dir_slot_get_rec(slot);
885
if (page_is_comp(page)) {
886
while (rec != rec2) {
888
rec2 = page_rec_get_next_low(rec2, TRUE);
891
while (rec != rec2) {
893
rec2 = page_rec_get_next_low(rec2, FALSE);
902
/************************************************************//**
903
Gets the pointer to the previous record.
904
@return pointer to previous record */
909
rec_t* rec) /*!< in: pointer to record, must not be page
912
return((rec_t*) page_rec_get_prev_const(rec));
915
/***************************************************************//**
916
Looks for the record which owns the given record.
917
@return the owner record */
920
page_rec_find_owner_rec(
921
/*====================*/
922
rec_t* rec) /*!< in: the physical record */
924
ut_ad(page_rec_check(rec));
926
if (page_rec_is_comp(rec)) {
927
while (rec_get_n_owned_new(rec) == 0) {
928
rec = page_rec_get_next(rec);
931
while (rec_get_n_owned_old(rec) == 0) {
932
rec = page_rec_get_next(rec);
939
/**********************************************************//**
940
Returns the base extra size of a physical record. This is the
941
size of the fixed header, independent of the record size.
942
@return REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */
945
page_rec_get_base_extra_size(
946
/*=========================*/
947
const rec_t* rec) /*!< in: physical record */
949
#if REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES
950
# error "REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES"
952
return(REC_N_NEW_EXTRA_BYTES + (ulint) !page_rec_is_comp(rec));
955
/************************************************************//**
956
Returns the sum of the sizes of the records in the record list, excluding
957
the infimum and supremum records.
958
@return data in bytes */
963
const page_t* page) /*!< in: index page */
967
ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
968
- (page_is_comp(page)
969
? PAGE_NEW_SUPREMUM_END
970
: PAGE_OLD_SUPREMUM_END)
971
- page_header_get_field(page, PAGE_GARBAGE));
973
ut_ad(ret < UNIV_PAGE_SIZE);
979
/************************************************************//**
980
Allocates a block of memory from the free list of an index page. */
985
page_t* page, /*!< in/out: index page */
986
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
987
space available for inserting the record,
989
rec_t* next_rec,/*!< in: pointer to the new head of the
991
ulint need) /*!< in: number of bytes allocated */
996
const rec_t* old_rec = page_header_get_ptr(page, PAGE_FREE);
1000
next_offs = rec_get_next_offs(old_rec, page_is_comp(page));
1001
ut_ad(next_rec == (next_offs ? page + next_offs : NULL));
1004
page_header_set_ptr(page, page_zip, PAGE_FREE, next_rec);
1006
garbage = page_header_get_field(page, PAGE_GARBAGE);
1007
ut_ad(garbage >= need);
1009
page_header_set_field(page, page_zip, PAGE_GARBAGE, garbage - need);
1012
/*************************************************************//**
1013
Calculates free space if a page is emptied.
1014
@return free space */
1017
page_get_free_space_of_empty(
1018
/*=========================*/
1019
ulint comp) /*!< in: nonzero=compact page layout */
1022
return((ulint)(UNIV_PAGE_SIZE
1023
- PAGE_NEW_SUPREMUM_END
1025
- 2 * PAGE_DIR_SLOT_SIZE));
1028
return((ulint)(UNIV_PAGE_SIZE
1029
- PAGE_OLD_SUPREMUM_END
1031
- 2 * PAGE_DIR_SLOT_SIZE));
1034
#ifndef UNIV_HOTBACKUP
1035
/***********************************************************************//**
1036
Write a 32-bit field in a data dictionary record. */
1039
page_rec_write_field(
1040
/*=================*/
1041
rec_t* rec, /*!< in/out: record to update */
1042
ulint i, /*!< in: index of the field to update */
1043
ulint val, /*!< in: value to write */
1044
mtr_t* mtr) /*!< in/out: mini-transaction */
1049
data = rec_get_nth_field_old(rec, i, &len);
1053
mlog_write_ulint(data, val, MLOG_4BYTES, mtr);
1055
#endif /* !UNIV_HOTBACKUP */
1057
/************************************************************//**
1058
Each user record on a page, and also the deleted user records in the heap
1059
takes its size plus the fraction of the dir cell size /
1060
PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
1061
value of page_get_free_space_of_empty, the insert is impossible, otherwise
1062
it is allowed. This function returns the maximum combined size of records
1063
which can be inserted on top of the record heap.
1064
@return maximum combined size for inserted records */
1067
page_get_max_insert_size(
1068
/*=====================*/
1069
const page_t* page, /*!< in: index page */
1070
ulint n_recs) /*!< in: number of records */
1075
if (page_is_comp(page)) {
1076
occupied = page_header_get_field(page, PAGE_HEAP_TOP)
1077
- PAGE_NEW_SUPREMUM_END
1078
+ page_dir_calc_reserved_space(
1079
n_recs + page_dir_get_n_heap(page) - 2);
1081
free_space = page_get_free_space_of_empty(TRUE);
1083
occupied = page_header_get_field(page, PAGE_HEAP_TOP)
1084
- PAGE_OLD_SUPREMUM_END
1085
+ page_dir_calc_reserved_space(
1086
n_recs + page_dir_get_n_heap(page) - 2);
1088
free_space = page_get_free_space_of_empty(FALSE);
1091
/* Above the 'n_recs +' part reserves directory space for the new
1092
inserted records; the '- 2' excludes page infimum and supremum
1095
if (occupied > free_space) {
1100
return(free_space - occupied);
1103
/************************************************************//**
1104
Returns the maximum combined size of records which can be inserted on top
1105
of the record heap if a page is first reorganized.
1106
@return maximum combined size for inserted records */
1109
page_get_max_insert_size_after_reorganize(
1110
/*======================================*/
1111
const page_t* page, /*!< in: index page */
1112
ulint n_recs) /*!< in: number of records */
1117
occupied = page_get_data_size(page)
1118
+ page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
1120
free_space = page_get_free_space_of_empty(page_is_comp(page));
1122
if (occupied > free_space) {
1127
return(free_space - occupied);
1130
/************************************************************//**
1131
Puts a record to free list. */
1136
page_t* page, /*!< in/out: index page */
1137
page_zip_des_t* page_zip, /*!< in/out: compressed page,
1139
rec_t* rec, /*!< in: pointer to the
1140
(origin of) record */
1141
const dict_index_t* index, /*!< in: index of rec */
1142
const ulint* offsets) /*!< in: array returned by
1143
rec_get_offsets() */
1148
ut_ad(rec_offs_validate(rec, index, offsets));
1149
free = page_header_get_ptr(page, PAGE_FREE);
1151
page_rec_set_next(rec, free);
1152
page_header_set_ptr(page, page_zip, PAGE_FREE, rec);
1154
garbage = page_header_get_field(page, PAGE_GARBAGE);
1156
page_header_set_field(page, page_zip, PAGE_GARBAGE,
1157
garbage + rec_offs_size(offsets));
1160
page_zip_dir_delete(page_zip, rec, index, offsets, free);
1162
page_header_set_field(page, page_zip, PAGE_N_RECS,
1163
page_get_n_recs(page) - 1);
1167
#ifdef UNIV_MATERIALIZE
1169
#define UNIV_INLINE UNIV_INLINE_ORIGINAL