64
65
/*******************************************************************
65
66
Looks for the directory slot which owns the given record. */
68
69
page_dir_find_owner_slot(
69
70
/*=====================*/
70
/* out: the directory slot number */
71
rec_t* rec) /* in: the physical record */
71
/* out: the directory slot number */
72
const rec_t* rec) /* in: the physical record */
74
register uint16_t rec_offs_bytes;
75
register page_dir_slot_t* slot;
75
register uint16 rec_offs_bytes;
76
register const page_dir_slot_t* slot;
76
77
register const page_dir_slot_t* first_slot;
77
register rec_t* r = rec;
78
register const rec_t* r = rec;
79
80
ut_ad(page_rec_check(rec));
81
page = buf_frame_align(rec);
82
page = page_align(rec);
82
83
first_slot = page_dir_get_nth_slot(page, 0);
83
84
slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
85
86
if (page_is_comp(page)) {
86
while (rec_get_n_owned(r, TRUE) == 0) {
87
r = page + rec_get_next_offs(r, TRUE);
87
while (rec_get_n_owned_new(r) == 0) {
88
r = rec_get_next_ptr_const(r, TRUE);
88
89
ut_ad(r >= page + PAGE_NEW_SUPREMUM);
89
90
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
92
while (rec_get_n_owned(r, FALSE) == 0) {
93
r = page + rec_get_next_offs(r, FALSE);
93
while (rec_get_n_owned_old(r) == 0) {
94
r = rec_get_next_ptr_const(r, FALSE);
94
95
ut_ad(r >= page + PAGE_OLD_SUPREMUM);
95
96
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
200
202
during a database recovery we assume that the max trx id of every
201
203
page is the maximum trx id assigned before the crash. */
203
mach_write_to_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID, trx_id);
205
mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id);
206
if (UNIV_LIKELY_NULL(page_zip)) {
207
page_zip_write_header(page_zip,
208
page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
205
if (block->is_hashed) {
206
213
rw_lock_x_unlock(&btr_search_latch);
210
/*****************************************************************
211
Calculates free space if a page is emptied. */
214
page_get_free_space_of_empty_noninline(
215
/*===================================*/
216
/* out: free space */
217
ulint comp) /* in: nonzero=compact page format */
219
return(page_get_free_space_of_empty(comp));
222
217
/****************************************************************
223
Allocates a block of memory from an index page. */
218
Allocates a block of memory from the heap of an index page. */
228
223
/* out: pointer to start of allocated
229
224
buffer, or NULL if allocation fails */
230
page_t* page, /* in: index page */
231
ulint need, /* in: number of bytes needed */
232
dict_index_t* index, /* in: record descriptor */
225
page_t* page, /* in/out: index page */
226
page_zip_des_t* page_zip,/* in/out: compressed page with enough
227
space available for inserting the record,
229
ulint need, /* in: total number of bytes needed */
233
230
ulint* heap_no)/* out: this contains the heap number
234
231
of the allocated record
235
232
if allocation succeeds */
242
237
ut_ad(page && heap_no);
244
/* If there are records in the free list, look if the first is
247
rec = page_header_get_ptr(page, PAGE_FREE);
250
mem_heap_t* heap = NULL;
251
ulint offsets_[REC_OFFS_NORMAL_SIZE];
252
ulint* offsets = offsets_;
253
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
255
offsets = rec_get_offsets(rec, index, offsets,
256
ULINT_UNDEFINED, &heap);
258
if (rec_offs_size(offsets) >= need) {
259
page_header_set_ptr(page, PAGE_FREE,
260
page_rec_get_next(rec));
262
garbage = page_header_get_field(page, PAGE_GARBAGE);
263
ut_ad(garbage >= need);
265
page_header_set_field(page, PAGE_GARBAGE,
268
*heap_no = rec_get_heap_no(rec, page_is_comp(page));
270
block = rec_get_start(rec, offsets);
271
if (UNIV_LIKELY_NULL(heap)) {
277
if (UNIV_LIKELY_NULL(heap)) {
282
/* Could not find space from the free list, try top of heap */
284
239
avl_space = page_get_max_insert_size(page, 1);
286
241
if (avl_space >= need) {
287
242
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
289
page_header_set_ptr(page, PAGE_HEAP_TOP, block + need);
244
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
290
246
*heap_no = page_dir_get_n_heap(page);
292
page_dir_set_n_heap(page, 1 + *heap_no);
248
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
439
409
/* 4. INITIALIZE THE PAGE */
441
page_header_set_field(page, PAGE_N_DIR_SLOTS, 2);
442
page_header_set_ptr(page, PAGE_HEAP_TOP, heap_top);
443
page_header_set_field(page, PAGE_N_HEAP, comp ? 0x8002 : 2);
444
page_header_set_ptr(page, PAGE_FREE, NULL);
445
page_header_set_field(page, PAGE_GARBAGE, 0);
446
page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
447
page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
448
page_header_set_field(page, PAGE_N_DIRECTION, 0);
449
page_header_set_field(page, PAGE_N_RECS, 0);
450
page_set_max_trx_id(page, ut_dulint_zero);
411
page_header_set_field(page, NULL, PAGE_N_DIR_SLOTS, 2);
412
page_header_set_ptr(page, NULL, PAGE_HEAP_TOP, heap_top);
413
page_header_set_field(page, NULL, PAGE_N_HEAP, comp
414
? 0x8000 | PAGE_HEAP_NO_USER_LOW
415
: PAGE_HEAP_NO_USER_LOW);
416
page_header_set_ptr(page, NULL, PAGE_FREE, NULL);
417
page_header_set_field(page, NULL, PAGE_GARBAGE, 0);
418
page_header_set_ptr(page, NULL, PAGE_LAST_INSERT, NULL);
419
page_header_set_field(page, NULL, PAGE_DIRECTION, PAGE_NO_DIRECTION);
420
page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
421
page_header_set_field(page, NULL, PAGE_N_RECS, 0);
422
page_set_max_trx_id(block, NULL, ut_dulint_zero);
451
423
memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
452
- (heap_top - page));
424
- page_offset(heap_top));
454
426
/* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
464
436
/* Set the next pointers in infimum and supremum */
466
rec_set_next_offs(infimum_rec, comp, (ulint)(supremum_rec - page));
467
rec_set_next_offs(supremum_rec, comp, 0);
438
if (UNIV_LIKELY(comp)) {
439
rec_set_next_offs_new(infimum_rec, PAGE_NEW_SUPREMUM);
440
rec_set_next_offs_new(supremum_rec, 0);
442
rec_set_next_offs_old(infimum_rec, PAGE_OLD_SUPREMUM);
443
rec_set_next_offs_old(supremum_rec, 0);
449
/**************************************************************
450
Create an uncompressed B-tree index page. */
455
/* out: pointer to the page */
456
buf_block_t* block, /* in: a buffer block where the
458
mtr_t* mtr, /* in: mini-transaction handle */
459
ulint comp) /* in: nonzero=compact page format */
461
page_create_write_log(buf_block_get_frame(block), mtr, comp);
462
return(page_create_low(block, comp));
465
/**************************************************************
466
Create a compressed B-tree index page. */
471
/* out: pointer to the page */
472
buf_block_t* block, /* in/out: a buffer frame where the
474
dict_index_t* index, /* in: the index of the page */
475
ulint level, /* in: the B-tree level of the page */
476
mtr_t* mtr) /* in: mini-transaction handle */
479
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
484
ut_ad(dict_table_is_comp(index->table));
486
page = page_create_low(block, TRUE);
487
mach_write_to_2(page + PAGE_HEADER + PAGE_LEVEL, level);
489
if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
490
/* The compression of a newly created page
491
should always succeed. */
472
498
/*****************************************************************
473
499
Differs from page_copy_rec_list_end, because this function does not
474
touch the lock table and max trx id on page. */
500
touch the lock table and max trx id on page or compress the page. */
477
503
page_copy_rec_list_end_no_locks(
478
504
/*============================*/
479
page_t* new_page, /* in: index page to copy to */
480
page_t* page, /* in: index page */
505
buf_block_t* new_block, /* in: index page to copy to */
506
buf_block_t* block, /* in: index page of rec */
481
507
rec_t* rec, /* in: record on page */
482
508
dict_index_t* index, /* in: record descriptor */
483
509
mtr_t* mtr) /* in: mtr */
511
page_t* new_page = buf_block_get_frame(new_block);
488
514
mem_heap_t* heap = NULL;
489
515
ulint offsets_[REC_OFFS_NORMAL_SIZE];
490
516
ulint* offsets = offsets_;
491
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
517
rec_offs_init(offsets_);
493
page_cur_position(rec, &cur1);
519
page_cur_position(rec, block, &cur1);
495
521
if (page_cur_is_before_first(&cur1)) {
500
526
ut_a((ibool)!!page_is_comp(new_page)
501
527
== dict_table_is_comp(index->table));
502
ut_a(page_is_comp(new_page) == page_is_comp(page));
528
ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
503
529
ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
504
(page_is_comp(new_page)
505
? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
530
(page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
507
page_cur_set_before_first(new_page, &cur2);
532
cur2 = page_get_infimum_rec(buf_block_get_frame(new_block));
509
534
/* Copy records from the original page to the new page */
511
sup = page_get_supremum_rec(page);
536
while (!page_cur_is_after_last(&cur1)) {
514
537
rec_t* cur1_rec = page_cur_get_rec(&cur1);
515
if (cur1_rec == sup) {
518
539
offsets = rec_get_offsets(cur1_rec, index, offsets,
519
540
ULINT_UNDEFINED, &heap);
520
if (UNIV_UNLIKELY(!page_cur_rec_insert(&cur2, cur1_rec, index,
541
ins_rec = page_cur_insert_rec_low(cur2, index,
542
cur1_rec, offsets, mtr);
543
if (UNIV_UNLIKELY(!ins_rec)) {
522
544
/* Track an assertion failure reported on the mailing
523
545
list on June 18th, 2003 */
525
buf_page_print(new_page);
526
buf_page_print(page);
547
buf_page_print(new_page, 0);
548
buf_page_print(page_align(rec), 0);
527
549
ut_print_timestamp(stderr);
530
552
"InnoDB: rec offset %lu, cur1 offset %lu,"
531
553
" cur2 offset %lu\n",
533
(ulong)(page_cur_get_rec(&cur1) - page),
534
(ulong)(page_cur_get_rec(&cur2) - new_page));
554
(ulong) page_offset(rec),
555
(ulong) page_offset(page_cur_get_rec(&cur1)),
556
(ulong) page_offset(cur2));
539
560
page_cur_move_to_next(&cur1);
540
page_cur_move_to_next(&cur2);
543
564
if (UNIV_LIKELY_NULL(heap)) {
549
570
Copies records from page to new_page, from a given record onward,
550
571
including that record. Infimum and supremum records are not copied.
551
572
The records are copied to the start of the record list on new_page. */
554
575
page_copy_rec_list_end(
555
576
/*===================*/
556
page_t* new_page, /* in: index page to copy to */
557
page_t* page, /* in: index page */
577
/* out: pointer to the original
578
successor of the infimum record
579
on new_page, or NULL on zip overflow
580
(new_block will be decompressed) */
581
buf_block_t* new_block, /* in/out: index page to copy to */
582
buf_block_t* block, /* in: index page containing rec */
558
583
rec_t* rec, /* in: record on page */
559
584
dict_index_t* index, /* in: record descriptor */
560
585
mtr_t* mtr) /* in: mtr */
562
if (page_dir_get_n_heap(new_page) == 2) {
563
page_copy_rec_list_end_to_created_page(new_page, page, rec,
587
page_t* new_page = buf_block_get_frame(new_block);
588
page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block);
589
page_t* page = page_align(rec);
590
rec_t* ret = page_rec_get_next(
591
page_get_infimum_rec(new_page));
592
ulint log_mode = 0; /* remove warning */
594
/* page_zip_validate() will fail here if btr_compress()
595
sets FIL_PAGE_PREV to FIL_NULL */
596
ut_ad(buf_block_get_frame(block) == page);
597
ut_ad(page_is_leaf(page) == page_is_leaf(new_page));
598
ut_ad(page_is_comp(page) == page_is_comp(new_page));
600
if (UNIV_LIKELY_NULL(new_page_zip)) {
601
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
604
if (page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW) {
605
page_copy_rec_list_end_to_created_page(new_page, rec,
566
page_copy_rec_list_end_no_locks(new_page, page, rec,
608
page_copy_rec_list_end_no_locks(new_block, block, rec,
612
if (UNIV_LIKELY_NULL(new_page_zip)) {
613
mtr_set_log_mode(mtr, log_mode);
616
(!page_zip_compress(new_page_zip, new_page, index, mtr))) {
617
/* Before trying to reorganize the page,
618
store the number of preceding records on the page. */
620
= page_rec_get_n_recs_before(ret);
623
(!page_zip_reorganize(new_block, index, mtr))) {
626
(!page_zip_decompress(new_page_zip,
630
ut_ad(page_validate(new_page, index));
633
/* The page was reorganized:
635
ret = new_page + PAGE_NEW_INFIMUM;
638
ret = rec_get_next_ptr(ret, TRUE);
570
644
/* Update the lock table, MAX_TRX_ID, and possible hash index */
572
lock_move_rec_list_end(new_page, page, rec);
574
page_update_max_trx_id(new_page, page_get_max_trx_id(page));
576
btr_search_move_or_delete_hash_entries(new_page, page, index);
646
lock_move_rec_list_end(new_block, block, rec);
648
page_update_max_trx_id(new_block, new_page_zip,
649
page_get_max_trx_id(page));
651
btr_search_move_or_delete_hash_entries(new_block, block, index);
579
656
/*****************************************************************
580
657
Copies records from page to new_page, up to the given record,
581
658
NOT including that record. Infimum and supremum records are not copied.
582
659
The records are copied to the end of the record list on new_page. */
585
662
page_copy_rec_list_start(
586
663
/*=====================*/
587
page_t* new_page, /* in: index page to copy to */
588
page_t* page, /* in: index page */
664
/* out: pointer to the original
665
predecessor of the supremum record
666
on new_page, or NULL on zip overflow
667
(new_block will be decompressed) */
668
buf_block_t* new_block, /* in/out: index page to copy to */
669
buf_block_t* block, /* in: index page containing rec */
589
670
rec_t* rec, /* in: record on page */
590
671
dict_index_t* index, /* in: record descriptor */
591
672
mtr_t* mtr) /* in: mtr */
674
page_t* new_page = buf_block_get_frame(new_block);
675
page_zip_des_t* new_page_zip = buf_block_get_page_zip(new_block);
678
ulint log_mode = 0 /* remove warning */;
596
679
mem_heap_t* heap = NULL;
681
= page_rec_get_prev(page_get_supremum_rec(new_page));
597
682
ulint offsets_[REC_OFFS_NORMAL_SIZE];
598
683
ulint* offsets = offsets_;
599
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
601
page_cur_set_before_first(page, &cur1);
603
if (rec == page_cur_get_rec(&cur1)) {
684
rec_offs_init(offsets_);
686
if (page_rec_is_infimum(rec)) {
691
if (UNIV_LIKELY_NULL(new_page_zip)) {
692
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
695
page_cur_set_before_first(block, &cur1);
608
696
page_cur_move_to_next(&cur1);
610
page_cur_set_after_last(new_page, &cur2);
611
page_cur_move_to_prev(&cur2);
612
old_end = page_cur_get_rec(&cur2);
614
700
/* Copy records from the original page to the new page */
616
702
while (page_cur_get_rec(&cur1) != rec) {
618
703
rec_t* cur1_rec = page_cur_get_rec(&cur1);
619
704
offsets = rec_get_offsets(cur1_rec, index, offsets,
620
705
ULINT_UNDEFINED, &heap);
621
ins_rec = page_cur_rec_insert(&cur2, cur1_rec, index,
706
cur2 = page_cur_insert_rec_low(cur2, index,
707
cur1_rec, offsets, mtr);
625
710
page_cur_move_to_next(&cur1);
626
page_cur_move_to_next(&cur2);
629
/* Update the lock table, MAX_TRX_ID, and possible hash index */
631
lock_move_rec_list_start(new_page, page, rec, old_end);
633
page_update_max_trx_id(new_page, page_get_max_trx_id(page));
635
btr_search_move_or_delete_hash_entries(new_page, page, index);
637
713
if (UNIV_LIKELY_NULL(heap)) {
638
714
mem_heap_free(heap);
717
if (UNIV_LIKELY_NULL(new_page_zip)) {
718
mtr_set_log_mode(mtr, log_mode);
721
(!page_zip_compress(new_page_zip, new_page, index, mtr))) {
722
/* Before trying to reorganize the page,
723
store the number of preceding records on the page. */
725
= page_rec_get_n_recs_before(ret);
728
(!page_zip_reorganize(new_block, index, mtr))) {
731
(!page_zip_decompress(new_page_zip,
735
ut_ad(page_validate(new_page, index));
738
/* The page was reorganized:
740
ret = new_page + PAGE_NEW_INFIMUM;
743
ret = rec_get_next_ptr(ret, TRUE);
749
/* Update MAX_TRX_ID, the lock table, and possible hash index */
751
page_update_max_trx_id(new_block, new_page_zip,
752
page_get_max_trx_id(page_align(rec)));
754
lock_move_rec_list_start(new_block, block, rec, ret);
756
btr_search_move_or_delete_hash_entries(new_block, block, index);
642
761
/**************************************************************
735
857
delete, or ULINT_UNDEFINED if not known */
736
858
mtr_t* mtr) /* in: mtr */
738
page_dir_slot_t* slot;
860
page_dir_slot_t*slot;
865
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
866
page_t* page = page_align(rec);
867
mem_heap_t* heap = NULL;
868
ulint offsets_[REC_OFFS_NORMAL_SIZE];
869
ulint* offsets = offsets_;
870
rec_offs_init(offsets_);
872
ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
873
ut_ad(!page_zip || page_rec_is_comp(rec));
874
#ifdef UNIV_ZIP_DEBUG
875
ut_a(!page_zip || page_zip_validate(page_zip, page));
876
#endif /* UNIV_ZIP_DEBUG */
878
if (page_rec_is_infimum(rec)) {
879
rec = page_rec_get_next(rec);
882
if (page_rec_is_supremum(rec)) {
749
887
/* Reset the last insert info in the page header and increment
750
888
the modify clock for the frame */
752
ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
753
page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
890
page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
755
892
/* The page gets invalid for optimistic searches: increment the
756
893
frame modify clock */
758
buf_frame_modify_clock_inc(page);
760
sup = page_get_supremum_rec(page);
762
comp = page_is_comp(page);
763
if (page_rec_is_infimum_low(rec - page)) {
764
rec = page_rec_get_next(rec);
767
page_delete_rec_list_write_log(rec, index, comp
895
buf_block_modify_clock_inc(block);
897
page_delete_rec_list_write_log(rec, index, page_is_comp(page)
768
898
? MLOG_COMP_LIST_END_DELETE
769
899
: MLOG_LIST_END_DELETE, mtr);
901
if (UNIV_LIKELY_NULL(page_zip)) {
904
ut_a(page_is_comp(page));
905
/* Individual deletes are not logged */
907
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
911
page_cur_position(rec, block, &cur);
913
offsets = rec_get_offsets(rec, index, offsets,
914
ULINT_UNDEFINED, &heap);
915
rec = rec_get_next_ptr(rec, TRUE);
916
#ifdef UNIV_ZIP_DEBUG
917
ut_a(page_zip_validate(page_zip, page));
918
#endif /* UNIV_ZIP_DEBUG */
919
page_cur_delete_rec(&cur, index, offsets, mtr);
920
} while (page_offset(rec) != PAGE_NEW_SUPREMUM);
922
if (UNIV_LIKELY_NULL(heap)) {
926
/* Restore log mode */
928
mtr_set_log_mode(mtr, log_mode);
776
932
prev_rec = page_rec_get_prev(rec);
778
last_rec = page_rec_get_prev(sup);
934
last_rec = page_rec_get_prev(page_get_supremum_rec(page));
780
936
if ((size == ULINT_UNDEFINED) || (n_recs == ULINT_UNDEFINED)) {
781
mem_heap_t* heap = NULL;
782
ulint offsets_[REC_OFFS_NORMAL_SIZE];
783
ulint* offsets = offsets_;
784
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
785
938
/* Calculate the sum of sizes and the number of records */
790
while (rec2 != sup) {
792
944
offsets = rec_get_offsets(rec2, index, offsets,
793
945
ULINT_UNDEFINED, &heap);
812
964
of the records owned by the supremum record, as it is allowed to be
813
965
less than PAGE_DIR_SLOT_MIN_N_OWNED */
818
while (rec_get_n_owned(rec2, comp) == 0) {
821
rec2 = page_rec_get_next(rec2);
967
if (page_is_comp(page)) {
971
while (rec_get_n_owned_new(rec2) == 0) {
974
rec2 = rec_get_next_ptr(rec2, TRUE);
977
ut_ad(rec_get_n_owned_new(rec2) > count);
979
n_owned = rec_get_n_owned_new(rec2) - count;
980
slot_index = page_dir_find_owner_slot(rec2);
981
slot = page_dir_get_nth_slot(page, slot_index);
986
while (rec_get_n_owned_old(rec2) == 0) {
989
rec2 = rec_get_next_ptr(rec2, FALSE);
992
ut_ad(rec_get_n_owned_old(rec2) > count);
994
n_owned = rec_get_n_owned_old(rec2) - count;
995
slot_index = page_dir_find_owner_slot(rec2);
996
slot = page_dir_get_nth_slot(page, slot_index);
824
ut_ad(rec_get_n_owned(rec2, comp) - count > 0);
826
n_owned = rec_get_n_owned(rec2, comp) - count;
828
slot_index = page_dir_find_owner_slot(rec2);
829
slot = page_dir_get_nth_slot(page, slot_index);
831
page_dir_slot_set_rec(slot, sup);
832
page_dir_slot_set_n_owned(slot, n_owned);
834
page_dir_set_n_slots(page, slot_index + 1);
999
page_dir_slot_set_rec(slot, page_get_supremum_rec(page));
1000
page_dir_slot_set_n_owned(slot, NULL, n_owned);
1002
page_dir_set_n_slots(page, NULL, slot_index + 1);
836
1004
/* Remove the record chain segment from the record chain */
837
1005
page_rec_set_next(prev_rec, page_get_supremum_rec(page));
839
1007
/* Catenate the deleted chain segment to the page free list */
841
free = page_header_get_ptr(page, PAGE_FREE);
843
page_rec_set_next(last_rec, free);
844
page_header_set_ptr(page, PAGE_FREE, rec);
846
page_header_set_field(page, PAGE_GARBAGE, size
1009
page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE));
1010
page_header_set_ptr(page, NULL, PAGE_FREE, rec);
1012
page_header_set_field(page, NULL, PAGE_GARBAGE, size
847
1013
+ page_header_get_field(page, PAGE_GARBAGE));
849
page_header_set_field(page, PAGE_N_RECS,
1015
page_header_set_field(page, NULL, PAGE_N_RECS,
850
1016
(ulint)(page_get_n_recs(page) - n_recs));
853
1019
/*****************************************************************
854
1020
Deletes records from page, up to the given record, NOT including
855
1021
that record. Infimum and supremum records are not deleted. */
858
1024
page_delete_rec_list_start(
859
1025
/*=======================*/
860
page_t* page, /* in: index page */
861
1026
rec_t* rec, /* in: record on page */
1027
buf_block_t* block, /* in: buffer block of the page */
862
1028
dict_index_t* index, /* in: record descriptor */
863
1029
mtr_t* mtr) /* in: mtr */
911
1082
/*****************************************************************
912
1083
Moves record list end to another page. Moved records include
916
1087
page_move_rec_list_end(
917
1088
/*===================*/
918
page_t* new_page, /* in: index page where to move */
919
page_t* page, /* in: index page */
1089
/* out: TRUE on success; FALSE on
1091
(new_block will be decompressed) */
1092
buf_block_t* new_block, /* in/out: index page where to move */
1093
buf_block_t* block, /* in: index page from where to move */
920
1094
rec_t* split_rec, /* in: first record to move */
921
1095
dict_index_t* index, /* in: record descriptor */
922
1096
mtr_t* mtr) /* in: mtr */
1098
page_t* new_page = buf_block_get_frame(new_block);
1099
ulint old_data_size;
1100
ulint new_data_size;
929
1104
old_data_size = page_get_data_size(new_page);
930
1105
old_n_recs = page_get_n_recs(new_page);
1106
#ifdef UNIV_ZIP_DEBUG
1108
page_zip_des_t* new_page_zip
1109
= buf_block_get_page_zip(new_block);
1110
page_zip_des_t* page_zip
1111
= buf_block_get_page_zip(block);
1112
ut_a(!new_page_zip == !page_zip);
1114
|| page_zip_validate(new_page_zip, new_page));
1116
|| page_zip_validate(page_zip, page_align(split_rec)));
1118
#endif /* UNIV_ZIP_DEBUG */
932
page_copy_rec_list_end(new_page, page, split_rec, index, mtr);
1120
if (UNIV_UNLIKELY(!page_copy_rec_list_end(new_block, block,
1121
split_rec, index, mtr))) {
934
1125
new_data_size = page_get_data_size(new_page);
935
1126
new_n_recs = page_get_n_recs(new_page);
937
1128
ut_ad(new_data_size >= old_data_size);
939
page_delete_rec_list_end(page, split_rec, index,
1130
page_delete_rec_list_end(split_rec, block, index,
940
1131
new_n_recs - old_n_recs,
941
1132
new_data_size - old_data_size, mtr);
944
1137
/*****************************************************************
945
1138
Moves record list start to another page. Moved records do not include
949
1142
page_move_rec_list_start(
950
1143
/*=====================*/
951
page_t* new_page, /* in: index page where to move */
952
page_t* page, /* in: index page */
1144
/* out: TRUE on success; FALSE on
1145
compression failure */
1146
buf_block_t* new_block, /* in/out: index page where to move */
1147
buf_block_t* block, /* in/out: page containing split_rec */
953
1148
rec_t* split_rec, /* in: first record not to move */
954
1149
dict_index_t* index, /* in: record descriptor */
955
1150
mtr_t* mtr) /* in: mtr */
957
page_copy_rec_list_start(new_page, page, split_rec, index, mtr);
959
page_delete_rec_list_start(page, split_rec, index, mtr);
1152
if (UNIV_UNLIKELY(!page_copy_rec_list_start(new_block, block,
1153
split_rec, index, mtr))) {
1157
page_delete_rec_list_start(split_rec, block, index, mtr);
962
1162
/***************************************************************************
963
1163
This is a low-level operation which is used in a database index creation
964
1164
to update the page number of a created B-tree to a data dictionary record. */
967
1167
page_rec_write_index_page_no(
968
1168
/*=========================*/
987
1187
the deleted ones inherits the records of the deleted slots. */
990
page_dir_delete_slots(
991
/*==================*/
992
page_t* page, /* in: the index page */
993
ulint start, /* in: first slot to be deleted */
994
ulint n) /* in: number of slots to delete (currently
995
only n == 1 allowed) */
1190
page_dir_delete_slot(
1191
/*=================*/
1192
page_t* page, /* in/out: the index page */
1193
page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
1194
ulint slot_no)/* in: slot to be deleted */
997
1196
page_dir_slot_t* slot;
1005
ut_ad(start + n < page_dir_get_n_slots(page));
1201
ut_ad(!page_zip || page_is_comp(page));
1203
ut_ad(slot_no + 1 < page_dir_get_n_slots(page));
1007
1205
n_slots = page_dir_get_n_slots(page);
1009
1207
/* 1. Reset the n_owned fields of the slots to be
1011
for (i = start; i < start + n; i++) {
1012
slot = page_dir_get_nth_slot(page, i);
1013
sum_owned += page_dir_slot_get_n_owned(slot);
1014
page_dir_slot_set_n_owned(slot, 0);
1209
slot = page_dir_get_nth_slot(page, slot_no);
1210
n_owned = page_dir_slot_get_n_owned(slot);
1211
page_dir_slot_set_n_owned(slot, page_zip, 0);
1017
1213
/* 2. Update the n_owned value of the first non-deleted slot */
1019
slot = page_dir_get_nth_slot(page, start + n);
1020
page_dir_slot_set_n_owned(slot,
1021
sum_owned + page_dir_slot_get_n_owned(slot));
1023
/* 3. Destroy start and other slots by copying slots */
1024
for (i = start + n; i < n_slots; i++) {
1025
slot = page_dir_get_nth_slot(page, i);
1026
rec = page_dir_slot_get_rec(slot);
1028
slot = page_dir_get_nth_slot(page, i - n);
1029
page_dir_slot_set_rec(slot, rec);
1215
slot = page_dir_get_nth_slot(page, slot_no + 1);
1216
page_dir_slot_set_n_owned(slot, page_zip,
1217
n_owned + page_dir_slot_get_n_owned(slot));
1219
/* 3. Destroy the slot by copying slots */
1220
for (i = slot_no + 1; i < n_slots; i++) {
1221
rec_t* rec = (rec_t*)
1222
page_dir_slot_get_rec(page_dir_get_nth_slot(page, i));
1223
page_dir_slot_set_rec(page_dir_get_nth_slot(page, i - 1), rec);
1032
/* 4. Update the page header */
1033
page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots - n);
1226
/* 4. Zero out the last slot, which will be removed */
1227
mach_write_to_2(page_dir_get_nth_slot(page, n_slots - 1), 0);
1229
/* 5. Update the page header */
1230
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots - 1);
1036
1233
/******************************************************************
1039
1236
of the caller. */
1044
page_t* page, /* in: the index page */
1045
ulint start, /* in: the slot above which the new slots are added */
1046
ulint n) /* in: number of slots to add (currently only n == 1
1241
page_t* page, /* in/out: the index page */
1242
page_zip_des_t* page_zip,/* in/out: comprssed page, or NULL */
1243
ulint start) /* in: the slot above which the new slots
1049
1246
page_dir_slot_t* slot;
1056
1249
n_slots = page_dir_get_n_slots(page);
1058
1251
ut_ad(start < n_slots - 1);
1060
1253
/* Update the page header */
1061
page_dir_set_n_slots(page, n_slots + n);
1254
page_dir_set_n_slots(page, page_zip, n_slots + 1);
1063
1256
/* Move slots up */
1065
for (i = n_slots - 1; i > start; i--) {
1067
slot = page_dir_get_nth_slot(page, i);
1068
rec = page_dir_slot_get_rec(slot);
1070
slot = page_dir_get_nth_slot(page, i + n);
1071
page_dir_slot_set_rec(slot, rec);
1257
slot = page_dir_get_nth_slot(page, n_slots);
1258
memmove(slot, slot + PAGE_DIR_SLOT_SIZE,
1259
(n_slots - 1 - start) * PAGE_DIR_SLOT_SIZE);
1075
1262
/********************************************************************
1076
1263
Splits a directory slot which owns too many records. */
1079
1266
page_dir_split_slot(
1080
1267
/*================*/
1081
page_t* page, /* in: the index page in question */
1082
ulint slot_no) /* in: the directory slot */
1268
page_t* page, /* in/out: index page */
1269
page_zip_des_t* page_zip,/* in/out: compressed page whose
1270
uncompressed part will be written, or NULL */
1271
ulint slot_no)/* in: the directory slot */
1085
1274
page_dir_slot_t* new_slot;
1177
1369
/* In this case we can just transfer one record owned
1178
1370
by the upper slot to the property of the lower slot */
1179
old_rec = page_dir_slot_get_rec(slot);
1180
new_rec = page_rec_get_next(old_rec);
1182
rec_set_n_owned(old_rec, page_is_comp(page), 0);
1183
rec_set_n_owned(new_rec, page_is_comp(page), n_owned + 1);
1371
old_rec = (rec_t*) page_dir_slot_get_rec(slot);
1373
if (page_is_comp(page)) {
1374
new_rec = rec_get_next_ptr(old_rec, TRUE);
1376
rec_set_n_owned_new(old_rec, page_zip, 0);
1377
rec_set_n_owned_new(new_rec, page_zip, n_owned + 1);
1379
new_rec = rec_get_next_ptr(old_rec, FALSE);
1381
rec_set_n_owned_old(old_rec, 0);
1382
rec_set_n_owned_old(new_rec, n_owned + 1);
1185
1385
page_dir_slot_set_rec(slot, new_rec);
1187
page_dir_slot_set_n_owned(up_slot, up_n_owned -1);
1387
page_dir_slot_set_n_owned(up_slot, page_zip, up_n_owned -1);
1189
1389
/* In this case we may merge the two slots */
1190
page_dir_delete_slots(page, slot_no, 1);
1390
page_dir_delete_slot(page, page_zip, slot_no);
1194
1394
/****************************************************************
1195
1395
Returns the middle record of the record list. If there are an even number
1196
1396
of records in the list, returns the first record of the upper half-list. */
1199
1399
page_get_middle_rec(
1200
1400
/*================*/
1242
1442
/*******************************************************************
1243
1443
Returns the number of records before the given record in chain.
1244
1444
The number includes infimum and supremum records. */
1247
1447
page_rec_get_n_recs_before(
1248
1448
/*=======================*/
1249
/* out: number of records */
1250
rec_t* rec) /* in: the physical record */
1449
/* out: number of records */
1450
const rec_t* rec) /* in: the physical record */
1252
page_dir_slot_t* slot;
1452
const page_dir_slot_t* slot;
1453
const rec_t* slot_rec;
1259
1458
ut_ad(page_rec_check(rec));
1261
page = buf_frame_align(rec);
1262
comp = page_is_comp(page);
1264
while (rec_get_n_owned(rec, comp) == 0) {
1266
rec = page_rec_get_next(rec);
1270
for (i = 0; ; i++) {
1271
slot = page_dir_get_nth_slot(page, i);
1272
slot_rec = page_dir_slot_get_rec(slot);
1274
n += rec_get_n_owned(slot_rec, comp);
1276
if (rec == slot_rec) {
1460
page = page_align(rec);
1461
if (page_is_comp(page)) {
1462
while (rec_get_n_owned_new(rec) == 0) {
1464
rec = rec_get_next_ptr_const(rec, TRUE);
1468
for (i = 0; ; i++) {
1469
slot = page_dir_get_nth_slot(page, i);
1470
slot_rec = page_dir_slot_get_rec(slot);
1472
n += rec_get_n_owned_new(slot_rec);
1474
if (rec == slot_rec) {
1480
while (rec_get_n_owned_old(rec) == 0) {
1482
rec = rec_get_next_ptr_const(rec, FALSE);
1486
for (i = 0; ; i++) {
1487
slot = page_dir_get_nth_slot(page, i);
1488
slot_rec = page_dir_slot_get_rec(slot);
1490
n += rec_get_n_owned_old(slot_rec);
1492
if (rec == slot_rec) {
1289
1506
/****************************************************************
1290
1507
Prints record contents including the data relevant only in
1291
1508
the index page context. */
1294
1511
page_rec_print(
1295
1512
/*===========*/
1296
rec_t* rec, /* in: physical record */
1513
const rec_t* rec, /* in: physical record */
1297
1514
const ulint* offsets)/* in: record descriptor */
1299
ulint comp = page_is_comp(buf_frame_align(rec));
1301
ut_a(!comp == !rec_offs_comp(offsets));
1516
ut_a(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
1302
1517
rec_print_new(stderr, rec, offsets);
1304
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1305
(ulong) rec_get_n_owned(rec, comp),
1306
(ulong) rec_get_heap_no(rec, comp),
1307
(ulong) rec_get_next_offs(rec, comp));
1518
if (page_rec_is_comp(rec)) {
1520
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1521
(ulong) rec_get_n_owned_new(rec),
1522
(ulong) rec_get_heap_no_new(rec),
1523
(ulong) rec_get_next_offs(rec, TRUE));
1526
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1527
(ulong) rec_get_n_owned_old(rec),
1528
(ulong) rec_get_heap_no_old(rec),
1529
(ulong) rec_get_next_offs(rec, TRUE));
1309
1532
page_rec_check(rec);
1310
1533
rec_validate(rec, offsets);
1728
if (count > UNIV_PAGE_SIZE) {
1730
"InnoDB: Page free list appears"
1731
" to be circular %lu\n",
1736
rec = page_rec_get_next(rec);
1739
if (page_dir_get_n_heap(page) != count + 1) {
1965
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
1967
"InnoDB: Page free list appears"
1968
" to be circular %lu\n",
1973
rec = page_rec_get_next(rec);
1976
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
1978
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
1979
(ulong) page_dir_get_n_heap(page),
1980
(ulong) (count + 1));
1991
/*******************************************************************
1992
This function checks the consistency of an index page when we do not
1993
know the index. This is also resilient so that this should never crash
1994
even if the page is total garbage. */
1997
page_simple_validate_new(
1998
/*=====================*/
1999
/* out: TRUE if ok */
2000
page_t* page) /* in: new-style index page */
2002
page_dir_slot_t* slot;
2011
ut_a(page_is_comp(page));
2013
/* Check first that the record heap and the directory do not
2016
n_slots = page_dir_get_n_slots(page);
2018
if (UNIV_UNLIKELY(n_slots > UNIV_PAGE_SIZE / 4)) {
2020
"InnoDB: Nonsensical number %lu"
2021
" of page dir slots\n", (ulong) n_slots);
2026
rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
2028
if (UNIV_UNLIKELY(rec_heap_top
2029
> page_dir_get_nth_slot(page, n_slots - 1))) {
2032
"InnoDB: Record heap and dir overlap on a page,"
2033
" heap top %lu, dir %lu\n",
2034
(ulong) page_header_get_field(page, PAGE_HEAP_TOP),
2036
page_offset(page_dir_get_nth_slot(page, n_slots - 1)));
2041
/* Validate the record list in a loop checking also that it is
2042
consistent with the page record directory. */
2047
slot = page_dir_get_nth_slot(page, slot_no);
2049
rec = page_get_infimum_rec(page);
2052
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2054
"InnoDB: Record %lu is above rec"
2056
(ulong) page_offset(rec),
2057
(ulong) page_offset(rec_heap_top));
2062
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec))) {
2063
/* This is a record pointed to by a dir slot */
2064
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec)
2068
"InnoDB: Wrong owned count %lu, %lu,"
2070
(ulong) rec_get_n_owned_new(rec),
2072
(ulong) page_offset(rec));
2078
(page_dir_slot_get_rec(slot) != rec)) {
2080
"InnoDB: Dir slot does not point"
2081
" to right rec %lu\n",
2082
(ulong) page_offset(rec));
2089
if (!page_rec_is_supremum(rec)) {
2091
slot = page_dir_get_nth_slot(page, slot_no);
2095
if (page_rec_is_supremum(rec)) {
2101
(rec_get_next_offs(rec, TRUE) < FIL_PAGE_DATA
2102
|| rec_get_next_offs(rec, TRUE) >= UNIV_PAGE_SIZE)) {
2104
"InnoDB: Next record offset nonsensical %lu"
2106
(ulong) rec_get_next_offs(rec, TRUE),
2107
(ulong) page_offset(rec));
2114
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2116
"InnoDB: Page record list appears"
2117
" to be circular %lu\n",
2122
rec = page_rec_get_next(rec);
2126
if (UNIV_UNLIKELY(rec_get_n_owned_new(rec) == 0)) {
2127
fprintf(stderr, "InnoDB: n owned is zero"
2128
" in a supremum rec\n");
2133
if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
2134
fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
2135
(ulong) slot_no, (ulong) (n_slots - 1));
2139
if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
2140
+ PAGE_HEAP_NO_USER_LOW
2142
fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
2143
(ulong) page_header_get_field(page, PAGE_N_RECS)
2144
+ PAGE_HEAP_NO_USER_LOW,
2145
(ulong) (count + 1));
2150
/* Check then the free list */
2151
rec = page_header_get_ptr(page, PAGE_FREE);
2153
while (rec != NULL) {
2154
if (UNIV_UNLIKELY(rec < page + FIL_PAGE_DATA
2155
|| rec >= page + UNIV_PAGE_SIZE)) {
2157
"InnoDB: Free list record has"
2158
" a nonsensical offset %lu\n",
2159
(ulong) page_offset(rec));
2164
if (UNIV_UNLIKELY(rec > rec_heap_top)) {
2166
"InnoDB: Free list record %lu"
2167
" is above rec heap top %lu\n",
2168
(ulong) page_offset(rec),
2169
(ulong) page_offset(rec_heap_top));
2176
if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
2178
"InnoDB: Page free list appears"
2179
" to be circular %lu\n",
2184
rec = page_rec_get_next(rec);
2187
if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
1741
2189
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
1742
2190
(ulong) page_dir_get_n_heap(page),
1823
2276
slot = page_dir_get_nth_slot(page, slot_no);
1825
page_cur_set_before_first(page, &cur);
2278
rec = page_get_infimum_rec(page);
1829
2281
offsets = rec_get_offsets(rec, index, offsets,
1830
2282
ULINT_UNDEFINED, &heap);
1832
if (comp && page_rec_is_user_rec(rec)
1833
&& rec_get_node_ptr_flag(rec)
1835
(btr_page_get_level_low(page) != 0)) {
2284
if (page_is_comp(page) && page_rec_is_user_rec(rec)
2285
&& UNIV_UNLIKELY(rec_get_node_ptr_flag(rec)
2286
== page_is_leaf(page))) {
1836
2287
fputs("InnoDB: node_ptr flag mismatch\n", stderr);
1837
2288
goto func_exit;
1840
if (!page_rec_validate(rec, offsets)) {
2291
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
1841
2292
goto func_exit;
1844
2295
/* Check that the records are in the ascending order */
1845
if ((count >= 2) && (!page_cur_is_after_last(&cur))) {
1846
if (!(1 == cmp_rec_rec(rec, old_rec,
1847
offsets, old_offsets, index))) {
2296
if (UNIV_LIKELY(count >= PAGE_HEAP_NO_USER_LOW)
2297
&& !page_rec_is_supremum(rec)) {
2299
(1 != cmp_rec_rec(rec, old_rec,
2300
offsets, old_offsets, index))) {
1848
2301
fprintf(stderr,
1849
2302
"InnoDB: Records in wrong order"
1850
2303
" on page %lu ",
1851
(ulong) buf_frame_get_page_no(page));
2304
(ulong) page_get_page_no(page));
1852
2305
dict_index_name_print(stderr, NULL, index);
1853
2306
fputs("\nInnoDB: previous record ", stderr);
1854
2307
rec_print_new(stderr, old_rec, old_offsets);