1
/*****************************************************************************
3
Copyright (C) 1994, 2010, 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 page/page0page.c
23
Created 2/2/1994 Heikki Tuuri
24
*******************************************************/
26
#include "page0page.h"
28
#include "page0page.ic"
35
#ifndef UNIV_HOTBACKUP
37
# include "lock0lock.h"
40
#endif /* !UNIV_HOTBACKUP */
45
The index page consists of a page header which contains the page's
46
id and other information. On top of it are the the index records
47
in a heap linked into a one way linear list according to alphabetic order.
49
Just below page end is an array of pointers which we call page directory,
50
to about every sixth record in the list. The pointers are placed in
51
the directory in the alphabetical order of the records pointed to,
52
enabling us to make binary search using the array. Each slot n:o I
53
in the directory points to a record, where a 4-bit field contains a count
54
of those records which are in the linear list between pointer I and
55
the pointer I - 1 in the directory, including the record
56
pointed to by pointer I and not including the record pointed to by I - 1.
57
We say that the record pointed to by slot I, or that slot I, owns
58
these records. The count is always kept in the range 4 to 8, with
59
the exception that it is 1 for the first slot, and 1--8 for the second slot.
61
An essentially binary search can be performed in the list of index
62
records, like we could do if we had pointer to every record in the
63
page directory. The data structure is, however, more efficient when
64
we are doing inserts, because most inserts are just pushed on a heap.
65
Only every 8th insert requires block move in the directory pointer
66
table, which itself is quite small. A record is deleted from the page
67
by just taking it off the linear list and updating the number of owned
68
records-field of the record which owns it, and updating the page directory,
69
if necessary. A special case is the one when the record owns itself.
70
Because the overhead of inserts is so small, we may also increase the
71
page size from the projected default of 8 kB to 64 kB without too
72
much loss of efficiency in inserts. Bigger page becomes actual
73
when the disk transfer rate compared to seek and latency time rises.
74
On the present system, the page size is set so that the page transfer
75
time (3 ms) is 20 % of the disk random access time (15 ms).
77
When the page is split, merged, or becomes full but contains deleted
78
records, we have to reorganize the page.
80
Assuming a page size of 8 kB, a typical index page of a secondary
81
index contains 300 index entries, and the size of the page directory
82
is 50 x 4 bytes = 200 bytes. */
84
/***************************************************************//**
85
Looks for the directory slot which owns the given record.
86
@return the directory slot number */
89
page_dir_find_owner_slot(
90
/*=====================*/
91
const rec_t* rec) /*!< in: the physical record */
94
register uint16 rec_offs_bytes;
95
register const page_dir_slot_t* slot;
96
register const page_dir_slot_t* first_slot;
97
register const rec_t* r = rec;
99
ut_ad(page_rec_check(rec));
101
page = page_align(rec);
102
first_slot = page_dir_get_nth_slot(page, 0);
103
slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
105
if (page_is_comp(page)) {
106
while (rec_get_n_owned_new(r) == 0) {
107
r = rec_get_next_ptr_const(r, TRUE);
108
ut_ad(r >= page + PAGE_NEW_SUPREMUM);
109
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
112
while (rec_get_n_owned_old(r) == 0) {
113
r = rec_get_next_ptr_const(r, FALSE);
114
ut_ad(r >= page + PAGE_OLD_SUPREMUM);
115
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
119
rec_offs_bytes = mach_encode_2(r - page);
121
while (UNIV_LIKELY(*(uint16*) slot != rec_offs_bytes)) {
123
if (UNIV_UNLIKELY(slot == first_slot)) {
125
"InnoDB: Probable data corruption on"
127
"InnoDB: Original record ",
128
(ulong) page_get_page_no(page));
130
if (page_is_comp(page)) {
131
fputs("(compact record)", stderr);
133
rec_print_old(stderr, rec);
137
"InnoDB: on that page.\n"
138
"InnoDB: Cannot find the dir slot for record ",
140
if (page_is_comp(page)) {
141
fputs("(compact record)", stderr);
143
rec_print_old(stderr, page
144
+ mach_decode_2(rec_offs_bytes));
147
"InnoDB: on that page!\n", stderr);
149
buf_page_print(page, 0);
154
slot += PAGE_DIR_SLOT_SIZE;
157
return(((ulint) (first_slot - slot)) / PAGE_DIR_SLOT_SIZE);
160
/**************************************************************//**
161
Used to check the consistency of a directory slot.
162
@return TRUE if succeed */
167
page_dir_slot_t* slot) /*!< in: slot */
175
page = page_align(slot);
177
n_slots = page_dir_get_n_slots(page);
179
ut_a(slot <= page_dir_get_nth_slot(page, 0));
180
ut_a(slot >= page_dir_get_nth_slot(page, n_slots - 1));
182
ut_a(page_rec_check(page_dir_slot_get_rec(slot)));
184
if (page_is_comp(page)) {
185
n_owned = rec_get_n_owned_new(page_dir_slot_get_rec(slot));
187
n_owned = rec_get_n_owned_old(page_dir_slot_get_rec(slot));
190
if (slot == page_dir_get_nth_slot(page, 0)) {
192
} else if (slot == page_dir_get_nth_slot(page, n_slots - 1)) {
194
ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
196
ut_a(n_owned >= PAGE_DIR_SLOT_MIN_N_OWNED);
197
ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
203
/*************************************************************//**
204
Sets the max trx id field value. */
209
buf_block_t* block, /*!< in/out: page */
210
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
211
trx_id_t trx_id, /*!< in: transaction id */
212
mtr_t* mtr) /*!< in/out: mini-transaction, or NULL */
214
page_t* page = buf_block_get_frame(block);
215
#ifndef UNIV_HOTBACKUP
216
const ibool is_hashed = block->is_hashed;
219
rw_lock_x_lock(&btr_search_latch);
222
ut_ad(!mtr || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
223
#endif /* !UNIV_HOTBACKUP */
225
/* It is not necessary to write this change to the redo log, as
226
during a database recovery we assume that the max trx id of every
227
page is the maximum trx id assigned before the crash. */
229
if (UNIV_LIKELY_NULL(page_zip)) {
230
mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id);
231
page_zip_write_header(page_zip,
232
page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
234
#ifndef UNIV_HOTBACKUP
236
mlog_write_ull(page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
238
#endif /* !UNIV_HOTBACKUP */
240
mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id);
243
#ifndef UNIV_HOTBACKUP
245
rw_lock_x_unlock(&btr_search_latch);
247
#endif /* !UNIV_HOTBACKUP */
250
/************************************************************//**
251
Allocates a block of memory from the heap of an index page.
252
@return pointer to start of allocated buffer, or NULL if allocation fails */
257
page_t* page, /*!< in/out: index page */
258
page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
259
space available for inserting the record,
261
ulint need, /*!< in: total number of bytes needed */
262
ulint* heap_no)/*!< out: this contains the heap number
263
of the allocated record
264
if allocation succeeds */
269
ut_ad(page && heap_no);
271
avl_space = page_get_max_insert_size(page, 1);
273
if (avl_space >= need) {
274
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
276
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
278
*heap_no = page_dir_get_n_heap(page);
280
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
288
#ifndef UNIV_HOTBACKUP
289
/**********************************************************//**
290
Writes a log record of page creation. */
293
page_create_write_log(
294
/*==================*/
295
buf_frame_t* frame, /*!< in: a buffer frame where the page is
297
mtr_t* mtr, /*!< in: mini-transaction handle */
298
ibool comp) /*!< in: TRUE=compact page format */
300
mlog_write_initial_log_record(frame, comp
301
? MLOG_COMP_PAGE_CREATE
302
: MLOG_PAGE_CREATE, mtr);
304
#else /* !UNIV_HOTBACKUP */
305
# define page_create_write_log(frame,mtr,comp) ((void) 0)
306
#endif /* !UNIV_HOTBACKUP */
308
/***********************************************************//**
309
Parses a redo log record of creating a page.
310
@return end of log record or NULL */
315
byte* ptr, /*!< in: buffer */
316
byte* /*end_ptr __attribute__((unused))*/, /*!< in: buffer end */
317
ulint comp, /*!< in: nonzero=compact page format */
318
buf_block_t* block, /*!< in: block or NULL */
319
mtr_t* mtr) /*!< in: mtr or NULL */
321
ut_ad(ptr && end_ptr);
323
/* The record is empty, except for the record initial part */
326
page_create(block, mtr, comp);
332
/**********************************************************//**
333
The index page creation function.
334
@return pointer to the page */
339
buf_block_t* block, /*!< in: a buffer block where the
341
ulint comp) /*!< in: nonzero=compact page format */
343
page_dir_slot_t* slot;
355
#if PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA
356
# error "PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA"
358
#if PAGE_BTR_IBUF_FREE_LIST_NODE + FLST_NODE_SIZE > PAGE_DATA
359
# error "PAGE_BTR_IBUF_FREE_LIST_NODE + FLST_NODE_SIZE > PAGE_DATA"
362
/* The infimum and supremum records use a dummy index. */
363
if (UNIV_LIKELY(comp)) {
364
index = dict_ind_compact;
366
index = dict_ind_redundant;
369
/* 1. INCREMENT MODIFY CLOCK */
370
buf_block_modify_clock_inc(block);
372
page = buf_block_get_frame(block);
374
fil_page_set_type(page, FIL_PAGE_INDEX);
376
heap = mem_heap_create(200);
378
/* 3. CREATE THE INFIMUM AND SUPREMUM RECORDS */
380
/* Create first a data tuple for infimum record */
381
tuple = dtuple_create(heap, 1);
382
dtuple_set_info_bits(tuple, REC_STATUS_INFIMUM);
383
field = dtuple_get_nth_field(tuple, 0);
385
dfield_set_data(field, "infimum", 8);
386
dtype_set(dfield_get_type(field),
387
DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, 8);
388
/* Set the corresponding physical record to its place in the page
391
heap_top = page + PAGE_DATA;
393
infimum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple, 0);
395
if (UNIV_LIKELY(comp)) {
396
ut_a(infimum_rec == page + PAGE_NEW_INFIMUM);
398
rec_set_n_owned_new(infimum_rec, NULL, 1);
399
rec_set_heap_no_new(infimum_rec, 0);
401
ut_a(infimum_rec == page + PAGE_OLD_INFIMUM);
403
rec_set_n_owned_old(infimum_rec, 1);
404
rec_set_heap_no_old(infimum_rec, 0);
407
offsets = rec_get_offsets(infimum_rec, index, NULL,
408
ULINT_UNDEFINED, &heap);
410
heap_top = rec_get_end(infimum_rec, offsets);
412
/* Create then a tuple for supremum */
414
tuple = dtuple_create(heap, 1);
415
dtuple_set_info_bits(tuple, REC_STATUS_SUPREMUM);
416
field = dtuple_get_nth_field(tuple, 0);
418
dfield_set_data(field, "supremum", comp ? 8 : 9);
419
dtype_set(dfield_get_type(field),
420
DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, comp ? 8 : 9);
422
supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple, 0);
424
if (UNIV_LIKELY(comp)) {
425
ut_a(supremum_rec == page + PAGE_NEW_SUPREMUM);
427
rec_set_n_owned_new(supremum_rec, NULL, 1);
428
rec_set_heap_no_new(supremum_rec, 1);
430
ut_a(supremum_rec == page + PAGE_OLD_SUPREMUM);
432
rec_set_n_owned_old(supremum_rec, 1);
433
rec_set_heap_no_old(supremum_rec, 1);
436
offsets = rec_get_offsets(supremum_rec, index, offsets,
437
ULINT_UNDEFINED, &heap);
438
heap_top = rec_get_end(supremum_rec, offsets);
440
ut_ad(heap_top == page
441
+ (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END));
445
/* 4. INITIALIZE THE PAGE */
447
page_header_set_field(page, NULL, PAGE_N_DIR_SLOTS, 2);
448
page_header_set_ptr(page, NULL, PAGE_HEAP_TOP, heap_top);
449
page_header_set_field(page, NULL, PAGE_N_HEAP, comp
450
? 0x8000 | PAGE_HEAP_NO_USER_LOW
451
: PAGE_HEAP_NO_USER_LOW);
452
page_header_set_ptr(page, NULL, PAGE_FREE, NULL);
453
page_header_set_field(page, NULL, PAGE_GARBAGE, 0);
454
page_header_set_ptr(page, NULL, PAGE_LAST_INSERT, NULL);
455
page_header_set_field(page, NULL, PAGE_DIRECTION, PAGE_NO_DIRECTION);
456
page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
457
page_header_set_field(page, NULL, PAGE_N_RECS, 0);
458
page_set_max_trx_id(block, NULL, 0, NULL);
459
memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
460
- page_offset(heap_top));
462
/* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
464
/* Set the slots to point to infimum and supremum. */
466
slot = page_dir_get_nth_slot(page, 0);
467
page_dir_slot_set_rec(slot, infimum_rec);
469
slot = page_dir_get_nth_slot(page, 1);
470
page_dir_slot_set_rec(slot, supremum_rec);
472
/* Set the next pointers in infimum and supremum */
474
if (UNIV_LIKELY(comp)) {
475
rec_set_next_offs_new(infimum_rec, PAGE_NEW_SUPREMUM);
476
rec_set_next_offs_new(supremum_rec, 0);
478
rec_set_next_offs_old(infimum_rec, PAGE_OLD_SUPREMUM);
479
rec_set_next_offs_old(supremum_rec, 0);
485
/**********************************************************//**
486
Create an uncompressed B-tree index page.
487
@return pointer to the page */
492
buf_block_t* block, /*!< in: a buffer block where the
494
mtr_t* mtr, /*!< in: mini-transaction handle */
495
ulint comp) /*!< in: nonzero=compact page format */
497
page_create_write_log(buf_block_get_frame(block), mtr, comp);
498
return(page_create_low(block, comp));
501
/**********************************************************//**
502
Create a compressed B-tree index page.
503
@return pointer to the page */
508
buf_block_t* block, /*!< in/out: a buffer frame where the
510
dict_index_t* index, /*!< in: the index of the page */
511
ulint level, /*!< in: the B-tree level of the page */
512
mtr_t* mtr) /*!< in: mini-transaction handle */
515
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
520
ut_ad(dict_table_is_comp(index->table));
522
page = page_create_low(block, TRUE);
523
mach_write_to_2(page + PAGE_HEADER + PAGE_LEVEL, level);
525
if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
526
/* The compression of a newly created page
527
should always succeed. */
534
/*************************************************************//**
535
Differs from page_copy_rec_list_end, because this function does not
536
touch the lock table and max trx id on page or compress the page. */
539
page_copy_rec_list_end_no_locks(
540
/*============================*/
541
buf_block_t* new_block, /*!< in: index page to copy to */
542
buf_block_t* block, /*!< in: index page of rec */
543
rec_t* rec, /*!< in: record on page */
544
dict_index_t* index, /*!< in: record descriptor */
545
mtr_t* mtr) /*!< in: mtr */
547
page_t* new_page = buf_block_get_frame(new_block);
550
mem_heap_t* heap = NULL;
551
ulint offsets_[REC_OFFS_NORMAL_SIZE];
552
ulint* offsets = offsets_;
553
rec_offs_init(offsets_);
555
page_cur_position(rec, block, &cur1);
557
if (page_cur_is_before_first(&cur1)) {
559
page_cur_move_to_next(&cur1);
562
ut_a((ibool)!!page_is_comp(new_page)
563
== dict_table_is_comp(index->table));
564
ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
565
ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
566
(page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
568
cur2 = page_get_infimum_rec(buf_block_get_frame(new_block));
570
/* Copy records from the original page to the new page */
572
while (!page_cur_is_after_last(&cur1)) {
573
rec_t* cur1_rec = page_cur_get_rec(&cur1);
575
offsets = rec_get_offsets(cur1_rec, index, offsets,
576
ULINT_UNDEFINED, &heap);
577
ins_rec = page_cur_insert_rec_low(cur2, index,
578
cur1_rec, offsets, mtr);
579
if (UNIV_UNLIKELY(!ins_rec)) {
580
/* Track an assertion failure reported on the mailing
581
list on June 18th, 2003 */
583
buf_page_print(new_page, 0);
584
buf_page_print(page_align(rec), 0);
585
ut_print_timestamp(stderr);
588
"InnoDB: rec offset %lu, cur1 offset %lu,"
589
" cur2 offset %lu\n",
590
(ulong) page_offset(rec),
591
(ulong) page_offset(page_cur_get_rec(&cur1)),
592
(ulong) page_offset(cur2));
596
page_cur_move_to_next(&cur1);
600
if (UNIV_LIKELY_NULL(heap)) {
605
#ifndef UNIV_HOTBACKUP
606
/*************************************************************//**
607
Copies records from page to new_page, from a given record onward,
608
including that record. Infimum and supremum records are not copied.
609
The records are copied to the start of the record list on new_page.
610
@return pointer to the original successor of the infimum record on
611
new_page, or NULL on zip overflow (new_block will be decompressed) */
614
page_copy_rec_list_end(
615
/*===================*/
616
buf_block_t* new_block, /*!< in/out: index page to copy to */
617
buf_block_t* block, /*!< in: index page containing rec */
618
rec_t* rec, /*!< in: record on page */
619
dict_index_t* index, /*!< in: record descriptor */
620
mtr_t* mtr) /*!< in: mtr */
622
page_t* new_page = buf_block_get_frame(new_block);
623
page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block);
624
page_t* page = page_align(rec);
625
rec_t* ret = page_rec_get_next(
626
page_get_infimum_rec(new_page));
627
ulint log_mode = 0; /* remove warning */
629
#ifdef UNIV_ZIP_DEBUG
631
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
634
/* Strict page_zip_validate() may fail here.
635
Furthermore, btr_compress() may set FIL_PAGE_PREV to
636
FIL_NULL on new_page while leaving it intact on
637
new_page_zip. So, we cannot validate new_page_zip. */
638
ut_a(page_zip_validate_low(page_zip, page, TRUE));
640
#endif /* UNIV_ZIP_DEBUG */
641
ut_ad(buf_block_get_frame(block) == page);
642
ut_ad(page_is_leaf(page) == page_is_leaf(new_page));
643
ut_ad(page_is_comp(page) == page_is_comp(new_page));
644
/* Here, "ret" may be pointing to a user record or the
645
predefined supremum record. */
647
if (UNIV_LIKELY_NULL(new_page_zip)) {
648
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
651
if (page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW) {
652
page_copy_rec_list_end_to_created_page(new_page, rec,
655
page_copy_rec_list_end_no_locks(new_block, block, rec,
659
/* Update PAGE_MAX_TRX_ID on the uncompressed page.
660
Modifications will be redo logged and copied to the compressed
661
page in page_zip_compress() or page_zip_reorganize() below. */
662
if (dict_index_is_sec_or_ibuf(index) && page_is_leaf(page)) {
663
page_update_max_trx_id(new_block, NULL,
664
page_get_max_trx_id(page), mtr);
667
if (UNIV_LIKELY_NULL(new_page_zip)) {
668
mtr_set_log_mode(mtr, log_mode);
671
(!page_zip_compress(new_page_zip, new_page, index, mtr))) {
672
/* Before trying to reorganize the page,
673
store the number of preceding records on the page. */
675
= page_rec_get_n_recs_before(ret);
676
/* Before copying, "ret" was the successor of
677
the predefined infimum record. It must still
678
have at least one predecessor (the predefined
679
infimum record, or a freshly copied record
680
that is smaller than "ret"). */
684
(!page_zip_reorganize(new_block, index, mtr))) {
687
(!page_zip_decompress(new_page_zip,
691
ut_ad(page_validate(new_page, index));
694
/* The page was reorganized:
696
ret = new_page + PAGE_NEW_INFIMUM;
699
ret = rec_get_next_ptr(ret, TRUE);
705
/* Update the lock table and possible hash index */
707
lock_move_rec_list_end(new_block, block, rec);
709
btr_search_move_or_delete_hash_entries(new_block, block, index);
714
/*************************************************************//**
715
Copies records from page to new_page, up to the given record,
716
NOT including that record. Infimum and supremum records are not copied.
717
The records are copied to the end of the record list on new_page.
718
@return pointer to the original predecessor of the supremum record on
719
new_page, or NULL on zip overflow (new_block will be decompressed) */
722
page_copy_rec_list_start(
723
/*=====================*/
724
buf_block_t* new_block, /*!< in/out: index page to copy to */
725
buf_block_t* block, /*!< in: index page containing rec */
726
rec_t* rec, /*!< in: record on page */
727
dict_index_t* index, /*!< in: record descriptor */
728
mtr_t* mtr) /*!< in: mtr */
730
page_t* new_page = buf_block_get_frame(new_block);
731
page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block);
734
ulint log_mode = 0 /* remove warning */;
735
mem_heap_t* heap = NULL;
737
= page_rec_get_prev(page_get_supremum_rec(new_page));
738
ulint offsets_[REC_OFFS_NORMAL_SIZE];
739
ulint* offsets = offsets_;
740
rec_offs_init(offsets_);
742
/* Here, "ret" may be pointing to a user record or the
743
predefined infimum record. */
745
if (page_rec_is_infimum(rec)) {
750
if (UNIV_LIKELY_NULL(new_page_zip)) {
751
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
754
page_cur_set_before_first(block, &cur1);
755
page_cur_move_to_next(&cur1);
759
/* Copy records from the original page to the new page */
761
while (page_cur_get_rec(&cur1) != rec) {
762
rec_t* cur1_rec = page_cur_get_rec(&cur1);
763
offsets = rec_get_offsets(cur1_rec, index, offsets,
764
ULINT_UNDEFINED, &heap);
765
cur2 = page_cur_insert_rec_low(cur2, index,
766
cur1_rec, offsets, mtr);
769
page_cur_move_to_next(&cur1);
772
if (UNIV_LIKELY_NULL(heap)) {
776
/* Update PAGE_MAX_TRX_ID on the uncompressed page.
777
Modifications will be redo logged and copied to the compressed
778
page in page_zip_compress() or page_zip_reorganize() below. */
779
if (dict_index_is_sec_or_ibuf(index)
780
&& page_is_leaf(page_align(rec))) {
781
page_update_max_trx_id(new_block, NULL,
782
page_get_max_trx_id(page_align(rec)),
786
if (UNIV_LIKELY_NULL(new_page_zip)) {
787
mtr_set_log_mode(mtr, log_mode);
790
(!page_zip_compress(new_page_zip, new_page, index, mtr))) {
791
/* Before trying to reorganize the page,
792
store the number of preceding records on the page. */
794
= page_rec_get_n_recs_before(ret);
795
/* Before copying, "ret" was the predecessor
796
of the predefined supremum record. If it was
797
the predefined infimum record, then it would
798
still be the infimum. Thus, the assertion
799
ut_a(ret_pos > 0) would fail here. */
802
(!page_zip_reorganize(new_block, index, mtr))) {
805
(!page_zip_decompress(new_page_zip,
809
ut_ad(page_validate(new_page, index));
812
/* The page was reorganized:
814
ret = new_page + PAGE_NEW_INFIMUM;
817
ret = rec_get_next_ptr(ret, TRUE);
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));
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));
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
slot = page_dir_get_nth_slot(page, slot_index);
1060
while (rec_get_n_owned_old(rec2) == 0) {
1063
rec2 = rec_get_next_ptr(rec2, FALSE);
1066
ut_ad(rec_get_n_owned_old(rec2) > count);
1068
n_owned = rec_get_n_owned_old(rec2) - count;
1069
slot_index = page_dir_find_owner_slot(rec2);
1070
slot = page_dir_get_nth_slot(page, slot_index);
1073
page_dir_slot_set_rec(slot, page_get_supremum_rec(page));
1074
page_dir_slot_set_n_owned(slot, NULL, n_owned);
1076
page_dir_set_n_slots(page, NULL, slot_index + 1);
1078
/* Remove the record chain segment from the record chain */
1079
page_rec_set_next(prev_rec, page_get_supremum_rec(page));
1081
/* Catenate the deleted chain segment to the page free list */
1083
page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE));
1084
page_header_set_ptr(page, NULL, PAGE_FREE, rec);
1086
page_header_set_field(page, NULL, PAGE_GARBAGE, size
1087
+ page_header_get_field(page, PAGE_GARBAGE));
1089
page_header_set_field(page, NULL, PAGE_N_RECS,
1090
(ulint)(page_get_n_recs(page) - n_recs));
1093
/*************************************************************//**
1094
Deletes records from page, up to the given record, NOT including
1095
that record. Infimum and supremum records are not deleted. */
1098
page_delete_rec_list_start(
1099
/*=======================*/
1100
rec_t* rec, /*!< in: record on page */
1101
buf_block_t* block, /*!< in: buffer block of the page */
1102
dict_index_t* index, /*!< in: record descriptor */
1103
mtr_t* mtr) /*!< in: mtr */
1107
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1108
ulint* offsets = offsets_;
1109
mem_heap_t* heap = NULL;
1112
rec_offs_init(offsets_);
1114
ut_ad((ibool) !!page_rec_is_comp(rec)
1115
== dict_table_is_comp(index->table));
1116
#ifdef UNIV_ZIP_DEBUG
1118
page_zip_des_t* page_zip= buf_block_get_page_zip(block);
1119
page_t* page = buf_block_get_frame(block);
1121
/* page_zip_validate() would detect a min_rec_mark mismatch
1122
in btr_page_split_and_insert()
1123
between btr_attach_half_pages() and insert_page = ...
1124
when btr_page_get_split_rec_to_left() holds
1125
(direction == FSP_DOWN). */
1126
ut_a(!page_zip || page_zip_validate_low(page_zip, page, TRUE));
1128
#endif /* UNIV_ZIP_DEBUG */
1130
if (page_rec_is_infimum(rec)) {
1135
if (page_rec_is_comp(rec)) {
1136
type = MLOG_COMP_LIST_START_DELETE;
1138
type = MLOG_LIST_START_DELETE;
1141
page_delete_rec_list_write_log(rec, index, type, mtr);
1143
page_cur_set_before_first(block, &cur1);
1144
page_cur_move_to_next(&cur1);
1146
/* Individual deletes are not logged */
1148
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
1150
while (page_cur_get_rec(&cur1) != rec) {
1151
offsets = rec_get_offsets(page_cur_get_rec(&cur1), index,
1152
offsets, ULINT_UNDEFINED, &heap);
1153
page_cur_delete_rec(&cur1, index, offsets, mtr);
1156
if (UNIV_LIKELY_NULL(heap)) {
1157
mem_heap_free(heap);
1160
/* Restore log mode */
1162
mtr_set_log_mode(mtr, log_mode);
1165
#ifndef UNIV_HOTBACKUP
1166
/*************************************************************//**
1167
Moves record list end to another page. Moved records include
1169
@return TRUE on success; FALSE on compression failure (new_block will
1173
page_move_rec_list_end(
1174
/*===================*/
1175
buf_block_t* new_block, /*!< in/out: index page where to move */
1176
buf_block_t* block, /*!< in: index page from where to move */
1177
rec_t* split_rec, /*!< in: first record to move */
1178
dict_index_t* index, /*!< in: record descriptor */
1179
mtr_t* mtr) /*!< in: mtr */
1181
page_t* new_page = buf_block_get_frame(new_block);
1182
ulint old_data_size;
1183
ulint new_data_size;
1187
old_data_size = page_get_data_size(new_page);
1188
old_n_recs = page_get_n_recs(new_page);
1189
#ifdef UNIV_ZIP_DEBUG
1191
page_zip_des_t* new_page_zip
1192
= buf_block_get_page_zip(new_block);
1193
page_zip_des_t* page_zip
1194
= buf_block_get_page_zip(block);
1195
ut_a(!new_page_zip == !page_zip);
1197
|| page_zip_validate(new_page_zip, new_page));
1199
|| page_zip_validate(page_zip, page_align(split_rec)));
1201
#endif /* UNIV_ZIP_DEBUG */
1203
if (UNIV_UNLIKELY(!page_copy_rec_list_end(new_block, block,
1204
split_rec, index, mtr))) {
1208
new_data_size = page_get_data_size(new_page);
1209
new_n_recs = page_get_n_recs(new_page);
1211
ut_ad(new_data_size >= old_data_size);
1213
page_delete_rec_list_end(split_rec, block, index,
1214
new_n_recs - old_n_recs,
1215
new_data_size - old_data_size, mtr);
1220
/*************************************************************//**
1221
Moves record list start to another page. Moved records do not include
1223
@return TRUE on success; FALSE on compression failure */
1226
page_move_rec_list_start(
1227
/*=====================*/
1228
buf_block_t* new_block, /*!< in/out: index page where to move */
1229
buf_block_t* block, /*!< in/out: page containing split_rec */
1230
rec_t* split_rec, /*!< in: first record not to move */
1231
dict_index_t* index, /*!< in: record descriptor */
1232
mtr_t* mtr) /*!< in: mtr */
1234
if (UNIV_UNLIKELY(!page_copy_rec_list_start(new_block, block,
1235
split_rec, index, mtr))) {
1239
page_delete_rec_list_start(split_rec, block, index, mtr);
1244
/***********************************************************************//**
1245
This is a low-level operation which is used in a database index creation
1246
to update the page number of a created B-tree to a data dictionary record. */
1249
page_rec_write_index_page_no(
1250
/*=========================*/
1251
rec_t* rec, /*!< in: record to update */
1252
ulint i, /*!< in: index of the field to update */
1253
ulint page_no,/*!< in: value to write */
1254
mtr_t* mtr) /*!< in: mtr */
1259
data = rec_get_nth_field_old(rec, i, &len);
1263
mlog_write_ulint(data, page_no, MLOG_4BYTES, mtr);
1265
#endif /* !UNIV_HOTBACKUP */
1267
/**************************************************************//**
1268
Used to delete n slots from the directory. This function updates
1269
also n_owned fields in the records, so that the first slot after
1270
the deleted ones inherits the records of the deleted slots. */
1273
page_dir_delete_slot(
1274
/*=================*/
1275
page_t* page, /*!< in/out: the index page */
1276
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
1277
ulint slot_no)/*!< in: slot to be deleted */
1279
page_dir_slot_t* slot;
1284
ut_ad(!page_zip || page_is_comp(page));
1286
ut_ad(slot_no + 1 < page_dir_get_n_slots(page));
1288
n_slots = page_dir_get_n_slots(page);
1290
/* 1. Reset the n_owned fields of the slots to be
1292
slot = page_dir_get_nth_slot(page, slot_no);
1293
n_owned = page_dir_slot_get_n_owned(slot);
1294
page_dir_slot_set_n_owned(slot, page_zip, 0);
1296
/* 2. Update the n_owned value of the first non-deleted slot */
1298
slot = page_dir_get_nth_slot(page, slot_no + 1);
1299
page_dir_slot_set_n_owned(slot, page_zip,
1300
n_owned + page_dir_slot_get_n_owned(slot));
1302
/* 3. Destroy the slot by copying slots */
1303
for (i = slot_no + 1; i < n_slots; i++) {
1304
rec_t* rec = (rec_t*)
1305
page_dir_slot_get_rec(page_dir_get_nth_slot(page, i));
1306
page_dir_slot_set_rec(page_dir_get_nth_slot(page, i - 1), rec);
1309
/* 4. Zero out the last slot, which will be removed */
1310
mach_write_to_2(page_dir_get_nth_slot(page, n_slots - 1), 0);
1312
/* 5. Update the page header */
1313
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots - 1);
1316
/**************************************************************//**
1317
Used to add n slots to the directory. Does not set the record pointers
1318
in the added slots or update n_owned values: this is the responsibility
1324
page_t* page, /*!< in/out: the index page */
1325
page_zip_des_t* page_zip,/*!< in/out: comprssed page, or NULL */
1326
ulint start) /*!< in: the slot above which the new slots
1329
page_dir_slot_t* slot;
1332
n_slots = page_dir_get_n_slots(page);
1334
ut_ad(start < n_slots - 1);
1336
/* Update the page header */
1337
page_dir_set_n_slots(page, page_zip, n_slots + 1);
1340
slot = page_dir_get_nth_slot(page, n_slots);
1341
memmove(slot, slot + PAGE_DIR_SLOT_SIZE,
1342
(n_slots - 1 - start) * PAGE_DIR_SLOT_SIZE);
1345
/****************************************************************//**
1346
Splits a directory slot which owns too many records. */
1349
page_dir_split_slot(
1350
/*================*/
1351
page_t* page, /*!< in/out: index page */
1352
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
1353
uncompressed part will be written, or NULL */
1354
ulint slot_no)/*!< in: the directory slot */
1357
page_dir_slot_t* new_slot;
1358
page_dir_slot_t* prev_slot;
1359
page_dir_slot_t* slot;
1364
ut_ad(!page_zip || page_is_comp(page));
1367
slot = page_dir_get_nth_slot(page, slot_no);
1369
n_owned = page_dir_slot_get_n_owned(slot);
1370
ut_ad(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED + 1);
1372
/* 1. We loop to find a record approximately in the middle of the
1373
records owned by the slot. */
1375
prev_slot = page_dir_get_nth_slot(page, slot_no - 1);
1376
rec = (rec_t*) page_dir_slot_get_rec(prev_slot);
1378
for (i = 0; i < n_owned / 2; i++) {
1379
rec = page_rec_get_next(rec);
1382
ut_ad(n_owned / 2 >= PAGE_DIR_SLOT_MIN_N_OWNED);
1384
/* 2. We add one directory slot immediately below the slot to be
1387
page_dir_add_slot(page, page_zip, slot_no - 1);
1389
/* The added slot is now number slot_no, and the old slot is
1390
now number slot_no + 1 */
1392
new_slot = page_dir_get_nth_slot(page, slot_no);
1393
slot = page_dir_get_nth_slot(page, slot_no + 1);
1395
/* 3. We store the appropriate values to the new slot. */
1397
page_dir_slot_set_rec(new_slot, rec);
1398
page_dir_slot_set_n_owned(new_slot, page_zip, n_owned / 2);
1400
/* 4. Finally, we update the number of records field of the
1403
page_dir_slot_set_n_owned(slot, page_zip, n_owned - (n_owned / 2));
1406
/*************************************************************//**
1407
Tries to balance the given directory slot with too few records with the upper
1408
neighbor, so that there are at least the minimum number of records owned by
1409
the slot; this may result in the merging of two slots. */
1412
page_dir_balance_slot(
1413
/*==================*/
1414
page_t* page, /*!< in/out: index page */
1415
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
1416
ulint slot_no)/*!< in: the directory slot */
1418
page_dir_slot_t* slot;
1419
page_dir_slot_t* up_slot;
1426
ut_ad(!page_zip || page_is_comp(page));
1429
slot = page_dir_get_nth_slot(page, slot_no);
1431
/* The last directory slot cannot be balanced with the upper
1432
neighbor, as there is none. */
1434
if (UNIV_UNLIKELY(slot_no == page_dir_get_n_slots(page) - 1)) {
1439
up_slot = page_dir_get_nth_slot(page, slot_no + 1);
1441
n_owned = page_dir_slot_get_n_owned(slot);
1442
up_n_owned = page_dir_slot_get_n_owned(up_slot);
1444
ut_ad(n_owned == PAGE_DIR_SLOT_MIN_N_OWNED - 1);
1446
/* If the upper slot has the minimum value of n_owned, we will merge
1447
the two slots, therefore we assert: */
1448
ut_ad(2 * PAGE_DIR_SLOT_MIN_N_OWNED - 1 <= PAGE_DIR_SLOT_MAX_N_OWNED);
1450
if (up_n_owned > PAGE_DIR_SLOT_MIN_N_OWNED) {
1452
/* In this case we can just transfer one record owned
1453
by the upper slot to the property of the lower slot */
1454
old_rec = (rec_t*) page_dir_slot_get_rec(slot);
1456
if (page_is_comp(page)) {
1457
new_rec = rec_get_next_ptr(old_rec, TRUE);
1459
rec_set_n_owned_new(old_rec, page_zip, 0);
1460
rec_set_n_owned_new(new_rec, page_zip, n_owned + 1);
1462
new_rec = rec_get_next_ptr(old_rec, FALSE);
1464
rec_set_n_owned_old(old_rec, 0);
1465
rec_set_n_owned_old(new_rec, n_owned + 1);
1468
page_dir_slot_set_rec(slot, new_rec);
1470
page_dir_slot_set_n_owned(up_slot, page_zip, up_n_owned -1);
1472
/* In this case we may merge the two slots */
1473
page_dir_delete_slot(page, page_zip, slot_no);
1477
#ifndef UNIV_HOTBACKUP
1478
/************************************************************//**
1479
Returns the middle record of the record list. If there are an even number
1480
of records in the list, returns the first record of the upper half-list.
1481
@return middle record */
1484
page_get_middle_rec(
1485
/*================*/
1486
page_t* page) /*!< in: page */
1488
page_dir_slot_t* slot;
1495
/* This many records we must leave behind */
1496
middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2;
1502
slot = page_dir_get_nth_slot(page, i);
1503
n_owned = page_dir_slot_get_n_owned(slot);
1505
if (count + n_owned > middle) {
1513
slot = page_dir_get_nth_slot(page, i - 1);
1514
rec = (rec_t*) page_dir_slot_get_rec(slot);
1515
rec = page_rec_get_next(rec);
1517
/* There are now count records behind rec */
1519
for (i = 0; i < middle - count; i++) {
1520
rec = page_rec_get_next(rec);
1525
#endif /* !UNIV_HOTBACKUP */
1527
/***************************************************************//**
1528
Returns the number of records before the given record in chain.
1529
The number includes infimum and supremum records.
1530
@return number of records */
1533
page_rec_get_n_recs_before(
1534
/*=======================*/
1535
const rec_t* rec) /*!< in: the physical record */
1537
const page_dir_slot_t* slot;
1538
const rec_t* slot_rec;
1543
ut_ad(page_rec_check(rec));
1545
page = page_align(rec);
1546
if (page_is_comp(page)) {
1547
while (rec_get_n_owned_new(rec) == 0) {
1549
rec = rec_get_next_ptr_const(rec, TRUE);
1553
for (i = 0; ; i++) {
1554
slot = page_dir_get_nth_slot(page, i);
1555
slot_rec = page_dir_slot_get_rec(slot);
1557
n += rec_get_n_owned_new(slot_rec);
1559
if (rec == slot_rec) {
1565
while (rec_get_n_owned_old(rec) == 0) {
1567
rec = rec_get_next_ptr_const(rec, FALSE);
1571
for (i = 0; ; i++) {
1572
slot = page_dir_get_nth_slot(page, i);
1573
slot_rec = page_dir_slot_get_rec(slot);
1575
n += rec_get_n_owned_old(slot_rec);
1577
if (rec == slot_rec) {
1591
#ifndef UNIV_HOTBACKUP
1592
/************************************************************//**
1593
Prints record contents including the data relevant only in
1594
the index page context. */
1599
const rec_t* rec, /*!< in: physical record */
1600
const ulint* offsets)/*!< in: record descriptor */
1602
ut_a(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
1603
rec_print_new(stderr, rec, offsets);
1604
if (page_rec_is_comp(rec)) {
1606
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1607
(ulong) rec_get_n_owned_new(rec),
1608
(ulong) rec_get_heap_no_new(rec),
1609
(ulong) rec_get_next_offs(rec, TRUE));
1612
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1613
(ulong) rec_get_n_owned_old(rec),
1614
(ulong) rec_get_heap_no_old(rec),
1615
(ulong) rec_get_next_offs(rec, TRUE));
1618
page_rec_check(rec);
1619
rec_validate(rec, offsets);
1622
/***************************************************************//**
1623
This is used to print the contents of the directory for
1624
debugging purposes. */
1629
page_t* page, /*!< in: index page */
1630
ulint pr_n) /*!< in: print n first and n last entries */
1634
page_dir_slot_t* slot;
1636
n = page_dir_get_n_slots(page);
1638
fprintf(stderr, "--------------------------------\n"
1641
"Directory stack top at offs: %lu; number of slots: %lu\n",
1642
page, (ulong) page_offset(page_dir_get_nth_slot(page, n - 1)),
1644
for (i = 0; i < n; i++) {
1645
slot = page_dir_get_nth_slot(page, i);
1646
if ((i == pr_n) && (i < n - pr_n)) {
1647
fputs(" ... \n", stderr);
1649
if ((i < pr_n) || (i >= n - pr_n)) {
1651
"Contents of slot: %lu: n_owned: %lu,"
1654
(ulong) page_dir_slot_get_n_owned(slot),
1656
page_offset(page_dir_slot_get_rec(slot)));
1659
fprintf(stderr, "Total of %lu records\n"
1660
"--------------------------------\n",
1661
(ulong) (PAGE_HEAP_NO_USER_LOW + page_get_n_recs(page)));
1664
/***************************************************************//**
1665
This is used to print the contents of the page record list for
1666
debugging purposes. */
1671
buf_block_t* block, /*!< in: index page */
1672
dict_index_t* index, /*!< in: dictionary index of the page */
1673
ulint pr_n) /*!< in: print n first and n last entries */
1675
page_t* page = block->frame;
1679
mem_heap_t* heap = NULL;
1680
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1681
ulint* offsets = offsets_;
1682
rec_offs_init(offsets_);
1684
ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table));
1687
"--------------------------------\n"
1688
"PAGE RECORD LIST\n"
1689
"Page address %p\n", page);
1691
n_recs = page_get_n_recs(page);
1693
page_cur_set_before_first(block, &cur);
1696
offsets = rec_get_offsets(cur.rec, index, offsets,
1697
ULINT_UNDEFINED, &heap);
1698
page_rec_print(cur.rec, offsets);
1700
if (count == pr_n) {
1703
if (page_cur_is_after_last(&cur)) {
1706
page_cur_move_to_next(&cur);
1710
if (n_recs > 2 * pr_n) {
1711
fputs(" ... \n", stderr);
1714
while (!page_cur_is_after_last(&cur)) {
1715
page_cur_move_to_next(&cur);
1717
if (count + pr_n >= n_recs) {
1718
offsets = rec_get_offsets(cur.rec, index, offsets,
1719
ULINT_UNDEFINED, &heap);
1720
page_rec_print(cur.rec, offsets);
1726
"Total of %lu records \n"
1727
"--------------------------------\n",
1728
(ulong) (count + 1));
1730
if (UNIV_LIKELY_NULL(heap)) {
1731
mem_heap_free(heap);
1735
/***************************************************************//**
1736
Prints the info in a page header. */
1744
"--------------------------------\n"
1745
"PAGE HEADER INFO\n"
1746
"Page address %p, n records %lu (%s)\n"
1747
"n dir slots %lu, heap top %lu\n"
1748
"Page n heap %lu, free %lu, garbage %lu\n"
1749
"Page last insert %lu, direction %lu, n direction %lu\n",
1750
page, (ulong) page_header_get_field(page, PAGE_N_RECS),
1751
page_is_comp(page) ? "compact format" : "original format",
1752
(ulong) page_header_get_field(page, PAGE_N_DIR_SLOTS),
1753
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
1754
(ulong) page_dir_get_n_heap(page),
1755
(ulong) page_header_get_field(page, PAGE_FREE),
1756
(ulong) page_header_get_field(page, PAGE_GARBAGE),
1757
(ulong) page_header_get_field(page, PAGE_LAST_INSERT),
1758
(ulong) page_header_get_field(page, PAGE_DIRECTION),
1759
(ulong) page_header_get_field(page, PAGE_N_DIRECTION));
1762
/***************************************************************//**
1763
This is used to print the contents of the page for
1764
debugging purposes. */
1769
buf_block_t* block, /*!< in: index page */
1770
dict_index_t* index, /*!< in: dictionary index of the page */
1771
ulint dn, /*!< in: print dn first and last entries
1773
ulint rn) /*!< in: print rn first and last records
1776
page_t* page = block->frame;
1778
page_header_print(page);
1779
page_dir_print(page, dn);
1780
page_print_list(block, index, rn);
1782
#endif /* !UNIV_HOTBACKUP */
1784
/***************************************************************//**
1785
The following is used to validate a record on a page. This function
1786
differs from rec_validate as it can also check the n_owned field and
1788
@return TRUE if ok */
1793
rec_t* rec, /*!< in: physical record */
1794
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
1800
page = page_align(rec);
1801
ut_a(!page_is_comp(page) == !rec_offs_comp(offsets));
1803
page_rec_check(rec);
1804
rec_validate(rec, offsets);
1806
if (page_rec_is_comp(rec)) {
1807
n_owned = rec_get_n_owned_new(rec);
1808
heap_no = rec_get_heap_no_new(rec);
1810
n_owned = rec_get_n_owned_old(rec);
1811
heap_no = rec_get_heap_no_old(rec);
1814
if (UNIV_UNLIKELY(!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED))) {
1816
"InnoDB: Dir slot of rec %lu, n owned too big %lu\n",
1817
(ulong) page_offset(rec), (ulong) n_owned);
1821
if (UNIV_UNLIKELY(!(heap_no < page_dir_get_n_heap(page)))) {
1823
"InnoDB: Heap no of rec %lu too big %lu %lu\n",
1824
(ulong) page_offset(rec), (ulong) heap_no,
1825
(ulong) page_dir_get_n_heap(page));
1832
#ifndef UNIV_HOTBACKUP
1833
/***************************************************************//**
1834
Checks that the first directory slot points to the infimum record and
1835
the last to the supremum. This function is intended to track if the
1836
bug fixed in 4.0.14 has caused corruption to users' databases. */
1841
const page_t* page) /*!< in: index page */
1845
ulint supremum_offs;
1847
n_slots = page_dir_get_n_slots(page);
1848
infimum_offs = mach_read_from_2(page_dir_get_nth_slot(page, 0));
1849
supremum_offs = mach_read_from_2(page_dir_get_nth_slot(page,
1852
if (UNIV_UNLIKELY(!page_rec_is_infimum_low(infimum_offs))) {
1855
"InnoDB: Page directory corruption:"
1856
" infimum not pointed to\n");
1857
buf_page_print(page, 0);
1860
if (UNIV_UNLIKELY(!page_rec_is_supremum_low(supremum_offs))) {
1863
"InnoDB: Page directory corruption:"
1864
" supremum not pointed to\n");
1865
buf_page_print(page, 0);
1868
#endif /* !UNIV_HOTBACKUP */
1870
/***************************************************************//**
1871
This function checks the consistency of an index page when we do not
1872
know the index. This is also resilient so that this should never crash
1873
even if the page is total garbage.
1874
@return TRUE if ok */
1877
page_simple_validate_old(
1878
/*=====================*/
1879
page_t* page) /*!< in: old-style index page */
1881
page_dir_slot_t* slot;
1890
ut_a(!page_is_comp(page));
1892
/* Check first that the record heap and the directory do not
1895
n_slots = page_dir_get_n_slots(page);
1897
if (UNIV_UNLIKELY(n_slots > UNIV_PAGE_SIZE / 4)) {
1899
"InnoDB: Nonsensical number %lu of page dir slots\n",
1905
rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
1907
if (UNIV_UNLIKELY(rec_heap_top
1908
> page_dir_get_nth_slot(page, n_slots - 1))) {
1911
"InnoDB: Record heap and dir overlap on a page,"
1912
" heap top %lu, dir %lu\n",
1913
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
1915
page_offset(page_dir_get_nth_slot(page, n_slots - 1)));
1920
/* Validate the record list in a loop checking also that it is
1921
consistent with the page record directory. */
1926
slot = page_dir_get_nth_slot(page, slot_no);
1928
rec = page_get_infimum_rec(page);
1931
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
1933
"InnoDB: Record %lu is above"
1934
" rec heap top %lu\n",
1935
(ulong)(rec - page),
1936
(ulong)(rec_heap_top - page));
1941
if (UNIV_UNLIKELY(rec_get_n_owned_old(rec))) {
1942
/* This is a record pointed to by a dir slot */
1943
if (UNIV_UNLIKELY(rec_get_n_owned_old(rec)
1947
"InnoDB: Wrong owned count %lu, %lu,"
1949
(ulong) rec_get_n_owned_old(rec),
1951
(ulong)(rec - page));
1957
(page_dir_slot_get_rec(slot) != rec)) {
1959
"InnoDB: Dir slot does not point"
1960
" to right rec %lu\n",
1961
(ulong)(rec - page));
1968
if (!page_rec_is_supremum(rec)) {
1970
slot = page_dir_get_nth_slot(page, slot_no);
1974
if (page_rec_is_supremum(rec)) {
1980
(rec_get_next_offs(rec, FALSE) < FIL_PAGE_DATA
1981
|| rec_get_next_offs(rec, FALSE) >= UNIV_PAGE_SIZE)) {
1983
"InnoDB: Next record offset"
1984
" nonsensical %lu for rec %lu\n",
1985
(ulong) rec_get_next_offs(rec, FALSE),
1986
(ulong) (rec - page));
1993
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
1995
"InnoDB: Page record list appears"
1996
" to be circular %lu\n",
2001
rec = page_rec_get_next(rec);
2005
if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) {
2006
fprintf(stderr, "InnoDB: n owned is zero in a supremum rec\n");
2011
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
2012
fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
2013
(ulong) slot_no, (ulong) (n_slots - 1));
2017
if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
2018
+ PAGE_HEAP_NO_USER_LOW
2020
fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
2021
(ulong) page_header_get_field(page, PAGE_N_RECS)
2022
+ PAGE_HEAP_NO_USER_LOW,
2023
(ulong) (count + 1));
2028
/* Check then the free list */
2029
rec = page_header_get_ptr(page, PAGE_FREE);
2031
while (rec != NULL) {
2032
if (UNIV_UNLIKELY(rec < page + FIL_PAGE_DATA
2033
|| rec >= page + UNIV_PAGE_SIZE)) {
2035
"InnoDB: Free list record has"
2036
" a nonsensical offset %lu\n",
2037
(ulong) (rec - page));
2042
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2044
"InnoDB: Free list record %lu"
2045
" is above rec heap top %lu\n",
2046
(ulong) (rec - page),
2047
(ulong) (rec_heap_top - page));
2054
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2056
"InnoDB: Page free list appears"
2057
" to be circular %lu\n",
2062
rec = page_rec_get_next(rec);
2065
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
2067
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
2068
(ulong) page_dir_get_n_heap(page),
2069
(ulong) (count + 1));
2080
/***************************************************************//**
2081
This function checks the consistency of an index page when we do not
2082
know the index. This is also resilient so that this should never crash
2083
even if the page is total garbage.
2084
@return TRUE if ok */
2087
page_simple_validate_new(
2088
/*=====================*/
2089
page_t* page) /*!< in: new-style index page */
2091
page_dir_slot_t* slot;
2100
ut_a(page_is_comp(page));
2102
/* Check first that the record heap and the directory do not
2105
n_slots = page_dir_get_n_slots(page);
2107
if (UNIV_UNLIKELY(n_slots > UNIV_PAGE_SIZE / 4)) {
2109
"InnoDB: Nonsensical number %lu"
2110
" of page dir slots\n", (ulong) n_slots);
2115
rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
2117
if (UNIV_UNLIKELY(rec_heap_top
2118
> page_dir_get_nth_slot(page, n_slots - 1))) {
2121
"InnoDB: Record heap and dir overlap on a page,"
2122
" heap top %lu, dir %lu\n",
2123
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
2125
page_offset(page_dir_get_nth_slot(page, n_slots - 1)));
2130
/* Validate the record list in a loop checking also that it is
2131
consistent with the page record directory. */
2136
slot = page_dir_get_nth_slot(page, slot_no);
2138
rec = page_get_infimum_rec(page);
2141
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2143
"InnoDB: Record %lu is above rec"
2145
(ulong) page_offset(rec),
2146
(ulong) page_offset(rec_heap_top));
2151
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec))) {
2152
/* This is a record pointed to by a dir slot */
2153
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec)
2157
"InnoDB: Wrong owned count %lu, %lu,"
2159
(ulong) rec_get_n_owned_new(rec),
2161
(ulong) page_offset(rec));
2167
(page_dir_slot_get_rec(slot) != rec)) {
2169
"InnoDB: Dir slot does not point"
2170
" to right rec %lu\n",
2171
(ulong) page_offset(rec));
2178
if (!page_rec_is_supremum(rec)) {
2180
slot = page_dir_get_nth_slot(page, slot_no);
2184
if (page_rec_is_supremum(rec)) {
2190
(rec_get_next_offs(rec, TRUE) < FIL_PAGE_DATA
2191
|| rec_get_next_offs(rec, TRUE) >= UNIV_PAGE_SIZE)) {
2193
"InnoDB: Next record offset nonsensical %lu"
2195
(ulong) rec_get_next_offs(rec, TRUE),
2196
(ulong) page_offset(rec));
2203
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2205
"InnoDB: Page record list appears"
2206
" to be circular %lu\n",
2211
rec = page_rec_get_next(rec);
2215
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec) == 0)) {
2216
fprintf(stderr, "InnoDB: n owned is zero"
2217
" in a supremum rec\n");
2222
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
2223
fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
2224
(ulong) slot_no, (ulong) (n_slots - 1));
2228
if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
2229
+ PAGE_HEAP_NO_USER_LOW
2231
fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
2232
(ulong) page_header_get_field(page, PAGE_N_RECS)
2233
+ PAGE_HEAP_NO_USER_LOW,
2234
(ulong) (count + 1));
2239
/* Check then the free list */
2240
rec = page_header_get_ptr(page, PAGE_FREE);
2242
while (rec != NULL) {
2243
if (UNIV_UNLIKELY(rec < page + FIL_PAGE_DATA
2244
|| rec >= page + UNIV_PAGE_SIZE)) {
2246
"InnoDB: Free list record has"
2247
" a nonsensical offset %lu\n",
2248
(ulong) page_offset(rec));
2253
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2255
"InnoDB: Free list record %lu"
2256
" is above rec heap top %lu\n",
2257
(ulong) page_offset(rec),
2258
(ulong) page_offset(rec_heap_top));
2265
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2267
"InnoDB: Page free list appears"
2268
" to be circular %lu\n",
2273
rec = page_rec_get_next(rec);
2276
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
2278
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
2279
(ulong) page_dir_get_n_heap(page),
2280
(ulong) (count + 1));
2291
/***************************************************************//**
2292
This function checks the consistency of an index page.
2293
@return TRUE if ok */
2298
page_t* page, /*!< in: index page */
2299
dict_index_t* index) /*!< in: data dictionary index containing
2300
the page record type definition */
2302
page_dir_slot_t*slot= NULL;
2303
mem_heap_t* heap= NULL;
2307
ulint rec_own_count= 0;
2311
rec_t* old_rec = NULL;
2316
ulint* offsets = NULL;
2317
ulint* old_offsets = NULL;
2318
void* buf_ptr= NULL;
2320
if (UNIV_UNLIKELY((ibool) !!page_is_comp(page)
2321
!= dict_table_is_comp(index->table))) {
2322
fputs("InnoDB: 'compact format' flag mismatch\n", stderr);
2325
if (page_is_comp(page)) {
2326
if (UNIV_UNLIKELY(!page_simple_validate_new(page))) {
2330
if (UNIV_UNLIKELY(!page_simple_validate_old(page))) {
2335
heap = mem_heap_create(UNIV_PAGE_SIZE + 200);
2337
/* The following buffer is used to check that the
2338
records in the page record heap do not overlap */
2340
buf_ptr= mem_heap_zalloc(heap, UNIV_PAGE_SIZE);
2341
buf = static_cast<byte *>(buf_ptr);
2343
/* Check first that the record heap and the directory do not
2346
n_slots = page_dir_get_n_slots(page);
2348
if (UNIV_UNLIKELY(!(page_header_get_ptr(page, PAGE_HEAP_TOP)
2349
<= page_dir_get_nth_slot(page, n_slots - 1)))) {
2352
"InnoDB: Record heap and dir overlap"
2353
" on space %lu page %lu index %s, %p, %p\n",
2354
(ulong) page_get_space_id(page),
2355
(ulong) page_get_page_no(page), index->name,
2356
page_header_get_ptr(page, PAGE_HEAP_TOP),
2357
page_dir_get_nth_slot(page, n_slots - 1));
2362
/* Validate the record list in a loop checking also that
2363
it is consistent with the directory. */
2368
slot = page_dir_get_nth_slot(page, slot_no);
2370
rec = page_get_infimum_rec(page);
2373
offsets = rec_get_offsets(rec, index, offsets,
2374
ULINT_UNDEFINED, &heap);
2376
if (page_is_comp(page) && page_rec_is_user_rec(rec)
2377
&& UNIV_UNLIKELY(rec_get_node_ptr_flag(rec)
2378
== page_is_leaf(page))) {
2379
fputs("InnoDB: node_ptr flag mismatch\n", stderr);
2383
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
2387
#ifndef UNIV_HOTBACKUP
2388
/* Check that the records are in the ascending order */
2389
if (UNIV_LIKELY(count >= PAGE_HEAP_NO_USER_LOW)
2390
&& !page_rec_is_supremum(rec)) {
2392
(1 != cmp_rec_rec(rec, old_rec,
2393
offsets, old_offsets, index))) {
2395
"InnoDB: Records in wrong order"
2396
" on space %lu page %lu index %s\n",
2397
(ulong) page_get_space_id(page),
2398
(ulong) page_get_page_no(page),
2400
fputs("\nInnoDB: previous record ", stderr);
2401
rec_print_new(stderr, old_rec, old_offsets);
2402
fputs("\nInnoDB: record ", stderr);
2403
rec_print_new(stderr, rec, offsets);
2409
#endif /* !UNIV_HOTBACKUP */
2411
if (page_rec_is_user_rec(rec)) {
2413
data_size += rec_offs_size(offsets);
2416
offs = page_offset(rec_get_start(rec, offsets));
2417
i = rec_offs_size(offsets);
2418
if (UNIV_UNLIKELY(offs + i >= UNIV_PAGE_SIZE)) {
2419
fputs("InnoDB: record offset out of bounds\n", stderr);
2424
if (UNIV_UNLIKELY(buf[offs + i])) {
2425
/* No other record may overlap this */
2427
fputs("InnoDB: Record overlaps another\n",
2435
if (page_is_comp(page)) {
2436
rec_own_count = rec_get_n_owned_new(rec);
2438
rec_own_count = rec_get_n_owned_old(rec);
2441
if (UNIV_UNLIKELY(rec_own_count)) {
2442
/* This is a record pointed to by a dir slot */
2443
if (UNIV_UNLIKELY(rec_own_count != own_count)) {
2445
"InnoDB: Wrong owned count %lu, %lu\n",
2446
(ulong) rec_own_count,
2451
if (page_dir_slot_get_rec(slot) != rec) {
2452
fputs("InnoDB: Dir slot does not"
2453
" point to right rec\n",
2458
page_dir_slot_check(slot);
2461
if (!page_rec_is_supremum(rec)) {
2463
slot = page_dir_get_nth_slot(page, slot_no);
2467
if (page_rec_is_supremum(rec)) {
2474
rec = page_rec_get_next(rec);
2476
/* set old_offsets to offsets; recycle offsets */
2478
ulint* tmp_offs = old_offsets;
2479
old_offsets = offsets;
2484
if (page_is_comp(page)) {
2485
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec) == 0)) {
2489
} else if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) {
2491
fputs("InnoDB: n owned is zero\n", stderr);
2495
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
2496
fprintf(stderr, "InnoDB: n slots wrong %lu %lu\n",
2497
(ulong) slot_no, (ulong) (n_slots - 1));
2501
if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
2502
+ PAGE_HEAP_NO_USER_LOW
2504
fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
2505
(ulong) page_header_get_field(page, PAGE_N_RECS)
2506
+ PAGE_HEAP_NO_USER_LOW,
2507
(ulong) (count + 1));
2511
if (UNIV_UNLIKELY(data_size != page_get_data_size(page))) {
2513
"InnoDB: Summed data size %lu, returned by func %lu\n",
2514
(ulong) data_size, (ulong) page_get_data_size(page));
2518
/* Check then the free list */
2519
rec = page_header_get_ptr(page, PAGE_FREE);
2521
while (rec != NULL) {
2522
offsets = rec_get_offsets(rec, index, offsets,
2523
ULINT_UNDEFINED, &heap);
2524
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
2530
offs = page_offset(rec_get_start(rec, offsets));
2531
i = rec_offs_size(offsets);
2532
if (UNIV_UNLIKELY(offs + i >= UNIV_PAGE_SIZE)) {
2533
fputs("InnoDB: record offset out of bounds\n", stderr);
2539
if (UNIV_UNLIKELY(buf[offs + i])) {
2540
fputs("InnoDB: Record overlaps another"
2541
" in free list\n", stderr);
2548
rec = page_rec_get_next(rec);
2551
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
2552
fprintf(stderr, "InnoDB: N heap is wrong %lu %lu\n",
2553
(ulong) page_dir_get_n_heap(page),
2561
mem_heap_free(heap);
2563
if (UNIV_UNLIKELY(ret == FALSE)) {
2566
"InnoDB: Apparent corruption"
2567
" in space %lu page %lu index %s\n",
2568
(ulong) page_get_space_id(page),
2569
(ulong) page_get_page_no(page),
2571
buf_page_print(page, 0);
2577
#ifndef UNIV_HOTBACKUP
2578
/***************************************************************//**
2579
Looks in the page record list for a record with the given heap number.
2580
@return record, NULL if not found */
2583
page_find_rec_with_heap_no(
2584
/*=======================*/
2585
const page_t* page, /*!< in: index page */
2586
ulint heap_no)/*!< in: heap number */
2590
if (page_is_comp(page)) {
2591
rec = page + PAGE_NEW_INFIMUM;
2594
ulint rec_heap_no = rec_get_heap_no_new(rec);
2596
if (rec_heap_no == heap_no) {
2599
} else if (rec_heap_no == PAGE_HEAP_NO_SUPREMUM) {
2604
rec = page + rec_get_next_offs(rec, TRUE);
2607
rec = page + PAGE_OLD_INFIMUM;
2610
ulint rec_heap_no = rec_get_heap_no_old(rec);
2612
if (rec_heap_no == heap_no) {
2615
} else if (rec_heap_no == PAGE_HEAP_NO_SUPREMUM) {
2620
rec = page + rec_get_next_offs(rec, FALSE);
2624
#endif /* !UNIV_HOTBACKUP */