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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 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(!ut_dulint_is_zero(trx_id) || recv_recovery_is_on());
98
ut_ad(page_is_leaf(buf_block_get_frame(block)));
100
if (ut_dulint_cmp(page_get_max_trx_id(buf_block_get_frame(block)),
103
page_set_max_trx_id(block, page_zip, trx_id, mtr);
107
/*************************************************************//**
108
Reads the given header field. */
111
page_header_get_field(
112
/*==================*/
113
const page_t* page, /*!< in: page */
114
ulint field) /*!< in: PAGE_LEVEL, ... */
117
ut_ad(field <= PAGE_INDEX_ID);
119
return(mach_read_from_2(page + PAGE_HEADER + field));
122
/*************************************************************//**
123
Sets the given header field. */
126
page_header_set_field(
127
/*==================*/
128
page_t* page, /*!< in/out: page */
129
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
130
uncompressed part will be updated, or NULL */
131
ulint field, /*!< in: PAGE_N_DIR_SLOTS, ... */
132
ulint val) /*!< in: value */
135
ut_ad(field <= PAGE_N_RECS);
136
ut_ad(field == PAGE_N_HEAP || val < UNIV_PAGE_SIZE);
137
ut_ad(field != PAGE_N_HEAP || (val & 0x7fff) < UNIV_PAGE_SIZE);
139
mach_write_to_2(page + PAGE_HEADER + field, val);
140
if (UNIV_LIKELY_NULL(page_zip)) {
141
page_zip_write_header(page_zip,
142
page + PAGE_HEADER + field, 2, NULL);
146
/*************************************************************//**
147
Returns the offset stored in the given header field.
148
@return offset from the start of the page, or 0 */
151
page_header_get_offs(
152
/*=================*/
153
const page_t* page, /*!< in: page */
154
ulint field) /*!< in: PAGE_FREE, ... */
159
ut_ad((field == PAGE_FREE)
160
|| (field == PAGE_LAST_INSERT)
161
|| (field == PAGE_HEAP_TOP));
163
offs = page_header_get_field(page, field);
165
ut_ad((field != PAGE_HEAP_TOP) || offs);
170
/*************************************************************//**
171
Sets the pointer stored in the given header field. */
176
page_t* page, /*!< in: page */
177
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
178
uncompressed part will be updated, or NULL */
179
ulint field, /*!< in: PAGE_FREE, ... */
180
const byte* ptr) /*!< in: pointer or NULL*/
185
ut_ad((field == PAGE_FREE)
186
|| (field == PAGE_LAST_INSERT)
187
|| (field == PAGE_HEAP_TOP));
195
ut_ad((field != PAGE_HEAP_TOP) || offs);
197
page_header_set_field(page, page_zip, field, offs);
200
#ifndef UNIV_HOTBACKUP
201
/*************************************************************//**
202
Resets the last insert info field in the page header. Writes to mlog
203
about this operation. */
206
page_header_reset_last_insert(
207
/*==========================*/
208
page_t* page, /*!< in/out: page */
209
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
210
uncompressed part will be updated, or NULL */
211
mtr_t* mtr) /*!< in: mtr */
215
if (UNIV_LIKELY_NULL(page_zip)) {
216
mach_write_to_2(page + (PAGE_HEADER + PAGE_LAST_INSERT), 0);
217
page_zip_write_header(page_zip,
218
page + (PAGE_HEADER + PAGE_LAST_INSERT),
221
mlog_write_ulint(page + (PAGE_HEADER + PAGE_LAST_INSERT), 0,
225
#endif /* !UNIV_HOTBACKUP */
227
/************************************************************//**
228
Determine whether the page is in new-style compact format.
229
@return nonzero if the page is in compact format, zero if it is in
235
const page_t* page) /*!< in: index page */
237
return(UNIV_EXPECT(page_header_get_field(page, PAGE_N_HEAP) & 0x8000,
241
/************************************************************//**
242
TRUE if the record is on a page in compact format.
243
@return nonzero if in compact format */
248
const rec_t* rec) /*!< in: record */
250
return(page_is_comp(page_align(rec)));
253
/***************************************************************//**
254
Returns the heap number of a record.
255
@return heap number */
258
page_rec_get_heap_no(
259
/*=================*/
260
const rec_t* rec) /*!< in: the physical record */
262
if (page_rec_is_comp(rec)) {
263
return(rec_get_heap_no_new(rec));
265
return(rec_get_heap_no_old(rec));
269
/************************************************************//**
270
Determine whether the page is a B-tree leaf.
271
@return TRUE if the page is a B-tree leaf */
276
const page_t* page) /*!< in: page */
278
return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
281
/************************************************************//**
282
Gets the offset of the first record on the page.
283
@return offset of the first record in record list, relative from page */
286
page_get_infimum_offset(
287
/*====================*/
288
const page_t* page) /*!< in: page which must have record(s) */
291
ut_ad(!page_offset(page));
293
if (page_is_comp(page)) {
294
return(PAGE_NEW_INFIMUM);
296
return(PAGE_OLD_INFIMUM);
300
/************************************************************//**
301
Gets the offset of the last record on the page.
302
@return offset of the last record in record list, relative from page */
305
page_get_supremum_offset(
306
/*=====================*/
307
const page_t* page) /*!< in: page which must have record(s) */
310
ut_ad(!page_offset(page));
312
if (page_is_comp(page)) {
313
return(PAGE_NEW_SUPREMUM);
315
return(PAGE_OLD_SUPREMUM);
319
/************************************************************//**
320
TRUE if the record is a user record on the page.
321
@return TRUE if a user record */
324
page_rec_is_user_rec_low(
325
/*=====================*/
326
ulint offset) /*!< in: record offset on page */
328
ut_ad(offset >= PAGE_NEW_INFIMUM);
329
#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
330
# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
332
#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
333
# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
335
#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
336
# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
338
#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
339
# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
341
#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
342
# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
344
#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
345
# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
347
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
349
return(UNIV_LIKELY(offset != PAGE_NEW_SUPREMUM)
350
&& UNIV_LIKELY(offset != PAGE_NEW_INFIMUM)
351
&& UNIV_LIKELY(offset != PAGE_OLD_INFIMUM)
352
&& UNIV_LIKELY(offset != PAGE_OLD_SUPREMUM));
355
/************************************************************//**
356
TRUE if the record is the supremum record on a page.
357
@return TRUE if the supremum record */
360
page_rec_is_supremum_low(
361
/*=====================*/
362
ulint offset) /*!< in: record offset on page */
364
ut_ad(offset >= PAGE_NEW_INFIMUM);
365
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
367
return(UNIV_UNLIKELY(offset == PAGE_NEW_SUPREMUM)
368
|| UNIV_UNLIKELY(offset == PAGE_OLD_SUPREMUM));
371
/************************************************************//**
372
TRUE if the record is the infimum record on a page.
373
@return TRUE if the infimum record */
376
page_rec_is_infimum_low(
377
/*====================*/
378
ulint offset) /*!< in: record offset on page */
380
ut_ad(offset >= PAGE_NEW_INFIMUM);
381
ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
383
return(UNIV_UNLIKELY(offset == PAGE_NEW_INFIMUM)
384
|| UNIV_UNLIKELY(offset == PAGE_OLD_INFIMUM));
387
/************************************************************//**
388
TRUE if the record is a user record on the page.
389
@return TRUE if a user record */
392
page_rec_is_user_rec(
393
/*=================*/
394
const rec_t* rec) /*!< in: record */
396
return(page_rec_is_user_rec_low(page_offset(rec)));
399
/************************************************************//**
400
TRUE if the record is the supremum record on a page.
401
@return TRUE if the supremum record */
404
page_rec_is_supremum(
405
/*=================*/
406
const rec_t* rec) /*!< in: record */
408
return(page_rec_is_supremum_low(page_offset(rec)));
411
/************************************************************//**
412
TRUE if the record is the infimum record on a page.
413
@return TRUE if the infimum record */
418
const rec_t* rec) /*!< in: record */
420
return(page_rec_is_infimum_low(page_offset(rec)));
423
#ifndef UNIV_HOTBACKUP
424
/*************************************************************//**
425
Compares a data tuple to a physical record. Differs from the function
426
cmp_dtuple_rec_with_match in the way that the record must reside on an
427
index page, and also page infimum and supremum records can be given in
428
the parameter rec. These are considered as the negative infinity and
429
the positive infinity in the alphabetical order.
430
@return 1, 0, -1, if dtuple is greater, equal, less than rec,
431
respectively, when only the common first fields are compared */
434
page_cmp_dtuple_rec_with_match(
435
/*===========================*/
436
const dtuple_t* dtuple, /*!< in: data tuple */
437
const rec_t* rec, /*!< in: physical record on a page; may also
438
be page infimum or supremum, in which case
439
matched-parameter values below are not
441
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
442
ulint* matched_fields, /*!< in/out: number of already completely
443
matched fields; when function returns
444
contains the value for current comparison */
445
ulint* matched_bytes) /*!< in/out: number of already matched
446
bytes within the first field not completely
447
matched; when function returns contains the
448
value for current comparison */
452
ut_ad(dtuple_check_typed(dtuple));
453
ut_ad(rec_offs_validate(rec, NULL, offsets));
454
ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
456
rec_offset = page_offset(rec);
458
if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_INFIMUM)
459
|| UNIV_UNLIKELY(rec_offset == PAGE_OLD_INFIMUM)) {
462
if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_SUPREMUM)
463
|| UNIV_UNLIKELY(rec_offset == PAGE_OLD_SUPREMUM)) {
467
return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
471
#endif /* !UNIV_HOTBACKUP */
473
/*************************************************************//**
474
Gets the page number.
475
@return page number */
480
const page_t* page) /*!< in: page */
482
ut_ad(page == page_align((page_t*) page));
483
return(mach_read_from_4(page + FIL_PAGE_OFFSET));
486
/*************************************************************//**
487
Gets the tablespace identifier.
493
const page_t* page) /*!< in: page */
495
ut_ad(page == page_align((page_t*) page));
496
return(mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
499
/*************************************************************//**
500
Gets the number of user records on page (infimum and supremum records
501
are not user records).
502
@return number of user records */
507
const page_t* page) /*!< in: index page */
509
return(page_header_get_field(page, PAGE_N_RECS));
512
/*************************************************************//**
513
Gets the number of dir slots in directory.
514
@return number of slots */
517
page_dir_get_n_slots(
518
/*=================*/
519
const page_t* page) /*!< in: index page */
521
return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
523
/*************************************************************//**
524
Sets the number of dir slots in directory. */
527
page_dir_set_n_slots(
528
/*=================*/
529
page_t* page, /*!< in/out: page */
530
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
531
uncompressed part will be updated, or NULL */
532
ulint n_slots)/*!< in: number of slots */
534
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots);
537
/*************************************************************//**
538
Gets the number of records in the heap.
539
@return number of user records */
544
const page_t* page) /*!< in: index page */
546
return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff);
549
/*************************************************************//**
550
Sets the number of records in the heap. */
555
page_t* page, /*!< in/out: index page */
556
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
557
uncompressed part will be updated, or NULL.
558
Note that the size of the dense page directory
559
in the compressed page trailer is
560
n_heap * PAGE_ZIP_DIR_SLOT_SIZE. */
561
ulint n_heap) /*!< in: number of records */
563
ut_ad(n_heap < 0x8000);
564
ut_ad(!page_zip || n_heap
565
== (page_header_get_field(page, PAGE_N_HEAP) & 0x7fff) + 1);
567
page_header_set_field(page, page_zip, PAGE_N_HEAP, n_heap
569
& page_header_get_field(page, PAGE_N_HEAP)));
573
/*************************************************************//**
574
Gets pointer to nth directory slot.
575
@return pointer to dir slot */
578
page_dir_get_nth_slot(
579
/*==================*/
580
const page_t* page, /*!< in: index page */
581
ulint n) /*!< in: position */
583
ut_ad(page_dir_get_n_slots(page) > n);
585
return((page_dir_slot_t*)
586
page + UNIV_PAGE_SIZE - PAGE_DIR
587
- (n + 1) * PAGE_DIR_SLOT_SIZE);
589
#endif /* UNIV_DEBUG */
591
/**************************************************************//**
592
Used to check the consistency of a record on a page.
593
@return TRUE if succeed */
598
const rec_t* rec) /*!< in: record */
600
const page_t* page = page_align(rec);
604
ut_a(page_offset(rec) <= page_header_get_field(page, PAGE_HEAP_TOP));
605
ut_a(page_offset(rec) >= PAGE_DATA);
610
/***************************************************************//**
611
Gets the record pointed to by a directory slot.
612
@return pointer to record */
615
page_dir_slot_get_rec(
616
/*==================*/
617
const page_dir_slot_t* slot) /*!< in: directory slot */
619
return(page_align(slot) + mach_read_from_2(slot));
622
/***************************************************************//**
623
This is used to set the record offset in a directory slot. */
626
page_dir_slot_set_rec(
627
/*==================*/
628
page_dir_slot_t* slot, /*!< in: directory slot */
629
rec_t* rec) /*!< in: record on the page */
631
ut_ad(page_rec_check(rec));
633
mach_write_to_2(slot, page_offset(rec));
636
/***************************************************************//**
637
Gets the number of records owned by a directory slot.
638
@return number of records */
641
page_dir_slot_get_n_owned(
642
/*======================*/
643
const page_dir_slot_t* slot) /*!< in: page directory slot */
645
const rec_t* rec = page_dir_slot_get_rec(slot);
646
if (page_rec_is_comp(slot)) {
647
return(rec_get_n_owned_new(rec));
649
return(rec_get_n_owned_old(rec));
653
/***************************************************************//**
654
This is used to set the owned records field of a directory slot. */
657
page_dir_slot_set_n_owned(
658
/*======================*/
659
page_dir_slot_t*slot, /*!< in/out: directory slot */
660
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
661
ulint n) /*!< in: number of records owned by the slot */
663
rec_t* rec = (rec_t*) page_dir_slot_get_rec(slot);
664
if (page_rec_is_comp(slot)) {
665
rec_set_n_owned_new(rec, page_zip, n);
668
rec_set_n_owned_old(rec, n);
672
/************************************************************//**
673
Calculates the space reserved for directory slots of a given number of
674
records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
675
PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
678
page_dir_calc_reserved_space(
679
/*=========================*/
680
ulint n_recs) /*!< in: number of records */
682
return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
683
/ PAGE_DIR_SLOT_MIN_N_OWNED);
686
/************************************************************//**
687
Gets the pointer to the next record on the page.
688
@return pointer to next record */
691
page_rec_get_next_low(
692
/*==================*/
693
const rec_t* rec, /*!< in: pointer to record */
694
ulint comp) /*!< in: nonzero=compact page layout */
699
ut_ad(page_rec_check(rec));
701
page = page_align(rec);
703
offs = rec_get_next_offs(rec, comp);
705
if (UNIV_UNLIKELY(offs >= UNIV_PAGE_SIZE)) {
707
"InnoDB: Next record offset is nonsensical %lu"
708
" in record at offset %lu\n"
709
"InnoDB: rec address %p, space id %lu, page %lu\n",
710
(ulong)offs, (ulong) page_offset(rec),
712
(ulong) page_get_space_id(page),
713
(ulong) page_get_page_no(page));
714
buf_page_print(page, 0);
719
if (UNIV_UNLIKELY(offs == 0)) {
727
/************************************************************//**
728
Gets the pointer to the next record on the page.
729
@return pointer to next record */
734
rec_t* rec) /*!< in: pointer to record */
736
return((rec_t*) page_rec_get_next_low(rec, page_rec_is_comp(rec)));
739
/************************************************************//**
740
Gets the pointer to the next record on the page.
741
@return pointer to next record */
744
page_rec_get_next_const(
745
/*====================*/
746
const rec_t* rec) /*!< in: pointer to record */
748
return(page_rec_get_next_low(rec, page_rec_is_comp(rec)));
751
/************************************************************//**
752
Sets the pointer to the next record on the page. */
757
rec_t* rec, /*!< in: pointer to record,
758
must not be page supremum */
759
rec_t* next) /*!< in: pointer to next record,
760
must not be page infimum */
764
ut_ad(page_rec_check(rec));
765
ut_ad(!page_rec_is_supremum(rec));
768
ut_ad(!next || !page_rec_is_infimum(next));
769
ut_ad(!next || page_align(rec) == page_align(next));
771
if (UNIV_LIKELY(next != NULL)) {
772
offs = page_offset(next);
777
if (page_rec_is_comp(rec)) {
778
rec_set_next_offs_new(rec, offs);
780
rec_set_next_offs_old(rec, offs);
784
/************************************************************//**
785
Gets the pointer to the previous record.
786
@return pointer to previous record */
789
page_rec_get_prev_const(
790
/*====================*/
791
const rec_t* rec) /*!< in: pointer to record, must not be page
794
const page_dir_slot_t* slot;
797
const rec_t* prev_rec = NULL;
800
ut_ad(page_rec_check(rec));
802
page = page_align(rec);
804
ut_ad(!page_rec_is_infimum(rec));
806
slot_no = page_dir_find_owner_slot(rec);
810
slot = page_dir_get_nth_slot(page, slot_no - 1);
812
rec2 = page_dir_slot_get_rec(slot);
814
if (page_is_comp(page)) {
815
while (rec != rec2) {
817
rec2 = page_rec_get_next_low(rec2, TRUE);
820
while (rec != rec2) {
822
rec2 = page_rec_get_next_low(rec2, FALSE);
831
/************************************************************//**
832
Gets the pointer to the previous record.
833
@return pointer to previous record */
838
rec_t* rec) /*!< in: pointer to record, must not be page
841
return((rec_t*) page_rec_get_prev_const(rec));
844
/***************************************************************//**
845
Looks for the record which owns the given record.
846
@return the owner record */
849
page_rec_find_owner_rec(
850
/*====================*/
851
rec_t* rec) /*!< in: the physical record */
853
ut_ad(page_rec_check(rec));
855
if (page_rec_is_comp(rec)) {
856
while (rec_get_n_owned_new(rec) == 0) {
857
rec = page_rec_get_next(rec);
860
while (rec_get_n_owned_old(rec) == 0) {
861
rec = page_rec_get_next(rec);
868
/**********************************************************//**
869
Returns the base extra size of a physical record. This is the
870
size of the fixed header, independent of the record size.
871
@return REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */
874
page_rec_get_base_extra_size(
875
/*=========================*/
876
const rec_t* rec) /*!< in: physical record */
878
#if REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES
879
# error "REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES"
881
return(REC_N_NEW_EXTRA_BYTES + (ulint) !page_rec_is_comp(rec));
884
/************************************************************//**
885
Returns the sum of the sizes of the records in the record list, excluding
886
the infimum and supremum records.
887
@return data in bytes */
892
const page_t* page) /*!< in: index page */
896
ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
897
- (page_is_comp(page)
898
? PAGE_NEW_SUPREMUM_END
899
: PAGE_OLD_SUPREMUM_END)
900
- page_header_get_field(page, PAGE_GARBAGE));
902
ut_ad(ret < UNIV_PAGE_SIZE);
908
/************************************************************//**
909
Allocates a block of memory from the free list of an index page. */
914
page_t* page, /*!< in/out: index page */
915
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
916
space available for inserting the record,
918
rec_t* next_rec,/*!< in: pointer to the new head of the
920
ulint need) /*!< in: number of bytes allocated */
925
const rec_t* old_rec = page_header_get_ptr(page, PAGE_FREE);
929
next_offs = rec_get_next_offs(old_rec, page_is_comp(page));
930
ut_ad(next_rec == (next_offs ? page + next_offs : NULL));
933
page_header_set_ptr(page, page_zip, PAGE_FREE, next_rec);
935
garbage = page_header_get_field(page, PAGE_GARBAGE);
936
ut_ad(garbage >= need);
938
page_header_set_field(page, page_zip, PAGE_GARBAGE, garbage - need);
941
/*************************************************************//**
942
Calculates free space if a page is emptied.
943
@return free space */
946
page_get_free_space_of_empty(
947
/*=========================*/
948
ulint comp) /*!< in: nonzero=compact page layout */
950
if (UNIV_LIKELY(comp)) {
951
return((ulint)(UNIV_PAGE_SIZE
952
- PAGE_NEW_SUPREMUM_END
954
- 2 * PAGE_DIR_SLOT_SIZE));
957
return((ulint)(UNIV_PAGE_SIZE
958
- PAGE_OLD_SUPREMUM_END
960
- 2 * PAGE_DIR_SLOT_SIZE));
963
/************************************************************//**
964
Each user record on a page, and also the deleted user records in the heap
965
takes its size plus the fraction of the dir cell size /
966
PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
967
value of page_get_free_space_of_empty, the insert is impossible, otherwise
968
it is allowed. This function returns the maximum combined size of records
969
which can be inserted on top of the record heap.
970
@return maximum combined size for inserted records */
973
page_get_max_insert_size(
974
/*=====================*/
975
const page_t* page, /*!< in: index page */
976
ulint n_recs) /*!< in: number of records */
981
if (page_is_comp(page)) {
982
occupied = page_header_get_field(page, PAGE_HEAP_TOP)
983
- PAGE_NEW_SUPREMUM_END
984
+ page_dir_calc_reserved_space(
985
n_recs + page_dir_get_n_heap(page) - 2);
987
free_space = page_get_free_space_of_empty(TRUE);
989
occupied = page_header_get_field(page, PAGE_HEAP_TOP)
990
- PAGE_OLD_SUPREMUM_END
991
+ page_dir_calc_reserved_space(
992
n_recs + page_dir_get_n_heap(page) - 2);
994
free_space = page_get_free_space_of_empty(FALSE);
997
/* Above the 'n_recs +' part reserves directory space for the new
998
inserted records; the '- 2' excludes page infimum and supremum
1001
if (occupied > free_space) {
1006
return(free_space - occupied);
1009
/************************************************************//**
1010
Returns the maximum combined size of records which can be inserted on top
1011
of the record heap if a page is first reorganized.
1012
@return maximum combined size for inserted records */
1015
page_get_max_insert_size_after_reorganize(
1016
/*======================================*/
1017
const page_t* page, /*!< in: index page */
1018
ulint n_recs) /*!< in: number of records */
1023
occupied = page_get_data_size(page)
1024
+ page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
1026
free_space = page_get_free_space_of_empty(page_is_comp(page));
1028
if (occupied > free_space) {
1033
return(free_space - occupied);
1036
/************************************************************//**
1037
Puts a record to free list. */
1042
page_t* page, /*!< in/out: index page */
1043
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
1044
rec_t* rec, /*!< in: pointer to the (origin of) record */
1045
dict_index_t* index, /*!< in: index of rec */
1046
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1051
ut_ad(rec_offs_validate(rec, index, offsets));
1052
free = page_header_get_ptr(page, PAGE_FREE);
1054
page_rec_set_next(rec, free);
1055
page_header_set_ptr(page, page_zip, PAGE_FREE, rec);
1057
garbage = page_header_get_field(page, PAGE_GARBAGE);
1059
page_header_set_field(page, page_zip, PAGE_GARBAGE,
1060
garbage + rec_offs_size(offsets));
1062
if (UNIV_LIKELY_NULL(page_zip)) {
1063
page_zip_dir_delete(page_zip, rec, index, offsets, free);
1065
page_header_set_field(page, page_zip, PAGE_N_RECS,
1066
page_get_n_recs(page) - 1);
1070
#ifdef UNIV_MATERIALIZE
1072
#define UNIV_INLINE UNIV_INLINE_ORIGINAL