1
/*****************************************************************************
3
Copyright (C) 1994, 2009, Innobase Oy. 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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 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);
139
if (UNIV_LIKELY_NULL(page_zip)) {
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 */
214
if (UNIV_LIKELY_NULL(page_zip)) {
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(UNIV_EXPECT(page_header_get_field(page, PAGE_N_HEAP) & 0x8000,
240
/************************************************************//**
241
TRUE if the record is on a page in compact format.
242
@return nonzero if in compact format */
247
const rec_t* rec) /*!< in: record */
249
return(page_is_comp(page_align(rec)));
252
/***************************************************************//**
253
Returns the heap number of a record.
254
@return heap number */
257
page_rec_get_heap_no(
258
/*=================*/
259
const rec_t* rec) /*!< in: the physical record */
261
if (page_rec_is_comp(rec)) {
262
return(rec_get_heap_no_new(rec));
264
return(rec_get_heap_no_old(rec));
268
/************************************************************//**
269
Determine whether the page is a B-tree leaf.
270
@return TRUE if the page is a B-tree leaf */
275
const page_t* page) /*!< in: page */
277
return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
280
/************************************************************//**
281
Gets the offset of the first record on the page.
282
@return offset of the first record in record list, relative from page */
285
page_get_infimum_offset(
286
/*====================*/
287
const page_t* page) /*!< in: page which must have record(s) */
290
ut_ad(!page_offset(page));
292
if (page_is_comp(page)) {
293
return(PAGE_NEW_INFIMUM);
295
return(PAGE_OLD_INFIMUM);
299
/************************************************************//**
300
Gets the offset of the last record on the page.
301
@return offset of the last record in record list, relative from page */
304
page_get_supremum_offset(
305
/*=====================*/
306
const page_t* page) /*!< in: page which must have record(s) */
309
ut_ad(!page_offset(page));
311
if (page_is_comp(page)) {
312
return(PAGE_NEW_SUPREMUM);
314
return(PAGE_OLD_SUPREMUM);
318
/************************************************************//**
319
TRUE if the record is a user record on the page.
320
@return TRUE if a user record */
323
page_rec_is_user_rec_low(
324
/*=====================*/
325
ulint offset) /*!< in: record offset on page */
327
ut_ad(offset >= PAGE_NEW_INFIMUM);
328
#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
329
# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
331
#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
332
# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
334
#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
335
# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
337
#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
338
# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
340
#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
341
# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
343
#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
344
# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
346
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
348
return(UNIV_LIKELY(offset != PAGE_NEW_SUPREMUM)
349
&& UNIV_LIKELY(offset != PAGE_NEW_INFIMUM)
350
&& UNIV_LIKELY(offset != PAGE_OLD_INFIMUM)
351
&& UNIV_LIKELY(offset != PAGE_OLD_SUPREMUM));
354
/************************************************************//**
355
TRUE if the record is the supremum record on a page.
356
@return TRUE if the supremum record */
359
page_rec_is_supremum_low(
360
/*=====================*/
361
ulint offset) /*!< in: record offset on page */
363
ut_ad(offset >= PAGE_NEW_INFIMUM);
364
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
366
return(UNIV_UNLIKELY(offset == PAGE_NEW_SUPREMUM)
367
|| UNIV_UNLIKELY(offset == PAGE_OLD_SUPREMUM));
370
/************************************************************//**
371
TRUE if the record is the infimum record on a page.
372
@return TRUE if the infimum record */
375
page_rec_is_infimum_low(
376
/*====================*/
377
ulint offset) /*!< in: record offset on page */
379
ut_ad(offset >= PAGE_NEW_INFIMUM);
380
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
382
return(UNIV_UNLIKELY(offset == PAGE_NEW_INFIMUM)
383
|| UNIV_UNLIKELY(offset == PAGE_OLD_INFIMUM));
386
/************************************************************//**
387
TRUE if the record is a user record on the page.
388
@return TRUE if a user record */
391
page_rec_is_user_rec(
392
/*=================*/
393
const rec_t* rec) /*!< in: record */
395
return(page_rec_is_user_rec_low(page_offset(rec)));
398
/************************************************************//**
399
TRUE if the record is the supremum record on a page.
400
@return TRUE if the supremum record */
403
page_rec_is_supremum(
404
/*=================*/
405
const rec_t* rec) /*!< in: record */
407
return(page_rec_is_supremum_low(page_offset(rec)));
410
/************************************************************//**
411
TRUE if the record is the infimum record on a page.
412
@return TRUE if the infimum record */
417
const rec_t* rec) /*!< in: record */
419
return(page_rec_is_infimum_low(page_offset(rec)));
422
#ifndef UNIV_HOTBACKUP
423
/*************************************************************//**
424
Compares a data tuple to a physical record. Differs from the function
425
cmp_dtuple_rec_with_match in the way that the record must reside on an
426
index page, and also page infimum and supremum records can be given in
427
the parameter rec. These are considered as the negative infinity and
428
the positive infinity in the alphabetical order.
429
@return 1, 0, -1, if dtuple is greater, equal, less than rec,
430
respectively, when only the common first fields are compared */
433
page_cmp_dtuple_rec_with_match(
434
/*===========================*/
435
const dtuple_t* dtuple, /*!< in: data tuple */
436
const rec_t* rec, /*!< in: physical record on a page; may also
437
be page infimum or supremum, in which case
438
matched-parameter values below are not
440
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
441
ulint* matched_fields, /*!< in/out: number of already completely
442
matched fields; when function returns
443
contains the value for current comparison */
444
ulint* matched_bytes) /*!< in/out: number of already matched
445
bytes within the first field not completely
446
matched; when function returns contains the
447
value for current comparison */
451
ut_ad(dtuple_check_typed(dtuple));
452
ut_ad(rec_offs_validate(rec, NULL, offsets));
453
ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
455
rec_offset = page_offset(rec);
457
if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_INFIMUM)
458
|| UNIV_UNLIKELY(rec_offset == PAGE_OLD_INFIMUM)) {
461
if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_SUPREMUM)
462
|| UNIV_UNLIKELY(rec_offset == PAGE_OLD_SUPREMUM)) {
466
return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
470
#endif /* !UNIV_HOTBACKUP */
472
/*************************************************************//**
473
Gets the page number.
474
@return page number */
479
const page_t* page) /*!< in: page */
481
ut_ad(page == page_align((page_t*) page));
482
return(mach_read_from_4(page + FIL_PAGE_OFFSET));
485
/*************************************************************//**
486
Gets the tablespace identifier.
492
const page_t* page) /*!< in: page */
494
ut_ad(page == page_align((page_t*) page));
495
return(mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
498
/*************************************************************//**
499
Gets the number of user records on page (infimum and supremum records
500
are not user records).
501
@return number of user records */
506
const page_t* page) /*!< in: index page */
508
return(page_header_get_field(page, PAGE_N_RECS));
511
/*************************************************************//**
512
Gets the number of dir slots in directory.
513
@return number of slots */
516
page_dir_get_n_slots(
517
/*=================*/
518
const page_t* page) /*!< in: index page */
520
return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
522
/*************************************************************//**
523
Sets the number of dir slots in directory. */
526
page_dir_set_n_slots(
527
/*=================*/
528
page_t* page, /*!< in/out: page */
529
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
530
uncompressed part will be updated, or NULL */
531
ulint n_slots)/*!< in: number of slots */
533
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots);
536
/*************************************************************//**
537
Gets the number of records in the heap.
538
@return number of user records */
543
const page_t* page) /*!< in: index page */
545
return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff);
548
/*************************************************************//**
549
Sets the number of records in the heap. */
554
page_t* page, /*!< in/out: index page */
555
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
556
uncompressed part will be updated, or NULL.
557
Note that the size of the dense page directory
558
in the compressed page trailer is
559
n_heap * PAGE_ZIP_DIR_SLOT_SIZE. */
560
ulint n_heap) /*!< in: number of records */
562
ut_ad(n_heap < 0x8000);
563
ut_ad(!page_zip || n_heap
564
== (page_header_get_field(page, PAGE_N_HEAP) & 0x7fff) + 1);
566
page_header_set_field(page, page_zip, PAGE_N_HEAP, n_heap
568
& page_header_get_field(page, PAGE_N_HEAP)));
572
/*************************************************************//**
573
Gets pointer to nth directory slot.
574
@return pointer to dir slot */
577
page_dir_get_nth_slot(
578
/*==================*/
579
const page_t* page, /*!< in: index page */
580
ulint n) /*!< in: position */
582
ut_ad(page_dir_get_n_slots(page) > n);
584
return((page_dir_slot_t*)
585
page + UNIV_PAGE_SIZE - PAGE_DIR
586
- (n + 1) * PAGE_DIR_SLOT_SIZE);
588
#endif /* UNIV_DEBUG */
590
/**************************************************************//**
591
Used to check the consistency of a record on a page.
592
@return TRUE if succeed */
597
const rec_t* rec) /*!< in: record */
599
const page_t* page = page_align(rec);
603
ut_a(page_offset(rec) <= page_header_get_field(page, PAGE_HEAP_TOP));
604
ut_a(page_offset(rec) >= PAGE_DATA);
609
/***************************************************************//**
610
Gets the record pointed to by a directory slot.
611
@return pointer to record */
614
page_dir_slot_get_rec(
615
/*==================*/
616
const page_dir_slot_t* slot) /*!< in: directory slot */
618
return(page_align(slot) + mach_read_from_2(slot));
621
/***************************************************************//**
622
This is used to set the record offset in a directory slot. */
625
page_dir_slot_set_rec(
626
/*==================*/
627
page_dir_slot_t* slot, /*!< in: directory slot */
628
rec_t* rec) /*!< in: record on the page */
630
ut_ad(page_rec_check(rec));
632
mach_write_to_2(slot, page_offset(rec));
635
/***************************************************************//**
636
Gets the number of records owned by a directory slot.
637
@return number of records */
640
page_dir_slot_get_n_owned(
641
/*======================*/
642
const page_dir_slot_t* slot) /*!< in: page directory slot */
644
const rec_t* rec = page_dir_slot_get_rec(slot);
645
if (page_rec_is_comp(slot)) {
646
return(rec_get_n_owned_new(rec));
648
return(rec_get_n_owned_old(rec));
652
/***************************************************************//**
653
This is used to set the owned records field of a directory slot. */
656
page_dir_slot_set_n_owned(
657
/*======================*/
658
page_dir_slot_t*slot, /*!< in/out: directory slot */
659
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
660
ulint n) /*!< in: number of records owned by the slot */
662
rec_t* rec = (rec_t*) page_dir_slot_get_rec(slot);
663
if (page_rec_is_comp(slot)) {
664
rec_set_n_owned_new(rec, page_zip, n);
667
rec_set_n_owned_old(rec, n);
671
/************************************************************//**
672
Calculates the space reserved for directory slots of a given number of
673
records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
674
PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
677
page_dir_calc_reserved_space(
678
/*=========================*/
679
ulint n_recs) /*!< in: number of records */
681
return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
682
/ PAGE_DIR_SLOT_MIN_N_OWNED);
685
/************************************************************//**
686
Gets the pointer to the next record on the page.
687
@return pointer to next record */
690
page_rec_get_next_low(
691
/*==================*/
692
const rec_t* rec, /*!< in: pointer to record */
693
ulint comp) /*!< in: nonzero=compact page layout */
698
ut_ad(page_rec_check(rec));
700
page = page_align(rec);
702
offs = rec_get_next_offs(rec, comp);
704
if (UNIV_UNLIKELY(offs >= UNIV_PAGE_SIZE)) {
706
"InnoDB: Next record offset is nonsensical %lu"
707
" in record at offset %lu\n"
708
"InnoDB: rec address %p, space id %lu, page %lu\n",
709
(ulong)offs, (ulong) page_offset(rec),
711
(ulong) page_get_space_id(page),
712
(ulong) page_get_page_no(page));
713
buf_page_print(page, 0);
718
if (UNIV_UNLIKELY(offs == 0)) {
726
/************************************************************//**
727
Gets the pointer to the next record on the page.
728
@return pointer to next record */
733
rec_t* rec) /*!< in: pointer to record */
735
return((rec_t*) page_rec_get_next_low(rec, page_rec_is_comp(rec)));
738
/************************************************************//**
739
Gets the pointer to the next record on the page.
740
@return pointer to next record */
743
page_rec_get_next_const(
744
/*====================*/
745
const rec_t* rec) /*!< in: pointer to record */
747
return(page_rec_get_next_low(rec, page_rec_is_comp(rec)));
750
/************************************************************//**
751
Sets the pointer to the next record on the page. */
756
rec_t* rec, /*!< in: pointer to record,
757
must not be page supremum */
758
rec_t* next) /*!< in: pointer to next record,
759
must not be page infimum */
763
ut_ad(page_rec_check(rec));
764
ut_ad(!page_rec_is_supremum(rec));
767
ut_ad(!next || !page_rec_is_infimum(next));
768
ut_ad(!next || page_align(rec) == page_align(next));
770
if (UNIV_LIKELY(next != NULL)) {
771
offs = page_offset(next);
776
if (page_rec_is_comp(rec)) {
777
rec_set_next_offs_new(rec, offs);
779
rec_set_next_offs_old(rec, offs);
783
/************************************************************//**
784
Gets the pointer to the previous record.
785
@return pointer to previous record */
788
page_rec_get_prev_const(
789
/*====================*/
790
const rec_t* rec) /*!< in: pointer to record, must not be page
793
const page_dir_slot_t* slot;
796
const rec_t* prev_rec = NULL;
799
ut_ad(page_rec_check(rec));
801
page = page_align(rec);
803
ut_ad(!page_rec_is_infimum(rec));
805
slot_no = page_dir_find_owner_slot(rec);
809
slot = page_dir_get_nth_slot(page, slot_no - 1);
811
rec2 = page_dir_slot_get_rec(slot);
813
if (page_is_comp(page)) {
814
while (rec != rec2) {
816
rec2 = page_rec_get_next_low(rec2, TRUE);
819
while (rec != rec2) {
821
rec2 = page_rec_get_next_low(rec2, FALSE);
830
/************************************************************//**
831
Gets the pointer to the previous record.
832
@return pointer to previous record */
837
rec_t* rec) /*!< in: pointer to record, must not be page
840
return((rec_t*) page_rec_get_prev_const(rec));
843
/***************************************************************//**
844
Looks for the record which owns the given record.
845
@return the owner record */
848
page_rec_find_owner_rec(
849
/*====================*/
850
rec_t* rec) /*!< in: the physical record */
852
ut_ad(page_rec_check(rec));
854
if (page_rec_is_comp(rec)) {
855
while (rec_get_n_owned_new(rec) == 0) {
856
rec = page_rec_get_next(rec);
859
while (rec_get_n_owned_old(rec) == 0) {
860
rec = page_rec_get_next(rec);
867
/**********************************************************//**
868
Returns the base extra size of a physical record. This is the
869
size of the fixed header, independent of the record size.
870
@return REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */
873
page_rec_get_base_extra_size(
874
/*=========================*/
875
const rec_t* rec) /*!< in: physical record */
877
#if REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES
878
# error "REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES"
880
return(REC_N_NEW_EXTRA_BYTES + (ulint) !page_rec_is_comp(rec));
883
/************************************************************//**
884
Returns the sum of the sizes of the records in the record list, excluding
885
the infimum and supremum records.
886
@return data in bytes */
891
const page_t* page) /*!< in: index page */
895
ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
896
- (page_is_comp(page)
897
? PAGE_NEW_SUPREMUM_END
898
: PAGE_OLD_SUPREMUM_END)
899
- page_header_get_field(page, PAGE_GARBAGE));
901
ut_ad(ret < UNIV_PAGE_SIZE);
907
/************************************************************//**
908
Allocates a block of memory from the free list of an index page. */
913
page_t* page, /*!< in/out: index page */
914
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
915
space available for inserting the record,
917
rec_t* next_rec,/*!< in: pointer to the new head of the
919
ulint need) /*!< in: number of bytes allocated */
924
const rec_t* old_rec = page_header_get_ptr(page, PAGE_FREE);
928
next_offs = rec_get_next_offs(old_rec, page_is_comp(page));
929
ut_ad(next_rec == (next_offs ? page + next_offs : NULL));
932
page_header_set_ptr(page, page_zip, PAGE_FREE, next_rec);
934
garbage = page_header_get_field(page, PAGE_GARBAGE);
935
ut_ad(garbage >= need);
937
page_header_set_field(page, page_zip, PAGE_GARBAGE, garbage - need);
940
/*************************************************************//**
941
Calculates free space if a page is emptied.
942
@return free space */
945
page_get_free_space_of_empty(
946
/*=========================*/
947
ulint comp) /*!< in: nonzero=compact page layout */
949
if (UNIV_LIKELY(comp)) {
950
return((ulint)(UNIV_PAGE_SIZE
951
- PAGE_NEW_SUPREMUM_END
953
- 2 * PAGE_DIR_SLOT_SIZE));
956
return((ulint)(UNIV_PAGE_SIZE
957
- PAGE_OLD_SUPREMUM_END
959
- 2 * PAGE_DIR_SLOT_SIZE));
962
/************************************************************//**
963
Each user record on a page, and also the deleted user records in the heap
964
takes its size plus the fraction of the dir cell size /
965
PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
966
value of page_get_free_space_of_empty, the insert is impossible, otherwise
967
it is allowed. This function returns the maximum combined size of records
968
which can be inserted on top of the record heap.
969
@return maximum combined size for inserted records */
972
page_get_max_insert_size(
973
/*=====================*/
974
const page_t* page, /*!< in: index page */
975
ulint n_recs) /*!< in: number of records */
980
if (page_is_comp(page)) {
981
occupied = page_header_get_field(page, PAGE_HEAP_TOP)
982
- PAGE_NEW_SUPREMUM_END
983
+ page_dir_calc_reserved_space(
984
n_recs + page_dir_get_n_heap(page) - 2);
986
free_space = page_get_free_space_of_empty(TRUE);
988
occupied = page_header_get_field(page, PAGE_HEAP_TOP)
989
- PAGE_OLD_SUPREMUM_END
990
+ page_dir_calc_reserved_space(
991
n_recs + page_dir_get_n_heap(page) - 2);
993
free_space = page_get_free_space_of_empty(FALSE);
996
/* Above the 'n_recs +' part reserves directory space for the new
997
inserted records; the '- 2' excludes page infimum and supremum
1000
if (occupied > free_space) {
1005
return(free_space - occupied);
1008
/************************************************************//**
1009
Returns the maximum combined size of records which can be inserted on top
1010
of the record heap if a page is first reorganized.
1011
@return maximum combined size for inserted records */
1014
page_get_max_insert_size_after_reorganize(
1015
/*======================================*/
1016
const page_t* page, /*!< in: index page */
1017
ulint n_recs) /*!< in: number of records */
1022
occupied = page_get_data_size(page)
1023
+ page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
1025
free_space = page_get_free_space_of_empty(page_is_comp(page));
1027
if (occupied > free_space) {
1032
return(free_space - occupied);
1035
/************************************************************//**
1036
Puts a record to free list. */
1041
page_t* page, /*!< in/out: index page */
1042
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
1043
rec_t* rec, /*!< in: pointer to the (origin of) record */
1044
dict_index_t* index, /*!< in: index of rec */
1045
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1050
ut_ad(rec_offs_validate(rec, index, offsets));
1051
free = page_header_get_ptr(page, PAGE_FREE);
1053
page_rec_set_next(rec, free);
1054
page_header_set_ptr(page, page_zip, PAGE_FREE, rec);
1056
garbage = page_header_get_field(page, PAGE_GARBAGE);
1058
page_header_set_field(page, page_zip, PAGE_GARBAGE,
1059
garbage + rec_offs_size(offsets));
1061
if (UNIV_LIKELY_NULL(page_zip)) {
1062
page_zip_dir_delete(page_zip, rec, index, offsets, free);
1064
page_header_set_field(page, page_zip, PAGE_N_RECS,
1065
page_get_n_recs(page) - 1);
1069
#ifdef UNIV_MATERIALIZE
1071
#define UNIV_INLINE UNIV_INLINE_ORIGINAL