1
/*****************************************************************************
3
Copyright (c) 1994, 2012, 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 page/page0page.c
23
Created 2/2/1994 Heikki Tuuri
24
*******************************************************/
27
#include "page0page.h"
29
#include "page0page.ic"
37
#ifndef UNIV_HOTBACKUP
39
# include "lock0lock.h"
42
#endif /* !UNIV_HOTBACKUP */
47
The index page consists of a page header which contains the page's
48
id and other information. On top of it are the index records
49
in a heap linked into a one way linear list according to alphabetic order.
51
Just below page end is an array of pointers which we call page directory,
52
to about every sixth record in the list. The pointers are placed in
53
the directory in the alphabetical order of the records pointed to,
54
enabling us to make binary search using the array. Each slot n:o I
55
in the directory points to a record, where a 4-bit field contains a count
56
of those records which are in the linear list between pointer I and
57
the pointer I - 1 in the directory, including the record
58
pointed to by pointer I and not including the record pointed to by I - 1.
59
We say that the record pointed to by slot I, or that slot I, owns
60
these records. The count is always kept in the range 4 to 8, with
61
the exception that it is 1 for the first slot, and 1--8 for the second slot.
63
An essentially binary search can be performed in the list of index
64
records, like we could do if we had pointer to every record in the
65
page directory. The data structure is, however, more efficient when
66
we are doing inserts, because most inserts are just pushed on a heap.
67
Only every 8th insert requires block move in the directory pointer
68
table, which itself is quite small. A record is deleted from the page
69
by just taking it off the linear list and updating the number of owned
70
records-field of the record which owns it, and updating the page directory,
71
if necessary. A special case is the one when the record owns itself.
72
Because the overhead of inserts is so small, we may also increase the
73
page size from the projected default of 8 kB to 64 kB without too
74
much loss of efficiency in inserts. Bigger page becomes actual
75
when the disk transfer rate compared to seek and latency time rises.
76
On the present system, the page size is set so that the page transfer
77
time (3 ms) is 20 % of the disk random access time (15 ms).
79
When the page is split, merged, or becomes full but contains deleted
80
records, we have to reorganize the page.
82
Assuming a page size of 8 kB, a typical index page of a secondary
83
index contains 300 index entries, and the size of the page directory
84
is 50 x 4 bytes = 200 bytes. */
86
/***************************************************************//**
87
Looks for the directory slot which owns the given record.
88
@return the directory slot number */
91
page_dir_find_owner_slot(
92
/*=====================*/
93
const rec_t* rec) /*!< in: the physical record */
96
register uint16 rec_offs_bytes;
97
register const page_dir_slot_t* slot;
98
register const page_dir_slot_t* first_slot;
99
register const rec_t* r = rec;
101
ut_ad(page_rec_check(rec));
103
page = page_align(rec);
104
first_slot = page_dir_get_nth_slot(page, 0);
105
slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
107
if (page_is_comp(page)) {
108
while (rec_get_n_owned_new(r) == 0) {
109
r = rec_get_next_ptr_const(r, TRUE);
110
ut_ad(r >= page + PAGE_NEW_SUPREMUM);
111
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
114
while (rec_get_n_owned_old(r) == 0) {
115
r = rec_get_next_ptr_const(r, FALSE);
116
ut_ad(r >= page + PAGE_OLD_SUPREMUM);
117
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
121
rec_offs_bytes = mach_encode_2(r - page);
123
while (UNIV_LIKELY(*(uint16*) slot != rec_offs_bytes)) {
125
if (UNIV_UNLIKELY(slot == first_slot)) {
127
"InnoDB: Probable data corruption on"
129
"InnoDB: Original record ",
130
(ulong) page_get_page_no(page));
132
if (page_is_comp(page)) {
133
fputs("(compact record)", stderr);
135
rec_print_old(stderr, rec);
139
"InnoDB: on that page.\n"
140
"InnoDB: Cannot find the dir slot for record ",
142
if (page_is_comp(page)) {
143
fputs("(compact record)", stderr);
145
rec_print_old(stderr, page
146
+ mach_decode_2(rec_offs_bytes));
149
"InnoDB: on that page!\n", stderr);
151
buf_page_print(page, 0, 0);
156
slot += PAGE_DIR_SLOT_SIZE;
159
return(((ulint) (first_slot - slot)) / PAGE_DIR_SLOT_SIZE);
162
/**************************************************************//**
163
Used to check the consistency of a directory slot.
164
@return TRUE if succeed */
169
const page_dir_slot_t* slot) /*!< in: slot */
177
page = page_align(slot);
179
n_slots = page_dir_get_n_slots(page);
181
ut_a(slot <= page_dir_get_nth_slot(page, 0));
182
ut_a(slot >= page_dir_get_nth_slot(page, n_slots - 1));
184
ut_a(page_rec_check(page_dir_slot_get_rec(slot)));
186
if (page_is_comp(page)) {
187
n_owned = rec_get_n_owned_new(page_dir_slot_get_rec(slot));
189
n_owned = rec_get_n_owned_old(page_dir_slot_get_rec(slot));
192
if (slot == page_dir_get_nth_slot(page, 0)) {
194
} else if (slot == page_dir_get_nth_slot(page, n_slots - 1)) {
196
ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
198
ut_a(n_owned >= PAGE_DIR_SLOT_MIN_N_OWNED);
199
ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
205
/*************************************************************//**
206
Sets the max trx id field value. */
211
buf_block_t* block, /*!< in/out: page */
212
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
213
trx_id_t trx_id, /*!< in: transaction id */
214
mtr_t* mtr) /*!< in/out: mini-transaction, or NULL */
216
page_t* page = buf_block_get_frame(block);
217
#ifndef UNIV_HOTBACKUP
218
ut_ad(!mtr || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
219
#endif /* !UNIV_HOTBACKUP */
221
/* It is not necessary to write this change to the redo log, as
222
during a database recovery we assume that the max trx id of every
223
page is the maximum trx id assigned before the crash. */
225
if (UNIV_LIKELY_NULL(page_zip)) {
226
mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id);
227
page_zip_write_header(page_zip,
228
page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
230
#ifndef UNIV_HOTBACKUP
232
mlog_write_ull(page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
234
#endif /* !UNIV_HOTBACKUP */
236
mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id);
240
/************************************************************//**
241
Allocates a block of memory from the heap of an index page.
242
@return pointer to start of allocated buffer, or NULL if allocation fails */
247
page_t* page, /*!< in/out: index page */
248
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
249
space available for inserting the record,
251
ulint need, /*!< in: total number of bytes needed */
252
ulint* heap_no)/*!< out: this contains the heap number
253
of the allocated record
254
if allocation succeeds */
259
ut_ad(page && heap_no);
261
avl_space = page_get_max_insert_size(page, 1);
263
if (avl_space >= need) {
264
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
266
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
268
*heap_no = page_dir_get_n_heap(page);
270
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
278
#ifndef UNIV_HOTBACKUP
279
/**********************************************************//**
280
Writes a log record of page creation. */
283
page_create_write_log(
284
/*==================*/
285
buf_frame_t* frame, /*!< in: a buffer frame where the page is
287
mtr_t* mtr, /*!< in: mini-transaction handle */
288
ibool comp) /*!< in: TRUE=compact page format */
290
mlog_write_initial_log_record(frame, comp
291
? MLOG_COMP_PAGE_CREATE
292
: MLOG_PAGE_CREATE, mtr);
294
#else /* !UNIV_HOTBACKUP */
295
# define page_create_write_log(frame,mtr,comp) ((void) 0)
296
#endif /* !UNIV_HOTBACKUP */
298
/***********************************************************//**
299
Parses a redo log record of creating a page.
300
@return end of log record or NULL */
305
byte* ptr, /*!< in: buffer */
306
byte* end_ptr __attribute__((unused)), /*!< in: buffer end */
307
ulint comp, /*!< in: nonzero=compact page format */
308
buf_block_t* block, /*!< in: block or NULL */
309
mtr_t* mtr) /*!< in: mtr or NULL */
311
ut_ad(ptr && end_ptr);
313
/* The record is empty, except for the record initial part */
316
page_create(block, mtr, comp);
322
/**********************************************************//**
323
The index page creation function.
324
@return pointer to the page */
329
buf_block_t* block, /*!< in: a buffer block where the
331
ulint comp) /*!< in: nonzero=compact page format */
333
page_dir_slot_t* slot;
345
#if PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA
346
# error "PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA"
348
#if PAGE_BTR_IBUF_FREE_LIST_NODE + FLST_NODE_SIZE > PAGE_DATA
349
# error "PAGE_BTR_IBUF_FREE_LIST_NODE + FLST_NODE_SIZE > PAGE_DATA"
352
/* The infimum and supremum records use a dummy index. */
353
if (UNIV_LIKELY(comp)) {
354
index = dict_ind_compact;
356
index = dict_ind_redundant;
359
/* 1. INCREMENT MODIFY CLOCK */
360
buf_block_modify_clock_inc(block);
362
page = buf_block_get_frame(block);
364
fil_page_set_type(page, FIL_PAGE_INDEX);
366
heap = mem_heap_create(200);
368
/* 3. CREATE THE INFIMUM AND SUPREMUM RECORDS */
370
/* Create first a data tuple for infimum record */
371
tuple = dtuple_create(heap, 1);
372
dtuple_set_info_bits(tuple, REC_STATUS_INFIMUM);
373
field = dtuple_get_nth_field(tuple, 0);
375
dfield_set_data(field, "infimum", 8);
376
dtype_set(dfield_get_type(field),
377
DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, 8);
378
/* Set the corresponding physical record to its place in the page
381
heap_top = page + PAGE_DATA;
383
infimum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple, 0);
385
if (UNIV_LIKELY(comp)) {
386
ut_a(infimum_rec == page + PAGE_NEW_INFIMUM);
388
rec_set_n_owned_new(infimum_rec, NULL, 1);
389
rec_set_heap_no_new(infimum_rec, 0);
391
ut_a(infimum_rec == page + PAGE_OLD_INFIMUM);
393
rec_set_n_owned_old(infimum_rec, 1);
394
rec_set_heap_no_old(infimum_rec, 0);
397
offsets = rec_get_offsets(infimum_rec, index, NULL,
398
ULINT_UNDEFINED, &heap);
400
heap_top = rec_get_end(infimum_rec, offsets);
402
/* Create then a tuple for supremum */
404
tuple = dtuple_create(heap, 1);
405
dtuple_set_info_bits(tuple, REC_STATUS_SUPREMUM);
406
field = dtuple_get_nth_field(tuple, 0);
408
dfield_set_data(field, "supremum", comp ? 8 : 9);
409
dtype_set(dfield_get_type(field),
410
DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, comp ? 8 : 9);
412
supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple, 0);
414
if (UNIV_LIKELY(comp)) {
415
ut_a(supremum_rec == page + PAGE_NEW_SUPREMUM);
417
rec_set_n_owned_new(supremum_rec, NULL, 1);
418
rec_set_heap_no_new(supremum_rec, 1);
420
ut_a(supremum_rec == page + PAGE_OLD_SUPREMUM);
422
rec_set_n_owned_old(supremum_rec, 1);
423
rec_set_heap_no_old(supremum_rec, 1);
426
offsets = rec_get_offsets(supremum_rec, index, offsets,
427
ULINT_UNDEFINED, &heap);
428
heap_top = rec_get_end(supremum_rec, offsets);
430
ut_ad(heap_top == page
431
+ (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END));
435
/* 4. INITIALIZE THE PAGE */
437
page_header_set_field(page, NULL, PAGE_N_DIR_SLOTS, 2);
438
page_header_set_ptr(page, NULL, PAGE_HEAP_TOP, heap_top);
439
page_header_set_field(page, NULL, PAGE_N_HEAP, comp
440
? 0x8000 | PAGE_HEAP_NO_USER_LOW
441
: PAGE_HEAP_NO_USER_LOW);
442
page_header_set_ptr(page, NULL, PAGE_FREE, NULL);
443
page_header_set_field(page, NULL, PAGE_GARBAGE, 0);
444
page_header_set_ptr(page, NULL, PAGE_LAST_INSERT, NULL);
445
page_header_set_field(page, NULL, PAGE_DIRECTION, PAGE_NO_DIRECTION);
446
page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
447
page_header_set_field(page, NULL, PAGE_N_RECS, 0);
448
page_set_max_trx_id(block, NULL, 0, NULL);
449
memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
450
- page_offset(heap_top));
452
/* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
454
/* Set the slots to point to infimum and supremum. */
456
slot = page_dir_get_nth_slot(page, 0);
457
page_dir_slot_set_rec(slot, infimum_rec);
459
slot = page_dir_get_nth_slot(page, 1);
460
page_dir_slot_set_rec(slot, supremum_rec);
462
/* Set the next pointers in infimum and supremum */
464
if (UNIV_LIKELY(comp)) {
465
rec_set_next_offs_new(infimum_rec, PAGE_NEW_SUPREMUM);
466
rec_set_next_offs_new(supremum_rec, 0);
468
rec_set_next_offs_old(infimum_rec, PAGE_OLD_SUPREMUM);
469
rec_set_next_offs_old(supremum_rec, 0);
475
/**********************************************************//**
476
Create an uncompressed B-tree index page.
477
@return pointer to the page */
482
buf_block_t* block, /*!< in: a buffer block where the
484
mtr_t* mtr, /*!< in: mini-transaction handle */
485
ulint comp) /*!< in: nonzero=compact page format */
487
page_create_write_log(buf_block_get_frame(block), mtr, comp);
488
return(page_create_low(block, comp));
491
/**********************************************************//**
492
Create a compressed B-tree index page.
493
@return pointer to the page */
498
buf_block_t* block, /*!< in/out: a buffer frame where the
500
dict_index_t* index, /*!< in: the index of the page */
501
ulint level, /*!< in: the B-tree level of the page */
502
mtr_t* mtr) /*!< in: mini-transaction handle */
505
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
510
ut_ad(dict_table_is_comp(index->table));
512
page = page_create_low(block, TRUE);
513
mach_write_to_2(page + PAGE_HEADER + PAGE_LEVEL, level);
515
if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
516
/* The compression of a newly created page
517
should always succeed. */
524
/*************************************************************//**
525
Differs from page_copy_rec_list_end, because this function does not
526
touch the lock table and max trx id on page or compress the page. */
529
page_copy_rec_list_end_no_locks(
530
/*============================*/
531
buf_block_t* new_block, /*!< in: index page to copy to */
532
buf_block_t* block, /*!< in: index page of rec */
533
rec_t* rec, /*!< in: record on page */
534
dict_index_t* index, /*!< in: record descriptor */
535
mtr_t* mtr) /*!< in: mtr */
537
page_t* new_page = buf_block_get_frame(new_block);
540
mem_heap_t* heap = NULL;
541
ulint offsets_[REC_OFFS_NORMAL_SIZE];
542
ulint* offsets = offsets_;
543
rec_offs_init(offsets_);
545
page_cur_position(rec, block, &cur1);
547
if (page_cur_is_before_first(&cur1)) {
549
page_cur_move_to_next(&cur1);
552
btr_assert_not_corrupted(new_block, index);
553
ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
554
ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
555
(page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
557
cur2 = page_get_infimum_rec(buf_block_get_frame(new_block));
559
/* Copy records from the original page to the new page */
561
while (!page_cur_is_after_last(&cur1)) {
562
rec_t* cur1_rec = page_cur_get_rec(&cur1);
564
offsets = rec_get_offsets(cur1_rec, index, offsets,
565
ULINT_UNDEFINED, &heap);
566
ins_rec = page_cur_insert_rec_low(cur2, index,
567
cur1_rec, offsets, mtr);
568
if (UNIV_UNLIKELY(!ins_rec)) {
569
/* Track an assertion failure reported on the mailing
570
list on June 18th, 2003 */
572
buf_page_print(new_page, 0,
573
BUF_PAGE_PRINT_NO_CRASH);
574
buf_page_print(page_align(rec), 0,
575
BUF_PAGE_PRINT_NO_CRASH);
576
ut_print_timestamp(stderr);
579
"InnoDB: rec offset %lu, cur1 offset %lu,"
580
" cur2 offset %lu\n",
581
(ulong) page_offset(rec),
582
(ulong) page_offset(page_cur_get_rec(&cur1)),
583
(ulong) page_offset(cur2));
587
page_cur_move_to_next(&cur1);
591
if (UNIV_LIKELY_NULL(heap)) {
596
#ifndef UNIV_HOTBACKUP
597
/*************************************************************//**
598
Copies records from page to new_page, from a given record onward,
599
including that record. Infimum and supremum records are not copied.
600
The records are copied to the start of the record list on new_page.
601
@return pointer to the original successor of the infimum record on
602
new_page, or NULL on zip overflow (new_block will be decompressed) */
605
page_copy_rec_list_end(
606
/*===================*/
607
buf_block_t* new_block, /*!< in/out: index page to copy to */
608
buf_block_t* block, /*!< in: index page containing rec */
609
rec_t* rec, /*!< in: record on page */
610
dict_index_t* index, /*!< in: record descriptor */
611
mtr_t* mtr) /*!< in: mtr */
613
page_t* new_page = buf_block_get_frame(new_block);
614
page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block);
615
page_t* page = page_align(rec);
616
rec_t* ret = page_rec_get_next(
617
page_get_infimum_rec(new_page));
618
ulint log_mode = 0; /* remove warning */
620
#ifdef UNIV_ZIP_DEBUG
622
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
625
/* Strict page_zip_validate() may fail here.
626
Furthermore, btr_compress() may set FIL_PAGE_PREV to
627
FIL_NULL on new_page while leaving it intact on
628
new_page_zip. So, we cannot validate new_page_zip. */
629
ut_a(page_zip_validate_low(page_zip, page, index, TRUE));
631
#endif /* UNIV_ZIP_DEBUG */
632
ut_ad(buf_block_get_frame(block) == page);
633
ut_ad(page_is_leaf(page) == page_is_leaf(new_page));
634
ut_ad(page_is_comp(page) == page_is_comp(new_page));
635
/* Here, "ret" may be pointing to a user record or the
636
predefined supremum record. */
638
if (UNIV_LIKELY_NULL(new_page_zip)) {
639
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
642
if (page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW) {
643
page_copy_rec_list_end_to_created_page(new_page, rec,
646
page_copy_rec_list_end_no_locks(new_block, block, rec,
650
/* Update PAGE_MAX_TRX_ID on the uncompressed page.
651
Modifications will be redo logged and copied to the compressed
652
page in page_zip_compress() or page_zip_reorganize() below. */
653
if (dict_index_is_sec_or_ibuf(index) && page_is_leaf(page)) {
654
page_update_max_trx_id(new_block, NULL,
655
page_get_max_trx_id(page), mtr);
658
if (UNIV_LIKELY_NULL(new_page_zip)) {
659
mtr_set_log_mode(mtr, log_mode);
662
(!page_zip_compress(new_page_zip, new_page, index, mtr))) {
663
/* Before trying to reorganize the page,
664
store the number of preceding records on the page. */
666
= page_rec_get_n_recs_before(ret);
667
/* Before copying, "ret" was the successor of
668
the predefined infimum record. It must still
669
have at least one predecessor (the predefined
670
infimum record, or a freshly copied record
671
that is smaller than "ret"). */
675
(!page_zip_reorganize(new_block, index, mtr))) {
677
btr_blob_dbg_remove(new_page, index,
678
"copy_end_reorg_fail");
680
(!page_zip_decompress(new_page_zip,
684
ut_ad(page_validate(new_page, index));
685
btr_blob_dbg_add(new_page, index,
686
"copy_end_reorg_fail");
689
/* The page was reorganized:
691
ret = new_page + PAGE_NEW_INFIMUM;
694
ret = rec_get_next_ptr(ret, TRUE);
700
/* Update the lock table and possible hash index */
702
lock_move_rec_list_end(new_block, block, rec);
704
btr_search_move_or_delete_hash_entries(new_block, block, index);
709
/*************************************************************//**
710
Copies records from page to new_page, up to the given record,
711
NOT including that record. Infimum and supremum records are not copied.
712
The records are copied to the end of the record list on new_page.
713
@return pointer to the original predecessor of the supremum record on
714
new_page, or NULL on zip overflow (new_block will be decompressed) */
717
page_copy_rec_list_start(
718
/*=====================*/
719
buf_block_t* new_block, /*!< in/out: index page to copy to */
720
buf_block_t* block, /*!< in: index page containing rec */
721
rec_t* rec, /*!< in: record on page */
722
dict_index_t* index, /*!< in: record descriptor */
723
mtr_t* mtr) /*!< in: mtr */
725
page_t* new_page = buf_block_get_frame(new_block);
726
page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block);
729
ulint log_mode = 0 /* remove warning */;
730
mem_heap_t* heap = NULL;
732
= page_rec_get_prev(page_get_supremum_rec(new_page));
733
ulint offsets_[REC_OFFS_NORMAL_SIZE];
734
ulint* offsets = offsets_;
735
rec_offs_init(offsets_);
737
/* Here, "ret" may be pointing to a user record or the
738
predefined infimum record. */
740
if (page_rec_is_infimum(rec)) {
745
if (UNIV_LIKELY_NULL(new_page_zip)) {
746
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
749
page_cur_set_before_first(block, &cur1);
750
page_cur_move_to_next(&cur1);
754
/* Copy records from the original page to the new page */
756
while (page_cur_get_rec(&cur1) != rec) {
757
rec_t* cur1_rec = page_cur_get_rec(&cur1);
758
offsets = rec_get_offsets(cur1_rec, index, offsets,
759
ULINT_UNDEFINED, &heap);
760
cur2 = page_cur_insert_rec_low(cur2, index,
761
cur1_rec, offsets, mtr);
764
page_cur_move_to_next(&cur1);
767
if (UNIV_LIKELY_NULL(heap)) {
771
/* Update PAGE_MAX_TRX_ID on the uncompressed page.
772
Modifications will be redo logged and copied to the compressed
773
page in page_zip_compress() or page_zip_reorganize() below. */
774
if (dict_index_is_sec_or_ibuf(index)
775
&& page_is_leaf(page_align(rec))) {
776
page_update_max_trx_id(new_block, NULL,
777
page_get_max_trx_id(page_align(rec)),
781
if (UNIV_LIKELY_NULL(new_page_zip)) {
782
mtr_set_log_mode(mtr, log_mode);
784
DBUG_EXECUTE_IF("page_copy_rec_list_start_compress_fail",
785
goto zip_reorganize;);
788
(!page_zip_compress(new_page_zip, new_page, index, mtr))) {
792
#endif /* DBUG_OFF */
793
/* Before trying to reorganize the page,
794
store the number of preceding records on the page. */
795
ret_pos = page_rec_get_n_recs_before(ret);
796
/* Before copying, "ret" was the predecessor
797
of the predefined supremum record. If it was
798
the predefined infimum record, then it would
799
still be the infimum, and we would have
803
(!page_zip_reorganize(new_block, index, mtr))) {
805
btr_blob_dbg_remove(new_page, index,
806
"copy_start_reorg_fail");
808
(!page_zip_decompress(new_page_zip,
812
ut_ad(page_validate(new_page, index));
813
btr_blob_dbg_add(new_page, index,
814
"copy_start_reorg_fail");
818
/* The page was reorganized: Seek to ret_pos. */
819
ret = page_rec_get_nth(new_page, ret_pos);
823
/* Update the lock table and possible hash index */
825
lock_move_rec_list_start(new_block, block, rec, ret);
827
btr_search_move_or_delete_hash_entries(new_block, block, index);
832
/**********************************************************//**
833
Writes a log record of a record list end or start deletion. */
836
page_delete_rec_list_write_log(
837
/*===========================*/
838
rec_t* rec, /*!< in: record on page */
839
dict_index_t* index, /*!< in: record descriptor */
840
byte type, /*!< in: operation type:
841
MLOG_LIST_END_DELETE, ... */
842
mtr_t* mtr) /*!< in: mtr */
845
ut_ad(type == MLOG_LIST_END_DELETE
846
|| type == MLOG_LIST_START_DELETE
847
|| type == MLOG_COMP_LIST_END_DELETE
848
|| type == MLOG_COMP_LIST_START_DELETE);
850
log_ptr = mlog_open_and_write_index(mtr, rec, index, type, 2);
852
/* Write the parameter as a 2-byte ulint */
853
mach_write_to_2(log_ptr, page_offset(rec));
854
mlog_close(mtr, log_ptr + 2);
857
#else /* !UNIV_HOTBACKUP */
858
# define page_delete_rec_list_write_log(rec,index,type,mtr) ((void) 0)
859
#endif /* !UNIV_HOTBACKUP */
861
/**********************************************************//**
862
Parses a log record of a record list end or start deletion.
863
@return end of log record or NULL */
866
page_parse_delete_rec_list(
867
/*=======================*/
868
byte type, /*!< in: MLOG_LIST_END_DELETE,
869
MLOG_LIST_START_DELETE,
870
MLOG_COMP_LIST_END_DELETE or
871
MLOG_COMP_LIST_START_DELETE */
872
byte* ptr, /*!< in: buffer */
873
byte* end_ptr,/*!< in: buffer end */
874
buf_block_t* block, /*!< in/out: buffer block or NULL */
875
dict_index_t* index, /*!< in: record descriptor */
876
mtr_t* mtr) /*!< in: mtr or NULL */
881
ut_ad(type == MLOG_LIST_END_DELETE
882
|| type == MLOG_LIST_START_DELETE
883
|| type == MLOG_COMP_LIST_END_DELETE
884
|| type == MLOG_COMP_LIST_START_DELETE);
886
/* Read the record offset as a 2-byte ulint */
888
if (end_ptr < ptr + 2) {
893
offset = mach_read_from_2(ptr);
901
page = buf_block_get_frame(block);
903
ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
905
if (type == MLOG_LIST_END_DELETE
906
|| type == MLOG_COMP_LIST_END_DELETE) {
907
page_delete_rec_list_end(page + offset, block, index,
908
ULINT_UNDEFINED, ULINT_UNDEFINED,
911
page_delete_rec_list_start(page + offset, block, index, mtr);
917
/*************************************************************//**
918
Deletes records from a page from a given record onward, including that record.
919
The infimum and supremum records are not deleted. */
922
page_delete_rec_list_end(
923
/*=====================*/
924
rec_t* rec, /*!< in: pointer to record on page */
925
buf_block_t* block, /*!< in: buffer block of the page */
926
dict_index_t* index, /*!< in: record descriptor */
927
ulint n_recs, /*!< in: number of records to delete,
928
or ULINT_UNDEFINED if not known */
929
ulint size, /*!< in: the sum of the sizes of the
930
records in the end of the chain to
931
delete, or ULINT_UNDEFINED if not known */
932
mtr_t* mtr) /*!< in: mtr */
934
page_dir_slot_t*slot;
939
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
940
page_t* page = page_align(rec);
941
mem_heap_t* heap = NULL;
942
ulint offsets_[REC_OFFS_NORMAL_SIZE];
943
ulint* offsets = offsets_;
944
rec_offs_init(offsets_);
946
ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
947
ut_ad(!page_zip || page_rec_is_comp(rec));
948
#ifdef UNIV_ZIP_DEBUG
949
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
950
#endif /* UNIV_ZIP_DEBUG */
952
if (page_rec_is_infimum(rec)) {
953
rec = page_rec_get_next(rec);
956
if (page_rec_is_supremum(rec)) {
961
/* Reset the last insert info in the page header and increment
962
the modify clock for the frame */
964
page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
966
/* The page gets invalid for optimistic searches: increment the
967
frame modify clock */
969
buf_block_modify_clock_inc(block);
971
page_delete_rec_list_write_log(rec, index, page_is_comp(page)
972
? MLOG_COMP_LIST_END_DELETE
973
: MLOG_LIST_END_DELETE, mtr);
975
if (UNIV_LIKELY_NULL(page_zip)) {
978
ut_a(page_is_comp(page));
979
/* Individual deletes are not logged */
981
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
985
page_cur_position(rec, block, &cur);
987
offsets = rec_get_offsets(rec, index, offsets,
988
ULINT_UNDEFINED, &heap);
989
rec = rec_get_next_ptr(rec, TRUE);
990
#ifdef UNIV_ZIP_DEBUG
991
ut_a(page_zip_validate(page_zip, page, index));
992
#endif /* UNIV_ZIP_DEBUG */
993
page_cur_delete_rec(&cur, index, offsets, mtr);
994
} while (page_offset(rec) != PAGE_NEW_SUPREMUM);
996
if (UNIV_LIKELY_NULL(heap)) {
1000
/* Restore log mode */
1002
mtr_set_log_mode(mtr, log_mode);
1006
prev_rec = page_rec_get_prev(rec);
1008
last_rec = page_rec_get_prev(page_get_supremum_rec(page));
1010
if ((size == ULINT_UNDEFINED) || (n_recs == ULINT_UNDEFINED)) {
1012
/* Calculate the sum of sizes and the number of records */
1018
offsets = rec_get_offsets(rec2, index, offsets,
1019
ULINT_UNDEFINED, &heap);
1020
s = rec_offs_size(offsets);
1021
ut_ad(rec2 - page + s - rec_offs_extra_size(offsets)
1023
ut_ad(size + s < UNIV_PAGE_SIZE);
1027
rec2 = page_rec_get_next(rec2);
1028
} while (!page_rec_is_supremum(rec2));
1030
if (UNIV_LIKELY_NULL(heap)) {
1031
mem_heap_free(heap);
1035
ut_ad(size < UNIV_PAGE_SIZE);
1037
/* Update the page directory; there is no need to balance the number
1038
of the records owned by the supremum record, as it is allowed to be
1039
less than PAGE_DIR_SLOT_MIN_N_OWNED */
1041
if (page_is_comp(page)) {
1045
while (rec_get_n_owned_new(rec2) == 0) {
1048
rec2 = rec_get_next_ptr(rec2, TRUE);
1051
ut_ad(rec_get_n_owned_new(rec2) > count);
1053
n_owned = rec_get_n_owned_new(rec2) - count;
1054
slot_index = page_dir_find_owner_slot(rec2);
1055
ut_ad(slot_index > 0);
1056
slot = page_dir_get_nth_slot(page, slot_index);
1061
while (rec_get_n_owned_old(rec2) == 0) {
1064
rec2 = rec_get_next_ptr(rec2, FALSE);
1067
ut_ad(rec_get_n_owned_old(rec2) > count);
1069
n_owned = rec_get_n_owned_old(rec2) - count;
1070
slot_index = page_dir_find_owner_slot(rec2);
1071
ut_ad(slot_index > 0);
1072
slot = page_dir_get_nth_slot(page, slot_index);
1075
page_dir_slot_set_rec(slot, page_get_supremum_rec(page));
1076
page_dir_slot_set_n_owned(slot, NULL, n_owned);
1078
page_dir_set_n_slots(page, NULL, slot_index + 1);
1080
/* Remove the record chain segment from the record chain */
1081
page_rec_set_next(prev_rec, page_get_supremum_rec(page));
1083
btr_blob_dbg_op(page, rec, index, "delete_end",
1084
btr_blob_dbg_remove_rec);
1086
/* Catenate the deleted chain segment to the page free list */
1088
page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE));
1089
page_header_set_ptr(page, NULL, PAGE_FREE, rec);
1091
page_header_set_field(page, NULL, PAGE_GARBAGE, size
1092
+ page_header_get_field(page, PAGE_GARBAGE));
1094
page_header_set_field(page, NULL, PAGE_N_RECS,
1095
(ulint)(page_get_n_recs(page) - n_recs));
1098
/*************************************************************//**
1099
Deletes records from page, up to the given record, NOT including
1100
that record. Infimum and supremum records are not deleted. */
1103
page_delete_rec_list_start(
1104
/*=======================*/
1105
rec_t* rec, /*!< in: record on page */
1106
buf_block_t* block, /*!< in: buffer block of the page */
1107
dict_index_t* index, /*!< in: record descriptor */
1108
mtr_t* mtr) /*!< in: mtr */
1112
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1113
ulint* offsets = offsets_;
1114
mem_heap_t* heap = NULL;
1117
rec_offs_init(offsets_);
1119
ut_ad((ibool) !!page_rec_is_comp(rec)
1120
== dict_table_is_comp(index->table));
1121
#ifdef UNIV_ZIP_DEBUG
1123
page_zip_des_t* page_zip= buf_block_get_page_zip(block);
1124
page_t* page = buf_block_get_frame(block);
1126
/* page_zip_validate() would detect a min_rec_mark mismatch
1127
in btr_page_split_and_insert()
1128
between btr_attach_half_pages() and insert_page = ...
1129
when btr_page_get_split_rec_to_left() holds
1130
(direction == FSP_DOWN). */
1132
|| page_zip_validate_low(page_zip, page, index, TRUE));
1134
#endif /* UNIV_ZIP_DEBUG */
1136
if (page_rec_is_infimum(rec)) {
1141
if (page_rec_is_comp(rec)) {
1142
type = MLOG_COMP_LIST_START_DELETE;
1144
type = MLOG_LIST_START_DELETE;
1147
page_delete_rec_list_write_log(rec, index, type, mtr);
1149
page_cur_set_before_first(block, &cur1);
1150
page_cur_move_to_next(&cur1);
1152
/* Individual deletes are not logged */
1154
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
1156
while (page_cur_get_rec(&cur1) != rec) {
1157
offsets = rec_get_offsets(page_cur_get_rec(&cur1), index,
1158
offsets, ULINT_UNDEFINED, &heap);
1159
page_cur_delete_rec(&cur1, index, offsets, mtr);
1162
if (UNIV_LIKELY_NULL(heap)) {
1163
mem_heap_free(heap);
1166
/* Restore log mode */
1168
mtr_set_log_mode(mtr, log_mode);
1171
#ifndef UNIV_HOTBACKUP
1172
/*************************************************************//**
1173
Moves record list end to another page. Moved records include
1175
@return TRUE on success; FALSE on compression failure (new_block will
1179
page_move_rec_list_end(
1180
/*===================*/
1181
buf_block_t* new_block, /*!< in/out: index page where to move */
1182
buf_block_t* block, /*!< in: index page from where to move */
1183
rec_t* split_rec, /*!< in: first record to move */
1184
dict_index_t* index, /*!< in: record descriptor */
1185
mtr_t* mtr) /*!< in: mtr */
1187
page_t* new_page = buf_block_get_frame(new_block);
1188
ulint old_data_size;
1189
ulint new_data_size;
1193
old_data_size = page_get_data_size(new_page);
1194
old_n_recs = page_get_n_recs(new_page);
1195
#ifdef UNIV_ZIP_DEBUG
1197
page_zip_des_t* new_page_zip
1198
= buf_block_get_page_zip(new_block);
1199
page_zip_des_t* page_zip
1200
= buf_block_get_page_zip(block);
1201
ut_a(!new_page_zip == !page_zip);
1203
|| page_zip_validate(new_page_zip, new_page, index));
1205
|| page_zip_validate(page_zip, page_align(split_rec),
1208
#endif /* UNIV_ZIP_DEBUG */
1210
if (UNIV_UNLIKELY(!page_copy_rec_list_end(new_block, block,
1211
split_rec, index, mtr))) {
1215
new_data_size = page_get_data_size(new_page);
1216
new_n_recs = page_get_n_recs(new_page);
1218
ut_ad(new_data_size >= old_data_size);
1220
page_delete_rec_list_end(split_rec, block, index,
1221
new_n_recs - old_n_recs,
1222
new_data_size - old_data_size, mtr);
1227
/*************************************************************//**
1228
Moves record list start to another page. Moved records do not include
1230
@return TRUE on success; FALSE on compression failure */
1233
page_move_rec_list_start(
1234
/*=====================*/
1235
buf_block_t* new_block, /*!< in/out: index page where to move */
1236
buf_block_t* block, /*!< in/out: page containing split_rec */
1237
rec_t* split_rec, /*!< in: first record not to move */
1238
dict_index_t* index, /*!< in: record descriptor */
1239
mtr_t* mtr) /*!< in: mtr */
1241
if (UNIV_UNLIKELY(!page_copy_rec_list_start(new_block, block,
1242
split_rec, index, mtr))) {
1246
page_delete_rec_list_start(split_rec, block, index, mtr);
1250
#endif /* !UNIV_HOTBACKUP */
1252
/**************************************************************//**
1253
Used to delete n slots from the directory. This function updates
1254
also n_owned fields in the records, so that the first slot after
1255
the deleted ones inherits the records of the deleted slots. */
1258
page_dir_delete_slot(
1259
/*=================*/
1260
page_t* page, /*!< in/out: the index page */
1261
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
1262
ulint slot_no)/*!< in: slot to be deleted */
1264
page_dir_slot_t* slot;
1269
ut_ad(!page_zip || page_is_comp(page));
1271
ut_ad(slot_no + 1 < page_dir_get_n_slots(page));
1273
n_slots = page_dir_get_n_slots(page);
1275
/* 1. Reset the n_owned fields of the slots to be
1277
slot = page_dir_get_nth_slot(page, slot_no);
1278
n_owned = page_dir_slot_get_n_owned(slot);
1279
page_dir_slot_set_n_owned(slot, page_zip, 0);
1281
/* 2. Update the n_owned value of the first non-deleted slot */
1283
slot = page_dir_get_nth_slot(page, slot_no + 1);
1284
page_dir_slot_set_n_owned(slot, page_zip,
1285
n_owned + page_dir_slot_get_n_owned(slot));
1287
/* 3. Destroy the slot by copying slots */
1288
for (i = slot_no + 1; i < n_slots; i++) {
1289
rec_t* rec = (rec_t*)
1290
page_dir_slot_get_rec(page_dir_get_nth_slot(page, i));
1291
page_dir_slot_set_rec(page_dir_get_nth_slot(page, i - 1), rec);
1294
/* 4. Zero out the last slot, which will be removed */
1295
mach_write_to_2(page_dir_get_nth_slot(page, n_slots - 1), 0);
1297
/* 5. Update the page header */
1298
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots - 1);
1301
/**************************************************************//**
1302
Used to add n slots to the directory. Does not set the record pointers
1303
in the added slots or update n_owned values: this is the responsibility
1309
page_t* page, /*!< in/out: the index page */
1310
page_zip_des_t* page_zip,/*!< in/out: comprssed page, or NULL */
1311
ulint start) /*!< in: the slot above which the new slots
1314
page_dir_slot_t* slot;
1317
n_slots = page_dir_get_n_slots(page);
1319
ut_ad(start < n_slots - 1);
1321
/* Update the page header */
1322
page_dir_set_n_slots(page, page_zip, n_slots + 1);
1325
slot = page_dir_get_nth_slot(page, n_slots);
1326
memmove(slot, slot + PAGE_DIR_SLOT_SIZE,
1327
(n_slots - 1 - start) * PAGE_DIR_SLOT_SIZE);
1330
/****************************************************************//**
1331
Splits a directory slot which owns too many records. */
1334
page_dir_split_slot(
1335
/*================*/
1336
page_t* page, /*!< in/out: index page */
1337
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
1338
uncompressed part will be written, or NULL */
1339
ulint slot_no)/*!< in: the directory slot */
1342
page_dir_slot_t* new_slot;
1343
page_dir_slot_t* prev_slot;
1344
page_dir_slot_t* slot;
1349
ut_ad(!page_zip || page_is_comp(page));
1352
slot = page_dir_get_nth_slot(page, slot_no);
1354
n_owned = page_dir_slot_get_n_owned(slot);
1355
ut_ad(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED + 1);
1357
/* 1. We loop to find a record approximately in the middle of the
1358
records owned by the slot. */
1360
prev_slot = page_dir_get_nth_slot(page, slot_no - 1);
1361
rec = (rec_t*) page_dir_slot_get_rec(prev_slot);
1363
for (i = 0; i < n_owned / 2; i++) {
1364
rec = page_rec_get_next(rec);
1367
ut_ad(n_owned / 2 >= PAGE_DIR_SLOT_MIN_N_OWNED);
1369
/* 2. We add one directory slot immediately below the slot to be
1372
page_dir_add_slot(page, page_zip, slot_no - 1);
1374
/* The added slot is now number slot_no, and the old slot is
1375
now number slot_no + 1 */
1377
new_slot = page_dir_get_nth_slot(page, slot_no);
1378
slot = page_dir_get_nth_slot(page, slot_no + 1);
1380
/* 3. We store the appropriate values to the new slot. */
1382
page_dir_slot_set_rec(new_slot, rec);
1383
page_dir_slot_set_n_owned(new_slot, page_zip, n_owned / 2);
1385
/* 4. Finally, we update the number of records field of the
1388
page_dir_slot_set_n_owned(slot, page_zip, n_owned - (n_owned / 2));
1391
/*************************************************************//**
1392
Tries to balance the given directory slot with too few records with the upper
1393
neighbor, so that there are at least the minimum number of records owned by
1394
the slot; this may result in the merging of two slots. */
1397
page_dir_balance_slot(
1398
/*==================*/
1399
page_t* page, /*!< in/out: index page */
1400
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
1401
ulint slot_no)/*!< in: the directory slot */
1403
page_dir_slot_t* slot;
1404
page_dir_slot_t* up_slot;
1411
ut_ad(!page_zip || page_is_comp(page));
1414
slot = page_dir_get_nth_slot(page, slot_no);
1416
/* The last directory slot cannot be balanced with the upper
1417
neighbor, as there is none. */
1419
if (UNIV_UNLIKELY(slot_no == page_dir_get_n_slots(page) - 1)) {
1424
up_slot = page_dir_get_nth_slot(page, slot_no + 1);
1426
n_owned = page_dir_slot_get_n_owned(slot);
1427
up_n_owned = page_dir_slot_get_n_owned(up_slot);
1429
ut_ad(n_owned == PAGE_DIR_SLOT_MIN_N_OWNED - 1);
1431
/* If the upper slot has the minimum value of n_owned, we will merge
1432
the two slots, therefore we assert: */
1433
ut_ad(2 * PAGE_DIR_SLOT_MIN_N_OWNED - 1 <= PAGE_DIR_SLOT_MAX_N_OWNED);
1435
if (up_n_owned > PAGE_DIR_SLOT_MIN_N_OWNED) {
1437
/* In this case we can just transfer one record owned
1438
by the upper slot to the property of the lower slot */
1439
old_rec = (rec_t*) page_dir_slot_get_rec(slot);
1441
if (page_is_comp(page)) {
1442
new_rec = rec_get_next_ptr(old_rec, TRUE);
1444
rec_set_n_owned_new(old_rec, page_zip, 0);
1445
rec_set_n_owned_new(new_rec, page_zip, n_owned + 1);
1447
new_rec = rec_get_next_ptr(old_rec, FALSE);
1449
rec_set_n_owned_old(old_rec, 0);
1450
rec_set_n_owned_old(new_rec, n_owned + 1);
1453
page_dir_slot_set_rec(slot, new_rec);
1455
page_dir_slot_set_n_owned(up_slot, page_zip, up_n_owned -1);
1457
/* In this case we may merge the two slots */
1458
page_dir_delete_slot(page, page_zip, slot_no);
1462
/************************************************************//**
1463
Returns the nth record of the record list.
1464
This is the inverse function of page_rec_get_n_recs_before().
1465
@return nth record */
1468
page_rec_get_nth_const(
1469
/*===================*/
1470
const page_t* page, /*!< in: page */
1471
ulint nth) /*!< in: nth record */
1473
const page_dir_slot_t* slot;
1479
return(page_get_infimum_rec(page));
1482
ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1));
1486
slot = page_dir_get_nth_slot(page, i);
1487
n_owned = page_dir_slot_get_n_owned(slot);
1489
if (n_owned > nth) {
1497
slot = page_dir_get_nth_slot(page, i - 1);
1498
rec = page_dir_slot_get_rec(slot);
1500
if (page_is_comp(page)) {
1502
rec = page_rec_get_next_low(rec, TRUE);
1507
rec = page_rec_get_next_low(rec, FALSE);
1515
/***************************************************************//**
1516
Returns the number of records before the given record in chain.
1517
The number includes infimum and supremum records.
1518
@return number of records */
1521
page_rec_get_n_recs_before(
1522
/*=======================*/
1523
const rec_t* rec) /*!< in: the physical record */
1525
const page_dir_slot_t* slot;
1526
const rec_t* slot_rec;
1531
ut_ad(page_rec_check(rec));
1533
page = page_align(rec);
1534
if (page_is_comp(page)) {
1535
while (rec_get_n_owned_new(rec) == 0) {
1537
rec = rec_get_next_ptr_const(rec, TRUE);
1541
for (i = 0; ; i++) {
1542
slot = page_dir_get_nth_slot(page, i);
1543
slot_rec = page_dir_slot_get_rec(slot);
1545
n += rec_get_n_owned_new(slot_rec);
1547
if (rec == slot_rec) {
1553
while (rec_get_n_owned_old(rec) == 0) {
1555
rec = rec_get_next_ptr_const(rec, FALSE);
1559
for (i = 0; ; i++) {
1560
slot = page_dir_get_nth_slot(page, i);
1561
slot_rec = page_dir_slot_get_rec(slot);
1563
n += rec_get_n_owned_old(slot_rec);
1565
if (rec == slot_rec) {
1575
ut_ad(n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1));
1580
#ifndef UNIV_HOTBACKUP
1581
/************************************************************//**
1582
Prints record contents including the data relevant only in
1583
the index page context. */
1588
const rec_t* rec, /*!< in: physical record */
1589
const ulint* offsets)/*!< in: record descriptor */
1591
ut_a(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
1592
rec_print_new(stderr, rec, offsets);
1593
if (page_rec_is_comp(rec)) {
1595
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1596
(ulong) rec_get_n_owned_new(rec),
1597
(ulong) rec_get_heap_no_new(rec),
1598
(ulong) rec_get_next_offs(rec, TRUE));
1601
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1602
(ulong) rec_get_n_owned_old(rec),
1603
(ulong) rec_get_heap_no_old(rec),
1604
(ulong) rec_get_next_offs(rec, FALSE));
1607
page_rec_check(rec);
1608
rec_validate(rec, offsets);
1611
# ifdef UNIV_BTR_PRINT
1612
/***************************************************************//**
1613
This is used to print the contents of the directory for
1614
debugging purposes. */
1619
page_t* page, /*!< in: index page */
1620
ulint pr_n) /*!< in: print n first and n last entries */
1624
page_dir_slot_t* slot;
1626
n = page_dir_get_n_slots(page);
1628
fprintf(stderr, "--------------------------------\n"
1631
"Directory stack top at offs: %lu; number of slots: %lu\n",
1632
page, (ulong) page_offset(page_dir_get_nth_slot(page, n - 1)),
1634
for (i = 0; i < n; i++) {
1635
slot = page_dir_get_nth_slot(page, i);
1636
if ((i == pr_n) && (i < n - pr_n)) {
1637
fputs(" ... \n", stderr);
1639
if ((i < pr_n) || (i >= n - pr_n)) {
1641
"Contents of slot: %lu: n_owned: %lu,"
1644
(ulong) page_dir_slot_get_n_owned(slot),
1646
page_offset(page_dir_slot_get_rec(slot)));
1649
fprintf(stderr, "Total of %lu records\n"
1650
"--------------------------------\n",
1651
(ulong) (PAGE_HEAP_NO_USER_LOW + page_get_n_recs(page)));
1654
/***************************************************************//**
1655
This is used to print the contents of the page record list for
1656
debugging purposes. */
1661
buf_block_t* block, /*!< in: index page */
1662
dict_index_t* index, /*!< in: dictionary index of the page */
1663
ulint pr_n) /*!< in: print n first and n last entries */
1665
page_t* page = block->frame;
1669
mem_heap_t* heap = NULL;
1670
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1671
ulint* offsets = offsets_;
1672
rec_offs_init(offsets_);
1674
ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table));
1677
"--------------------------------\n"
1678
"PAGE RECORD LIST\n"
1679
"Page address %p\n", page);
1681
n_recs = page_get_n_recs(page);
1683
page_cur_set_before_first(block, &cur);
1686
offsets = rec_get_offsets(cur.rec, index, offsets,
1687
ULINT_UNDEFINED, &heap);
1688
page_rec_print(cur.rec, offsets);
1690
if (count == pr_n) {
1693
if (page_cur_is_after_last(&cur)) {
1696
page_cur_move_to_next(&cur);
1700
if (n_recs > 2 * pr_n) {
1701
fputs(" ... \n", stderr);
1704
while (!page_cur_is_after_last(&cur)) {
1705
page_cur_move_to_next(&cur);
1707
if (count + pr_n >= n_recs) {
1708
offsets = rec_get_offsets(cur.rec, index, offsets,
1709
ULINT_UNDEFINED, &heap);
1710
page_rec_print(cur.rec, offsets);
1716
"Total of %lu records \n"
1717
"--------------------------------\n",
1718
(ulong) (count + 1));
1720
if (UNIV_LIKELY_NULL(heap)) {
1721
mem_heap_free(heap);
1725
/***************************************************************//**
1726
Prints the info in a page header. */
1734
"--------------------------------\n"
1735
"PAGE HEADER INFO\n"
1736
"Page address %p, n records %lu (%s)\n"
1737
"n dir slots %lu, heap top %lu\n"
1738
"Page n heap %lu, free %lu, garbage %lu\n"
1739
"Page last insert %lu, direction %lu, n direction %lu\n",
1740
page, (ulong) page_header_get_field(page, PAGE_N_RECS),
1741
page_is_comp(page) ? "compact format" : "original format",
1742
(ulong) page_header_get_field(page, PAGE_N_DIR_SLOTS),
1743
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
1744
(ulong) page_dir_get_n_heap(page),
1745
(ulong) page_header_get_field(page, PAGE_FREE),
1746
(ulong) page_header_get_field(page, PAGE_GARBAGE),
1747
(ulong) page_header_get_field(page, PAGE_LAST_INSERT),
1748
(ulong) page_header_get_field(page, PAGE_DIRECTION),
1749
(ulong) page_header_get_field(page, PAGE_N_DIRECTION));
1752
/***************************************************************//**
1753
This is used to print the contents of the page for
1754
debugging purposes. */
1759
buf_block_t* block, /*!< in: index page */
1760
dict_index_t* index, /*!< in: dictionary index of the page */
1761
ulint dn, /*!< in: print dn first and last entries
1763
ulint rn) /*!< in: print rn first and last records
1766
page_t* page = block->frame;
1768
page_header_print(page);
1769
page_dir_print(page, dn);
1770
page_print_list(block, index, rn);
1772
# endif /* UNIV_BTR_PRINT */
1773
#endif /* !UNIV_HOTBACKUP */
1775
/***************************************************************//**
1776
The following is used to validate a record on a page. This function
1777
differs from rec_validate as it can also check the n_owned field and
1779
@return TRUE if ok */
1784
const rec_t* rec, /*!< in: physical record */
1785
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1791
page = page_align(rec);
1792
ut_a(!page_is_comp(page) == !rec_offs_comp(offsets));
1794
page_rec_check(rec);
1795
rec_validate(rec, offsets);
1797
if (page_rec_is_comp(rec)) {
1798
n_owned = rec_get_n_owned_new(rec);
1799
heap_no = rec_get_heap_no_new(rec);
1801
n_owned = rec_get_n_owned_old(rec);
1802
heap_no = rec_get_heap_no_old(rec);
1805
if (UNIV_UNLIKELY(!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED))) {
1807
"InnoDB: Dir slot of rec %lu, n owned too big %lu\n",
1808
(ulong) page_offset(rec), (ulong) n_owned);
1812
if (UNIV_UNLIKELY(!(heap_no < page_dir_get_n_heap(page)))) {
1814
"InnoDB: Heap no of rec %lu too big %lu %lu\n",
1815
(ulong) page_offset(rec), (ulong) heap_no,
1816
(ulong) page_dir_get_n_heap(page));
1823
#ifndef UNIV_HOTBACKUP
1824
/***************************************************************//**
1825
Checks that the first directory slot points to the infimum record and
1826
the last to the supremum. This function is intended to track if the
1827
bug fixed in 4.0.14 has caused corruption to users' databases. */
1832
const page_t* page) /*!< in: index page */
1836
ulint supremum_offs;
1838
n_slots = page_dir_get_n_slots(page);
1839
infimum_offs = mach_read_from_2(page_dir_get_nth_slot(page, 0));
1840
supremum_offs = mach_read_from_2(page_dir_get_nth_slot(page,
1843
if (UNIV_UNLIKELY(!page_rec_is_infimum_low(infimum_offs))) {
1846
"InnoDB: Page directory corruption:"
1847
" infimum not pointed to\n");
1848
buf_page_print(page, 0, 0);
1851
if (UNIV_UNLIKELY(!page_rec_is_supremum_low(supremum_offs))) {
1854
"InnoDB: Page directory corruption:"
1855
" supremum not pointed to\n");
1856
buf_page_print(page, 0, 0);
1859
#endif /* !UNIV_HOTBACKUP */
1861
/***************************************************************//**
1862
This function checks the consistency of an index page when we do not
1863
know the index. This is also resilient so that this should never crash
1864
even if the page is total garbage.
1865
@return TRUE if ok */
1868
page_simple_validate_old(
1869
/*=====================*/
1870
const page_t* page) /*!< in: index page in ROW_FORMAT=REDUNDANT */
1872
const page_dir_slot_t* slot;
1876
const byte* rec_heap_top;
1881
ut_a(!page_is_comp(page));
1883
/* Check first that the record heap and the directory do not
1886
n_slots = page_dir_get_n_slots(page);
1888
if (UNIV_UNLIKELY(n_slots > UNIV_PAGE_SIZE / 4)) {
1890
"InnoDB: Nonsensical number %lu of page dir slots\n",
1896
rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
1898
if (UNIV_UNLIKELY(rec_heap_top
1899
> page_dir_get_nth_slot(page, n_slots - 1))) {
1902
"InnoDB: Record heap and dir overlap on a page,"
1903
" heap top %lu, dir %lu\n",
1904
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
1906
page_offset(page_dir_get_nth_slot(page, n_slots - 1)));
1911
/* Validate the record list in a loop checking also that it is
1912
consistent with the page record directory. */
1917
slot = page_dir_get_nth_slot(page, slot_no);
1919
rec = page_get_infimum_rec(page);
1922
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
1924
"InnoDB: Record %lu is above"
1925
" rec heap top %lu\n",
1926
(ulong)(rec - page),
1927
(ulong)(rec_heap_top - page));
1932
if (UNIV_UNLIKELY(rec_get_n_owned_old(rec))) {
1933
/* This is a record pointed to by a dir slot */
1934
if (UNIV_UNLIKELY(rec_get_n_owned_old(rec)
1938
"InnoDB: Wrong owned count %lu, %lu,"
1940
(ulong) rec_get_n_owned_old(rec),
1942
(ulong)(rec - page));
1948
(page_dir_slot_get_rec(slot) != rec)) {
1950
"InnoDB: Dir slot does not point"
1951
" to right rec %lu\n",
1952
(ulong)(rec - page));
1959
if (!page_rec_is_supremum(rec)) {
1961
slot = page_dir_get_nth_slot(page, slot_no);
1965
if (page_rec_is_supremum(rec)) {
1971
(rec_get_next_offs(rec, FALSE) < FIL_PAGE_DATA
1972
|| rec_get_next_offs(rec, FALSE) >= UNIV_PAGE_SIZE)) {
1974
"InnoDB: Next record offset"
1975
" nonsensical %lu for rec %lu\n",
1976
(ulong) rec_get_next_offs(rec, FALSE),
1977
(ulong) (rec - page));
1984
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
1986
"InnoDB: Page record list appears"
1987
" to be circular %lu\n",
1992
rec = page_rec_get_next_const(rec);
1996
if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) {
1997
fprintf(stderr, "InnoDB: n owned is zero in a supremum rec\n");
2002
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
2003
fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
2004
(ulong) slot_no, (ulong) (n_slots - 1));
2008
if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
2009
+ PAGE_HEAP_NO_USER_LOW
2011
fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
2012
(ulong) page_header_get_field(page, PAGE_N_RECS)
2013
+ PAGE_HEAP_NO_USER_LOW,
2014
(ulong) (count + 1));
2019
/* Check then the free list */
2020
rec = page_header_get_ptr(page, PAGE_FREE);
2022
while (rec != NULL) {
2023
if (UNIV_UNLIKELY(rec < page + FIL_PAGE_DATA
2024
|| rec >= page + UNIV_PAGE_SIZE)) {
2026
"InnoDB: Free list record has"
2027
" a nonsensical offset %lu\n",
2028
(ulong) (rec - page));
2033
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2035
"InnoDB: Free list record %lu"
2036
" is above rec heap top %lu\n",
2037
(ulong) (rec - page),
2038
(ulong) (rec_heap_top - page));
2045
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2047
"InnoDB: Page free list appears"
2048
" to be circular %lu\n",
2053
rec = page_rec_get_next_const(rec);
2056
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
2058
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
2059
(ulong) page_dir_get_n_heap(page),
2060
(ulong) (count + 1));
2071
/***************************************************************//**
2072
This function checks the consistency of an index page when we do not
2073
know the index. This is also resilient so that this should never crash
2074
even if the page is total garbage.
2075
@return TRUE if ok */
2078
page_simple_validate_new(
2079
/*=====================*/
2080
const page_t* page) /*!< in: index page in ROW_FORMAT!=REDUNDANT */
2082
const page_dir_slot_t* slot;
2086
const byte* rec_heap_top;
2091
ut_a(page_is_comp(page));
2093
/* Check first that the record heap and the directory do not
2096
n_slots = page_dir_get_n_slots(page);
2098
if (UNIV_UNLIKELY(n_slots > UNIV_PAGE_SIZE / 4)) {
2100
"InnoDB: Nonsensical number %lu"
2101
" of page dir slots\n", (ulong) n_slots);
2106
rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
2108
if (UNIV_UNLIKELY(rec_heap_top
2109
> page_dir_get_nth_slot(page, n_slots - 1))) {
2112
"InnoDB: Record heap and dir overlap on a page,"
2113
" heap top %lu, dir %lu\n",
2114
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
2116
page_offset(page_dir_get_nth_slot(page, n_slots - 1)));
2121
/* Validate the record list in a loop checking also that it is
2122
consistent with the page record directory. */
2127
slot = page_dir_get_nth_slot(page, slot_no);
2129
rec = page_get_infimum_rec(page);
2132
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2134
"InnoDB: Record %lu is above rec"
2136
(ulong) page_offset(rec),
2137
(ulong) page_offset(rec_heap_top));
2142
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec))) {
2143
/* This is a record pointed to by a dir slot */
2144
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec)
2148
"InnoDB: Wrong owned count %lu, %lu,"
2150
(ulong) rec_get_n_owned_new(rec),
2152
(ulong) page_offset(rec));
2158
(page_dir_slot_get_rec(slot) != rec)) {
2160
"InnoDB: Dir slot does not point"
2161
" to right rec %lu\n",
2162
(ulong) page_offset(rec));
2169
if (!page_rec_is_supremum(rec)) {
2171
slot = page_dir_get_nth_slot(page, slot_no);
2175
if (page_rec_is_supremum(rec)) {
2181
(rec_get_next_offs(rec, TRUE) < FIL_PAGE_DATA
2182
|| rec_get_next_offs(rec, TRUE) >= UNIV_PAGE_SIZE)) {
2184
"InnoDB: Next record offset nonsensical %lu"
2186
(ulong) rec_get_next_offs(rec, TRUE),
2187
(ulong) page_offset(rec));
2194
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2196
"InnoDB: Page record list appears"
2197
" to be circular %lu\n",
2202
rec = page_rec_get_next_const(rec);
2206
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec) == 0)) {
2207
fprintf(stderr, "InnoDB: n owned is zero"
2208
" in a supremum rec\n");
2213
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
2214
fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
2215
(ulong) slot_no, (ulong) (n_slots - 1));
2219
if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
2220
+ PAGE_HEAP_NO_USER_LOW
2222
fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
2223
(ulong) page_header_get_field(page, PAGE_N_RECS)
2224
+ PAGE_HEAP_NO_USER_LOW,
2225
(ulong) (count + 1));
2230
/* Check then the free list */
2231
rec = page_header_get_ptr(page, PAGE_FREE);
2233
while (rec != NULL) {
2234
if (UNIV_UNLIKELY(rec < page + FIL_PAGE_DATA
2235
|| rec >= page + UNIV_PAGE_SIZE)) {
2237
"InnoDB: Free list record has"
2238
" a nonsensical offset %lu\n",
2239
(ulong) page_offset(rec));
2244
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2246
"InnoDB: Free list record %lu"
2247
" is above rec heap top %lu\n",
2248
(ulong) page_offset(rec),
2249
(ulong) page_offset(rec_heap_top));
2256
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2258
"InnoDB: Page free list appears"
2259
" to be circular %lu\n",
2264
rec = page_rec_get_next_const(rec);
2267
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
2269
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
2270
(ulong) page_dir_get_n_heap(page),
2271
(ulong) (count + 1));
2282
/***************************************************************//**
2283
This function checks the consistency of an index page.
2284
@return TRUE if ok */
2289
const page_t* page, /*!< in: index page */
2290
dict_index_t* index) /*!< in: data dictionary index containing
2291
the page record type definition */
2293
const page_dir_slot_t* slot;
2298
ulint rec_own_count;
2302
const rec_t* old_rec = NULL;
2307
ulint* offsets = NULL;
2308
ulint* old_offsets = NULL;
2310
if (UNIV_UNLIKELY((ibool) !!page_is_comp(page)
2311
!= dict_table_is_comp(index->table))) {
2312
fputs("InnoDB: 'compact format' flag mismatch\n", stderr);
2315
if (page_is_comp(page)) {
2316
if (UNIV_UNLIKELY(!page_simple_validate_new(page))) {
2320
if (UNIV_UNLIKELY(!page_simple_validate_old(page))) {
2325
heap = mem_heap_create(UNIV_PAGE_SIZE + 200);
2327
/* The following buffer is used to check that the
2328
records in the page record heap do not overlap */
2330
buf = mem_heap_zalloc(heap, UNIV_PAGE_SIZE);
2332
/* Check first that the record heap and the directory do not
2335
n_slots = page_dir_get_n_slots(page);
2337
if (UNIV_UNLIKELY(!(page_header_get_ptr(page, PAGE_HEAP_TOP)
2338
<= page_dir_get_nth_slot(page, n_slots - 1)))) {
2341
"InnoDB: Record heap and dir overlap"
2342
" on space %lu page %lu index %s, %p, %p\n",
2343
(ulong) page_get_space_id(page),
2344
(ulong) page_get_page_no(page), index->name,
2345
page_header_get_ptr(page, PAGE_HEAP_TOP),
2346
page_dir_get_nth_slot(page, n_slots - 1));
2351
/* Validate the record list in a loop checking also that
2352
it is consistent with the directory. */
2357
slot = page_dir_get_nth_slot(page, slot_no);
2359
rec = page_get_infimum_rec(page);
2362
offsets = rec_get_offsets(rec, index, offsets,
2363
ULINT_UNDEFINED, &heap);
2365
if (page_is_comp(page) && page_rec_is_user_rec(rec)
2366
&& UNIV_UNLIKELY(rec_get_node_ptr_flag(rec)
2367
== page_is_leaf(page))) {
2368
fputs("InnoDB: node_ptr flag mismatch\n", stderr);
2372
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
2376
#ifndef UNIV_HOTBACKUP
2377
/* Check that the records are in the ascending order */
2378
if (UNIV_LIKELY(count >= PAGE_HEAP_NO_USER_LOW)
2379
&& !page_rec_is_supremum(rec)) {
2381
(1 != cmp_rec_rec(rec, old_rec,
2382
offsets, old_offsets, index))) {
2384
"InnoDB: Records in wrong order"
2385
" on space %lu page %lu index %s\n",
2386
(ulong) page_get_space_id(page),
2387
(ulong) page_get_page_no(page),
2389
fputs("\nInnoDB: previous record ", stderr);
2390
rec_print_new(stderr, old_rec, old_offsets);
2391
fputs("\nInnoDB: record ", stderr);
2392
rec_print_new(stderr, rec, offsets);
2398
#endif /* !UNIV_HOTBACKUP */
2400
if (page_rec_is_user_rec(rec)) {
2402
data_size += rec_offs_size(offsets);
2405
offs = page_offset(rec_get_start(rec, offsets));
2406
i = rec_offs_size(offsets);
2407
if (UNIV_UNLIKELY(offs + i >= UNIV_PAGE_SIZE)) {
2408
fputs("InnoDB: record offset out of bounds\n", stderr);
2413
if (UNIV_UNLIKELY(buf[offs + i])) {
2414
/* No other record may overlap this */
2416
fputs("InnoDB: Record overlaps another\n",
2424
if (page_is_comp(page)) {
2425
rec_own_count = rec_get_n_owned_new(rec);
2427
rec_own_count = rec_get_n_owned_old(rec);
2430
if (UNIV_UNLIKELY(rec_own_count)) {
2431
/* This is a record pointed to by a dir slot */
2432
if (UNIV_UNLIKELY(rec_own_count != own_count)) {
2434
"InnoDB: Wrong owned count %lu, %lu\n",
2435
(ulong) rec_own_count,
2440
if (page_dir_slot_get_rec(slot) != rec) {
2441
fputs("InnoDB: Dir slot does not"
2442
" point to right rec\n",
2447
page_dir_slot_check(slot);
2450
if (!page_rec_is_supremum(rec)) {
2452
slot = page_dir_get_nth_slot(page, slot_no);
2456
if (page_rec_is_supremum(rec)) {
2463
rec = page_rec_get_next_const(rec);
2465
/* set old_offsets to offsets; recycle offsets */
2467
ulint* offs = old_offsets;
2468
old_offsets = offsets;
2473
if (page_is_comp(page)) {
2474
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec) == 0)) {
2478
} else if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) {
2480
fputs("InnoDB: n owned is zero\n", stderr);
2484
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
2485
fprintf(stderr, "InnoDB: n slots wrong %lu %lu\n",
2486
(ulong) slot_no, (ulong) (n_slots - 1));
2490
if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
2491
+ PAGE_HEAP_NO_USER_LOW
2493
fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
2494
(ulong) page_header_get_field(page, PAGE_N_RECS)
2495
+ PAGE_HEAP_NO_USER_LOW,
2496
(ulong) (count + 1));
2500
if (UNIV_UNLIKELY(data_size != page_get_data_size(page))) {
2502
"InnoDB: Summed data size %lu, returned by func %lu\n",
2503
(ulong) data_size, (ulong) page_get_data_size(page));
2507
/* Check then the free list */
2508
rec = page_header_get_ptr(page, PAGE_FREE);
2510
while (rec != NULL) {
2511
offsets = rec_get_offsets(rec, index, offsets,
2512
ULINT_UNDEFINED, &heap);
2513
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
2519
offs = page_offset(rec_get_start(rec, offsets));
2520
i = rec_offs_size(offsets);
2521
if (UNIV_UNLIKELY(offs + i >= UNIV_PAGE_SIZE)) {
2522
fputs("InnoDB: record offset out of bounds\n", stderr);
2528
if (UNIV_UNLIKELY(buf[offs + i])) {
2529
fputs("InnoDB: Record overlaps another"
2530
" in free list\n", stderr);
2537
rec = page_rec_get_next_const(rec);
2540
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
2541
fprintf(stderr, "InnoDB: N heap is wrong %lu %lu\n",
2542
(ulong) page_dir_get_n_heap(page),
2550
mem_heap_free(heap);
2552
if (UNIV_UNLIKELY(ret == FALSE)) {
2555
"InnoDB: Apparent corruption"
2556
" in space %lu page %lu index %s\n",
2557
(ulong) page_get_space_id(page),
2558
(ulong) page_get_page_no(page),
2560
buf_page_print(page, 0, 0);
2566
#ifndef UNIV_HOTBACKUP
2567
/***************************************************************//**
2568
Looks in the page record list for a record with the given heap number.
2569
@return record, NULL if not found */
2572
page_find_rec_with_heap_no(
2573
/*=======================*/
2574
const page_t* page, /*!< in: index page */
2575
ulint heap_no)/*!< in: heap number */
2579
if (page_is_comp(page)) {
2580
rec = page + PAGE_NEW_INFIMUM;
2583
ulint rec_heap_no = rec_get_heap_no_new(rec);
2585
if (rec_heap_no == heap_no) {
2588
} else if (rec_heap_no == PAGE_HEAP_NO_SUPREMUM) {
2593
rec = page + rec_get_next_offs(rec, TRUE);
2596
rec = page + PAGE_OLD_INFIMUM;
2599
ulint rec_heap_no = rec_get_heap_no_old(rec);
2601
if (rec_heap_no == heap_no) {
2604
} else if (rec_heap_no == PAGE_HEAP_NO_SUPREMUM) {
2609
rec = page + rec_get_next_offs(rec, FALSE);
2613
#endif /* !UNIV_HOTBACKUP */