Drizzled Public API Documentation

btr0btr.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1994, 2010, Innobase Oy. All Rights Reserved.
00004 
00005 This program is free software; you can redistribute it and/or modify it under
00006 the terms of the GNU General Public License as published by the Free Software
00007 Foundation; version 2 of the License.
00008 
00009 This program is distributed in the hope that it will be useful, but WITHOUT
00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 
00013 You should have received a copy of the GNU General Public License along with
00014 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00015 St, Fifth Floor, Boston, MA 02110-1301 USA
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 Latching strategy of the InnoDB B-tree
00048 --------------------------------------
00049 A tree latch protects all non-leaf nodes of the tree. Each node of a tree
00050 also has a latch of its own.
00051 
00052 A B-tree operation normally first acquires an S-latch on the tree. It
00053 searches down the tree and releases the tree latch when it has the
00054 leaf node latch. To save CPU time we do not acquire any latch on
00055 non-leaf nodes of the tree during a search, those pages are only bufferfixed.
00056 
00057 If an operation needs to restructure the tree, it acquires an X-latch on
00058 the tree before searching to a leaf node. If it needs, for example, to
00059 split a leaf,
00060 (1) InnoDB decides the split point in the leaf,
00061 (2) allocates a new page,
00062 (3) inserts the appropriate node pointer to the first non-leaf level,
00063 (4) releases the tree X-latch,
00064 (5) and then moves records from the leaf to the new allocated page.
00065 
00066 Node pointers
00067 -------------
00068 Leaf pages of a B-tree contain the index records stored in the
00069 tree. On levels n > 0 we store 'node pointers' to pages on level
00070 n - 1. For each page there is exactly one node pointer stored:
00071 thus the our tree is an ordinary B-tree, not a B-link tree.
00072 
00073 A node pointer contains a prefix P of an index record. The prefix
00074 is long enough so that it determines an index record uniquely.
00075 The file page number of the child page is added as the last
00076 field. To the child page we can store node pointers or index records
00077 which are >= P in the alphabetical order, but < P1 if there is
00078 a next node pointer on the level, and P1 is its prefix.
00079 
00080 If a node pointer with a prefix P points to a non-leaf child,
00081 then the leftmost record in the child must have the same
00082 prefix P. If it points to a leaf node, the child is not required
00083 to contain any record with a prefix equal to P. The leaf case
00084 is decided this way to allow arbitrary deletions in a leaf node
00085 without touching upper levels of the tree.
00086 
00087 We have predefined a special minimum record which we
00088 define as the smallest record in any alphabetical order.
00089 A minimum record is denoted by setting a bit in the record
00090 header. A minimum record acts as the prefix of a node pointer
00091 which points to a leftmost node on any level of the tree.
00092 
00093 File page allocation
00094 --------------------
00095 In the root node of a B-tree there are two file segment headers.
00096 The leaf pages of a tree are allocated from one file segment, to
00097 make them consecutive on disk if possible. From the other file segment
00098 we allocate pages for the non-leaf levels of the tree.
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 /* UNIV_BTR_DEBUG */
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 /* UNIV_BTR_DEBUG */
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     /* The caller must already have a latch to the brother */
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 /* UNIV_BTR_DEBUG */
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     /* The caller must already have a latch to the brother */
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 /* UNIV_BTR_DEBUG */
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     /* Set the level of the new index page */
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   /* Parameter TRUE below states that the caller has made the
00385   reservation for free extents, and thus we know that a page can
00386   be allocated: */
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   /* The page gets invalid for optimistic searches: increment the frame
00489   modify clock */
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   /* The child address is in the last field */
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   /* Create the two new segments (one, in the case of an ibuf tree) for
00748   the index tree; the segment headers are put on the allocated root page
00749   (for an ibuf tree, not in the root, but on a separate ibuf header
00750   page) */
00751 
00752   if (type & DICT_IBUF) {
00753     /* Allocate first the ibuf header page */
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     /* Allocate then the next page to the segment: it will be the
00763     tree root page */
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     /* It is an insert buffer tree: initialize the free list */
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     /* It is a non-ibuf tree: create a file segment for leaf
00798     pages */
00799     if (!fseg_create(space, page_no,
00800          PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) {
00801       /* Not enough space for new segment, free root
00802       segment before return. */
00803       btr_free_root(space, zip_size, page_no, mtr);
00804 
00805       return(FIL_NULL);
00806     }
00807 
00808     /* The fseg create acquires a second latch on the page,
00809     therefore we must declare it: */
00810     buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
00811   }
00812 
00813   /* Create a new index page on the the allocated segment page */
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     /* Set the level of the new index page */
00822     btr_page_set_level(page, NULL, 0, mtr);
00823   }
00824 
00825   block->check_index_page_at_flush = TRUE;
00826 
00827   /* Set the index id of the page */
00828   btr_page_set_index_id(page, page_zip, index_id, mtr);
00829 
00830   /* Set the next node and previous node fields */
00831   btr_page_set_next(page, page_zip, FIL_NULL, mtr);
00832   btr_page_set_prev(page, page_zip, FIL_NULL, mtr);
00833 
00834   /* We reset the free bits for the page to allow creation of several
00835   trees in the same mtr, otherwise the latch on a bitmap page would
00836   prevent it because of the latching order */
00837 
00838   if (!(type & DICT_CLUSTERED)) {
00839     ibuf_reset_free_bits(block);
00840   }
00841 
00842   /* In the following assertion we test that two records of maximum
00843   allowed size fit on the root page: this fact is needed to ensure
00844   correctness of split algorithms */
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 /* UNIV_BTR_DEBUG */
00877 
00878   /* NOTE: page hash indexes are dropped when a page is freed inside
00879   fsp0fsp. */
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 /* UNIV_BTR_DEBUG */
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 /* UNIV_BTR_DEBUG */
00932 
00933   while (!fseg_free_step(header, mtr)) {};
00934 }
00935 #endif /* !UNIV_HOTBACKUP */
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 /* UNIV_ZIP_DEBUG */
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   /* Write the log record */
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 /* !UNIV_HOTBACKUP */
00978 
00979   /* Turn logging off */
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 /* !UNIV_HOTBACKUP */
00985   ut_ad(block == back_block1);
00986   temp_block = back_block2;
00987 #endif /* !UNIV_HOTBACKUP */
00988   temp_page = temp_block->frame;
00989 
00990   /* Copy the old page to temporary space */
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 /* !UNIV_HOTBACKUP */
01000 
01001   /* Recreate the page: note that global data on page (possible
01002   segment headers, next page-field, etc.) is preserved intact */
01003 
01004   page_create(block, mtr, dict_table_is_comp(index->table));
01005 
01006   /* Copy the records from the temporary space to the recreated page;
01007   do not copy the lock bits yet */
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     /* Copy max trx id to recreated page */
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     /* In crash recovery, dict_index_is_sec_or_ibuf() always
01018     returns TRUE, even for clustered indexes.  max_trx_id is
01019     unused in clustered index pages. */
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     /* Restore the old page and exit. */
01028 
01029 #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
01030     /* Check that the bytes that we skip are identical. */
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 /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
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 /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
01048 
01049     goto func_exit;
01050   }
01051 
01052 #ifndef UNIV_HOTBACKUP
01053   if (UNIV_LIKELY(!recovery)) {
01054     /* Update the record lock bitmaps */
01055     lock_move_reorganize_page(block, temp_block);
01056   }
01057 #endif /* !UNIV_HOTBACKUP */
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 /* UNIV_ZIP_DEBUG */
01084 #ifndef UNIV_HOTBACKUP
01085   buf_block_free(temp_block);
01086 #endif /* !UNIV_HOTBACKUP */
01087 
01088   /* Restore logging mode */
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 /* !UNIV_HOTBACKUP */
01113 
01114 /***********************************************************/
01117 UNIV_INTERN
01118 byte*
01119 btr_parse_page_reorganize(
01120 /*======================*/
01121   byte*   ptr,  
01122   byte*   /*end_ptr __attribute__((unused))*/,
01124   dict_index_t* index,  
01125   buf_block_t*  block,  
01126   mtr_t*    mtr)  
01127 {
01128   ut_ad(ptr && end_ptr);
01129 
01130   /* The record is empty, except for the record initial part */
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 /* UNIV_ZIP_DEBUG */
01159 
01160   btr_search_drop_page_hash_index(block);
01161 
01162   /* Recreate the page: note that global data on page (possible
01163   segment headers, next page-field, etc.) is preserved intact */
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 /* UNIV_ZIP_DEBUG */
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 /* UNIV_BTR_DEBUG */
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   /* Allocate a new page to the tree. Root splitting is done by first
01233   moving the root records to the new page, emptying the root, putting
01234   a node pointer to the new page, and then splitting the new page. */
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   /* Set the next node and previous node fields of new page */
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   /* Copy the records from root to the new page one by one. */
01253 
01254   if (0
01255 #ifdef UNIV_ZIP_COPY
01256       || new_page_zip
01257 #endif /* UNIV_ZIP_COPY */
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     /* Copy the page byte for byte. */
01265     page_zip_copy_recs(new_page_zip, new_page,
01266            root_page_zip, root, index, mtr);
01267 
01268     /* Update the lock table and possible hash index. */
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   /* If this is a pessimistic insert which is actually done to
01278   perform a pessimistic update then we have stored the lock
01279   information of the record to be inserted on the infimum of the
01280   root page: we cannot discard the lock structs on the root page */
01281 
01282   lock_update_root_raise(new_block, root_block);
01283 
01284   /* Create a memory heap where the node pointer is stored */
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   /* Build the node pointer (= node key and page address) for the
01291   child */
01292 
01293   node_ptr = dict_index_build_node_ptr(index, rec, new_page_no, heap,
01294                level);
01295   /* The node pointer must be marked as the predefined minimum record,
01296   as there is no lower alphabetical limit to records in the leftmost
01297   node of a level: */
01298   dtuple_set_info_bits(node_ptr,
01299            dtuple_get_info_bits(node_ptr)
01300            | REC_INFO_MIN_REC_FLAG);
01301 
01302   /* Rebuild the root page to get free space */
01303   btr_page_empty(root_block, root_page_zip, index, level + 1, mtr);
01304 
01305   /* Set the next node and previous node fields, although
01306   they should already have been set.  The previous node field
01307   must be FIL_NULL if root_page_zip != NULL, because the
01308   REC_INFO_MIN_REC_FLAG (of the first user record) will be
01309   set if and only if btr_page_get_prev() == FIL_NULL. */
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   /* Insert node pointer to the root */
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   /* The root page should only contain the node pointer
01323   to new_page at this point.  Thus, the data should fit. */
01324   ut_a(node_ptr_rec);
01325 
01326   /* Free the memory heap */
01327   mem_heap_free(heap);
01328 
01329   /* We play safe and reset the free bits for the new page */
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   /* Reposition the cursor to the child node */
01340   page_cur_search(new_block, index, tuple,
01341       PAGE_CUR_LE, page_cursor);
01342 
01343   /* Split the child and insert tuple */
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     /* If the convergence is in the middle of a page, include also
01374     the record immediately before the new insert to the upper
01375     page. Otherwise, we could repeatedly move from page to page
01376     lots of records smaller than the convergence point. */
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   /* We use eager heuristics: if the new insert would be right after
01413   the previous insert on the same page, we assume that there is a
01414   pattern of sequential inserts here. */
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       /* Split at the new record to insert */
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       /* If there are >= 2 user records up from the insert
01435       point, split all but 1 off. We want to keep one because
01436       then sequential inserts can use the adaptive hash
01437       index, as they can do the necessary checks of the right
01438       search position just by looking at the records on this
01439       page. */
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     /* Estimate the free space of an empty compressed page. */
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   /* free_space is now the free space of a created new page */
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   /* We start to include records to the left half, and when the
01512   space reserved by them exceeds half of total_space, then if
01513   the included records fit on the left page, they will be put there
01514   if something was left over also for the right page,
01515   otherwise the last included record will be the first on the right
01516   half page */
01517 
01518   do {
01519     /* Decide the next record to include */
01520     if (rec == ins_rec) {
01521       rec = NULL; /* NULL denotes that tuple is
01522           now included */
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       /* Include tuple */
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     /* The next record will be the first on
01545     the right half page if it is not the
01546     supremum record of page */
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   /* free_space is now the free space of a created new page */
01610 
01611   total_data   = page_get_data_size(page) + insert_size;
01612   total_n_recs = page_get_n_recs(page) + 1;
01613 
01614   /* We determine which records (from rec to end_rec, not including
01615   end_rec) will end up on the other half page from tuple when it is
01616   inserted. */
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     /* Ok, there will be enough available space on the
01635     half page where the tuple is inserted */
01636 
01637     return(TRUE);
01638   }
01639 
01640   offs = NULL;
01641 
01642   while (rec != end_rec) {
01643     /* In this loop we calculate the amount of reserved
01644     space after rec is removed from page. */
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       /* Ok, there will be enough available space on the
01656       half page where the tuple is inserted */
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   /* Create a memory heap where the data tuple is stored */
01734   heap = mem_heap_create(1024);
01735 
01736   /* Based on split direction, decide upper and lower pages */
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     /* Look up the index for the node pointer to page */
01750     offsets = btr_page_get_father_block(NULL, heap, index,
01751                 block, mtr, &cursor);
01752 
01753     /* Replace the address of the old child node (= page) with the
01754     address of the new lower half */
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   /* Get the level of the split pages */
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   /* Build the node pointer (= node key and page address) for the upper
01776   half */
01777 
01778   node_ptr_upper = dict_index_build_node_ptr(index, split_rec,
01779                upper_page_no, heap, level);
01780 
01781   /* Insert it next to the pointer to the lower half. Note that this
01782   may generate recursion leading to a split on the higher level. */
01783 
01784   btr_insert_on_non_leaf_level(index, level + 1, node_ptr_upper, mtr);
01785 
01786   /* Free the memory heap */
01787   mem_heap_free(heap);
01788 
01789   /* Get the previous and next pages of page */
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   /* Update page links of the level */
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 /* UNIV_BTR_DEBUG */
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 /* UNIV_BTR_DEBUG */
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   /* Read the first user record in the page. */
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; /* remove warning */
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 /* UNIV_SYNC_DEBUG */
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   /* 1. Decide the split record; split_rec == NULL means that the
01933   tuple to be inserted should be the first record on the upper
01934   half-page */
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     /* If there is only one record in the index page, we
01957     can't split the node in the middle by default. We need
01958     to determine whether the new record will be inserted
01959     to the left or right. */
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   /* 2. Allocate a new page to the index */
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   /* 3. Calculate the first record on the upper half-page, and the
01981   first record (move_limit) on original page which ends up on the
01982   upper half */
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       /* If a compressed page has already been split,
01995       avoid further splits by inserting the record
01996       to an empty page. */
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   /* 4. Do first the modifications in the tree structure */
02017 
02018   btr_attach_half_pages(cursor->index, block,
02019             first_rec, new_block, direction, mtr);
02020 
02021   /* If the split is made on the leaf level and the insert will fit
02022   on the appropriate half-page, we may release the tree x-latch.
02023   We can then move the records after releasing the tree latch,
02024   thus reducing the tree latch contention. */
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   /* 5. Move then the records to the new page */
02048   if (direction == FSP_DOWN) {
02049     /*    fputs("Split left\n", stderr); */
02050 
02051     if (0
02052 #ifdef UNIV_ZIP_COPY
02053         || page_zip
02054 #endif /* UNIV_ZIP_COPY */
02055         || UNIV_UNLIKELY
02056         (!page_move_rec_list_start(new_block, block, move_limit,
02057                  cursor->index, mtr))) {
02058       /* For some reason, compressing new_page failed,
02059       even though it should contain fewer records than
02060       the original page.  Copy the page byte for byte
02061       and then delete the records from both pages
02062       as appropriate.  Deleting will always succeed. */
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       /* Update the lock table and possible hash index. */
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       /* Delete the records from the source page. */
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     /*    fputs("Split right\n", stderr); */
02093 
02094     if (0
02095 #ifdef UNIV_ZIP_COPY
02096         || page_zip
02097 #endif /* UNIV_ZIP_COPY */
02098         || UNIV_UNLIKELY
02099         (!page_move_rec_list_end(new_block, block, move_limit,
02100                cursor->index, mtr))) {
02101       /* For some reason, compressing new_page failed,
02102       even though it should contain fewer records than
02103       the original page.  Copy the page byte for byte
02104       and then delete the records from both pages
02105       as appropriate.  Deleting will always succeed. */
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       /* Update the lock table and possible hash index. */
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       /* Delete the records from the source page. */
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 /* UNIV_ZIP_DEBUG */
02141 
02142   /* At this point, split_rec, move_limit and first_rec may point
02143   to garbage on the old page. */
02144 
02145   /* 6. The split and the tree modification is now completed. Decide the
02146   page where the tuple should be inserted */
02147 
02148   if (insert_left) {
02149     insert_block = left_block;
02150   } else {
02151     insert_block = right_block;
02152   }
02153 
02154   /* 7. Reposition the cursor for insert and try insertion */
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 /* UNIV_ZIP_DEBUG */
02175 
02176   if (UNIV_LIKELY(rec != NULL)) {
02177 
02178     goto func_exit;
02179   }
02180 
02181   /* 8. If insert did not fit, try page reorganization */
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     /* The insert did not fit on the page: loop back to the
02196     start of the function for a new split */
02197 insert_failed:
02198     /* We play safe and reset the free bits for new_page */
02199     if (!dict_index_is_clust(cursor->index)) {
02200       ibuf_reset_free_bits(new_block);
02201     }
02202 
02203     /* fprintf(stderr, "Split second round %lu\n",
02204     page_get_page_no(page)); */
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   /* Insert fit on the page: update the free bits for the
02215   left and right pages in the same mtr */
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   /* Get the previous and next page numbers of page */
02255 
02256   prev_page_no = btr_page_get_prev(page, mtr);
02257   next_page_no = btr_page_get_next(page, mtr);
02258 
02259   /* Update page links of the level */
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 /* UNIV_BTR_DEBUG */
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 /* UNIV_BTR_DEBUG */
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   /* Write rec offset as a 2-byte ulint */
02310   mlog_catenate_ulint(mtr, page_offset(rec), MLOG_2BYTES);
02311 }
02312 #else /* !UNIV_HOTBACKUP */
02313 # define btr_set_min_rec_mark_log(rec,comp,mtr) ((void) 0)
02314 #endif /* !UNIV_HOTBACKUP */
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   /* Delete node pointer on father page */
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     /* Store all ancestor pages so we can reset their
02449     levels later on.  We have to do all the searches on
02450     the tree now because later on, after we've replaced
02451     the first level, the tree is in an inconsistent state
02452     and can not be searched. */
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   /* Make the father empty */
02470   btr_page_empty(father_block, father_page_zip, index, page_level, mtr);
02471 
02472   /* Copy the records to the father page one by one. */
02473   if (0
02474 #ifdef UNIV_ZIP_COPY
02475       || father_page_zip
02476 #endif /* UNIV_ZIP_COPY */
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     /* Copy the page byte for byte. */
02487     page_zip_copy_recs(father_page_zip, father_page,
02488            page_zip, page, index, mtr);
02489 
02490     /* Update the lock table and possible hash index. */
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   /* Go upward to root page, decrementing levels by one. */
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 /* UNIV_ZIP_DEBUG */
02512   }
02513 
02514   /* Free the file page */
02515   btr_page_free(index, block, mtr);
02516 
02517   /* We play it safe and reset the free bits for the father */
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   /* Decide the page to which we try to merge and which will inherit
02588   the locks */
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 /* UNIV_BTR_DEBUG */
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 /* UNIV_BTR_DEBUG */
02610   } else {
02611     /* The page is the only one on the level, lift the records
02612     to the father */
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 /* UNIV_BTR_DEBUG */
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     /* No space for merge */
02629 err_exit:
02630     /* We play it safe and reset the free bits. */
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     /* We have to reorganize merge_page */
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       /* Add fault tolerance, though this should
02663       never happen */
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 /* UNIV_ZIP_DEBUG */
02679 
02680   /* Move records to the merge page */
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     /* Remove the page from the level list */
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 /* UNIV_BTR_DEBUG */
02702 
02703     if (UNIV_LIKELY_NULL(merge_page_zip)) {
02704       /* The function page_zip_compress(), which will be
02705       invoked by page_copy_rec_list_end() below,
02706       requires that FIL_PAGE_PREV be FIL_NULL.
02707       Clear the field, but prepare to restore it. */
02708 #ifdef UNIV_BTR_DEBUG
02709       memcpy(fil_page_prev, merge_page + FIL_PAGE_PREV, 4);
02710 #endif /* UNIV_BTR_DEBUG */
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       /* FIL_PAGE_PREV was restored from merge_page_zip. */
02725       ut_a(!memcmp(fil_page_prev,
02726              merge_page + FIL_PAGE_PREV, 4));
02727 #endif /* UNIV_BTR_DEBUG */
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       /* Restore FIL_PAGE_PREV in order to avoid an assertion
02736       failure in btr_level_list_remove(), which will set
02737       the field again to FIL_NULL.  Even though this makes
02738       merge_page and merge_page_zip inconsistent for a
02739       split second, it is harmless, because the pages
02740       are X-latched. */
02741       memcpy(merge_page + FIL_PAGE_PREV, fil_page_prev, 4);
02742     }
02743 #endif /* UNIV_BTR_DEBUG */
02744 
02745     /* Remove the page from the level list */
02746     btr_level_list_remove(space, zip_size, page, mtr);
02747 
02748     /* Replace the address of the old child node (= page) with the
02749     address of the merge page to the right */
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     /* Update the free bits of the B-tree page in the
02764     insert buffer bitmap.  This has to be done in a
02765     separate mini-transaction that is committed before the
02766     main mini-transaction.  We cannot update the insert
02767     buffer bitmap in this mini-transaction, because
02768     btr_compress() can be invoked recursively without
02769     committing the mini-transaction in between.  Since
02770     insert buffer bitmap pages have a lower rank than
02771     B-tree pages, we must not access other pages in the
02772     same mini-transaction after accessing an insert buffer
02773     bitmap page. */
02774 
02775     /* The free bits in the insert buffer bitmap must
02776     never exceed the free space on a page.  It is safe to
02777     decrement or reset the bits in the bitmap in a
02778     mini-transaction that is committed before the
02779     mini-transaction that affects the free space. */
02780 
02781     /* It is unsafe to increment the bits in a separately
02782     committed mini-transaction, because in crash recovery,
02783     the free bits could momentarily be set too high. */
02784 
02785     if (zip_size) {
02786       /* Because the free bits may be incremented
02787       and we cannot update the insert buffer bitmap
02788       in the same mini-transaction, the only safe
02789       thing we can do here is the pessimistic
02790       approach: reset the free bits. */
02791       ibuf_reset_free_bits(merge_block);
02792     } else {
02793       /* On uncompressed pages, the free bits will
02794       never increase here.  Thus, it is safe to
02795       write the bits accurately in a separate
02796       mini-transaction. */
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 /* UNIV_ZIP_DEBUG */
02807 
02808   /* Free the file page */
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   /* Save the PAGE_MAX_TRX_ID from the leaf page. */
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     /* Free the file page */
02853     btr_page_free(index, block, mtr);
02854 
02855     block = father;
02856     page_level++;
02857   }
02858 
02859   /* block is the root page, which must be empty, except
02860   for the node pointer to the (now discarded) block(s). */
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 /* UNIV_BTR_DEBUG */
02872 
02873   btr_page_empty(block, buf_block_get_page_zip(block), index, 0, mtr);
02874 
02875   if (!dict_index_is_clust(index)) {
02876     /* We play it safe and reset the free bits for the root */
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   /* Decide the page which will inherit the locks */
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 /* UNIV_BTR_DEBUG */
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 /* UNIV_BTR_DEBUG */
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     /* We have to mark the leftmost node pointer on the right
02955     side page as the predefined minimum record */
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     /* This will make page_zip_validate() fail on merge_page
02961     until btr_level_list_remove() completes.  This is harmless,
02962     because everything will take place within a single
02963     mini-transaction and because writing to the redo log
02964     is an atomic operation (performed by mtr_commit()). */
02965     btr_set_min_rec_mark(node_ptr, mtr);
02966   }
02967 
02968   btr_node_ptr_delete(index, block, mtr);
02969 
02970   /* Remove the page from the level list */
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 /* UNIV_ZIP_DEBUG */
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   /* Free the file page */
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       /* If this is the leaf level, do nothing */
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 /* UNIV_BTR_PRINT */
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 /* UNIV_DEBUG */
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     /* The insert buffer index tree can contain records from any
03221     other index: we cannot check the number of fields or
03222     their length */
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     /* Note that if fixed_size != 0, it equals the
03264     length of a fixed-size column in the clustered index.
03265     A prefix index of the column is of fixed, but different
03266     length.  When fixed_size == 0, prefix_len is the maximum
03267     length of the prefix index column. */
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; /* remove warning */
03393   page_t*   right_page = 0; /* remove warning */
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 /* UNIV_ZIP_DEBUG */
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 /* UNIV_ZIP_DEBUG */
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   /* Now we are on the desired level. Loop through the pages on that
03443   level. */
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 /* UNIV_ZIP_DEBUG */
03458 
03459   /* Check ordering etc. of records */
03460 
03461   if (!page_validate(page, index)) {
03462     btr_validate_report1(index, level, block);
03463 
03464     ret = FALSE;
03465   } else if (level == 0) {
03466     /* We are on level 0. Check that the records have the right
03467     number of fields, and field lengths are right. */
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     /* Check father node pointers */
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   /* Commit the mini-transaction to release the latch on 'page'.
03705   Re-acquire the latch on right_page, which will become 'page'
03706   on the next loop.  The page has already been checked. */
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 /* !UNIV_HOTBACKUP */