66
65
/*******************************************************************
67
66
Looks for the directory slot which owns the given record. */
70
69
page_dir_find_owner_slot(
71
70
/*=====================*/
72
/* out: the directory slot number */
73
rec_t* rec) /* in: the physical record */
71
/* out: the directory slot number */
72
const rec_t* rec) /* in: the physical record */
76
75
register uint16 rec_offs_bytes;
77
register page_dir_slot_t* slot;
76
register const page_dir_slot_t* slot;
78
77
register const page_dir_slot_t* first_slot;
79
register rec_t* r = rec;
78
register const rec_t* r = rec;
81
80
ut_ad(page_rec_check(rec));
83
page = buf_frame_align(rec);
82
page = page_align(rec);
84
83
first_slot = page_dir_get_nth_slot(page, 0);
85
84
slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
87
86
if (page_is_comp(page)) {
88
while (rec_get_n_owned(r, TRUE) == 0) {
89
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);
90
89
ut_ad(r >= page + PAGE_NEW_SUPREMUM);
91
90
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
94
while (rec_get_n_owned(r, FALSE) == 0) {
95
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);
96
95
ut_ad(r >= page + PAGE_OLD_SUPREMUM);
97
96
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
202
202
during a database recovery we assume that the max trx id of every
203
203
page is the maximum trx id assigned before the crash. */
205
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),
207
if (block->is_hashed) {
208
213
rw_lock_x_unlock(&btr_search_latch);
212
/*****************************************************************
213
Calculates free space if a page is emptied. */
216
page_get_free_space_of_empty_noninline(
217
/*===================================*/
218
/* out: free space */
219
ulint comp) /* in: nonzero=compact page format */
221
return(page_get_free_space_of_empty(comp));
224
217
/****************************************************************
225
Allocates a block of memory from an index page. */
218
Allocates a block of memory from the heap of an index page. */
230
223
/* out: pointer to start of allocated
231
224
buffer, or NULL if allocation fails */
232
page_t* page, /* in: index page */
233
ulint need, /* in: number of bytes needed */
234
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 */
235
230
ulint* heap_no)/* out: this contains the heap number
236
231
of the allocated record
237
232
if allocation succeeds */
244
237
ut_ad(page && heap_no);
246
/* If there are records in the free list, look if the first is
249
rec = page_header_get_ptr(page, PAGE_FREE);
252
mem_heap_t* heap = NULL;
253
ulint offsets_[REC_OFFS_NORMAL_SIZE];
254
ulint* offsets = offsets_;
255
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
257
offsets = rec_get_offsets(rec, index, offsets,
258
ULINT_UNDEFINED, &heap);
260
if (rec_offs_size(offsets) >= need) {
261
page_header_set_ptr(page, PAGE_FREE,
262
page_rec_get_next(rec));
264
garbage = page_header_get_field(page, PAGE_GARBAGE);
265
ut_ad(garbage >= need);
267
page_header_set_field(page, PAGE_GARBAGE,
270
*heap_no = rec_get_heap_no(rec, page_is_comp(page));
272
block = rec_get_start(rec, offsets);
273
if (UNIV_LIKELY_NULL(heap)) {
279
if (UNIV_LIKELY_NULL(heap)) {
284
/* Could not find space from the free list, try top of heap */
286
239
avl_space = page_get_max_insert_size(page, 1);
288
241
if (avl_space >= need) {
289
242
block = page_header_get_ptr(page, PAGE_HEAP_TOP);
291
page_header_set_ptr(page, PAGE_HEAP_TOP, block + need);
244
page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
292
246
*heap_no = page_dir_get_n_heap(page);
294
page_dir_set_n_heap(page, 1 + *heap_no);
248
page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
441
409
/* 4. INITIALIZE THE PAGE */
443
page_header_set_field(page, PAGE_N_DIR_SLOTS, 2);
444
page_header_set_ptr(page, PAGE_HEAP_TOP, heap_top);
445
page_header_set_field(page, PAGE_N_HEAP, comp ? 0x8002 : 2);
446
page_header_set_ptr(page, PAGE_FREE, NULL);
447
page_header_set_field(page, PAGE_GARBAGE, 0);
448
page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
449
page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
450
page_header_set_field(page, PAGE_N_DIRECTION, 0);
451
page_header_set_field(page, PAGE_N_RECS, 0);
452
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);
453
423
memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
454
- (heap_top - page));
424
- page_offset(heap_top));
456
426
/* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
466
436
/* Set the next pointers in infimum and supremum */
468
rec_set_next_offs(infimum_rec, comp, (ulint)(supremum_rec - page));
469
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. */
474
498
/*****************************************************************
475
499
Differs from page_copy_rec_list_end, because this function does not
476
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. */
479
503
page_copy_rec_list_end_no_locks(
480
504
/*============================*/
481
page_t* new_page, /* in: index page to copy to */
482
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 */
483
507
rec_t* rec, /* in: record on page */
484
508
dict_index_t* index, /* in: record descriptor */
485
509
mtr_t* mtr) /* in: mtr */
511
page_t* new_page = buf_block_get_frame(new_block);
490
514
mem_heap_t* heap = NULL;
491
515
ulint offsets_[REC_OFFS_NORMAL_SIZE];
492
516
ulint* offsets = offsets_;
493
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
517
rec_offs_init(offsets_);
495
page_cur_position(rec, &cur1);
519
page_cur_position(rec, block, &cur1);
497
521
if (page_cur_is_before_first(&cur1)) {
502
526
ut_a((ibool)!!page_is_comp(new_page)
503
527
== dict_table_is_comp(index->table));
504
ut_a(page_is_comp(new_page) == page_is_comp(page));
528
ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
505
529
ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
506
(page_is_comp(new_page)
507
? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
530
(page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
509
page_cur_set_before_first(new_page, &cur2);
532
cur2 = page_get_infimum_rec(buf_block_get_frame(new_block));
511
534
/* Copy records from the original page to the new page */
513
sup = page_get_supremum_rec(page);
536
while (!page_cur_is_after_last(&cur1)) {
516
537
rec_t* cur1_rec = page_cur_get_rec(&cur1);
517
if (cur1_rec == sup) {
520
539
offsets = rec_get_offsets(cur1_rec, index, offsets,
521
540
ULINT_UNDEFINED, &heap);
522
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)) {
524
544
/* Track an assertion failure reported on the mailing
525
545
list on June 18th, 2003 */
527
buf_page_print(new_page);
528
buf_page_print(page);
547
buf_page_print(new_page, 0);
548
buf_page_print(page_align(rec), 0);
529
549
ut_print_timestamp(stderr);
532
552
"InnoDB: rec offset %lu, cur1 offset %lu,"
533
553
" cur2 offset %lu\n",
535
(ulong)(page_cur_get_rec(&cur1) - page),
536
(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));
541
560
page_cur_move_to_next(&cur1);
542
page_cur_move_to_next(&cur2);
545
564
if (UNIV_LIKELY_NULL(heap)) {
551
570
Copies records from page to new_page, from a given record onward,
552
571
including that record. Infimum and supremum records are not copied.
553
572
The records are copied to the start of the record list on new_page. */
556
575
page_copy_rec_list_end(
557
576
/*===================*/
558
page_t* new_page, /* in: index page to copy to */
559
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 */
560
583
rec_t* rec, /* in: record on page */
561
584
dict_index_t* index, /* in: record descriptor */
562
585
mtr_t* mtr) /* in: mtr */
564
if (page_dir_get_n_heap(new_page) == 2) {
565
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,
568
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);
572
644
/* Update the lock table, MAX_TRX_ID, and possible hash index */
574
lock_move_rec_list_end(new_page, page, rec);
576
page_update_max_trx_id(new_page, page_get_max_trx_id(page));
578
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);
581
656
/*****************************************************************
582
657
Copies records from page to new_page, up to the given record,
583
658
NOT including that record. Infimum and supremum records are not copied.
584
659
The records are copied to the end of the record list on new_page. */
587
662
page_copy_rec_list_start(
588
663
/*=====================*/
589
page_t* new_page, /* in: index page to copy to */
590
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 */
591
670
rec_t* rec, /* in: record on page */
592
671
dict_index_t* index, /* in: record descriptor */
593
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 */;
598
679
mem_heap_t* heap = NULL;
681
= page_rec_get_prev(page_get_supremum_rec(new_page));
599
682
ulint offsets_[REC_OFFS_NORMAL_SIZE];
600
683
ulint* offsets = offsets_;
601
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
603
page_cur_set_before_first(page, &cur1);
605
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);
610
696
page_cur_move_to_next(&cur1);
612
page_cur_set_after_last(new_page, &cur2);
613
page_cur_move_to_prev(&cur2);
614
old_end = page_cur_get_rec(&cur2);
616
700
/* Copy records from the original page to the new page */
618
702
while (page_cur_get_rec(&cur1) != rec) {
620
703
rec_t* cur1_rec = page_cur_get_rec(&cur1);
621
704
offsets = rec_get_offsets(cur1_rec, index, offsets,
622
705
ULINT_UNDEFINED, &heap);
623
ins_rec = page_cur_rec_insert(&cur2, cur1_rec, index,
706
cur2 = page_cur_insert_rec_low(cur2, index,
707
cur1_rec, offsets, mtr);
627
710
page_cur_move_to_next(&cur1);
628
page_cur_move_to_next(&cur2);
631
/* Update the lock table, MAX_TRX_ID, and possible hash index */
633
lock_move_rec_list_start(new_page, page, rec, old_end);
635
page_update_max_trx_id(new_page, page_get_max_trx_id(page));
637
btr_search_move_or_delete_hash_entries(new_page, page, index);
639
713
if (UNIV_LIKELY_NULL(heap)) {
640
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);
644
761
/**************************************************************
737
857
delete, or ULINT_UNDEFINED if not known */
738
858
mtr_t* mtr) /* in: mtr */
740
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)) {
751
887
/* Reset the last insert info in the page header and increment
752
888
the modify clock for the frame */
754
ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
755
page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
890
page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
757
892
/* The page gets invalid for optimistic searches: increment the
758
893
frame modify clock */
760
buf_frame_modify_clock_inc(page);
762
sup = page_get_supremum_rec(page);
764
comp = page_is_comp(page);
765
if (page_rec_is_infimum_low(rec - page)) {
766
rec = page_rec_get_next(rec);
769
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)
770
898
? MLOG_COMP_LIST_END_DELETE
771
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);
778
932
prev_rec = page_rec_get_prev(rec);
780
last_rec = page_rec_get_prev(sup);
934
last_rec = page_rec_get_prev(page_get_supremum_rec(page));
782
936
if ((size == ULINT_UNDEFINED) || (n_recs == ULINT_UNDEFINED)) {
783
mem_heap_t* heap = NULL;
784
ulint offsets_[REC_OFFS_NORMAL_SIZE];
785
ulint* offsets = offsets_;
786
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
787
938
/* Calculate the sum of sizes and the number of records */
792
while (rec2 != sup) {
794
944
offsets = rec_get_offsets(rec2, index, offsets,
795
945
ULINT_UNDEFINED, &heap);
814
964
of the records owned by the supremum record, as it is allowed to be
815
965
less than PAGE_DIR_SLOT_MIN_N_OWNED */
820
while (rec_get_n_owned(rec2, comp) == 0) {
823
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);
826
ut_ad(rec_get_n_owned(rec2, comp) - count > 0);
828
n_owned = rec_get_n_owned(rec2, comp) - count;
830
slot_index = page_dir_find_owner_slot(rec2);
831
slot = page_dir_get_nth_slot(page, slot_index);
833
page_dir_slot_set_rec(slot, sup);
834
page_dir_slot_set_n_owned(slot, n_owned);
836
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);
838
1004
/* Remove the record chain segment from the record chain */
839
1005
page_rec_set_next(prev_rec, page_get_supremum_rec(page));
841
1007
/* Catenate the deleted chain segment to the page free list */
843
free = page_header_get_ptr(page, PAGE_FREE);
845
page_rec_set_next(last_rec, free);
846
page_header_set_ptr(page, PAGE_FREE, rec);
848
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
849
1013
+ page_header_get_field(page, PAGE_GARBAGE));
851
page_header_set_field(page, PAGE_N_RECS,
1015
page_header_set_field(page, NULL, PAGE_N_RECS,
852
1016
(ulint)(page_get_n_recs(page) - n_recs));
855
1019
/*****************************************************************
856
1020
Deletes records from page, up to the given record, NOT including
857
1021
that record. Infimum and supremum records are not deleted. */
860
1024
page_delete_rec_list_start(
861
1025
/*=======================*/
862
page_t* page, /* in: index page */
863
1026
rec_t* rec, /* in: record on page */
1027
buf_block_t* block, /* in: buffer block of the page */
864
1028
dict_index_t* index, /* in: record descriptor */
865
1029
mtr_t* mtr) /* in: mtr */
913
1082
/*****************************************************************
914
1083
Moves record list end to another page. Moved records include
918
1087
page_move_rec_list_end(
919
1088
/*===================*/
920
page_t* new_page, /* in: index page where to move */
921
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 */
922
1094
rec_t* split_rec, /* in: first record to move */
923
1095
dict_index_t* index, /* in: record descriptor */
924
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;
931
1104
old_data_size = page_get_data_size(new_page);
932
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 */
934
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))) {
936
1125
new_data_size = page_get_data_size(new_page);
937
1126
new_n_recs = page_get_n_recs(new_page);
939
1128
ut_ad(new_data_size >= old_data_size);
941
page_delete_rec_list_end(page, split_rec, index,
1130
page_delete_rec_list_end(split_rec, block, index,
942
1131
new_n_recs - old_n_recs,
943
1132
new_data_size - old_data_size, mtr);
946
1137
/*****************************************************************
947
1138
Moves record list start to another page. Moved records do not include
951
1142
page_move_rec_list_start(
952
1143
/*=====================*/
953
page_t* new_page, /* in: index page where to move */
954
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 */
955
1148
rec_t* split_rec, /* in: first record not to move */
956
1149
dict_index_t* index, /* in: record descriptor */
957
1150
mtr_t* mtr) /* in: mtr */
959
page_copy_rec_list_start(new_page, page, split_rec, index, mtr);
961
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);
964
1162
/***************************************************************************
965
1163
This is a low-level operation which is used in a database index creation
966
1164
to update the page number of a created B-tree to a data dictionary record. */
969
1167
page_rec_write_index_page_no(
970
1168
/*=========================*/
989
1187
the deleted ones inherits the records of the deleted slots. */
992
page_dir_delete_slots(
993
/*==================*/
994
page_t* page, /* in: the index page */
995
ulint start, /* in: first slot to be deleted */
996
ulint n) /* in: number of slots to delete (currently
997
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 */
999
1196
page_dir_slot_t* slot;
1001
ulint sum_owned = 0;
1007
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));
1009
1205
n_slots = page_dir_get_n_slots(page);
1011
1207
/* 1. Reset the n_owned fields of the slots to be
1013
for (i = start; i < start + n; i++) {
1014
slot = page_dir_get_nth_slot(page, i);
1015
sum_owned += page_dir_slot_get_n_owned(slot);
1016
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);
1019
1213
/* 2. Update the n_owned value of the first non-deleted slot */
1021
slot = page_dir_get_nth_slot(page, start + n);
1022
page_dir_slot_set_n_owned(slot,
1023
sum_owned + page_dir_slot_get_n_owned(slot));
1025
/* 3. Destroy start and other slots by copying slots */
1026
for (i = start + n; i < n_slots; i++) {
1027
slot = page_dir_get_nth_slot(page, i);
1028
rec = page_dir_slot_get_rec(slot);
1030
slot = page_dir_get_nth_slot(page, i - n);
1031
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);
1034
/* 4. Update the page header */
1035
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);
1038
1233
/******************************************************************
1041
1236
of the caller. */
1046
page_t* page, /* in: the index page */
1047
ulint start, /* in: the slot above which the new slots are added */
1048
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
1051
1246
page_dir_slot_t* slot;
1058
1249
n_slots = page_dir_get_n_slots(page);
1060
1251
ut_ad(start < n_slots - 1);
1062
1253
/* Update the page header */
1063
page_dir_set_n_slots(page, n_slots + n);
1254
page_dir_set_n_slots(page, page_zip, n_slots + 1);
1065
1256
/* Move slots up */
1067
for (i = n_slots - 1; i > start; i--) {
1069
slot = page_dir_get_nth_slot(page, i);
1070
rec = page_dir_slot_get_rec(slot);
1072
slot = page_dir_get_nth_slot(page, i + n);
1073
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);
1077
1262
/********************************************************************
1078
1263
Splits a directory slot which owns too many records. */
1081
1266
page_dir_split_slot(
1082
1267
/*================*/
1083
page_t* page, /* in: the index page in question */
1084
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 */
1087
1274
page_dir_slot_t* new_slot;
1179
1369
/* In this case we can just transfer one record owned
1180
1370
by the upper slot to the property of the lower slot */
1181
old_rec = page_dir_slot_get_rec(slot);
1182
new_rec = page_rec_get_next(old_rec);
1184
rec_set_n_owned(old_rec, page_is_comp(page), 0);
1185
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);
1187
1385
page_dir_slot_set_rec(slot, new_rec);
1189
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);
1191
1389
/* In this case we may merge the two slots */
1192
page_dir_delete_slots(page, slot_no, 1);
1390
page_dir_delete_slot(page, page_zip, slot_no);
1196
1394
/****************************************************************
1197
1395
Returns the middle record of the record list. If there are an even number
1198
1396
of records in the list, returns the first record of the upper half-list. */
1201
1399
page_get_middle_rec(
1202
1400
/*================*/
1244
1442
/*******************************************************************
1245
1443
Returns the number of records before the given record in chain.
1246
1444
The number includes infimum and supremum records. */
1249
1447
page_rec_get_n_recs_before(
1250
1448
/*=======================*/
1251
/* out: number of records */
1252
rec_t* rec) /* in: the physical record */
1449
/* out: number of records */
1450
const rec_t* rec) /* in: the physical record */
1254
page_dir_slot_t* slot;
1452
const page_dir_slot_t* slot;
1453
const rec_t* slot_rec;
1261
1458
ut_ad(page_rec_check(rec));
1263
page = buf_frame_align(rec);
1264
comp = page_is_comp(page);
1266
while (rec_get_n_owned(rec, comp) == 0) {
1268
rec = page_rec_get_next(rec);
1272
for (i = 0; ; i++) {
1273
slot = page_dir_get_nth_slot(page, i);
1274
slot_rec = page_dir_slot_get_rec(slot);
1276
n += rec_get_n_owned(slot_rec, comp);
1278
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) {
1291
1506
/****************************************************************
1292
1507
Prints record contents including the data relevant only in
1293
1508
the index page context. */
1296
1511
page_rec_print(
1297
1512
/*===========*/
1298
rec_t* rec, /* in: physical record */
1513
const rec_t* rec, /* in: physical record */
1299
1514
const ulint* offsets)/* in: record descriptor */
1301
ulint comp = page_is_comp(buf_frame_align(rec));
1303
ut_a(!comp == !rec_offs_comp(offsets));
1516
ut_a(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
1304
1517
rec_print_new(stderr, rec, offsets);
1306
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1307
(ulong) rec_get_n_owned(rec, comp),
1308
(ulong) rec_get_heap_no(rec, comp),
1309
(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));
1311
1532
page_rec_check(rec);
1312
1533
rec_validate(rec, offsets);
1730
if (count > UNIV_PAGE_SIZE) {
1732
"InnoDB: Page free list appears"
1733
" to be circular %lu\n",
1738
rec = page_rec_get_next(rec);
1741
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)) {
1743
2189
fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
1744
2190
(ulong) page_dir_get_n_heap(page),
1825
2276
slot = page_dir_get_nth_slot(page, slot_no);
1827
page_cur_set_before_first(page, &cur);
2278
rec = page_get_infimum_rec(page);
1831
2281
offsets = rec_get_offsets(rec, index, offsets,
1832
2282
ULINT_UNDEFINED, &heap);
1834
if (comp && page_rec_is_user_rec(rec)
1835
&& rec_get_node_ptr_flag(rec)
1837
(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))) {
1838
2287
fputs("InnoDB: node_ptr flag mismatch\n", stderr);
1839
2288
goto func_exit;
1842
if (!page_rec_validate(rec, offsets)) {
2291
if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
1843
2292
goto func_exit;
1846
2295
/* Check that the records are in the ascending order */
1847
if ((count >= 2) && (!page_cur_is_after_last(&cur))) {
1848
if (!(1 == cmp_rec_rec(rec, old_rec,
1849
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))) {
1850
2301
fprintf(stderr,
1851
2302
"InnoDB: Records in wrong order"
1852
2303
" on page %lu ",
1853
(ulong) buf_frame_get_page_no(page));
2304
(ulong) page_get_page_no(page));
1854
2305
dict_index_name_print(stderr, NULL, index);
1855
2306
fputs("\nInnoDB: previous record ", stderr);
1856
2307
rec_print_new(stderr, old_rec, old_offsets);