00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00026 #include "btr0btr.h"
00027
00028 #ifdef UNIV_NONINL
00029 #include "btr0btr.ic"
00030 #endif
00031
00032 #include "fsp0fsp.h"
00033 #include "page0page.h"
00034 #include "xtrabackup_api.h"
00035
00036 #ifndef UNIV_HOTBACKUP
00037 #include "btr0cur.h"
00038 #include "btr0sea.h"
00039 #include "btr0pcur.h"
00040 #include "rem0cmp.h"
00041 #include "lock0lock.h"
00042 #include "ibuf0ibuf.h"
00043 #include "trx0trx.h"
00044 #include "page0zip.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 #ifdef UNIV_BTR_DEBUG
00102
00105 static
00106 ibool
00107 btr_root_fseg_validate(
00108
00109 const fseg_header_t* seg_header,
00110 ulint space)
00111 {
00112 ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET);
00113
00114 ut_a(mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space);
00115 ut_a(offset >= FIL_PAGE_DATA);
00116 ut_a(offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
00117 return(TRUE);
00118 }
00119 #endif
00120
00121
00124 buf_block_t*
00125 btr_root_block_get(
00126
00127 dict_index_t* index,
00128 mtr_t* mtr)
00129 {
00130 ulint space;
00131 ulint zip_size;
00132 ulint root_page_no;
00133 buf_block_t* block;
00134
00135 space = dict_index_get_space(index);
00136 zip_size = dict_table_zip_size(index->table);
00137 root_page_no = dict_index_get_page(index);
00138
00139 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
00140 ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
00141 == dict_table_is_comp(index->table));
00142 #ifdef UNIV_BTR_DEBUG
00143 if (!dict_index_is_ibuf(index)) {
00144 const page_t* root = buf_block_get_frame(block);
00145
00146 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
00147 + root, space));
00148 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
00149 + root, space));
00150 }
00151 #endif
00152
00153 return(block);
00154 }
00155
00156
00159 UNIV_INTERN
00160 page_t*
00161 btr_root_get(
00162
00163 dict_index_t* index,
00164 mtr_t* mtr)
00165 {
00166 return(buf_block_get_frame(btr_root_block_get(index, mtr)));
00167 }
00168
00169
00173 UNIV_INTERN
00174 rec_t*
00175 btr_get_prev_user_rec(
00176
00177 rec_t* rec,
00178 mtr_t* mtr)
00180 {
00181 page_t* page;
00182 page_t* prev_page;
00183 ulint prev_page_no;
00184
00185 if (!page_rec_is_infimum(rec)) {
00186
00187 rec_t* prev_rec = page_rec_get_prev(rec);
00188
00189 if (!page_rec_is_infimum(prev_rec)) {
00190
00191 return(prev_rec);
00192 }
00193 }
00194
00195 page = page_align(rec);
00196 prev_page_no = btr_page_get_prev(page, mtr);
00197
00198 if (prev_page_no != FIL_NULL) {
00199
00200 ulint space;
00201 ulint zip_size;
00202 buf_block_t* prev_block;
00203
00204 space = page_get_space_id(page);
00205 zip_size = fil_space_get_zip_size(space);
00206
00207 prev_block = buf_page_get_with_no_latch(space, zip_size,
00208 prev_page_no, mtr);
00209 prev_page = buf_block_get_frame(prev_block);
00210
00211 ut_ad(mtr_memo_contains(mtr, prev_block,
00212 MTR_MEMO_PAGE_S_FIX)
00213 || mtr_memo_contains(mtr, prev_block,
00214 MTR_MEMO_PAGE_X_FIX));
00215 #ifdef UNIV_BTR_DEBUG
00216 ut_a(page_is_comp(prev_page) == page_is_comp(page));
00217 ut_a(btr_page_get_next(prev_page, mtr)
00218 == page_get_page_no(page));
00219 #endif
00220
00221 return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
00222 }
00223
00224 return(NULL);
00225 }
00226
00227
00231 UNIV_INTERN
00232 rec_t*
00233 btr_get_next_user_rec(
00234
00235 rec_t* rec,
00236 mtr_t* mtr)
00238 {
00239 page_t* page;
00240 page_t* next_page;
00241 ulint next_page_no;
00242
00243 if (!page_rec_is_supremum(rec)) {
00244
00245 rec_t* next_rec = page_rec_get_next(rec);
00246
00247 if (!page_rec_is_supremum(next_rec)) {
00248
00249 return(next_rec);
00250 }
00251 }
00252
00253 page = page_align(rec);
00254 next_page_no = btr_page_get_next(page, mtr);
00255
00256 if (next_page_no != FIL_NULL) {
00257 ulint space;
00258 ulint zip_size;
00259 buf_block_t* next_block;
00260
00261 space = page_get_space_id(page);
00262 zip_size = fil_space_get_zip_size(space);
00263
00264 next_block = buf_page_get_with_no_latch(space, zip_size,
00265 next_page_no, mtr);
00266 next_page = buf_block_get_frame(next_block);
00267
00268 ut_ad(mtr_memo_contains(mtr, next_block, MTR_MEMO_PAGE_S_FIX)
00269 || mtr_memo_contains(mtr, next_block,
00270 MTR_MEMO_PAGE_X_FIX));
00271 #ifdef UNIV_BTR_DEBUG
00272 ut_a(page_is_comp(next_page) == page_is_comp(page));
00273 ut_a(btr_page_get_prev(next_page, mtr)
00274 == page_get_page_no(page));
00275 #endif
00276
00277 return(page_rec_get_next(page_get_infimum_rec(next_page)));
00278 }
00279
00280 return(NULL);
00281 }
00282
00283
00286 static
00287 void
00288 btr_page_create(
00289
00290 buf_block_t* block,
00291 page_zip_des_t* page_zip,
00292 dict_index_t* index,
00293 ulint level,
00294 mtr_t* mtr)
00295 {
00296 page_t* page = buf_block_get_frame(block);
00297
00298 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
00299
00300 if (UNIV_LIKELY_NULL(page_zip)) {
00301 page_create_zip(block, index, level, mtr);
00302 } else {
00303 page_create(block, mtr, dict_table_is_comp(index->table));
00304
00305 btr_page_set_level(page, NULL, level, mtr);
00306 }
00307
00308 block->check_index_page_at_flush = TRUE;
00309
00310 btr_page_set_index_id(page, page_zip, index->id, mtr);
00311 }
00312
00313
00317 static
00318 buf_block_t*
00319 btr_page_alloc_for_ibuf(
00320
00321 dict_index_t* index,
00322 mtr_t* mtr)
00323 {
00324 fil_addr_t node_addr;
00325 page_t* root;
00326 page_t* new_page;
00327 buf_block_t* new_block;
00328
00329 root = btr_root_get(index, mtr);
00330
00331 node_addr = flst_get_first(root + PAGE_HEADER
00332 + PAGE_BTR_IBUF_FREE_LIST, mtr);
00333 ut_a(node_addr.page != FIL_NULL);
00334
00335 new_block = buf_page_get(dict_index_get_space(index),
00336 dict_table_zip_size(index->table),
00337 node_addr.page, RW_X_LATCH, mtr);
00338 new_page = buf_block_get_frame(new_block);
00339 buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
00340
00341 flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
00342 new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
00343 mtr);
00344 ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
00345 mtr));
00346
00347 return(new_block);
00348 }
00349
00350
00354 UNIV_INTERN
00355 buf_block_t*
00356 btr_page_alloc(
00357
00358 dict_index_t* index,
00359 ulint hint_page_no,
00360 byte file_direction,
00362 ulint level,
00364 mtr_t* mtr)
00365 {
00366 fseg_header_t* seg_header;
00367 page_t* root;
00368 buf_block_t* new_block;
00369 ulint new_page_no;
00370
00371 if (dict_index_is_ibuf(index)) {
00372
00373 return(btr_page_alloc_for_ibuf(index, mtr));
00374 }
00375
00376 root = btr_root_get(index, mtr);
00377
00378 if (level == 0) {
00379 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
00380 } else {
00381 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
00382 }
00383
00384
00385
00386
00387
00388 new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
00389 file_direction, TRUE, mtr);
00390 if (new_page_no == FIL_NULL) {
00391
00392 return(NULL);
00393 }
00394
00395 new_block = buf_page_get(dict_index_get_space(index),
00396 dict_table_zip_size(index->table),
00397 new_page_no, RW_X_LATCH, mtr);
00398 buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
00399
00400 return(new_block);
00401 }
00402
00403
00406 UNIV_INTERN
00407 ulint
00408 btr_get_size(
00409
00410 dict_index_t* index,
00411 ulint flag)
00412 {
00413 fseg_header_t* seg_header;
00414 page_t* root;
00415 ulint n;
00416 ulint dummy;
00417 mtr_t mtr;
00418
00419 mtr_start(&mtr);
00420
00421 mtr_s_lock(dict_index_get_lock(index), &mtr);
00422
00423 root = btr_root_get(index, &mtr);
00424
00425 if (flag == BTR_N_LEAF_PAGES) {
00426 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
00427
00428 fseg_n_reserved_pages(seg_header, &n, &mtr);
00429
00430 } else if (flag == BTR_TOTAL_SIZE) {
00431 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
00432
00433 n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
00434
00435 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
00436
00437 n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
00438 } else {
00439 ut_error;
00440 }
00441
00442 mtr_commit(&mtr);
00443
00444 return(n);
00445 }
00446
00447
00450 static
00451 void
00452 btr_page_free_for_ibuf(
00453
00454 dict_index_t* index,
00455 buf_block_t* block,
00456 mtr_t* mtr)
00457 {
00458 page_t* root;
00459
00460 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
00461 root = btr_root_get(index, mtr);
00462
00463 flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
00464 buf_block_get_frame(block)
00465 + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
00466
00467 ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
00468 mtr));
00469 }
00470
00471
00475 UNIV_INTERN
00476 void
00477 btr_page_free_low(
00478
00479 dict_index_t* index,
00480 buf_block_t* block,
00481 ulint level,
00482 mtr_t* mtr)
00483 {
00484 fseg_header_t* seg_header;
00485 page_t* root;
00486
00487 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
00488
00489
00490
00491 buf_block_modify_clock_inc(block);
00492
00493 if (dict_index_is_ibuf(index)) {
00494
00495 btr_page_free_for_ibuf(index, block, mtr);
00496
00497 return;
00498 }
00499
00500 root = btr_root_get(index, mtr);
00501
00502 if (level == 0) {
00503 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
00504 } else {
00505 seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
00506 }
00507
00508 fseg_free_page(seg_header,
00509 buf_block_get_space(block),
00510 buf_block_get_page_no(block), mtr);
00511 }
00512
00513
00516 UNIV_INTERN
00517 void
00518 btr_page_free(
00519
00520 dict_index_t* index,
00521 buf_block_t* block,
00522 mtr_t* mtr)
00523 {
00524 ulint level;
00525
00526 level = btr_page_get_level(buf_block_get_frame(block), mtr);
00527
00528 btr_page_free_low(index, block, level, mtr);
00529 }
00530
00531
00533 UNIV_INLINE
00534 void
00535 btr_node_ptr_set_child_page_no(
00536
00537 rec_t* rec,
00538 page_zip_des_t* page_zip,
00540 const ulint* offsets,
00541 ulint page_no,
00542 mtr_t* mtr)
00543 {
00544 byte* field;
00545 ulint len;
00546
00547 ut_ad(rec_offs_validate(rec, NULL, offsets));
00548 ut_ad(!page_is_leaf(page_align(rec)));
00549 ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
00550
00551
00552 field = rec_get_nth_field(rec, offsets,
00553 rec_offs_n_fields(offsets) - 1, &len);
00554
00555 ut_ad(len == REC_NODE_PTR_SIZE);
00556
00557 if (UNIV_LIKELY_NULL(page_zip)) {
00558 page_zip_write_node_ptr(page_zip, rec,
00559 rec_offs_data_size(offsets),
00560 page_no, mtr);
00561 } else {
00562 mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr);
00563 }
00564 }
00565
00566
00569 buf_block_t*
00570 btr_node_ptr_get_child(
00571
00572 const rec_t* node_ptr,
00573 dict_index_t* index,
00574 const ulint* offsets,
00575 mtr_t* mtr)
00576 {
00577 ulint page_no;
00578 ulint space;
00579
00580 ut_ad(rec_offs_validate(node_ptr, index, offsets));
00581 space = page_get_space_id(page_align(node_ptr));
00582 page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
00583
00584 return(btr_block_get(space, dict_table_zip_size(index->table),
00585 page_no, RW_X_LATCH, mtr));
00586 }
00587
00588
00592 static
00593 ulint*
00594 btr_page_get_father_node_ptr_func(
00595
00596 ulint* offsets,
00597 mem_heap_t* heap,
00598 btr_cur_t* cursor,
00601 const char* file,
00602 ulint line,
00603 mtr_t* mtr)
00604 {
00605 dtuple_t* tuple;
00606 rec_t* user_rec;
00607 rec_t* node_ptr;
00608 ulint level;
00609 ulint page_no;
00610 dict_index_t* index;
00611
00612 page_no = buf_block_get_page_no(btr_cur_get_block(cursor));
00613 index = btr_cur_get_index(cursor);
00614
00615 ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
00616 MTR_MEMO_X_LOCK));
00617
00618 ut_ad(dict_index_get_page(index) != page_no);
00619
00620 level = btr_page_get_level(btr_cur_get_page(cursor), mtr);
00621
00622 user_rec = btr_cur_get_rec(cursor);
00623 ut_a(page_rec_is_user_rec(user_rec));
00624 tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
00625
00626 btr_cur_search_to_nth_level(index, level + 1, tuple, PAGE_CUR_LE,
00627 BTR_CONT_MODIFY_TREE, cursor, 0,
00628 file, line, mtr);
00629
00630 node_ptr = btr_cur_get_rec(cursor);
00631 ut_ad(!page_rec_is_comp(node_ptr)
00632 || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR);
00633 offsets = rec_get_offsets(node_ptr, index, offsets,
00634 ULINT_UNDEFINED, &heap);
00635
00636 if (UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr, offsets)
00637 != page_no)) {
00638 rec_t* print_rec;
00639 fputs("InnoDB: Dump of the child page:\n", stderr);
00640 buf_page_print(page_align(user_rec), 0);
00641 fputs("InnoDB: Dump of the parent page:\n", stderr);
00642 buf_page_print(page_align(node_ptr), 0);
00643
00644 fputs("InnoDB: Corruption of an index tree: table ", stderr);
00645 ut_print_name(stderr, NULL, TRUE, index->table_name);
00646 fputs(", index ", stderr);
00647 ut_print_name(stderr, NULL, FALSE, index->name);
00648 fprintf(stderr, ",\n"
00649 "InnoDB: father ptr page no %lu, child page no %lu\n",
00650 (ulong)
00651 btr_node_ptr_get_child_page_no(node_ptr, offsets),
00652 (ulong) page_no);
00653 print_rec = page_rec_get_next(
00654 page_get_infimum_rec(page_align(user_rec)));
00655 offsets = rec_get_offsets(print_rec, index,
00656 offsets, ULINT_UNDEFINED, &heap);
00657 page_rec_print(print_rec, offsets);
00658 offsets = rec_get_offsets(node_ptr, index, offsets,
00659 ULINT_UNDEFINED, &heap);
00660 page_rec_print(node_ptr, offsets);
00661
00662 fputs("InnoDB: You should dump + drop + reimport the table"
00663 " to fix the\n"
00664 "InnoDB: corruption. If the crash happens at "
00665 "the database startup, see\n"
00666 "InnoDB: " REFMAN "forcing-recovery.html about\n"
00667 "InnoDB: forcing recovery. "
00668 "Then dump + drop + reimport.\n", stderr);
00669
00670 ut_error;
00671 }
00672
00673 return(offsets);
00674 }
00675
00676 #define btr_page_get_father_node_ptr(of,heap,cur,mtr) \
00677 btr_page_get_father_node_ptr_func(of,heap,cur,__FILE__,__LINE__,mtr)
00678
00679
00683 static
00684 ulint*
00685 btr_page_get_father_block(
00686
00687 ulint* offsets,
00688 mem_heap_t* heap,
00689 dict_index_t* index,
00690 buf_block_t* block,
00691 mtr_t* mtr,
00692 btr_cur_t* cursor)
00694 {
00695 rec_t* rec
00696 = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
00697 block)));
00698 btr_cur_position(index, rec, block, cursor);
00699 return(btr_page_get_father_node_ptr(offsets, heap, cursor, mtr));
00700 }
00701
00702
00705 static
00706 void
00707 btr_page_get_father(
00708
00709 dict_index_t* index,
00710 buf_block_t* block,
00711 mtr_t* mtr,
00712 btr_cur_t* cursor)
00714 {
00715 mem_heap_t* heap;
00716 rec_t* rec
00717 = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
00718 block)));
00719 btr_cur_position(index, rec, block, cursor);
00720
00721 heap = mem_heap_create(100);
00722 btr_page_get_father_node_ptr(NULL, heap, cursor, mtr);
00723 mem_heap_free(heap);
00724 }
00725
00726
00729 UNIV_INTERN
00730 ulint
00731 btr_create(
00732
00733 ulint type,
00734 ulint space,
00735 ulint zip_size,
00737 index_id_t index_id,
00738 dict_index_t* index,
00739 mtr_t* mtr)
00740 {
00741 ulint page_no;
00742 buf_block_t* block;
00743 buf_frame_t* frame;
00744 page_t* page;
00745 page_zip_des_t* page_zip;
00746
00747
00748
00749
00750
00751
00752 if (type & DICT_IBUF) {
00753
00754 buf_block_t* ibuf_hdr_block = fseg_create(
00755 space, 0,
00756 IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
00757
00758 buf_block_dbg_add_level(ibuf_hdr_block, SYNC_TREE_NODE_NEW);
00759
00760 ut_ad(buf_block_get_page_no(ibuf_hdr_block)
00761 == IBUF_HEADER_PAGE_NO);
00762
00763
00764
00765 page_no = fseg_alloc_free_page(buf_block_get_frame(
00766 ibuf_hdr_block)
00767 + IBUF_HEADER
00768 + IBUF_TREE_SEG_HEADER,
00769 IBUF_TREE_ROOT_PAGE_NO,
00770 FSP_UP, mtr);
00771 ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
00772
00773 block = buf_page_get(space, zip_size, page_no,
00774 RW_X_LATCH, mtr);
00775 } else {
00776 block = fseg_create(space, 0,
00777 PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
00778 }
00779
00780 if (block == NULL) {
00781
00782 return(FIL_NULL);
00783 }
00784
00785 page_no = buf_block_get_page_no(block);
00786 frame = buf_block_get_frame(block);
00787
00788 buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
00789
00790 if (type & DICT_IBUF) {
00791
00792
00793 ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
00794
00795 flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
00796 } else {
00797
00798
00799 if (!fseg_create(space, page_no,
00800 PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) {
00801
00802
00803 btr_free_root(space, zip_size, page_no, mtr);
00804
00805 return(FIL_NULL);
00806 }
00807
00808
00809
00810 buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
00811 }
00812
00813
00814 page_zip = buf_block_get_page_zip(block);
00815
00816 if (UNIV_LIKELY_NULL(page_zip)) {
00817 page = page_create_zip(block, index, 0, mtr);
00818 } else {
00819 page = page_create(block, mtr,
00820 dict_table_is_comp(index->table));
00821
00822 btr_page_set_level(page, NULL, 0, mtr);
00823 }
00824
00825 block->check_index_page_at_flush = TRUE;
00826
00827
00828 btr_page_set_index_id(page, page_zip, index_id, mtr);
00829
00830
00831 btr_page_set_next(page, page_zip, FIL_NULL, mtr);
00832 btr_page_set_prev(page, page_zip, FIL_NULL, mtr);
00833
00834
00835
00836
00837
00838 if (!(type & DICT_CLUSTERED)) {
00839 ibuf_reset_free_bits(block);
00840 }
00841
00842
00843
00844
00845
00846 ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE);
00847
00848 return(page_no);
00849 }
00850
00851
00854 UNIV_INTERN
00855 void
00856 btr_free_but_not_root(
00857
00858 ulint space,
00859 ulint zip_size,
00861 ulint root_page_no)
00862 {
00863 ibool finished;
00864 page_t* root;
00865 mtr_t mtr;
00866
00867 leaf_loop:
00868 mtr_start(&mtr);
00869
00870 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
00871 #ifdef UNIV_BTR_DEBUG
00872 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
00873 + root, space));
00874 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
00875 + root, space));
00876 #endif
00877
00878
00879
00880
00881 finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
00882 &mtr);
00883 mtr_commit(&mtr);
00884
00885 if (!finished) {
00886
00887 goto leaf_loop;
00888 }
00889 top_loop:
00890 mtr_start(&mtr);
00891
00892 root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
00893 #ifdef UNIV_BTR_DEBUG
00894 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
00895 + root, space));
00896 #endif
00897
00898 finished = fseg_free_step_not_header(
00899 root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
00900 mtr_commit(&mtr);
00901
00902 if (!finished) {
00903
00904 goto top_loop;
00905 }
00906 }
00907
00908
00910 UNIV_INTERN
00911 void
00912 btr_free_root(
00913
00914 ulint space,
00915 ulint zip_size,
00917 ulint root_page_no,
00918 mtr_t* mtr)
00920 {
00921 buf_block_t* block;
00922 fseg_header_t* header;
00923
00924 block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
00925
00926 btr_search_drop_page_hash_index(block);
00927
00928 header = buf_block_get_frame(block) + PAGE_HEADER + PAGE_BTR_SEG_TOP;
00929 #ifdef UNIV_BTR_DEBUG
00930 ut_a(btr_root_fseg_validate(header, space));
00931 #endif
00932
00933 while (!fseg_free_step(header, mtr)) {};
00934 }
00935 #endif
00936
00937
00939 static
00940 ibool
00941 btr_page_reorganize_low(
00942
00943 ibool recovery,
00948 buf_block_t* block,
00949 dict_index_t* index,
00950 mtr_t* mtr)
00951 {
00952 buf_pool_t* buf_pool = buf_pool_from_bpage(&block->page);
00953 page_t* page = buf_block_get_frame(block);
00954 page_zip_des_t* page_zip = buf_block_get_page_zip(block);
00955 buf_block_t* temp_block;
00956 page_t* temp_page;
00957 ulint log_mode;
00958 ulint data_size1;
00959 ulint data_size2;
00960 ulint max_ins_size1;
00961 ulint max_ins_size2;
00962 ibool success = FALSE;
00963
00964 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
00965 ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
00966 #ifdef UNIV_ZIP_DEBUG
00967 ut_a(!page_zip || page_zip_validate(page_zip, page));
00968 #endif
00969 data_size1 = page_get_data_size(page);
00970 max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
00971
00972 #ifndef UNIV_HOTBACKUP
00973
00974 mlog_open_and_write_index(mtr, page, index, page_is_comp(page)
00975 ? MLOG_COMP_PAGE_REORGANIZE
00976 : MLOG_PAGE_REORGANIZE, 0);
00977 #endif
00978
00979
00980 log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
00981
00982 #ifndef UNIV_HOTBACKUP
00983 temp_block = buf_block_alloc(buf_pool, 0);
00984 #else
00985 ut_ad(block == back_block1);
00986 temp_block = back_block2;
00987 #endif
00988 temp_page = temp_block->frame;
00989
00990
00991 buf_frame_copy(temp_page, page);
00992
00993 #ifndef UNIV_HOTBACKUP
00994 if (UNIV_LIKELY(!recovery)) {
00995 btr_search_drop_page_hash_index(block);
00996 }
00997
00998 block->check_index_page_at_flush = TRUE;
00999 #endif
01000
01001
01002
01003
01004 page_create(block, mtr, dict_table_is_comp(index->table));
01005
01006
01007
01008
01009 page_copy_rec_list_end_no_locks(block, temp_block,
01010 page_get_infimum_rec(temp_page),
01011 index, mtr);
01012
01013 if (dict_index_is_sec_or_ibuf(index) && page_is_leaf(page)) {
01014
01015 trx_id_t max_trx_id = page_get_max_trx_id(temp_page);
01016 page_set_max_trx_id(block, NULL, max_trx_id, mtr);
01017
01018
01019
01020 ut_ad(max_trx_id != 0 || recovery);
01021 }
01022
01023 if (UNIV_LIKELY_NULL(page_zip)
01024 && UNIV_UNLIKELY
01025 (!page_zip_compress(page_zip, page, index, NULL))) {
01026
01027
01028
01029 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
01030
01031 ut_a(!memcmp(page, temp_page, PAGE_HEADER));
01032 ut_a(!memcmp(PAGE_HEADER + PAGE_N_RECS + page,
01033 PAGE_HEADER + PAGE_N_RECS + temp_page,
01034 PAGE_DATA - (PAGE_HEADER + PAGE_N_RECS)));
01035 ut_a(!memcmp(UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page,
01036 UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + temp_page,
01037 FIL_PAGE_DATA_END));
01038 #endif
01039
01040 memcpy(PAGE_HEADER + page, PAGE_HEADER + temp_page,
01041 PAGE_N_RECS - PAGE_N_DIR_SLOTS);
01042 memcpy(PAGE_DATA + page, PAGE_DATA + temp_page,
01043 UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END);
01044
01045 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
01046 ut_a(!memcmp(page, temp_page, UNIV_PAGE_SIZE));
01047 #endif
01048
01049 goto func_exit;
01050 }
01051
01052 #ifndef UNIV_HOTBACKUP
01053 if (UNIV_LIKELY(!recovery)) {
01054
01055 lock_move_reorganize_page(block, temp_block);
01056 }
01057 #endif
01058
01059 data_size2 = page_get_data_size(page);
01060 max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1);
01061
01062 if (UNIV_UNLIKELY(data_size1 != data_size2)
01063 || UNIV_UNLIKELY(max_ins_size1 != max_ins_size2)) {
01064 buf_page_print(page, 0);
01065 buf_page_print(temp_page, 0);
01066 fprintf(stderr,
01067 "InnoDB: Error: page old data size %lu"
01068 " new data size %lu\n"
01069 "InnoDB: Error: page old max ins size %lu"
01070 " new max ins size %lu\n"
01071 "InnoDB: Submit a detailed bug report"
01072 " to http://bugs.mysql.com\n",
01073 (unsigned long) data_size1, (unsigned long) data_size2,
01074 (unsigned long) max_ins_size1,
01075 (unsigned long) max_ins_size2);
01076 } else {
01077 success = TRUE;
01078 }
01079
01080 func_exit:
01081 #ifdef UNIV_ZIP_DEBUG
01082 ut_a(!page_zip || page_zip_validate(page_zip, page));
01083 #endif
01084 #ifndef UNIV_HOTBACKUP
01085 buf_block_free(temp_block);
01086 #endif
01087
01088
01089 mtr_set_log_mode(mtr, log_mode);
01090
01091 return(success);
01092 }
01093
01094 #ifndef UNIV_HOTBACKUP
01095
01102 UNIV_INTERN
01103 ibool
01104 btr_page_reorganize(
01105
01106 buf_block_t* block,
01107 dict_index_t* index,
01108 mtr_t* mtr)
01109 {
01110 return(btr_page_reorganize_low(FALSE, block, index, mtr));
01111 }
01112 #endif
01113
01114
01117 UNIV_INTERN
01118 byte*
01119 btr_parse_page_reorganize(
01120
01121 byte* ptr,
01122 byte* ,
01124 dict_index_t* index,
01125 buf_block_t* block,
01126 mtr_t* mtr)
01127 {
01128 ut_ad(ptr && end_ptr);
01129
01130
01131
01132 if (UNIV_LIKELY(block != NULL)) {
01133 btr_page_reorganize_low(TRUE, block, index, mtr);
01134 }
01135
01136 return(ptr);
01137 }
01138
01139 #ifndef UNIV_HOTBACKUP
01140
01142 static
01143 void
01144 btr_page_empty(
01145
01146 buf_block_t* block,
01147 page_zip_des_t* page_zip,
01148 dict_index_t* index,
01149 ulint level,
01150 mtr_t* mtr)
01151 {
01152 page_t* page = buf_block_get_frame(block);
01153
01154 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
01155 ut_ad(page_zip == buf_block_get_page_zip(block));
01156 #ifdef UNIV_ZIP_DEBUG
01157 ut_a(!page_zip || page_zip_validate(page_zip, page));
01158 #endif
01159
01160 btr_search_drop_page_hash_index(block);
01161
01162
01163
01164
01165 if (UNIV_LIKELY_NULL(page_zip)) {
01166 page_create_zip(block, index, level, mtr);
01167 } else {
01168 page_create(block, mtr, dict_table_is_comp(index->table));
01169 btr_page_set_level(page, NULL, level, mtr);
01170 }
01171
01172 block->check_index_page_at_flush = TRUE;
01173 }
01174
01175
01182 UNIV_INTERN
01183 rec_t*
01184 btr_root_raise_and_insert(
01185
01186 btr_cur_t* cursor,
01190 const dtuple_t* tuple,
01191 ulint n_ext,
01192 mtr_t* mtr)
01193 {
01194 dict_index_t* index;
01195 page_t* root;
01196 page_t* new_page;
01197 ulint new_page_no;
01198 rec_t* rec;
01199 mem_heap_t* heap;
01200 dtuple_t* node_ptr;
01201 ulint level;
01202 rec_t* node_ptr_rec;
01203 page_cur_t* page_cursor;
01204 page_zip_des_t* root_page_zip;
01205 page_zip_des_t* new_page_zip;
01206 buf_block_t* root_block;
01207 buf_block_t* new_block;
01208
01209 root = btr_cur_get_page(cursor);
01210 root_block = btr_cur_get_block(cursor);
01211 root_page_zip = buf_block_get_page_zip(root_block);
01212 #ifdef UNIV_ZIP_DEBUG
01213 ut_a(!root_page_zip || page_zip_validate(root_page_zip, root));
01214 #endif
01215 index = btr_cur_get_index(cursor);
01216 #ifdef UNIV_BTR_DEBUG
01217 if (!dict_index_is_ibuf(index)) {
01218 ulint space = dict_index_get_space(index);
01219
01220 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
01221 + root, space));
01222 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
01223 + root, space));
01224 }
01225
01226 ut_a(dict_index_get_page(index) == page_get_page_no(root));
01227 #endif
01228 ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
01229 MTR_MEMO_X_LOCK));
01230 ut_ad(mtr_memo_contains(mtr, root_block, MTR_MEMO_PAGE_X_FIX));
01231
01232
01233
01234
01235
01236 level = btr_page_get_level(root, mtr);
01237
01238 new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr);
01239 new_page = buf_block_get_frame(new_block);
01240 new_page_zip = buf_block_get_page_zip(new_block);
01241 ut_a(!new_page_zip == !root_page_zip);
01242 ut_a(!new_page_zip
01243 || page_zip_get_size(new_page_zip)
01244 == page_zip_get_size(root_page_zip));
01245
01246 btr_page_create(new_block, new_page_zip, index, level, mtr);
01247
01248
01249 btr_page_set_next(new_page, new_page_zip, FIL_NULL, mtr);
01250 btr_page_set_prev(new_page, new_page_zip, FIL_NULL, mtr);
01251
01252
01253
01254 if (0
01255 #ifdef UNIV_ZIP_COPY
01256 || new_page_zip
01257 #endif
01258 || UNIV_UNLIKELY
01259 (!page_copy_rec_list_end(new_block, root_block,
01260 page_get_infimum_rec(root),
01261 index, mtr))) {
01262 ut_a(new_page_zip);
01263
01264
01265 page_zip_copy_recs(new_page_zip, new_page,
01266 root_page_zip, root, index, mtr);
01267
01268
01269
01270 lock_move_rec_list_end(new_block, root_block,
01271 page_get_infimum_rec(root));
01272
01273 btr_search_move_or_delete_hash_entries(new_block, root_block,
01274 index);
01275 }
01276
01277
01278
01279
01280
01281
01282 lock_update_root_raise(new_block, root_block);
01283
01284
01285 heap = mem_heap_create(100);
01286
01287 rec = page_rec_get_next(page_get_infimum_rec(new_page));
01288 new_page_no = buf_block_get_page_no(new_block);
01289
01290
01291
01292
01293 node_ptr = dict_index_build_node_ptr(index, rec, new_page_no, heap,
01294 level);
01295
01296
01297
01298 dtuple_set_info_bits(node_ptr,
01299 dtuple_get_info_bits(node_ptr)
01300 | REC_INFO_MIN_REC_FLAG);
01301
01302
01303 btr_page_empty(root_block, root_page_zip, index, level + 1, mtr);
01304
01305
01306
01307
01308
01309
01310 btr_page_set_next(root, root_page_zip, FIL_NULL, mtr);
01311 btr_page_set_prev(root, root_page_zip, FIL_NULL, mtr);
01312
01313 page_cursor = btr_cur_get_page_cur(cursor);
01314
01315
01316
01317 page_cur_set_before_first(root_block, page_cursor);
01318
01319 node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr,
01320 index, 0, mtr);
01321
01322
01323
01324 ut_a(node_ptr_rec);
01325
01326
01327 mem_heap_free(heap);
01328
01329
01330
01331 #if 0
01332 fprintf(stderr, "Root raise new page no %lu\n", new_page_no);
01333 #endif
01334
01335 if (!dict_index_is_clust(index)) {
01336 ibuf_reset_free_bits(new_block);
01337 }
01338
01339
01340 page_cur_search(new_block, index, tuple,
01341 PAGE_CUR_LE, page_cursor);
01342
01343
01344 return(btr_page_split_and_insert(cursor, tuple, n_ext, mtr));
01345 }
01346
01347
01351 UNIV_INTERN
01352 ibool
01353 btr_page_get_split_rec_to_left(
01354
01355 btr_cur_t* cursor,
01356 rec_t** split_rec)
01360 {
01361 page_t* page;
01362 rec_t* insert_point;
01363 rec_t* infimum;
01364
01365 page = btr_cur_get_page(cursor);
01366 insert_point = btr_cur_get_rec(cursor);
01367
01368 if (page_header_get_ptr(page, PAGE_LAST_INSERT)
01369 == page_rec_get_next(insert_point)) {
01370
01371 infimum = page_get_infimum_rec(page);
01372
01373
01374
01375
01376
01377
01378 if (infimum != insert_point
01379 && page_rec_get_next(infimum) != insert_point) {
01380
01381 *split_rec = insert_point;
01382 } else {
01383 *split_rec = page_rec_get_next(insert_point);
01384 }
01385
01386 return(TRUE);
01387 }
01388
01389 return(FALSE);
01390 }
01391
01392
01396 UNIV_INTERN
01397 ibool
01398 btr_page_get_split_rec_to_right(
01399
01400 btr_cur_t* cursor,
01401 rec_t** split_rec)
01405 {
01406 page_t* page;
01407 rec_t* insert_point;
01408
01409 page = btr_cur_get_page(cursor);
01410 insert_point = btr_cur_get_rec(cursor);
01411
01412
01413
01414
01415
01416 if (UNIV_LIKELY(page_header_get_ptr(page, PAGE_LAST_INSERT)
01417 == insert_point)) {
01418
01419 rec_t* next_rec;
01420
01421 next_rec = page_rec_get_next(insert_point);
01422
01423 if (page_rec_is_supremum(next_rec)) {
01424 split_at_new:
01425
01426 *split_rec = NULL;
01427 } else {
01428 rec_t* next_next_rec = page_rec_get_next(next_rec);
01429 if (page_rec_is_supremum(next_next_rec)) {
01430
01431 goto split_at_new;
01432 }
01433
01434
01435
01436
01437
01438
01439
01440
01441 *split_rec = next_next_rec;
01442 }
01443
01444 return(TRUE);
01445 }
01446
01447 return(FALSE);
01448 }
01449
01450
01456 static
01457 rec_t*
01458 btr_page_get_split_rec(
01459
01460 btr_cur_t* cursor,
01461 const dtuple_t* tuple,
01462 ulint n_ext)
01463 {
01464 page_t* page;
01465 page_zip_des_t* page_zip;
01466 ulint insert_size;
01467 ulint free_space;
01468 ulint total_data;
01469 ulint total_n_recs;
01470 ulint total_space;
01471 ulint incl_data;
01472 rec_t* ins_rec;
01473 rec_t* rec;
01474 rec_t* next_rec;
01475 ulint n;
01476 mem_heap_t* heap;
01477 ulint* offsets;
01478
01479 page = btr_cur_get_page(cursor);
01480
01481 insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
01482 free_space = page_get_free_space_of_empty(page_is_comp(page));
01483
01484 page_zip = btr_cur_get_page_zip(cursor);
01485 if (UNIV_LIKELY_NULL(page_zip)) {
01486
01487 ulint free_space_zip = page_zip_empty_size(
01488 cursor->index->n_fields,
01489 page_zip_get_size(page_zip));
01490
01491 if (UNIV_LIKELY(free_space > (ulint) free_space_zip)) {
01492 free_space = (ulint) free_space_zip;
01493 }
01494 }
01495
01496
01497
01498 total_data = page_get_data_size(page) + insert_size;
01499 total_n_recs = page_get_n_recs(page) + 1;
01500 ut_ad(total_n_recs >= 2);
01501 total_space = total_data + page_dir_calc_reserved_space(total_n_recs);
01502
01503 n = 0;
01504 incl_data = 0;
01505 ins_rec = btr_cur_get_rec(cursor);
01506 rec = page_get_infimum_rec(page);
01507
01508 heap = NULL;
01509 offsets = NULL;
01510
01511
01512
01513
01514
01515
01516
01517
01518 do {
01519
01520 if (rec == ins_rec) {
01521 rec = NULL;
01522
01523 } else if (rec == NULL) {
01524 rec = page_rec_get_next(ins_rec);
01525 } else {
01526 rec = page_rec_get_next(rec);
01527 }
01528
01529 if (rec == NULL) {
01530
01531 incl_data += insert_size;
01532 } else {
01533 offsets = rec_get_offsets(rec, cursor->index,
01534 offsets, ULINT_UNDEFINED,
01535 &heap);
01536 incl_data += rec_offs_size(offsets);
01537 }
01538
01539 n++;
01540 } while (incl_data + page_dir_calc_reserved_space(n)
01541 < total_space / 2);
01542
01543 if (incl_data + page_dir_calc_reserved_space(n) <= free_space) {
01544
01545
01546
01547
01548 if (rec == ins_rec) {
01549 rec = NULL;
01550
01551 goto func_exit;
01552 } else if (rec == NULL) {
01553 next_rec = page_rec_get_next(ins_rec);
01554 } else {
01555 next_rec = page_rec_get_next(rec);
01556 }
01557 ut_ad(next_rec);
01558 if (!page_rec_is_supremum(next_rec)) {
01559 rec = next_rec;
01560 }
01561 }
01562
01563 func_exit:
01564 if (UNIV_LIKELY_NULL(heap)) {
01565 mem_heap_free(heap);
01566 }
01567 return(rec);
01568 }
01569
01570
01574 static
01575 ibool
01576 btr_page_insert_fits(
01577
01578 btr_cur_t* cursor,
01580 const rec_t* split_rec,
01583 const ulint* offsets,
01585 const dtuple_t* tuple,
01586 ulint n_ext,
01587 mem_heap_t* heap)
01588 {
01589 page_t* page;
01590 ulint insert_size;
01591 ulint free_space;
01592 ulint total_data;
01593 ulint total_n_recs;
01594 const rec_t* rec;
01595 const rec_t* end_rec;
01596 ulint* offs;
01597
01598 page = btr_cur_get_page(cursor);
01599
01600 ut_ad(!split_rec == !offsets);
01601 ut_ad(!offsets
01602 || !page_is_comp(page) == !rec_offs_comp(offsets));
01603 ut_ad(!offsets
01604 || rec_offs_validate(split_rec, cursor->index, offsets));
01605
01606 insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
01607 free_space = page_get_free_space_of_empty(page_is_comp(page));
01608
01609
01610
01611 total_data = page_get_data_size(page) + insert_size;
01612 total_n_recs = page_get_n_recs(page) + 1;
01613
01614
01615
01616
01617
01618 if (split_rec == NULL) {
01619 rec = page_rec_get_next(page_get_infimum_rec(page));
01620 end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
01621
01622 } else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
01623
01624 rec = page_rec_get_next(page_get_infimum_rec(page));
01625 end_rec = split_rec;
01626 } else {
01627 rec = split_rec;
01628 end_rec = page_get_supremum_rec(page);
01629 }
01630
01631 if (total_data + page_dir_calc_reserved_space(total_n_recs)
01632 <= free_space) {
01633
01634
01635
01636
01637 return(TRUE);
01638 }
01639
01640 offs = NULL;
01641
01642 while (rec != end_rec) {
01643
01644
01645
01646 offs = rec_get_offsets(rec, cursor->index, offs,
01647 ULINT_UNDEFINED, &heap);
01648
01649 total_data -= rec_offs_size(offs);
01650 total_n_recs--;
01651
01652 if (total_data + page_dir_calc_reserved_space(total_n_recs)
01653 <= free_space) {
01654
01655
01656
01657
01658 return(TRUE);
01659 }
01660
01661 rec = page_rec_get_next_const(rec);
01662 }
01663
01664 return(FALSE);
01665 }
01666
01667
01670 UNIV_INTERN
01671 void
01672 btr_insert_on_non_leaf_level_func(
01673
01674 dict_index_t* index,
01675 ulint level,
01676 dtuple_t* tuple,
01677 const char* file,
01678 ulint line,
01679 mtr_t* mtr)
01680 {
01681 big_rec_t* dummy_big_rec;
01682 btr_cur_t cursor;
01683 ulint err;
01684 rec_t* rec;
01685
01686 ut_ad(level > 0);
01687
01688 btr_cur_search_to_nth_level(index, level, tuple, PAGE_CUR_LE,
01689 BTR_CONT_MODIFY_TREE,
01690 &cursor, 0, file, line, mtr);
01691
01692 err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
01693 | BTR_KEEP_SYS_FLAG
01694 | BTR_NO_UNDO_LOG_FLAG,
01695 &cursor, tuple, &rec,
01696 &dummy_big_rec, 0, NULL, mtr);
01697 ut_a(err == DB_SUCCESS);
01698 }
01699
01700
01703 static
01704 void
01705 btr_attach_half_pages(
01706
01707 dict_index_t* index,
01708 buf_block_t* block,
01709 rec_t* split_rec,
01711 buf_block_t* new_block,
01712 ulint direction,
01713 mtr_t* mtr)
01714 {
01715 ulint space;
01716 ulint zip_size;
01717 ulint prev_page_no;
01718 ulint next_page_no;
01719 ulint level;
01720 page_t* page = buf_block_get_frame(block);
01721 page_t* lower_page;
01722 page_t* upper_page;
01723 ulint lower_page_no;
01724 ulint upper_page_no;
01725 page_zip_des_t* lower_page_zip;
01726 page_zip_des_t* upper_page_zip;
01727 dtuple_t* node_ptr_upper;
01728 mem_heap_t* heap;
01729
01730 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
01731 ut_ad(mtr_memo_contains(mtr, new_block, MTR_MEMO_PAGE_X_FIX));
01732
01733
01734 heap = mem_heap_create(1024);
01735
01736
01737 if (direction == FSP_DOWN) {
01738
01739 btr_cur_t cursor;
01740 ulint* offsets;
01741
01742 lower_page = buf_block_get_frame(new_block);
01743 lower_page_no = buf_block_get_page_no(new_block);
01744 lower_page_zip = buf_block_get_page_zip(new_block);
01745 upper_page = buf_block_get_frame(block);
01746 upper_page_no = buf_block_get_page_no(block);
01747 upper_page_zip = buf_block_get_page_zip(block);
01748
01749
01750 offsets = btr_page_get_father_block(NULL, heap, index,
01751 block, mtr, &cursor);
01752
01753
01754
01755
01756 btr_node_ptr_set_child_page_no(
01757 btr_cur_get_rec(&cursor),
01758 btr_cur_get_page_zip(&cursor),
01759 offsets, lower_page_no, mtr);
01760 mem_heap_empty(heap);
01761 } else {
01762 lower_page = buf_block_get_frame(block);
01763 lower_page_no = buf_block_get_page_no(block);
01764 lower_page_zip = buf_block_get_page_zip(block);
01765 upper_page = buf_block_get_frame(new_block);
01766 upper_page_no = buf_block_get_page_no(new_block);
01767 upper_page_zip = buf_block_get_page_zip(new_block);
01768 }
01769
01770
01771 level = btr_page_get_level(buf_block_get_frame(block), mtr);
01772 ut_ad(level
01773 == btr_page_get_level(buf_block_get_frame(new_block), mtr));
01774
01775
01776
01777
01778 node_ptr_upper = dict_index_build_node_ptr(index, split_rec,
01779 upper_page_no, heap, level);
01780
01781
01782
01783
01784 btr_insert_on_non_leaf_level(index, level + 1, node_ptr_upper, mtr);
01785
01786
01787 mem_heap_free(heap);
01788
01789
01790
01791 prev_page_no = btr_page_get_prev(page, mtr);
01792 next_page_no = btr_page_get_next(page, mtr);
01793 space = buf_block_get_space(block);
01794 zip_size = buf_block_get_zip_size(block);
01795
01796
01797
01798 if (prev_page_no != FIL_NULL) {
01799 buf_block_t* prev_block = btr_block_get(space, zip_size,
01800 prev_page_no,
01801 RW_X_LATCH, mtr);
01802 #ifdef UNIV_BTR_DEBUG
01803 ut_a(page_is_comp(prev_block->frame) == page_is_comp(page));
01804 ut_a(btr_page_get_next(prev_block->frame, mtr)
01805 == buf_block_get_page_no(block));
01806 #endif
01807
01808 btr_page_set_next(buf_block_get_frame(prev_block),
01809 buf_block_get_page_zip(prev_block),
01810 lower_page_no, mtr);
01811 }
01812
01813 if (next_page_no != FIL_NULL) {
01814 buf_block_t* next_block = btr_block_get(space, zip_size,
01815 next_page_no,
01816 RW_X_LATCH, mtr);
01817 #ifdef UNIV_BTR_DEBUG
01818 ut_a(page_is_comp(next_block->frame) == page_is_comp(page));
01819 ut_a(btr_page_get_prev(next_block->frame, mtr)
01820 == page_get_page_no(page));
01821 #endif
01822
01823 btr_page_set_prev(buf_block_get_frame(next_block),
01824 buf_block_get_page_zip(next_block),
01825 upper_page_no, mtr);
01826 }
01827
01828 btr_page_set_prev(lower_page, lower_page_zip, prev_page_no, mtr);
01829 btr_page_set_next(lower_page, lower_page_zip, upper_page_no, mtr);
01830
01831 btr_page_set_prev(upper_page, upper_page_zip, lower_page_no, mtr);
01832 btr_page_set_next(upper_page, upper_page_zip, next_page_no, mtr);
01833 }
01834
01835
01838 static
01839 ibool
01840 btr_page_tuple_smaller(
01841
01842 btr_cur_t* cursor,
01843 const dtuple_t* tuple,
01844 ulint* offsets,
01845 ulint n_uniq,
01847 mem_heap_t** heap)
01848 {
01849 buf_block_t* block;
01850 const rec_t* first_rec;
01851 page_cur_t pcur;
01852
01853
01854 block = btr_cur_get_block(cursor);
01855 page_cur_set_before_first(block, &pcur);
01856 page_cur_move_to_next(&pcur);
01857 first_rec = page_cur_get_rec(&pcur);
01858
01859 offsets = rec_get_offsets(
01860 first_rec, cursor->index, offsets,
01861 n_uniq, heap);
01862
01863 return(cmp_dtuple_rec(tuple, first_rec, offsets) < 0);
01864 }
01865
01866
01875 UNIV_INTERN
01876 rec_t*
01877 btr_page_split_and_insert(
01878
01879 btr_cur_t* cursor,
01882 const dtuple_t* tuple,
01883 ulint n_ext,
01884 mtr_t* mtr)
01885 {
01886 buf_block_t* block;
01887 page_t* page;
01888 page_zip_des_t* page_zip;
01889 ulint page_no;
01890 byte direction;
01891 ulint hint_page_no;
01892 buf_block_t* new_block;
01893 page_t* new_page;
01894 page_zip_des_t* new_page_zip;
01895 rec_t* split_rec;
01896 buf_block_t* left_block;
01897 buf_block_t* right_block;
01898 buf_block_t* insert_block;
01899 page_cur_t* page_cursor;
01900 rec_t* first_rec;
01901 byte* buf = 0;
01902 rec_t* move_limit;
01903 ibool insert_will_fit;
01904 ibool insert_left;
01905 ulint n_iterations = 0;
01906 rec_t* rec;
01907 mem_heap_t* heap;
01908 ulint n_uniq;
01909 ulint* offsets;
01910
01911 heap = mem_heap_create(1024);
01912 n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
01913 func_start:
01914 mem_heap_empty(heap);
01915 offsets = NULL;
01916
01917 ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index),
01918 MTR_MEMO_X_LOCK));
01919 #ifdef UNIV_SYNC_DEBUG
01920 ut_ad(rw_lock_own(dict_index_get_lock(cursor->index), RW_LOCK_EX));
01921 #endif
01922
01923 block = btr_cur_get_block(cursor);
01924 page = buf_block_get_frame(block);
01925 page_zip = buf_block_get_page_zip(block);
01926
01927 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
01928 ut_ad(page_get_n_recs(page) >= 1);
01929
01930 page_no = buf_block_get_page_no(block);
01931
01932
01933
01934
01935 insert_left = FALSE;
01936
01937 if (n_iterations > 0) {
01938 direction = FSP_UP;
01939 hint_page_no = page_no + 1;
01940 split_rec = btr_page_get_split_rec(cursor, tuple, n_ext);
01941
01942 if (UNIV_UNLIKELY(split_rec == NULL)) {
01943 insert_left = btr_page_tuple_smaller(
01944 cursor, tuple, offsets, n_uniq, &heap);
01945 }
01946 } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
01947 direction = FSP_UP;
01948 hint_page_no = page_no + 1;
01949 } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) {
01950 direction = FSP_DOWN;
01951 hint_page_no = page_no - 1;
01952 ut_ad(split_rec);
01953 } else {
01954 direction = FSP_UP;
01955 hint_page_no = page_no + 1;
01956
01957
01958
01959
01960
01961 if (page_get_n_recs(page) > 1) {
01962 split_rec = page_get_middle_rec(page);
01963 } else if (btr_page_tuple_smaller(cursor, tuple,
01964 offsets, n_uniq, &heap)) {
01965 split_rec = page_rec_get_next(
01966 page_get_infimum_rec(page));
01967 } else {
01968 split_rec = NULL;
01969 }
01970 }
01971
01972
01973 new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
01974 btr_page_get_level(page, mtr), mtr);
01975 new_page = buf_block_get_frame(new_block);
01976 new_page_zip = buf_block_get_page_zip(new_block);
01977 btr_page_create(new_block, new_page_zip, cursor->index,
01978 btr_page_get_level(page, mtr), mtr);
01979
01980
01981
01982
01983
01984 if (split_rec) {
01985 first_rec = move_limit = split_rec;
01986
01987 offsets = rec_get_offsets(split_rec, cursor->index, offsets,
01988 n_uniq, &heap);
01989
01990 insert_left = cmp_dtuple_rec(tuple, split_rec, offsets) < 0;
01991
01992 if (UNIV_UNLIKELY(!insert_left && new_page_zip
01993 && n_iterations > 0)) {
01994
01995
01996
01997 split_rec = NULL;
01998 goto insert_empty;
01999 }
02000 } else if (UNIV_UNLIKELY(insert_left)) {
02001 ut_a(n_iterations > 0);
02002 first_rec = page_rec_get_next(page_get_infimum_rec(page));
02003 move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
02004 } else {
02005 insert_empty:
02006 ut_ad(!split_rec);
02007 ut_ad(!insert_left);
02008 buf = (unsigned char *)mem_alloc(rec_get_converted_size(cursor->index,
02009 tuple, n_ext));
02010
02011 first_rec = rec_convert_dtuple_to_rec(buf, cursor->index,
02012 tuple, n_ext);
02013 move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
02014 }
02015
02016
02017
02018 btr_attach_half_pages(cursor->index, block,
02019 first_rec, new_block, direction, mtr);
02020
02021
02022
02023
02024
02025
02026 if (split_rec) {
02027 insert_will_fit = !new_page_zip
02028 && btr_page_insert_fits(cursor, split_rec,
02029 offsets, tuple, n_ext, heap);
02030 } else {
02031 if (!insert_left) {
02032 mem_free(buf);
02033 buf = NULL;
02034 }
02035
02036 insert_will_fit = !new_page_zip
02037 && btr_page_insert_fits(cursor, NULL,
02038 NULL, tuple, n_ext, heap);
02039 }
02040
02041 if (insert_will_fit && page_is_leaf(page)) {
02042
02043 mtr_memo_release(mtr, dict_index_get_lock(cursor->index),
02044 MTR_MEMO_X_LOCK);
02045 }
02046
02047
02048 if (direction == FSP_DOWN) {
02049
02050
02051 if (0
02052 #ifdef UNIV_ZIP_COPY
02053 || page_zip
02054 #endif
02055 || UNIV_UNLIKELY
02056 (!page_move_rec_list_start(new_block, block, move_limit,
02057 cursor->index, mtr))) {
02058
02059
02060
02061
02062
02063 ut_a(new_page_zip);
02064
02065 page_zip_copy_recs(new_page_zip, new_page,
02066 page_zip, page, cursor->index, mtr);
02067 page_delete_rec_list_end(move_limit - page + new_page,
02068 new_block, cursor->index,
02069 ULINT_UNDEFINED,
02070 ULINT_UNDEFINED, mtr);
02071
02072
02073
02074 lock_move_rec_list_start(
02075 new_block, block, move_limit,
02076 new_page + PAGE_NEW_INFIMUM);
02077
02078 btr_search_move_or_delete_hash_entries(
02079 new_block, block, cursor->index);
02080
02081
02082
02083 page_delete_rec_list_start(move_limit, block,
02084 cursor->index, mtr);
02085 }
02086
02087 left_block = new_block;
02088 right_block = block;
02089
02090 lock_update_split_left(right_block, left_block);
02091 } else {
02092
02093
02094 if (0
02095 #ifdef UNIV_ZIP_COPY
02096 || page_zip
02097 #endif
02098 || UNIV_UNLIKELY
02099 (!page_move_rec_list_end(new_block, block, move_limit,
02100 cursor->index, mtr))) {
02101
02102
02103
02104
02105
02106 ut_a(new_page_zip);
02107
02108 page_zip_copy_recs(new_page_zip, new_page,
02109 page_zip, page, cursor->index, mtr);
02110 page_delete_rec_list_start(move_limit - page
02111 + new_page, new_block,
02112 cursor->index, mtr);
02113
02114
02115
02116 lock_move_rec_list_end(new_block, block, move_limit);
02117
02118 btr_search_move_or_delete_hash_entries(
02119 new_block, block, cursor->index);
02120
02121
02122
02123 page_delete_rec_list_end(move_limit, block,
02124 cursor->index,
02125 ULINT_UNDEFINED,
02126 ULINT_UNDEFINED, mtr);
02127 }
02128
02129 left_block = block;
02130 right_block = new_block;
02131
02132 lock_update_split_right(right_block, left_block);
02133 }
02134
02135 #ifdef UNIV_ZIP_DEBUG
02136 if (UNIV_LIKELY_NULL(page_zip)) {
02137 ut_a(page_zip_validate(page_zip, page));
02138 ut_a(page_zip_validate(new_page_zip, new_page));
02139 }
02140 #endif
02141
02142
02143
02144
02145
02146
02147
02148 if (insert_left) {
02149 insert_block = left_block;
02150 } else {
02151 insert_block = right_block;
02152 }
02153
02154
02155 page_cursor = btr_cur_get_page_cur(cursor);
02156
02157 page_cur_search(insert_block, cursor->index, tuple,
02158 PAGE_CUR_LE, page_cursor);
02159
02160 rec = page_cur_tuple_insert(page_cursor, tuple,
02161 cursor->index, n_ext, mtr);
02162
02163 #ifdef UNIV_ZIP_DEBUG
02164 {
02165 page_t* insert_page
02166 = buf_block_get_frame(insert_block);
02167
02168 page_zip_des_t* insert_page_zip
02169 = buf_block_get_page_zip(insert_block);
02170
02171 ut_a(!insert_page_zip
02172 || page_zip_validate(insert_page_zip, insert_page));
02173 }
02174 #endif
02175
02176 if (UNIV_LIKELY(rec != NULL)) {
02177
02178 goto func_exit;
02179 }
02180
02181
02182
02183 if (UNIV_UNLIKELY
02184 (!btr_page_reorganize(insert_block, cursor->index, mtr))) {
02185
02186 goto insert_failed;
02187 }
02188
02189 page_cur_search(insert_block, cursor->index, tuple,
02190 PAGE_CUR_LE, page_cursor);
02191 rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
02192 n_ext, mtr);
02193
02194 if (UNIV_UNLIKELY(rec == NULL)) {
02195
02196
02197 insert_failed:
02198
02199 if (!dict_index_is_clust(cursor->index)) {
02200 ibuf_reset_free_bits(new_block);
02201 }
02202
02203
02204
02205 n_iterations++;
02206 ut_ad(n_iterations < 2
02207 || buf_block_get_page_zip(insert_block));
02208 ut_ad(!insert_will_fit);
02209
02210 goto func_start;
02211 }
02212
02213 func_exit:
02214
02215
02216
02217 if (!dict_index_is_clust(cursor->index) && page_is_leaf(page)) {
02218 ibuf_update_free_bits_for_two_pages_low(
02219 buf_block_get_zip_size(left_block),
02220 left_block, right_block, mtr);
02221 }
02222
02223 #if 0
02224 fprintf(stderr, "Split and insert done %lu %lu\n",
02225 buf_block_get_page_no(left_block),
02226 buf_block_get_page_no(right_block));
02227 #endif
02228
02229 ut_ad(page_validate(buf_block_get_frame(left_block), cursor->index));
02230 ut_ad(page_validate(buf_block_get_frame(right_block), cursor->index));
02231
02232 mem_heap_free(heap);
02233 return(rec);
02234 }
02235
02236
02238 static
02239 void
02240 btr_level_list_remove(
02241
02242 ulint space,
02243 ulint zip_size,
02245 page_t* page,
02246 mtr_t* mtr)
02247 {
02248 ulint prev_page_no;
02249 ulint next_page_no;
02250
02251 ut_ad(page && mtr);
02252 ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
02253 ut_ad(space == page_get_space_id(page));
02254
02255
02256 prev_page_no = btr_page_get_prev(page, mtr);
02257 next_page_no = btr_page_get_next(page, mtr);
02258
02259
02260
02261 if (prev_page_no != FIL_NULL) {
02262 buf_block_t* prev_block
02263 = btr_block_get(space, zip_size, prev_page_no,
02264 RW_X_LATCH, mtr);
02265 page_t* prev_page
02266 = buf_block_get_frame(prev_block);
02267 #ifdef UNIV_BTR_DEBUG
02268 ut_a(page_is_comp(prev_page) == page_is_comp(page));
02269 ut_a(btr_page_get_next(prev_page, mtr)
02270 == page_get_page_no(page));
02271 #endif
02272
02273 btr_page_set_next(prev_page,
02274 buf_block_get_page_zip(prev_block),
02275 next_page_no, mtr);
02276 }
02277
02278 if (next_page_no != FIL_NULL) {
02279 buf_block_t* next_block
02280 = btr_block_get(space, zip_size, next_page_no,
02281 RW_X_LATCH, mtr);
02282 page_t* next_page
02283 = buf_block_get_frame(next_block);
02284 #ifdef UNIV_BTR_DEBUG
02285 ut_a(page_is_comp(next_page) == page_is_comp(page));
02286 ut_a(btr_page_get_prev(next_page, mtr)
02287 == page_get_page_no(page));
02288 #endif
02289
02290 btr_page_set_prev(next_page,
02291 buf_block_get_page_zip(next_block),
02292 prev_page_no, mtr);
02293 }
02294 }
02295
02296
02299 UNIV_INLINE
02300 void
02301 btr_set_min_rec_mark_log(
02302
02303 rec_t* rec,
02304 byte type,
02305 mtr_t* mtr)
02306 {
02307 mlog_write_initial_log_record(rec, type, mtr);
02308
02309
02310 mlog_catenate_ulint(mtr, page_offset(rec), MLOG_2BYTES);
02311 }
02312 #else
02313 # define btr_set_min_rec_mark_log(rec,comp,mtr) ((void) 0)
02314 #endif
02315
02316
02320 UNIV_INTERN
02321 byte*
02322 btr_parse_set_min_rec_mark(
02323
02324 byte* ptr,
02325 byte* end_ptr,
02326 ulint comp,
02327 page_t* page,
02328 mtr_t* mtr)
02329 {
02330 rec_t* rec;
02331
02332 if (end_ptr < ptr + 2) {
02333
02334 return(NULL);
02335 }
02336
02337 if (page) {
02338 ut_a(!page_is_comp(page) == !comp);
02339
02340 rec = page + mach_read_from_2(ptr);
02341
02342 btr_set_min_rec_mark(rec, mtr);
02343 }
02344
02345 return(ptr + 2);
02346 }
02347
02348
02350 UNIV_INTERN
02351 void
02352 btr_set_min_rec_mark(
02353
02354 rec_t* rec,
02355 mtr_t* mtr)
02356 {
02357 ulint info_bits;
02358
02359 if (UNIV_LIKELY(page_rec_is_comp(rec))) {
02360 info_bits = rec_get_info_bits(rec, TRUE);
02361
02362 rec_set_info_bits_new(rec, info_bits | REC_INFO_MIN_REC_FLAG);
02363
02364 btr_set_min_rec_mark_log(rec, MLOG_COMP_REC_MIN_MARK, mtr);
02365 } else {
02366 info_bits = rec_get_info_bits(rec, FALSE);
02367
02368 rec_set_info_bits_old(rec, info_bits | REC_INFO_MIN_REC_FLAG);
02369
02370 btr_set_min_rec_mark_log(rec, MLOG_REC_MIN_MARK, mtr);
02371 }
02372 }
02373
02374 #ifndef UNIV_HOTBACKUP
02375
02377 UNIV_INTERN
02378 void
02379 btr_node_ptr_delete(
02380
02381 dict_index_t* index,
02382 buf_block_t* block,
02383 mtr_t* mtr)
02384 {
02385 btr_cur_t cursor;
02386 ibool compressed;
02387 ulint err;
02388
02389 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
02390
02391
02392 btr_page_get_father(index, block, mtr, &cursor);
02393
02394 compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, RB_NONE,
02395 mtr);
02396 ut_a(err == DB_SUCCESS);
02397
02398 if (!compressed) {
02399 btr_cur_compress_if_useful(&cursor, mtr);
02400 }
02401 }
02402
02403
02406 static
02407 void
02408 btr_lift_page_up(
02409
02410 dict_index_t* index,
02411 buf_block_t* block,
02415 mtr_t* mtr)
02416 {
02417 buf_block_t* father_block;
02418 page_t* father_page;
02419 ulint page_level;
02420 page_zip_des_t* father_page_zip;
02421 page_t* page = buf_block_get_frame(block);
02422 ulint root_page_no;
02423 buf_block_t* blocks[BTR_MAX_LEVELS];
02424 ulint n_blocks;
02425 ulint i;
02426
02427 ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
02428 ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
02429 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
02430
02431 page_level = btr_page_get_level(page, mtr);
02432 root_page_no = dict_index_get_page(index);
02433
02434 {
02435 btr_cur_t cursor;
02436 mem_heap_t* heap = mem_heap_create(100);
02437 ulint* offsets;
02438 buf_block_t* b;
02439
02440 offsets = btr_page_get_father_block(NULL, heap, index,
02441 block, mtr, &cursor);
02442 father_block = btr_cur_get_block(&cursor);
02443 father_page_zip = buf_block_get_page_zip(father_block);
02444 father_page = buf_block_get_frame(father_block);
02445
02446 n_blocks = 0;
02447
02448
02449
02450
02451
02452
02453 for (b = father_block;
02454 buf_block_get_page_no(b) != root_page_no; ) {
02455 ut_a(n_blocks < BTR_MAX_LEVELS);
02456
02457 offsets = btr_page_get_father_block(offsets, heap,
02458 index, b,
02459 mtr, &cursor);
02460
02461 blocks[n_blocks++] = b = btr_cur_get_block(&cursor);
02462 }
02463
02464 mem_heap_free(heap);
02465 }
02466
02467 btr_search_drop_page_hash_index(block);
02468
02469
02470 btr_page_empty(father_block, father_page_zip, index, page_level, mtr);
02471
02472
02473 if (0
02474 #ifdef UNIV_ZIP_COPY
02475 || father_page_zip
02476 #endif
02477 || UNIV_UNLIKELY
02478 (!page_copy_rec_list_end(father_block, block,
02479 page_get_infimum_rec(page),
02480 index, mtr))) {
02481 const page_zip_des_t* page_zip
02482 = buf_block_get_page_zip(block);
02483 ut_a(father_page_zip);
02484 ut_a(page_zip);
02485
02486
02487 page_zip_copy_recs(father_page_zip, father_page,
02488 page_zip, page, index, mtr);
02489
02490
02491
02492 lock_move_rec_list_end(father_block, block,
02493 page_get_infimum_rec(page));
02494
02495 btr_search_move_or_delete_hash_entries(father_block, block,
02496 index);
02497 }
02498
02499 lock_update_copy_and_discard(father_block, block);
02500
02501
02502 for (i = 0; i < n_blocks; i++, page_level++) {
02503 page_t* inner_page = buf_block_get_frame(blocks[i]);
02504 page_zip_des_t* page_zip= buf_block_get_page_zip(blocks[i]);
02505
02506 ut_ad(btr_page_get_level(page, mtr) == page_level + 1);
02507
02508 btr_page_set_level(inner_page, page_zip, page_level, mtr);
02509 #ifdef UNIV_ZIP_DEBUG
02510 ut_a(!page_zip || page_zip_validate(page_zip, inner_page));
02511 #endif
02512 }
02513
02514
02515 btr_page_free(index, block, mtr);
02516
02517
02518 if (!dict_index_is_clust(index)) {
02519 ibuf_reset_free_bits(father_block);
02520 }
02521 ut_ad(page_validate(father_page, index));
02522 ut_ad(btr_check_node_ptr(index, father_block, mtr));
02523 }
02524
02525
02535 UNIV_INTERN
02536 ibool
02537 btr_compress(
02538
02539 btr_cur_t* cursor,
02543 mtr_t* mtr)
02544 {
02545 dict_index_t* index;
02546 ulint space;
02547 ulint zip_size;
02548 ulint left_page_no;
02549 ulint right_page_no;
02550 buf_block_t* merge_block;
02551 page_t* merge_page;
02552 page_zip_des_t* merge_page_zip;
02553 ibool is_left;
02554 buf_block_t* block;
02555 page_t* page;
02556 btr_cur_t father_cursor;
02557 mem_heap_t* heap;
02558 ulint* offsets;
02559 ulint data_size;
02560 ulint n_recs;
02561 ulint max_ins_size;
02562 ulint max_ins_size_reorg;
02563
02564 block = btr_cur_get_block(cursor);
02565 page = btr_cur_get_page(cursor);
02566 index = btr_cur_get_index(cursor);
02567 ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table));
02568
02569 ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
02570 MTR_MEMO_X_LOCK));
02571 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
02572 space = dict_index_get_space(index);
02573 zip_size = dict_table_zip_size(index->table);
02574
02575 left_page_no = btr_page_get_prev(page, mtr);
02576 right_page_no = btr_page_get_next(page, mtr);
02577
02578 #if 0
02579 fprintf(stderr, "Merge left page %lu right %lu \n",
02580 left_page_no, right_page_no);
02581 #endif
02582
02583 heap = mem_heap_create(100);
02584 offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
02585 &father_cursor);
02586
02587
02588
02589
02590 is_left = left_page_no != FIL_NULL;
02591
02592 if (is_left) {
02593
02594 merge_block = btr_block_get(space, zip_size, left_page_no,
02595 RW_X_LATCH, mtr);
02596 merge_page = buf_block_get_frame(merge_block);
02597 #ifdef UNIV_BTR_DEBUG
02598 ut_a(btr_page_get_next(merge_page, mtr)
02599 == buf_block_get_page_no(block));
02600 #endif
02601 } else if (right_page_no != FIL_NULL) {
02602
02603 merge_block = btr_block_get(space, zip_size, right_page_no,
02604 RW_X_LATCH, mtr);
02605 merge_page = buf_block_get_frame(merge_block);
02606 #ifdef UNIV_BTR_DEBUG
02607 ut_a(btr_page_get_prev(merge_page, mtr)
02608 == buf_block_get_page_no(block));
02609 #endif
02610 } else {
02611
02612
02613 btr_lift_page_up(index, block, mtr);
02614 mem_heap_free(heap);
02615 return(TRUE);
02616 }
02617
02618 n_recs = page_get_n_recs(page);
02619 data_size = page_get_data_size(page);
02620 #ifdef UNIV_BTR_DEBUG
02621 ut_a(page_is_comp(merge_page) == page_is_comp(page));
02622 #endif
02623
02624 max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
02625 merge_page, n_recs);
02626 if (data_size > max_ins_size_reorg) {
02627
02628
02629 err_exit:
02630
02631 if (zip_size
02632 && page_is_leaf(merge_page)
02633 && !dict_index_is_clust(index)) {
02634 ibuf_reset_free_bits(merge_block);
02635 }
02636
02637 mem_heap_free(heap);
02638 return(FALSE);
02639 }
02640
02641 ut_ad(page_validate(merge_page, index));
02642
02643 max_ins_size = page_get_max_insert_size(merge_page, n_recs);
02644
02645 if (UNIV_UNLIKELY(data_size > max_ins_size)) {
02646
02647
02648
02649 if (UNIV_UNLIKELY(!btr_page_reorganize(merge_block,
02650 index, mtr))) {
02651
02652 goto err_exit;
02653 }
02654
02655 max_ins_size = page_get_max_insert_size(merge_page, n_recs);
02656
02657 ut_ad(page_validate(merge_page, index));
02658 ut_ad(max_ins_size == max_ins_size_reorg);
02659
02660 if (UNIV_UNLIKELY(data_size > max_ins_size)) {
02661
02662
02663
02664
02665 goto err_exit;
02666 }
02667 }
02668
02669 merge_page_zip = buf_block_get_page_zip(merge_block);
02670 #ifdef UNIV_ZIP_DEBUG
02671 if (UNIV_LIKELY_NULL(merge_page_zip)) {
02672 const page_zip_des_t* page_zip
02673 = buf_block_get_page_zip(block);
02674 ut_a(page_zip);
02675 ut_a(page_zip_validate(merge_page_zip, merge_page));
02676 ut_a(page_zip_validate(page_zip, page));
02677 }
02678 #endif
02679
02680
02681 if (is_left) {
02682 rec_t* orig_pred = page_copy_rec_list_start(
02683 merge_block, block, page_get_supremum_rec(page),
02684 index, mtr);
02685
02686 if (UNIV_UNLIKELY(!orig_pred)) {
02687 goto err_exit;
02688 }
02689
02690 btr_search_drop_page_hash_index(block);
02691
02692
02693 btr_level_list_remove(space, zip_size, page, mtr);
02694
02695 btr_node_ptr_delete(index, block, mtr);
02696 lock_update_merge_left(merge_block, orig_pred, block);
02697 } else {
02698 rec_t* orig_succ;
02699 #ifdef UNIV_BTR_DEBUG
02700 byte fil_page_prev[4];
02701 #endif
02702
02703 if (UNIV_LIKELY_NULL(merge_page_zip)) {
02704
02705
02706
02707
02708 #ifdef UNIV_BTR_DEBUG
02709 memcpy(fil_page_prev, merge_page + FIL_PAGE_PREV, 4);
02710 #endif
02711 #if FIL_NULL != 0xffffffff
02712 # error "FIL_NULL != 0xffffffff"
02713 #endif
02714 memset(merge_page + FIL_PAGE_PREV, 0xff, 4);
02715 }
02716
02717 orig_succ = page_copy_rec_list_end(merge_block, block,
02718 page_get_infimum_rec(page),
02719 cursor->index, mtr);
02720
02721 if (UNIV_UNLIKELY(!orig_succ)) {
02722 ut_a(merge_page_zip);
02723 #ifdef UNIV_BTR_DEBUG
02724
02725 ut_a(!memcmp(fil_page_prev,
02726 merge_page + FIL_PAGE_PREV, 4));
02727 #endif
02728 goto err_exit;
02729 }
02730
02731 btr_search_drop_page_hash_index(block);
02732
02733 #ifdef UNIV_BTR_DEBUG
02734 if (UNIV_LIKELY_NULL(merge_page_zip)) {
02735
02736
02737
02738
02739
02740
02741 memcpy(merge_page + FIL_PAGE_PREV, fil_page_prev, 4);
02742 }
02743 #endif
02744
02745
02746 btr_level_list_remove(space, zip_size, page, mtr);
02747
02748
02749
02750
02751 btr_node_ptr_set_child_page_no(
02752 btr_cur_get_rec(&father_cursor),
02753 btr_cur_get_page_zip(&father_cursor),
02754 offsets, right_page_no, mtr);
02755 btr_node_ptr_delete(index, merge_block, mtr);
02756
02757 lock_update_merge_right(merge_block, orig_succ, block);
02758 }
02759
02760 mem_heap_free(heap);
02761
02762 if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) {
02763
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785 if (zip_size) {
02786
02787
02788
02789
02790
02791 ibuf_reset_free_bits(merge_block);
02792 } else {
02793
02794
02795
02796
02797 ibuf_update_free_bits_if_full(merge_block,
02798 UNIV_PAGE_SIZE,
02799 ULINT_UNDEFINED);
02800 }
02801 }
02802
02803 ut_ad(page_validate(merge_page, index));
02804 #ifdef UNIV_ZIP_DEBUG
02805 ut_a(!merge_page_zip || page_zip_validate(merge_page_zip, merge_page));
02806 #endif
02807
02808
02809 btr_page_free(index, block, mtr);
02810
02811 ut_ad(btr_check_node_ptr(index, merge_block, mtr));
02812 return(TRUE);
02813 }
02814
02815
02820 static
02821 void
02822 btr_discard_only_page_on_level(
02823
02824 dict_index_t* index,
02825 buf_block_t* block,
02826 mtr_t* mtr)
02827 {
02828 ulint page_level = 0;
02829 trx_id_t max_trx_id;
02830
02831
02832 max_trx_id = page_get_max_trx_id(buf_block_get_frame(block));
02833
02834 while (buf_block_get_page_no(block) != dict_index_get_page(index)) {
02835 btr_cur_t cursor;
02836 buf_block_t* father;
02837 const page_t* page = buf_block_get_frame(block);
02838
02839 ut_a(page_get_n_recs(page) == 1);
02840 ut_a(page_level == btr_page_get_level(page, mtr));
02841 ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
02842 ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
02843
02844 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
02845 btr_search_drop_page_hash_index(block);
02846
02847 btr_page_get_father(index, block, mtr, &cursor);
02848 father = btr_cur_get_block(&cursor);
02849
02850 lock_update_discard(father, PAGE_HEAP_NO_SUPREMUM, block);
02851
02852
02853 btr_page_free(index, block, mtr);
02854
02855 block = father;
02856 page_level++;
02857 }
02858
02859
02860
02861
02862 #ifdef UNIV_BTR_DEBUG
02863 if (!dict_index_is_ibuf(index)) {
02864 const page_t* root = buf_block_get_frame(block);
02865 const ulint space = dict_index_get_space(index);
02866 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
02867 + root, space));
02868 ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
02869 + root, space));
02870 }
02871 #endif
02872
02873 btr_page_empty(block, buf_block_get_page_zip(block), index, 0, mtr);
02874
02875 if (!dict_index_is_clust(index)) {
02876
02877 ibuf_reset_free_bits(block);
02878
02879 if (page_is_leaf(buf_block_get_frame(block))) {
02880 ut_a(max_trx_id);
02881 page_set_max_trx_id(block,
02882 buf_block_get_page_zip(block),
02883 max_trx_id, mtr);
02884 }
02885 }
02886 }
02887
02888
02892 UNIV_INTERN
02893 void
02894 btr_discard_page(
02895
02896 btr_cur_t* cursor,
02898 mtr_t* mtr)
02899 {
02900 dict_index_t* index;
02901 ulint space;
02902 ulint zip_size;
02903 ulint left_page_no;
02904 ulint right_page_no;
02905 buf_block_t* merge_block;
02906 page_t* merge_page;
02907 buf_block_t* block;
02908 page_t* page;
02909 rec_t* node_ptr;
02910
02911 block = btr_cur_get_block(cursor);
02912 index = btr_cur_get_index(cursor);
02913
02914 ut_ad(dict_index_get_page(index) != buf_block_get_page_no(block));
02915 ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
02916 MTR_MEMO_X_LOCK));
02917 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
02918 space = dict_index_get_space(index);
02919 zip_size = dict_table_zip_size(index->table);
02920
02921
02922
02923 left_page_no = btr_page_get_prev(buf_block_get_frame(block), mtr);
02924 right_page_no = btr_page_get_next(buf_block_get_frame(block), mtr);
02925
02926 if (left_page_no != FIL_NULL) {
02927 merge_block = btr_block_get(space, zip_size, left_page_no,
02928 RW_X_LATCH, mtr);
02929 merge_page = buf_block_get_frame(merge_block);
02930 #ifdef UNIV_BTR_DEBUG
02931 ut_a(btr_page_get_next(merge_page, mtr)
02932 == buf_block_get_page_no(block));
02933 #endif
02934 } else if (right_page_no != FIL_NULL) {
02935 merge_block = btr_block_get(space, zip_size, right_page_no,
02936 RW_X_LATCH, mtr);
02937 merge_page = buf_block_get_frame(merge_block);
02938 #ifdef UNIV_BTR_DEBUG
02939 ut_a(btr_page_get_prev(merge_page, mtr)
02940 == buf_block_get_page_no(block));
02941 #endif
02942 } else {
02943 btr_discard_only_page_on_level(index, block, mtr);
02944
02945 return;
02946 }
02947
02948 page = buf_block_get_frame(block);
02949 ut_a(page_is_comp(merge_page) == page_is_comp(page));
02950 btr_search_drop_page_hash_index(block);
02951
02952 if (left_page_no == FIL_NULL && !page_is_leaf(page)) {
02953
02954
02955
02956 node_ptr = page_rec_get_next(page_get_infimum_rec(merge_page));
02957
02958 ut_ad(page_rec_is_user_rec(node_ptr));
02959
02960
02961
02962
02963
02964
02965 btr_set_min_rec_mark(node_ptr, mtr);
02966 }
02967
02968 btr_node_ptr_delete(index, block, mtr);
02969
02970
02971 btr_level_list_remove(space, zip_size, page, mtr);
02972 #ifdef UNIV_ZIP_DEBUG
02973 {
02974 page_zip_des_t* merge_page_zip
02975 = buf_block_get_page_zip(merge_block);
02976 ut_a(!merge_page_zip
02977 || page_zip_validate(merge_page_zip, merge_page));
02978 }
02979 #endif
02980
02981 if (left_page_no != FIL_NULL) {
02982 lock_update_discard(merge_block, PAGE_HEAP_NO_SUPREMUM,
02983 block);
02984 } else {
02985 lock_update_discard(merge_block,
02986 lock_get_min_heap_no(merge_block),
02987 block);
02988 }
02989
02990
02991 btr_page_free(index, block, mtr);
02992
02993 ut_ad(btr_check_node_ptr(index, merge_block, mtr));
02994 }
02995
02996 #ifdef UNIV_BTR_PRINT
02997
02999 UNIV_INTERN
03000 void
03001 btr_print_size(
03002
03003 dict_index_t* index)
03004 {
03005 page_t* root;
03006 fseg_header_t* seg;
03007 mtr_t mtr;
03008
03009 if (dict_index_is_ibuf(index)) {
03010 fputs("Sorry, cannot print info of an ibuf tree:"
03011 " use ibuf functions\n", stderr);
03012
03013 return;
03014 }
03015
03016 mtr_start(&mtr);
03017
03018 root = btr_root_get(index, &mtr);
03019
03020 seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
03021
03022 fputs("INFO OF THE NON-LEAF PAGE SEGMENT\n", stderr);
03023 fseg_print(seg, &mtr);
03024
03025 if (!(index->type & DICT_UNIVERSAL)) {
03026
03027 seg = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
03028
03029 fputs("INFO OF THE LEAF PAGE SEGMENT\n", stderr);
03030 fseg_print(seg, &mtr);
03031 }
03032
03033 mtr_commit(&mtr);
03034 }
03035
03036
03038 static
03039 void
03040 btr_print_recursive(
03041
03042 dict_index_t* index,
03043 buf_block_t* block,
03044 ulint width,
03046 mem_heap_t** heap,
03047 ulint** offsets,
03048 mtr_t* mtr)
03049 {
03050 const page_t* page = buf_block_get_frame(block);
03051 page_cur_t cursor;
03052 ulint n_recs;
03053 ulint i = 0;
03054 mtr_t mtr2;
03055
03056 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
03057 fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n",
03058 (ulong) btr_page_get_level(page, mtr),
03059 (ulong) buf_block_get_page_no(block));
03060
03061 page_print(block, index, width, width);
03062
03063 n_recs = page_get_n_recs(page);
03064
03065 page_cur_set_before_first(block, &cursor);
03066 page_cur_move_to_next(&cursor);
03067
03068 while (!page_cur_is_after_last(&cursor)) {
03069
03070 if (page_is_leaf(page)) {
03071
03072
03073
03074 } else if ((i <= width) || (i >= n_recs - width)) {
03075
03076 const rec_t* node_ptr;
03077
03078 mtr_start(&mtr2);
03079
03080 node_ptr = page_cur_get_rec(&cursor);
03081
03082 *offsets = rec_get_offsets(node_ptr, index, *offsets,
03083 ULINT_UNDEFINED, heap);
03084 btr_print_recursive(index,
03085 btr_node_ptr_get_child(node_ptr,
03086 index,
03087 *offsets,
03088 &mtr2),
03089 width, heap, offsets, &mtr2);
03090 mtr_commit(&mtr2);
03091 }
03092
03093 page_cur_move_to_next(&cursor);
03094 i++;
03095 }
03096 }
03097
03098
03100 UNIV_INTERN
03101 void
03102 btr_print_index(
03103
03104 dict_index_t* index,
03105 ulint width)
03107 {
03108 mtr_t mtr;
03109 buf_block_t* root;
03110 mem_heap_t* heap = NULL;
03111 ulint offsets_[REC_OFFS_NORMAL_SIZE];
03112 ulint* offsets = offsets_;
03113 rec_offs_init(offsets_);
03114
03115 fputs("--------------------------\n"
03116 "INDEX TREE PRINT\n", stderr);
03117
03118 mtr_start(&mtr);
03119
03120 root = btr_root_block_get(index, &mtr);
03121
03122 btr_print_recursive(index, root, width, &heap, &offsets, &mtr);
03123 if (UNIV_LIKELY_NULL(heap)) {
03124 mem_heap_free(heap);
03125 }
03126
03127 mtr_commit(&mtr);
03128
03129 btr_validate_index(index, NULL);
03130 }
03131 #endif
03132
03133 #ifdef UNIV_DEBUG
03134
03137 UNIV_INTERN
03138 ibool
03139 btr_check_node_ptr(
03140
03141 dict_index_t* index,
03142 buf_block_t* block,
03143 mtr_t* mtr)
03144 {
03145 mem_heap_t* heap;
03146 dtuple_t* tuple;
03147 ulint* offsets;
03148 btr_cur_t cursor;
03149 page_t* page = buf_block_get_frame(block);
03150
03151 ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
03152 if (dict_index_get_page(index) == buf_block_get_page_no(block)) {
03153
03154 return(TRUE);
03155 }
03156
03157 heap = mem_heap_create(256);
03158 offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
03159 &cursor);
03160
03161 if (page_is_leaf(page)) {
03162
03163 goto func_exit;
03164 }
03165
03166 tuple = dict_index_build_node_ptr(
03167 index, page_rec_get_next(page_get_infimum_rec(page)), 0, heap,
03168 btr_page_get_level(page, mtr));
03169
03170 ut_a(!cmp_dtuple_rec(tuple, btr_cur_get_rec(&cursor), offsets));
03171 func_exit:
03172 mem_heap_free(heap);
03173
03174 return(TRUE);
03175 }
03176 #endif
03177
03178
03180 static
03181 void
03182 btr_index_rec_validate_report(
03183
03184 const page_t* page,
03185 const rec_t* rec,
03186 const dict_index_t* index)
03187 {
03188 fputs("InnoDB: Record in ", stderr);
03189 dict_index_name_print(stderr, NULL, index);
03190 fprintf(stderr, ", page %lu, at offset %lu\n",
03191 page_get_page_no(page), (ulint) page_offset(rec));
03192 }
03193
03194
03198 UNIV_INTERN
03199 ibool
03200 btr_index_rec_validate(
03201
03202 const rec_t* rec,
03203 const dict_index_t* index,
03204 ibool dump_on_error)
03207 {
03208 ulint len;
03209 ulint n;
03210 ulint i;
03211 const page_t* page;
03212 mem_heap_t* heap = NULL;
03213 ulint offsets_[REC_OFFS_NORMAL_SIZE];
03214 ulint* offsets = offsets_;
03215 rec_offs_init(offsets_);
03216
03217 page = page_align(rec);
03218
03219 if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
03220
03221
03222
03223
03224 return(TRUE);
03225 }
03226
03227 if (UNIV_UNLIKELY((ibool)!!page_is_comp(page)
03228 != dict_table_is_comp(index->table))) {
03229 btr_index_rec_validate_report(page, rec, index);
03230 fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
03231 (ulong) !!page_is_comp(page),
03232 (ulong) dict_table_is_comp(index->table));
03233
03234 return(FALSE);
03235 }
03236
03237 n = dict_index_get_n_fields(index);
03238
03239 if (!page_is_comp(page)
03240 && UNIV_UNLIKELY(rec_get_n_fields_old(rec) != n)) {
03241 btr_index_rec_validate_report(page, rec, index);
03242 fprintf(stderr, "InnoDB: has %lu fields, should have %lu\n",
03243 (ulong) rec_get_n_fields_old(rec), (ulong) n);
03244
03245 if (dump_on_error) {
03246 buf_page_print(page, 0);
03247
03248 fputs("InnoDB: corrupt record ", stderr);
03249 rec_print_old(stderr, rec);
03250 putc('\n', stderr);
03251 }
03252 return(FALSE);
03253 }
03254
03255 offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
03256
03257 for (i = 0; i < n; i++) {
03258 ulint fixed_size = dict_col_get_fixed_size(
03259 dict_index_get_nth_col(index, i), page_is_comp(page));
03260
03261 rec_get_nth_field_offs(offsets, i, &len);
03262
03263
03264
03265
03266
03267
03268
03269 if ((dict_index_get_nth_field(index, i)->prefix_len == 0
03270 && len != UNIV_SQL_NULL && fixed_size
03271 && len != fixed_size)
03272 || (dict_index_get_nth_field(index, i)->prefix_len > 0
03273 && len != UNIV_SQL_NULL
03274 && len
03275 > dict_index_get_nth_field(index, i)->prefix_len)) {
03276
03277 btr_index_rec_validate_report(page, rec, index);
03278 fprintf(stderr,
03279 "InnoDB: field %lu len is %lu,"
03280 " should be %lu\n",
03281 (ulong) i, (ulong) len, (ulong) fixed_size);
03282
03283 if (dump_on_error) {
03284 buf_page_print(page, 0);
03285
03286 fputs("InnoDB: corrupt record ", stderr);
03287 rec_print_new(stderr, rec, offsets);
03288 putc('\n', stderr);
03289 }
03290 if (UNIV_LIKELY_NULL(heap)) {
03291 mem_heap_free(heap);
03292 }
03293 return(FALSE);
03294 }
03295 }
03296
03297 if (UNIV_LIKELY_NULL(heap)) {
03298 mem_heap_free(heap);
03299 }
03300 return(TRUE);
03301 }
03302
03303
03307 static
03308 ibool
03309 btr_index_page_validate(
03310
03311 buf_block_t* block,
03312 dict_index_t* index)
03313 {
03314 page_cur_t cur;
03315 ibool ret = TRUE;
03316
03317 page_cur_set_before_first(block, &cur);
03318 page_cur_move_to_next(&cur);
03319
03320 for (;;) {
03321 if (page_cur_is_after_last(&cur)) {
03322
03323 break;
03324 }
03325
03326 if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
03327
03328 return(FALSE);
03329 }
03330
03331 page_cur_move_to_next(&cur);
03332 }
03333
03334 return(ret);
03335 }
03336
03337
03339 static
03340 void
03341 btr_validate_report1(
03342
03343 dict_index_t* index,
03344 ulint level,
03345 const buf_block_t* block)
03346 {
03347 fprintf(stderr, "InnoDB: Error in page %lu of ",
03348 buf_block_get_page_no(block));
03349 dict_index_name_print(stderr, NULL, index);
03350 if (level) {
03351 fprintf(stderr, ", index tree level %lu", level);
03352 }
03353 putc('\n', stderr);
03354 }
03355
03356
03358 static
03359 void
03360 btr_validate_report2(
03361
03362 const dict_index_t* index,
03363 ulint level,
03364 const buf_block_t* block1,
03365 const buf_block_t* block2)
03366 {
03367 fprintf(stderr, "InnoDB: Error in pages %lu and %lu of ",
03368 buf_block_get_page_no(block1),
03369 buf_block_get_page_no(block2));
03370 dict_index_name_print(stderr, NULL, index);
03371 if (level) {
03372 fprintf(stderr, ", index tree level %lu", level);
03373 }
03374 putc('\n', stderr);
03375 }
03376
03377
03380 static
03381 ibool
03382 btr_validate_level(
03383
03384 dict_index_t* index,
03385 trx_t* trx,
03386 ulint level)
03387 {
03388 ulint space;
03389 ulint zip_size;
03390 buf_block_t* block;
03391 page_t* page;
03392 buf_block_t* right_block = 0;
03393 page_t* right_page = 0;
03394 page_t* father_page;
03395 btr_cur_t node_cur;
03396 btr_cur_t right_node_cur;
03397 rec_t* rec;
03398 ulint right_page_no;
03399 ulint left_page_no;
03400 page_cur_t cursor;
03401 dtuple_t* node_ptr_tuple;
03402 ibool ret = TRUE;
03403 mtr_t mtr;
03404 mem_heap_t* heap = mem_heap_create(256);
03405 ulint* offsets = NULL;
03406 ulint* offsets2= NULL;
03407 #ifdef UNIV_ZIP_DEBUG
03408 page_zip_des_t* page_zip;
03409 #endif
03410
03411 mtr_start(&mtr);
03412
03413 mtr_x_lock(dict_index_get_lock(index), &mtr);
03414
03415 block = btr_root_block_get(index, &mtr);
03416 page = buf_block_get_frame(block);
03417
03418 space = dict_index_get_space(index);
03419 zip_size = dict_table_zip_size(index->table);
03420
03421 while (level != btr_page_get_level(page, &mtr)) {
03422 const rec_t* node_ptr;
03423
03424 ut_a(space == buf_block_get_space(block));
03425 ut_a(space == page_get_space_id(page));
03426 #ifdef UNIV_ZIP_DEBUG
03427 page_zip = buf_block_get_page_zip(block);
03428 ut_a(!page_zip || page_zip_validate(page_zip, page));
03429 #endif
03430 ut_a(!page_is_leaf(page));
03431
03432 page_cur_set_before_first(block, &cursor);
03433 page_cur_move_to_next(&cursor);
03434
03435 node_ptr = page_cur_get_rec(&cursor);
03436 offsets = rec_get_offsets(node_ptr, index, offsets,
03437 ULINT_UNDEFINED, &heap);
03438 block = btr_node_ptr_get_child(node_ptr, index, offsets, &mtr);
03439 page = buf_block_get_frame(block);
03440 }
03441
03442
03443
03444 loop:
03445 if (trx_is_interrupted(trx)) {
03446 mtr_commit(&mtr);
03447 mem_heap_free(heap);
03448 return(ret);
03449 }
03450 mem_heap_empty(heap);
03451 offsets = offsets2 = NULL;
03452 mtr_x_lock(dict_index_get_lock(index), &mtr);
03453
03454 #ifdef UNIV_ZIP_DEBUG
03455 page_zip = buf_block_get_page_zip(block);
03456 ut_a(!page_zip || page_zip_validate(page_zip, page));
03457 #endif
03458
03459
03460
03461 if (!page_validate(page, index)) {
03462 btr_validate_report1(index, level, block);
03463
03464 ret = FALSE;
03465 } else if (level == 0) {
03466
03467
03468
03469 if (!btr_index_page_validate(block, index)) {
03470
03471 ret = FALSE;
03472 }
03473 }
03474
03475 ut_a(btr_page_get_level(page, &mtr) == level);
03476
03477 right_page_no = btr_page_get_next(page, &mtr);
03478 left_page_no = btr_page_get_prev(page, &mtr);
03479
03480 ut_a(page_get_n_recs(page) > 0 || (level == 0
03481 && page_get_page_no(page)
03482 == dict_index_get_page(index)));
03483
03484 if (right_page_no != FIL_NULL) {
03485 const rec_t* right_rec;
03486 right_block = btr_block_get(space, zip_size, right_page_no,
03487 RW_X_LATCH, &mtr);
03488 right_page = buf_block_get_frame(right_block);
03489 if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
03490 != page_get_page_no(page))) {
03491 btr_validate_report2(index, level, block, right_block);
03492 fputs("InnoDB: broken FIL_PAGE_NEXT"
03493 " or FIL_PAGE_PREV links\n", stderr);
03494 buf_page_print(page, 0);
03495 buf_page_print(right_page, 0);
03496
03497 ret = FALSE;
03498 }
03499
03500 if (UNIV_UNLIKELY(page_is_comp(right_page)
03501 != page_is_comp(page))) {
03502 btr_validate_report2(index, level, block, right_block);
03503 fputs("InnoDB: 'compact' flag mismatch\n", stderr);
03504 buf_page_print(page, 0);
03505 buf_page_print(right_page, 0);
03506
03507 ret = FALSE;
03508
03509 goto node_ptr_fails;
03510 }
03511
03512 rec = page_rec_get_prev(page_get_supremum_rec(page));
03513 right_rec = page_rec_get_next(page_get_infimum_rec(
03514 right_page));
03515 offsets = rec_get_offsets(rec, index,
03516 offsets, ULINT_UNDEFINED, &heap);
03517 offsets2 = rec_get_offsets(right_rec, index,
03518 offsets2, ULINT_UNDEFINED, &heap);
03519 if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
03520 offsets, offsets2,
03521 index) >= 0)) {
03522
03523 btr_validate_report2(index, level, block, right_block);
03524
03525 fputs("InnoDB: records in wrong order"
03526 " on adjacent pages\n", stderr);
03527
03528 buf_page_print(page, 0);
03529 buf_page_print(right_page, 0);
03530
03531 fputs("InnoDB: record ", stderr);
03532 rec = page_rec_get_prev(page_get_supremum_rec(page));
03533 rec_print(stderr, rec, index);
03534 putc('\n', stderr);
03535 fputs("InnoDB: record ", stderr);
03536 rec = page_rec_get_next(
03537 page_get_infimum_rec(right_page));
03538 rec_print(stderr, rec, index);
03539 putc('\n', stderr);
03540
03541 ret = FALSE;
03542 }
03543 }
03544
03545 if (level > 0 && left_page_no == FIL_NULL) {
03546 ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
03547 page_rec_get_next(page_get_infimum_rec(page)),
03548 page_is_comp(page)));
03549 }
03550
03551 if (buf_block_get_page_no(block) != dict_index_get_page(index)) {
03552
03553
03554
03555 rec_t* node_ptr;
03556
03557 offsets = btr_page_get_father_block(offsets, heap, index,
03558 block, &mtr, &node_cur);
03559 father_page = btr_cur_get_page(&node_cur);
03560 node_ptr = btr_cur_get_rec(&node_cur);
03561
03562 btr_cur_position(
03563 index, page_rec_get_prev(page_get_supremum_rec(page)),
03564 block, &node_cur);
03565 offsets = btr_page_get_father_node_ptr(offsets, heap,
03566 &node_cur, &mtr);
03567
03568 if (UNIV_UNLIKELY(node_ptr != btr_cur_get_rec(&node_cur))
03569 || UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr,
03570 offsets)
03571 != buf_block_get_page_no(block))) {
03572
03573 btr_validate_report1(index, level, block);
03574
03575 fputs("InnoDB: node pointer to the page is wrong\n",
03576 stderr);
03577
03578 buf_page_print(father_page, 0);
03579 buf_page_print(page, 0);
03580
03581 fputs("InnoDB: node ptr ", stderr);
03582 rec_print(stderr, node_ptr, index);
03583
03584 rec = btr_cur_get_rec(&node_cur);
03585 fprintf(stderr, "\n"
03586 "InnoDB: node ptr child page n:o %lu\n",
03587 (ulong) btr_node_ptr_get_child_page_no(
03588 rec, offsets));
03589
03590 fputs("InnoDB: record on page ", stderr);
03591 rec_print_new(stderr, rec, offsets);
03592 putc('\n', stderr);
03593 ret = FALSE;
03594
03595 goto node_ptr_fails;
03596 }
03597
03598 if (!page_is_leaf(page)) {
03599 node_ptr_tuple = dict_index_build_node_ptr(
03600 index,
03601 page_rec_get_next(page_get_infimum_rec(page)),
03602 0, heap, btr_page_get_level(page, &mtr));
03603
03604 if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
03605 offsets)) {
03606 const rec_t* first_rec = page_rec_get_next(
03607 page_get_infimum_rec(page));
03608
03609 btr_validate_report1(index, level, block);
03610
03611 buf_page_print(father_page, 0);
03612 buf_page_print(page, 0);
03613
03614 fputs("InnoDB: Error: node ptrs differ"
03615 " on levels > 0\n"
03616 "InnoDB: node ptr ", stderr);
03617 rec_print_new(stderr, node_ptr, offsets);
03618 fputs("InnoDB: first rec ", stderr);
03619 rec_print(stderr, first_rec, index);
03620 putc('\n', stderr);
03621 ret = FALSE;
03622
03623 goto node_ptr_fails;
03624 }
03625 }
03626
03627 if (left_page_no == FIL_NULL) {
03628 ut_a(node_ptr == page_rec_get_next(
03629 page_get_infimum_rec(father_page)));
03630 ut_a(btr_page_get_prev(father_page, &mtr) == FIL_NULL);
03631 }
03632
03633 if (right_page_no == FIL_NULL) {
03634 ut_a(node_ptr == page_rec_get_prev(
03635 page_get_supremum_rec(father_page)));
03636 ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
03637 } else {
03638 const rec_t* right_node_ptr
03639 = page_rec_get_next(node_ptr);
03640
03641 offsets = btr_page_get_father_block(
03642 offsets, heap, index, right_block,
03643 &mtr, &right_node_cur);
03644 if (right_node_ptr
03645 != page_get_supremum_rec(father_page)) {
03646
03647 if (btr_cur_get_rec(&right_node_cur)
03648 != right_node_ptr) {
03649 ret = FALSE;
03650 fputs("InnoDB: node pointer to"
03651 " the right page is wrong\n",
03652 stderr);
03653
03654 btr_validate_report1(index, level,
03655 block);
03656
03657 buf_page_print(father_page, 0);
03658 buf_page_print(page, 0);
03659 buf_page_print(right_page, 0);
03660 }
03661 } else {
03662 page_t* right_father_page
03663 = btr_cur_get_page(&right_node_cur);
03664
03665 if (btr_cur_get_rec(&right_node_cur)
03666 != page_rec_get_next(
03667 page_get_infimum_rec(
03668 right_father_page))) {
03669 ret = FALSE;
03670 fputs("InnoDB: node pointer 2 to"
03671 " the right page is wrong\n",
03672 stderr);
03673
03674 btr_validate_report1(index, level,
03675 block);
03676
03677 buf_page_print(father_page, 0);
03678 buf_page_print(right_father_page, 0);
03679 buf_page_print(page, 0);
03680 buf_page_print(right_page, 0);
03681 }
03682
03683 if (page_get_page_no(right_father_page)
03684 != btr_page_get_next(father_page, &mtr)) {
03685
03686 ret = FALSE;
03687 fputs("InnoDB: node pointer 3 to"
03688 " the right page is wrong\n",
03689 stderr);
03690
03691 btr_validate_report1(index, level,
03692 block);
03693
03694 buf_page_print(father_page, 0);
03695 buf_page_print(right_father_page, 0);
03696 buf_page_print(page, 0);
03697 buf_page_print(right_page, 0);
03698 }
03699 }
03700 }
03701 }
03702
03703 node_ptr_fails:
03704
03705
03706
03707 mtr_commit(&mtr);
03708
03709 if (right_page_no != FIL_NULL) {
03710 mtr_start(&mtr);
03711
03712 block = btr_block_get(space, zip_size, right_page_no,
03713 RW_X_LATCH, &mtr);
03714 page = buf_block_get_frame(block);
03715
03716 goto loop;
03717 }
03718
03719 mem_heap_free(heap);
03720 return(ret);
03721 }
03722
03723
03726 UNIV_INTERN
03727 ibool
03728 btr_validate_index(
03729
03730 dict_index_t* index,
03731 trx_t* trx)
03732 {
03733 mtr_t mtr;
03734 page_t* root;
03735 ulint i;
03736 ulint n;
03737
03738 mtr_start(&mtr);
03739 mtr_x_lock(dict_index_get_lock(index), &mtr);
03740
03741 root = btr_root_get(index, &mtr);
03742 n = btr_page_get_level(root, &mtr);
03743
03744 for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {
03745 if (!btr_validate_level(index, trx, n - i)) {
03746
03747 mtr_commit(&mtr);
03748
03749 return(FALSE);
03750 }
03751 }
03752
03753 mtr_commit(&mtr);
03754
03755 return(TRUE);
03756 }
03757 #endif