Drizzled Public API Documentation

ibuf0ibuf.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1997, 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 "ibuf0ibuf.h"
00027 
00029 #define IBUF_BITS_PER_PAGE  4
00030 #if IBUF_BITS_PER_PAGE % 2
00031 # error "IBUF_BITS_PER_PAGE must be an even number!"
00032 #endif
00033 
00034 #define IBUF_BITMAP   PAGE_DATA
00035 
00036 #ifdef UNIV_NONINL
00037 #include "ibuf0ibuf.ic"
00038 #endif
00039 
00040 #ifndef UNIV_HOTBACKUP
00041 
00042 #include "buf0buf.h"
00043 #include "buf0rea.h"
00044 #include "fsp0fsp.h"
00045 #include "trx0sys.h"
00046 #include "fil0fil.h"
00047 #include "thr0loc.h"
00048 #include "rem0rec.h"
00049 #include "btr0cur.h"
00050 #include "btr0pcur.h"
00051 #include "btr0btr.h"
00052 #include "row0upd.h"
00053 #include "sync0sync.h"
00054 #include "dict0boot.h"
00055 #include "fut0lst.h"
00056 #include "lock0lock.h"
00057 #include "log0recv.h"
00058 #include "que0que.h"
00059 #include "srv0start.h" /* srv_shutdown_state */
00060 
00061 /*  STRUCTURE OF AN INSERT BUFFER RECORD
00062 
00063 In versions < 4.1.x:
00064 
00065 1. The first field is the page number.
00066 2. The second field is an array which stores type info for each subsequent
00067    field. We store the information which affects the ordering of records, and
00068    also the physical storage size of an SQL NULL value. E.g., for CHAR(10) it
00069    is 10 bytes.
00070 3. Next we have the fields of the actual index record.
00071 
00072 In versions >= 4.1.x:
00073 
00074 Note that contary to what we planned in the 1990's, there will only be one
00075 insert buffer tree, and that is in the system tablespace of InnoDB.
00076 
00077 1. The first field is the space id.
00078 2. The second field is a one-byte marker (0) which differentiates records from
00079    the < 4.1.x storage format.
00080 3. The third field is the page number.
00081 4. The fourth field contains the type info, where we have also added 2 bytes to
00082    store the charset. In the compressed table format of 5.0.x we must add more
00083    information here so that we can build a dummy 'index' struct which 5.0.x
00084    can use in the binary search on the index page in the ibuf merge phase.
00085 5. The rest of the fields contain the fields of the actual index record.
00086 
00087 In versions >= 5.0.3:
00088 
00089 The first byte of the fourth field is an additional marker (0) if the record
00090 is in the compact format.  The presence of this marker can be detected by
00091 looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
00092 
00093 The high-order bit of the character set field in the type info is the
00094 "nullable" flag for the field.
00095 
00096 In versions >= 5.5:
00097 
00098 The optional marker byte at the start of the fourth field is replaced by
00099 mandatory 3 fields, totaling 4 bytes:
00100 
00101  1. 2 bytes: Counter field, used to sort records within a (space id, page
00102     no) in the order they were added. This is needed so that for example the
00103     sequence of operations "INSERT x, DEL MARK x, INSERT x" is handled
00104     correctly.
00105 
00106  2. 1 byte: Operation type (see ibuf_op_t).
00107 
00108  3. 1 byte: Flags. Currently only one flag exists, IBUF_REC_COMPACT.
00109 
00110 To ensure older records, which do not have counters to enforce correct
00111 sorting, are merged before any new records, ibuf_insert checks if we're
00112 trying to insert to a position that contains old-style records, and if so,
00113 refuses the insert. Thus, ibuf pages are gradually converted to the new
00114 format as their corresponding buffer pool pages are read into memory.
00115 */
00116 
00117 
00118 /*  PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
00119 
00120 If an OS thread performs any operation that brings in disk pages from
00121 non-system tablespaces into the buffer pool, or creates such a page there,
00122 then the operation may have as a side effect an insert buffer index tree
00123 compression. Thus, the tree latch of the insert buffer tree may be acquired
00124 in the x-mode, and also the file space latch of the system tablespace may
00125 be acquired in the x-mode.
00126 
00127 Also, an insert to an index in a non-system tablespace can have the same
00128 effect. How do we know this cannot lead to a deadlock of OS threads? There
00129 is a problem with the i\o-handler threads: they break the latching order
00130 because they own x-latches to pages which are on a lower level than the
00131 insert buffer tree latch, its page latches, and the tablespace latch an
00132 insert buffer operation can reserve.
00133 
00134 The solution is the following: Let all the tree and page latches connected
00135 with the insert buffer be later in the latching order than the fsp latch and
00136 fsp page latches.
00137 
00138 Insert buffer pages must be such that the insert buffer is never invoked
00139 when these pages are accessed as this would result in a recursion violating
00140 the latching order. We let a special i/o-handler thread take care of i/o to
00141 the insert buffer pages and the ibuf bitmap pages, as well as the fsp bitmap
00142 pages and the first inode page, which contains the inode of the ibuf tree: let
00143 us call all these ibuf pages. To prevent deadlocks, we do not let a read-ahead
00144 access both non-ibuf and ibuf pages.
00145 
00146 Then an i/o-handler for the insert buffer never needs to access recursively the
00147 insert buffer tree and thus obeys the latching order. On the other hand, other
00148 i/o-handlers for other tablespaces may require access to the insert buffer,
00149 but because all kinds of latches they need to access there are later in the
00150 latching order, no violation of the latching order occurs in this case,
00151 either.
00152 
00153 A problem is how to grow and contract an insert buffer tree. As it is later
00154 in the latching order than the fsp management, we have to reserve the fsp
00155 latch first, before adding or removing pages from the insert buffer tree.
00156 We let the insert buffer tree have its own file space management: a free
00157 list of pages linked to the tree root. To prevent recursive using of the
00158 insert buffer when adding pages to the tree, we must first load these pages
00159 to memory, obtaining a latch on them, and only after that add them to the
00160 free list of the insert buffer tree. More difficult is removing of pages
00161 from the free list. If there is an excess of pages in the free list of the
00162 ibuf tree, they might be needed if some thread reserves the fsp latch,
00163 intending to allocate more file space. So we do the following: if a thread
00164 reserves the fsp latch, we check the writer count field of the latch. If
00165 this field has value 1, it means that the thread did not own the latch
00166 before entering the fsp system, and the mtr of the thread contains no
00167 modifications to the fsp pages. Now we are free to reserve the ibuf latch,
00168 and check if there is an excess of pages in the free list. We can then, in a
00169 separate mini-transaction, take them out of the free list and free them to
00170 the fsp system.
00171 
00172 To avoid deadlocks in the ibuf system, we divide file pages into three levels:
00173 
00174 (1) non-ibuf pages,
00175 (2) ibuf tree pages and the pages in the ibuf tree free list, and
00176 (3) ibuf bitmap pages.
00177 
00178 No OS thread is allowed to access higher level pages if it has latches to
00179 lower level pages; even if the thread owns a B-tree latch it must not access
00180 the B-tree non-leaf pages if it has latches on lower level pages. Read-ahead
00181 is only allowed for level 1 and 2 pages. Dedicated i/o-handler threads handle
00182 exclusively level 1 i/o. A dedicated i/o handler thread handles exclusively
00183 level 2 i/o. However, if an OS thread does the i/o handling for itself, i.e.,
00184 it uses synchronous aio, it can access any pages, as long as it obeys the
00185 access order rules. */
00186 
00188 #define IBUF_POOL_SIZE_PER_MAX_SIZE 2
00189 
00191 #define IBUF_TABLE_NAME   "SYS_IBUF_TABLE"
00192 
00194 UNIV_INTERN ibuf_use_t  ibuf_use    = IBUF_USE_ALL;
00195 
00196 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
00197 
00198 UNIV_INTERN uint  ibuf_debug;
00199 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
00200 
00202 UNIV_INTERN ibuf_t* ibuf      = NULL;
00203 
00205 UNIV_INTERN ulint ibuf_flush_count  = 0;
00206 
00207 #ifdef UNIV_PFS_MUTEX
00208 UNIV_INTERN mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key;
00209 UNIV_INTERN mysql_pfs_key_t ibuf_mutex_key;
00210 UNIV_INTERN mysql_pfs_key_t ibuf_bitmap_mutex_key;
00211 #endif /* UNIV_PFS_MUTEX */
00212 
00213 #ifdef UNIV_IBUF_COUNT_DEBUG
00214 
00215 #define IBUF_COUNT_N_SPACES 4
00216 
00217 #define IBUF_COUNT_N_PAGES  130000
00218 
00220 static ulint  ibuf_counts[IBUF_COUNT_N_SPACES][IBUF_COUNT_N_PAGES];
00221 
00222 /******************************************************************/
00224 UNIV_INLINE
00225 void
00226 ibuf_count_check(
00227 /*=============*/
00228   ulint space_id, 
00229   ulint page_no)  
00230 {
00231   if (space_id < IBUF_COUNT_N_SPACES && page_no < IBUF_COUNT_N_PAGES) {
00232     return;
00233   }
00234 
00235   fprintf(stderr,
00236     "InnoDB: UNIV_IBUF_COUNT_DEBUG limits space_id and page_no\n"
00237     "InnoDB: and breaks crash recovery.\n"
00238     "InnoDB: space_id=%lu, should be 0<=space_id<%lu\n"
00239     "InnoDB: page_no=%lu, should be 0<=page_no<%lu\n",
00240     (ulint) space_id, (ulint) IBUF_COUNT_N_SPACES,
00241     (ulint) page_no, (ulint) IBUF_COUNT_N_PAGES);
00242   ut_error;
00243 }
00244 #endif
00245 
00247 /* @{ */
00248 #define IBUF_BITMAP_FREE  0 
00250 #define IBUF_BITMAP_BUFFERED  2 
00252 #define IBUF_BITMAP_IBUF  3 
00256 /* @} */
00257 
00258 /* Various constants for checking the type of an ibuf record and extracting
00259 data from it. For details, see the description of the record format at the
00260 top of this file. */
00261 
00265 /* @{ */
00266 #define IBUF_REC_INFO_SIZE  4 
00268 #if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
00269 # error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
00270 #endif
00271 
00272 /* Offsets for the fields at the beginning of the fourth field */
00273 #define IBUF_REC_OFFSET_COUNTER 0 
00274 #define IBUF_REC_OFFSET_TYPE  2 
00275 #define IBUF_REC_OFFSET_FLAGS 3 
00277 /* Record flag masks */
00278 #define IBUF_REC_COMPACT  0x1 
00285 static mutex_t  ibuf_pessimistic_insert_mutex;
00286 
00288 static mutex_t  ibuf_mutex;
00289 
00291 static mutex_t  ibuf_bitmap_mutex;
00292 
00294 #define IBUF_MERGE_AREA     8
00295 
00299 #define IBUF_MERGE_THRESHOLD    4
00300 
00303 #define IBUF_MAX_N_PAGES_MERGED   IBUF_MERGE_AREA
00304 
00308 #define IBUF_CONTRACT_ON_INSERT_NON_SYNC  0
00309 
00313 #define IBUF_CONTRACT_ON_INSERT_SYNC    5
00314 
00318 #define IBUF_CONTRACT_DO_NOT_INSERT   10
00319 
00320 /* TODO: how to cope with drop table if there are records in the insert
00321 buffer for the indexes of the table? Is there actually any problem,
00322 because ibuf merge is done to a page when it is read in, and it is
00323 still physically like the index page even if the index would have been
00324 dropped! So, there seems to be no problem. */
00325 
00326 /******************************************************************/
00329 UNIV_INLINE
00330 void
00331 ibuf_enter(void)
00332 /*============*/
00333 {
00334   ibool*  ptr;
00335 
00336   ptr = thr_local_get_in_ibuf_field();
00337 
00338   ut_ad(*ptr == FALSE);
00339 
00340   *ptr = TRUE;
00341 }
00342 
00343 /******************************************************************/
00346 UNIV_INLINE
00347 void
00348 ibuf_exit(void)
00349 /*===========*/
00350 {
00351   ibool*  ptr;
00352 
00353   ptr = thr_local_get_in_ibuf_field();
00354 
00355   ut_ad(*ptr == TRUE);
00356 
00357   *ptr = FALSE;
00358 }
00359 
00360 /******************************************************************/
00367 UNIV_INTERN
00368 ibool
00369 ibuf_inside(void)
00370 /*=============*/
00371 {
00372   return(*thr_local_get_in_ibuf_field());
00373 }
00374 
00375 /******************************************************************/
00378 static
00379 page_t*
00380 ibuf_header_page_get(
00381 /*=================*/
00382   mtr_t*  mtr)  
00383 {
00384   buf_block_t*  block;
00385 
00386   ut_ad(!ibuf_inside());
00387 
00388   block = buf_page_get(
00389     IBUF_SPACE_ID, 0, FSP_IBUF_HEADER_PAGE_NO, RW_X_LATCH, mtr);
00390   buf_block_dbg_add_level(block, SYNC_IBUF_HEADER);
00391 
00392   return(buf_block_get_frame(block));
00393 }
00394 
00395 /******************************************************************/
00398 static
00399 page_t*
00400 ibuf_tree_root_get(
00401 /*===============*/
00402   mtr_t*    mtr)  
00403 {
00404   buf_block_t*  block;
00405   page_t*   root;
00406 
00407   ut_ad(ibuf_inside());
00408   ut_ad(mutex_own(&ibuf_mutex));
00409 
00410   mtr_x_lock(dict_index_get_lock(ibuf->index), mtr);
00411 
00412   block = buf_page_get(
00413     IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr);
00414 
00415   buf_block_dbg_add_level(block, SYNC_TREE_NODE);
00416 
00417   root = buf_block_get_frame(block);
00418 
00419   ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
00420   ut_ad(page_get_page_no(root) == FSP_IBUF_TREE_ROOT_PAGE_NO);
00421   ut_ad(ibuf->empty == (page_get_n_recs(root) == 0));
00422 
00423   return(root);
00424 }
00425 
00426 #ifdef UNIV_IBUF_COUNT_DEBUG
00427 /******************************************************************/
00431 UNIV_INTERN
00432 ulint
00433 ibuf_count_get(
00434 /*===========*/
00435   ulint space,  
00436   ulint page_no)
00437 {
00438   ibuf_count_check(space, page_no);
00439 
00440   return(ibuf_counts[space][page_no]);
00441 }
00442 
00443 /******************************************************************/
00445 static
00446 void
00447 ibuf_count_set(
00448 /*===========*/
00449   ulint space,  
00450   ulint page_no,
00451   ulint val)  
00452 {
00453   ibuf_count_check(space, page_no);
00454   ut_a(val < UNIV_PAGE_SIZE);
00455 
00456   ibuf_counts[space][page_no] = val;
00457 }
00458 #endif
00459 
00460 /******************************************************************/
00462 UNIV_INTERN
00463 void
00464 ibuf_close(void)
00465 /*============*/
00466 {
00467   mutex_free(&ibuf_pessimistic_insert_mutex);
00468   memset(&ibuf_pessimistic_insert_mutex,
00469          0x0, sizeof(ibuf_pessimistic_insert_mutex));
00470 
00471   mutex_free(&ibuf_mutex);
00472   memset(&ibuf_mutex, 0x0, sizeof(ibuf_mutex));
00473 
00474   mutex_free(&ibuf_bitmap_mutex);
00475   memset(&ibuf_bitmap_mutex, 0x0, sizeof(ibuf_mutex));
00476 
00477   mem_free(ibuf);
00478   ibuf = NULL;
00479 }
00480 
00481 /******************************************************************/
00484 static
00485 void
00486 ibuf_size_update(
00487 /*=============*/
00488   const page_t* root, 
00489   mtr_t*    mtr)  
00490 {
00491   ut_ad(mutex_own(&ibuf_mutex));
00492 
00493   ibuf->free_list_len = flst_get_len(root + PAGE_HEADER
00494              + PAGE_BTR_IBUF_FREE_LIST, mtr);
00495 
00496   ibuf->height = 1 + btr_page_get_level(root, mtr);
00497 
00498   /* the '1 +' is the ibuf header page */
00499   ibuf->size = ibuf->seg_size - (1 + ibuf->free_list_len);
00500 }
00501 
00502 /******************************************************************/
00505 UNIV_INTERN
00506 void
00507 ibuf_init_at_db_start(void)
00508 /*=======================*/
00509 {
00510   page_t*   root;
00511   mtr_t   mtr;
00512   dict_table_t* table;
00513   mem_heap_t* heap;
00514   dict_index_t* index;
00515   ulint   n_used;
00516   page_t*   header_page;
00517   ulint   error;
00518 
00519   ibuf = static_cast<ibuf_t *>(mem_alloc(sizeof(ibuf_t)));
00520 
00521   memset(ibuf, 0, sizeof(*ibuf));
00522 
00523   /* Note that also a pessimistic delete can sometimes make a B-tree
00524   grow in size, as the references on the upper levels of the tree can
00525   change */
00526 
00527   ibuf->max_size = ut_min(buf_pool_get_curr_size() / UNIV_PAGE_SIZE
00528         / IBUF_POOL_SIZE_PER_MAX_SIZE,
00529         srv_ibuf_max_size / UNIV_PAGE_SIZE);
00530   srv_ibuf_max_size = ibuf->max_size * UNIV_PAGE_SIZE;
00531 
00532   mutex_create(ibuf_pessimistic_insert_mutex_key,
00533          &ibuf_pessimistic_insert_mutex,
00534          SYNC_IBUF_PESS_INSERT_MUTEX);
00535 
00536   mutex_create(ibuf_mutex_key,
00537          &ibuf_mutex, SYNC_IBUF_MUTEX);
00538 
00539   mutex_create(ibuf_bitmap_mutex_key,
00540          &ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
00541 
00542   mtr_start(&mtr);
00543 
00544   mutex_enter(&ibuf_mutex);
00545 
00546   mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, NULL), &mtr);
00547 
00548   header_page = ibuf_header_page_get(&mtr);
00549 
00550   fseg_n_reserved_pages(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
00551             &n_used, &mtr);
00552   ibuf_enter();
00553 
00554   ut_ad(n_used >= 2);
00555 
00556   ibuf->seg_size = n_used;
00557 
00558   {
00559     buf_block_t*  block;
00560 
00561     block = buf_page_get(
00562       IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO,
00563       RW_X_LATCH, &mtr);
00564     buf_block_dbg_add_level(block, SYNC_TREE_NODE);
00565 
00566     root = buf_block_get_frame(block);
00567   }
00568 
00569   ibuf_size_update(root, &mtr);
00570   mutex_exit(&ibuf_mutex);
00571 
00572   ibuf->empty = (page_get_n_recs(root) == 0);
00573   mtr_commit(&mtr);
00574 
00575   ibuf_exit();
00576 
00577   heap = mem_heap_create(450);
00578 
00579   /* Use old-style record format for the insert buffer. */
00580   table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0);
00581 
00582   dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
00583 
00584   table->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
00585 
00586   dict_table_add_to_cache(table, heap);
00587   mem_heap_free(heap);
00588 
00589   index = dict_mem_index_create(
00590     IBUF_TABLE_NAME, "CLUST_IND",
00591     IBUF_SPACE_ID, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 1);
00592 
00593   dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
00594 
00595   index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
00596 
00597   error = dict_index_add_to_cache(table, index,
00598           FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
00599   ut_a(error == DB_SUCCESS);
00600 
00601   ibuf->index = dict_table_get_first_index(table);
00602 }
00603 #endif /* !UNIV_HOTBACKUP */
00604 /*********************************************************************/
00606 UNIV_INTERN
00607 void
00608 ibuf_bitmap_page_init(
00609 /*==================*/
00610   buf_block_t*  block,  
00611   mtr_t*    mtr)  
00612 {
00613   page_t* page;
00614   ulint byte_offset;
00615   ulint zip_size = buf_block_get_zip_size(block);
00616 
00617   ut_a(ut_is_2pow(zip_size));
00618 
00619   page = buf_block_get_frame(block);
00620   fil_page_set_type(page, FIL_PAGE_IBUF_BITMAP);
00621 
00622   /* Write all zeros to the bitmap */
00623 
00624   if (!zip_size) {
00625     byte_offset = UT_BITS_IN_BYTES(UNIV_PAGE_SIZE
00626                  * IBUF_BITS_PER_PAGE);
00627   } else {
00628     byte_offset = UT_BITS_IN_BYTES(zip_size * IBUF_BITS_PER_PAGE);
00629   }
00630 
00631   memset(page + IBUF_BITMAP, 0, byte_offset);
00632 
00633   /* The remaining area (up to the page trailer) is uninitialized. */
00634 
00635 #ifndef UNIV_HOTBACKUP
00636   mlog_write_initial_log_record(page, MLOG_IBUF_BITMAP_INIT, mtr);
00637 #endif /* !UNIV_HOTBACKUP */
00638 }
00639 
00640 /*********************************************************************/
00643 UNIV_INTERN
00644 byte*
00645 ibuf_parse_bitmap_init(
00646 /*===================*/
00647   byte*   ptr,  
00648   byte*   /*end_ptr __attribute__((unused))*/, 
00649   buf_block_t*  block,  
00650   mtr_t*    mtr)  
00651 {
00652   ut_ad(ptr && end_ptr);
00653 
00654   if (block) {
00655     ibuf_bitmap_page_init(block, mtr);
00656   }
00657 
00658   return(ptr);
00659 }
00660 #ifndef UNIV_HOTBACKUP
00661 /********************************************************************/
00664 UNIV_INLINE
00665 ulint
00666 ibuf_bitmap_page_get_bits(
00667 /*======================*/
00668   const page_t* page, 
00669   ulint   page_no,
00670   ulint   zip_size,
00672   ulint   bit,  
00674   mtr_t*    /*mtr __attribute__((unused))*/)
00677 {
00678   ulint byte_offset;
00679   ulint bit_offset;
00680   ulint map_byte;
00681   ulint value;
00682 
00683   ut_ad(bit < IBUF_BITS_PER_PAGE);
00684 #if IBUF_BITS_PER_PAGE % 2
00685 # error "IBUF_BITS_PER_PAGE % 2 != 0"
00686 #endif
00687   ut_ad(ut_is_2pow(zip_size));
00688   ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
00689 
00690   if (!zip_size) {
00691     bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE
00692       + bit;
00693   } else {
00694     bit_offset = (page_no & (zip_size - 1)) * IBUF_BITS_PER_PAGE
00695       + bit;
00696   }
00697 
00698   byte_offset = bit_offset / 8;
00699   bit_offset = bit_offset % 8;
00700 
00701   ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
00702 
00703   map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
00704 
00705   value = ut_bit_get_nth(map_byte, bit_offset);
00706 
00707   if (bit == IBUF_BITMAP_FREE) {
00708     ut_ad(bit_offset + 1 < 8);
00709 
00710     value = value * 2 + ut_bit_get_nth(map_byte, bit_offset + 1);
00711   }
00712 
00713   return(value);
00714 }
00715 
00716 /********************************************************************/
00718 static
00719 void
00720 ibuf_bitmap_page_set_bits(
00721 /*======================*/
00722   page_t* page, 
00723   ulint page_no,
00724   ulint zip_size,
00726   ulint bit,  
00727   ulint val,  
00728   mtr_t*  mtr)  
00729 {
00730   ulint byte_offset;
00731   ulint bit_offset;
00732   ulint map_byte;
00733 
00734   ut_ad(bit < IBUF_BITS_PER_PAGE);
00735 #if IBUF_BITS_PER_PAGE % 2
00736 # error "IBUF_BITS_PER_PAGE % 2 != 0"
00737 #endif
00738   ut_ad(ut_is_2pow(zip_size));
00739   ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
00740 #ifdef UNIV_IBUF_COUNT_DEBUG
00741   ut_a((bit != IBUF_BITMAP_BUFFERED) || (val != FALSE)
00742        || (0 == ibuf_count_get(page_get_space_id(page),
00743              page_no)));
00744 #endif
00745   if (!zip_size) {
00746     bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE
00747       + bit;
00748   } else {
00749     bit_offset = (page_no & (zip_size - 1)) * IBUF_BITS_PER_PAGE
00750       + bit;
00751   }
00752 
00753   byte_offset = bit_offset / 8;
00754   bit_offset = bit_offset % 8;
00755 
00756   ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
00757 
00758   map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
00759 
00760   if (bit == IBUF_BITMAP_FREE) {
00761     ut_ad(bit_offset + 1 < 8);
00762     ut_ad(val <= 3);
00763 
00764     map_byte = ut_bit_set_nth(map_byte, bit_offset, val / 2);
00765     map_byte = ut_bit_set_nth(map_byte, bit_offset + 1, val % 2);
00766   } else {
00767     ut_ad(val <= 1);
00768     map_byte = ut_bit_set_nth(map_byte, bit_offset, val);
00769   }
00770 
00771   mlog_write_ulint(page + IBUF_BITMAP + byte_offset, map_byte,
00772        MLOG_1BYTE, mtr);
00773 }
00774 
00775 /********************************************************************/
00778 UNIV_INLINE
00779 ulint
00780 ibuf_bitmap_page_no_calc(
00781 /*=====================*/
00782   ulint zip_size, 
00784   ulint page_no)  
00785 {
00786   ut_ad(ut_is_2pow(zip_size));
00787 
00788   if (!zip_size) {
00789     return(FSP_IBUF_BITMAP_OFFSET
00790            + (page_no & ~(UNIV_PAGE_SIZE - 1)));
00791   } else {
00792     return(FSP_IBUF_BITMAP_OFFSET
00793            + (page_no & ~(zip_size - 1)));
00794   }
00795 }
00796 
00797 /********************************************************************/
00803 static
00804 page_t*
00805 ibuf_bitmap_get_map_page_func(
00806 /*==========================*/
00807   ulint   space,  
00808   ulint   page_no,
00809   ulint   zip_size,
00811   const char* file, 
00812   ulint   line, 
00813   mtr_t*    mtr)  
00814 {
00815   buf_block_t*  block;
00816 
00817   block = buf_page_get_gen(space, zip_size,
00818          ibuf_bitmap_page_no_calc(zip_size, page_no),
00819          RW_X_LATCH, NULL, BUF_GET,
00820          file, line, mtr);
00821   buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
00822 
00823   return(buf_block_get_frame(block));
00824 }
00825 
00826 /********************************************************************/
00836 #define ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr)   \
00837   ibuf_bitmap_get_map_page_func(space, page_no, zip_size,   \
00838               __FILE__, __LINE__, mtr)
00839 
00840 /************************************************************************/
00845 UNIV_INLINE
00846 void
00847 ibuf_set_free_bits_low(
00848 /*===================*/
00849   ulint     zip_size,
00851   const buf_block_t*  block,  
00854   ulint     val,  
00855   mtr_t*      mtr)  
00856 {
00857   page_t* bitmap_page;
00858   ulint space;
00859   ulint page_no;
00860 
00861   if (!page_is_leaf(buf_block_get_frame(block))) {
00862 
00863     return;
00864   }
00865 
00866   space = buf_block_get_space(block);
00867   page_no = buf_block_get_page_no(block);
00868   bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
00869 #ifdef UNIV_IBUF_DEBUG
00870 # if 0
00871   fprintf(stderr,
00872     "Setting space %lu page %lu free bits to %lu should be %lu\n",
00873     space, page_no, val,
00874     ibuf_index_page_calc_free(zip_size, block));
00875 # endif
00876 
00877   ut_a(val <= ibuf_index_page_calc_free(zip_size, block));
00878 #endif /* UNIV_IBUF_DEBUG */
00879   ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
00880           IBUF_BITMAP_FREE, val, mtr);
00881 }
00882 
00883 /************************************************************************/
00888 UNIV_INTERN
00889 void
00890 ibuf_set_free_bits_func(
00891 /*====================*/
00892   buf_block_t*  block,  
00894 #ifdef UNIV_IBUF_DEBUG
00895   ulint   max_val,
00898 #endif /* UNIV_IBUF_DEBUG */
00899   ulint   val)  
00900 {
00901   mtr_t mtr;
00902   page_t* page;
00903   page_t* bitmap_page;
00904   ulint space;
00905   ulint page_no;
00906   ulint zip_size;
00907 
00908   page = buf_block_get_frame(block);
00909 
00910   if (!page_is_leaf(page)) {
00911 
00912     return;
00913   }
00914 
00915   mtr_start(&mtr);
00916 
00917   space = buf_block_get_space(block);
00918   page_no = buf_block_get_page_no(block);
00919   zip_size = buf_block_get_zip_size(block);
00920   bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, &mtr);
00921 
00922 #ifdef UNIV_IBUF_DEBUG
00923   if (max_val != ULINT_UNDEFINED) {
00924     ulint old_val;
00925 
00926     old_val = ibuf_bitmap_page_get_bits(
00927       bitmap_page, page_no, zip_size,
00928       IBUF_BITMAP_FREE, &mtr);
00929 # if 0
00930     if (old_val != max_val) {
00931       fprintf(stderr,
00932         "Ibuf: page %lu old val %lu max val %lu\n",
00933         page_get_page_no(page),
00934         old_val, max_val);
00935     }
00936 # endif
00937 
00938     ut_a(old_val <= max_val);
00939   }
00940 # if 0
00941   fprintf(stderr, "Setting page no %lu free bits to %lu should be %lu\n",
00942     page_get_page_no(page), val,
00943     ibuf_index_page_calc_free(zip_size, block));
00944 # endif
00945 
00946   ut_a(val <= ibuf_index_page_calc_free(zip_size, block));
00947 #endif /* UNIV_IBUF_DEBUG */
00948   ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
00949           IBUF_BITMAP_FREE, val, &mtr);
00950   mtr_commit(&mtr);
00951 }
00952 
00953 /************************************************************************/
00962 UNIV_INTERN
00963 void
00964 ibuf_reset_free_bits(
00965 /*=================*/
00966   buf_block_t*  block)  
00969 {
00970   ibuf_set_free_bits(block, 0, ULINT_UNDEFINED);
00971 }
00972 
00973 /**********************************************************************/
00981 UNIV_INTERN
00982 void
00983 ibuf_update_free_bits_low(
00984 /*======================*/
00985   const buf_block_t*  block,    
00986   ulint     max_ins_size, 
00991   mtr_t*      mtr)    
00992 {
00993   ulint before;
00994   ulint after;
00995 
00996   ut_a(!buf_block_get_page_zip(block));
00997 
00998   before = ibuf_index_page_calc_free_bits(0, max_ins_size);
00999 
01000   after = ibuf_index_page_calc_free(0, block);
01001 
01002   /* This approach cannot be used on compressed pages, since the
01003   computed value of "before" often does not match the current
01004   state of the bitmap.  This is because the free space may
01005   increase or decrease when a compressed page is reorganized. */
01006   if (before != after) {
01007     ibuf_set_free_bits_low(0, block, after, mtr);
01008   }
01009 }
01010 
01011 /**********************************************************************/
01019 UNIV_INTERN
01020 void
01021 ibuf_update_free_bits_zip(
01022 /*======================*/
01023   buf_block_t*  block,  
01024   mtr_t*    mtr)  
01025 {
01026   page_t* bitmap_page;
01027   ulint space;
01028   ulint page_no;
01029   ulint zip_size;
01030   ulint after;
01031 
01032   space = buf_block_get_space(block);
01033   page_no = buf_block_get_page_no(block);
01034   zip_size = buf_block_get_zip_size(block);
01035 
01036   ut_a(page_is_leaf(buf_block_get_frame(block)));
01037   ut_a(zip_size);
01038 
01039   bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
01040 
01041   after = ibuf_index_page_calc_free_zip(zip_size, block);
01042 
01043   if (after == 0) {
01044     /* We move the page to the front of the buffer pool LRU list:
01045     the purpose of this is to prevent those pages to which we
01046     cannot make inserts using the insert buffer from slipping
01047     out of the buffer pool */
01048 
01049     buf_page_make_young(&block->page);
01050   }
01051 
01052   ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
01053           IBUF_BITMAP_FREE, after, mtr);
01054 }
01055 
01056 /**********************************************************************/
01063 UNIV_INTERN
01064 void
01065 ibuf_update_free_bits_for_two_pages_low(
01066 /*====================================*/
01067   ulint   zip_size,
01069   buf_block_t*  block1, 
01070   buf_block_t*  block2, 
01071   mtr_t*    mtr)  
01072 {
01073   ulint state;
01074 
01075   /* As we have to x-latch two random bitmap pages, we have to acquire
01076   the bitmap mutex to prevent a deadlock with a similar operation
01077   performed by another OS thread. */
01078 
01079   mutex_enter(&ibuf_bitmap_mutex);
01080 
01081   state = ibuf_index_page_calc_free(zip_size, block1);
01082 
01083   ibuf_set_free_bits_low(zip_size, block1, state, mtr);
01084 
01085   state = ibuf_index_page_calc_free(zip_size, block2);
01086 
01087   ibuf_set_free_bits_low(zip_size, block2, state, mtr);
01088 
01089   mutex_exit(&ibuf_bitmap_mutex);
01090 }
01091 
01092 /**********************************************************************/
01095 UNIV_INLINE
01096 ibool
01097 ibuf_fixed_addr_page(
01098 /*=================*/
01099   ulint space,  
01100   ulint zip_size,
01102   ulint page_no)
01103 {
01104   return((space == IBUF_SPACE_ID && page_no == IBUF_TREE_ROOT_PAGE_NO)
01105          || ibuf_bitmap_page(zip_size, page_no));
01106 }
01107 
01108 /***********************************************************************/
01112 UNIV_INTERN
01113 ibool
01114 ibuf_page(
01115 /*======*/
01116   ulint space,  
01117   ulint zip_size,
01118   ulint page_no,
01119   mtr_t*  mtr)  
01123 {
01124   ibool ret;
01125   mtr_t local_mtr;
01126   page_t* bitmap_page;
01127 
01128   ut_ad(!recv_no_ibuf_operations);
01129 
01130         if (srv_fake_write)
01131           return(FALSE);
01132 
01133   if (ibuf_fixed_addr_page(space, zip_size, page_no)) {
01134 
01135     return(TRUE);
01136   } else if (space != IBUF_SPACE_ID) {
01137 
01138     return(FALSE);
01139   }
01140 
01141   ut_ad(fil_space_get_type(IBUF_SPACE_ID) == FIL_TABLESPACE);
01142 
01143   if (mtr == NULL) {
01144     mtr = &local_mtr;
01145     mtr_start(mtr);
01146   }
01147 
01148   bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
01149 
01150   ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
01151           IBUF_BITMAP_IBUF, mtr);
01152 
01153   if (mtr == &local_mtr) {
01154     mtr_commit(mtr);
01155   }
01156 
01157   return(ret);
01158 }
01159 
01160 /********************************************************************/
01163 static
01164 ulint
01165 ibuf_rec_get_page_no(
01166 /*=================*/
01167   const rec_t*  rec)  
01168 {
01169   const byte* field;
01170   ulint   len;
01171 
01172   ut_ad(ibuf_inside());
01173   ut_ad(rec_get_n_fields_old(rec) > 2);
01174 
01175   field = rec_get_nth_field_old(rec, 1, &len);
01176 
01177   if (len == 1) {
01178     /* This is of the >= 4.1.x record format */
01179     ut_a(trx_sys_multiple_tablespace_format);
01180 
01181     field = rec_get_nth_field_old(rec, 2, &len);
01182   } else {
01183     ut_a(trx_doublewrite_must_reset_space_ids);
01184     ut_a(!trx_sys_multiple_tablespace_format);
01185 
01186     field = rec_get_nth_field_old(rec, 0, &len);
01187   }
01188 
01189   ut_a(len == 4);
01190 
01191   return(mach_read_from_4(field));
01192 }
01193 
01194 /********************************************************************/
01198 static
01199 ulint
01200 ibuf_rec_get_space(
01201 /*===============*/
01202   const rec_t*  rec)  
01203 {
01204   const byte* field;
01205   ulint   len;
01206 
01207   ut_ad(ibuf_inside());
01208   ut_ad(rec_get_n_fields_old(rec) > 2);
01209 
01210   field = rec_get_nth_field_old(rec, 1, &len);
01211 
01212   if (len == 1) {
01213     /* This is of the >= 4.1.x record format */
01214 
01215     ut_a(trx_sys_multiple_tablespace_format);
01216     field = rec_get_nth_field_old(rec, 0, &len);
01217     ut_a(len == 4);
01218 
01219     return(mach_read_from_4(field));
01220   }
01221 
01222   ut_a(trx_doublewrite_must_reset_space_ids);
01223   ut_a(!trx_sys_multiple_tablespace_format);
01224 
01225   return(0);
01226 }
01227 
01228 /****************************************************************/
01230 static
01231 void
01232 ibuf_rec_get_info(
01233 /*==============*/
01234   const rec_t*  rec,    
01235   ibuf_op_t*  op,   
01236   ibool*    comp,   
01237   ulint*    info_len, 
01240   ulint*    counter)  
01241 {
01242   const byte* types;
01243   ulint   fields;
01244   ulint   len;
01245 
01246   /* Local variables to shadow arguments. */
01247   ibuf_op_t op_local;
01248   ibool   comp_local;
01249   ulint   info_len_local;
01250   ulint   counter_local;
01251 
01252   ut_ad(ibuf_inside());
01253   fields = rec_get_n_fields_old(rec);
01254   ut_a(fields > 4);
01255 
01256   types = rec_get_nth_field_old(rec, 3, &len);
01257 
01258   info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
01259 
01260   switch (info_len_local) {
01261   case 0:
01262   case 1:
01263     op_local = IBUF_OP_INSERT;
01264     comp_local = info_len_local;
01265     ut_ad(!counter);
01266     counter_local = ULINT_UNDEFINED;
01267     break;
01268 
01269   case IBUF_REC_INFO_SIZE:
01270     op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE];
01271     comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT;
01272     counter_local = mach_read_from_2(
01273       types + IBUF_REC_OFFSET_COUNTER);
01274     break;
01275 
01276   default:
01277     ut_error;
01278   }
01279 
01280   ut_a(op_local < IBUF_OP_COUNT);
01281   ut_a((len - info_len_local) ==
01282        (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
01283 
01284   if (op) {
01285     *op = op_local;
01286   }
01287 
01288   if (comp) {
01289     *comp = comp_local;
01290   }
01291 
01292   if (info_len) {
01293     *info_len = info_len_local;
01294   }
01295 
01296   if (counter) {
01297     *counter = counter_local;
01298   }
01299 }
01300 
01301 /****************************************************************/
01304 static
01305 ibuf_op_t
01306 ibuf_rec_get_op_type(
01307 /*=================*/
01308   const rec_t*  rec)  
01309 {
01310   ulint   len;
01311 
01312   ut_ad(ibuf_inside());
01313   ut_ad(rec_get_n_fields_old(rec) > 2);
01314 
01315   (void) rec_get_nth_field_old(rec, 1, &len);
01316 
01317   if (len > 1) {
01318     /* This is a < 4.1.x format record */
01319 
01320     return(IBUF_OP_INSERT);
01321   } else {
01322     ibuf_op_t op;
01323 
01324     ibuf_rec_get_info(rec, &op, NULL, NULL, NULL);
01325 
01326     return(op);
01327   }
01328 }
01329 
01330 /****************************************************************/
01335 UNIV_INTERN
01336 ulint
01337 ibuf_rec_get_counter(
01338 /*=================*/
01339   const rec_t*  rec)  
01340 {
01341   const byte* ptr;
01342   ulint   len;
01343 
01344   if (rec_get_n_fields_old(rec) < 4) {
01345 
01346     return(ULINT_UNDEFINED);
01347   }
01348 
01349   ptr = rec_get_nth_field_old(rec, 3, &len);
01350 
01351   if (len >= 2) {
01352 
01353     return(mach_read_from_2(ptr));
01354   } else {
01355 
01356     return(ULINT_UNDEFINED);
01357   }
01358 }
01359 
01360 /****************************************************************/
01363 static
01364 void
01365 ibuf_add_ops(
01366 /*=========*/
01367   ulint*    arr,  
01368   const ulint*  ops)  
01370 {
01371   ulint i;
01372 
01373 #ifndef HAVE_ATOMIC_BUILTINS
01374   ut_ad(mutex_own(&ibuf_mutex));
01375 #endif /* !HAVE_ATOMIC_BUILTINS */
01376 
01377   for (i = 0; i < IBUF_OP_COUNT; i++) {
01378 #ifdef HAVE_ATOMIC_BUILTINS
01379     os_atomic_increment_ulint(&arr[i], ops[i]);
01380 #else /* HAVE_ATOMIC_BUILTINS */
01381     arr[i] += ops[i];
01382 #endif /* HAVE_ATOMIC_BUILTINS */
01383   }
01384 }
01385 
01386 /****************************************************************/
01388 static
01389 void
01390 ibuf_print_ops(
01391 /*===========*/
01392   const ulint*  ops,  
01393   FILE*   file) 
01394 {
01395   static const char* op_names[] = {
01396     "insert",
01397     "delete mark",
01398     "delete"
01399   };
01400   ulint i;
01401 
01402   ut_a(UT_ARR_SIZE(op_names) == IBUF_OP_COUNT);
01403 
01404   for (i = 0; i < IBUF_OP_COUNT; i++) {
01405     fprintf(file, "%s %lu%s", op_names[i],
01406       (ulong) ops[i], (i < (IBUF_OP_COUNT - 1)) ? ", " : "");
01407   }
01408 
01409   putc('\n', file);
01410 }
01411 
01412 /********************************************************************/
01415 static
01416 dict_index_t*
01417 ibuf_dummy_index_create(
01418 /*====================*/
01419   ulint   n,  
01420   ibool   comp) 
01421 {
01422   dict_table_t* table;
01423   dict_index_t* index;
01424 
01425   table = dict_mem_table_create("IBUF_DUMMY",
01426               DICT_HDR_SPACE, n,
01427               comp ? DICT_TF_COMPACT : 0);
01428 
01429   index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY",
01430               DICT_HDR_SPACE, 0, n);
01431 
01432   index->table = table;
01433 
01434   /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
01435   index->cached = TRUE;
01436 
01437   return(index);
01438 }
01439 /********************************************************************/
01441 static
01442 void
01443 ibuf_dummy_index_add_col(
01444 /*=====================*/
01445   dict_index_t* index,  
01446   const dtype_t*  type, 
01447   ulint   len)  
01448 {
01449   ulint i = index->table->n_def;
01450   dict_mem_table_add_col(index->table, NULL, NULL,
01451              dtype_get_mtype(type),
01452              dtype_get_prtype(type),
01453              dtype_get_len(type));
01454   dict_index_add_col(index, index->table,
01455          dict_table_get_nth_col(index->table, i), len);
01456 }
01457 /********************************************************************/
01459 static
01460 void
01461 ibuf_dummy_index_free(
01462 /*==================*/
01463   dict_index_t* index)  
01464 {
01465   dict_table_t* table = index->table;
01466 
01467   dict_mem_index_free(index);
01468   dict_mem_table_free(table);
01469 }
01470 
01471 /*********************************************************************/
01479 UNIV_INLINE
01480 dtuple_t*
01481 ibuf_build_entry_pre_4_1_x(
01482 /*=======================*/
01483   const rec_t*  ibuf_rec, 
01484   mem_heap_t* heap,   
01485   dict_index_t**  pindex)   
01487 {
01488   ulint   i;
01489   ulint   len;
01490   const byte* types;
01491   dtuple_t* tuple;
01492   ulint   n_fields;
01493 
01494   ut_a(trx_doublewrite_must_reset_space_ids);
01495   ut_a(!trx_sys_multiple_tablespace_format);
01496 
01497   n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
01498   tuple = dtuple_create(heap, n_fields);
01499   types = rec_get_nth_field_old(ibuf_rec, 1, &len);
01500 
01501   ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
01502 
01503   for (i = 0; i < n_fields; i++) {
01504     const byte* data;
01505     dfield_t* field;
01506 
01507     field = dtuple_get_nth_field(tuple, i);
01508 
01509     data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
01510 
01511     dfield_set_data(field, data, len);
01512 
01513     dtype_read_for_order_and_null_size(
01514       dfield_get_type(field),
01515       types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
01516   }
01517 
01518   *pindex = ibuf_dummy_index_create(n_fields, FALSE);
01519 
01520   return(tuple);
01521 }
01522 
01523 /*********************************************************************/
01539 static
01540 dtuple_t*
01541 ibuf_build_entry_from_ibuf_rec(
01542 /*===========================*/
01543   const rec_t*  ibuf_rec, 
01544   mem_heap_t* heap,   
01545   dict_index_t**  pindex)   
01547 {
01548   dtuple_t* tuple;
01549   dfield_t* field;
01550   ulint   n_fields;
01551   const byte* types;
01552   const byte* data;
01553   ulint   len;
01554   ulint   info_len;
01555   ulint   i;
01556   ulint   comp;
01557   dict_index_t* index;
01558 
01559   data = rec_get_nth_field_old(ibuf_rec, 1, &len);
01560 
01561   if (len > 1) {
01562     /* This a < 4.1.x format record */
01563 
01564     return(ibuf_build_entry_pre_4_1_x(ibuf_rec, heap, pindex));
01565   }
01566 
01567   /* This a >= 4.1.x format record */
01568 
01569   ut_a(trx_sys_multiple_tablespace_format);
01570   ut_a(*data == 0);
01571   ut_a(rec_get_n_fields_old(ibuf_rec) > 4);
01572 
01573   n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
01574 
01575   tuple = dtuple_create(heap, n_fields);
01576 
01577   types = rec_get_nth_field_old(ibuf_rec, 3, &len);
01578 
01579   ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL);
01580 
01581   index = ibuf_dummy_index_create(n_fields, comp);
01582 
01583   len -= info_len;
01584   types += info_len;
01585 
01586   ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
01587 
01588   for (i = 0; i < n_fields; i++) {
01589     field = dtuple_get_nth_field(tuple, i);
01590 
01591     data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
01592 
01593     dfield_set_data(field, data, len);
01594 
01595     dtype_new_read_for_order_and_null_size(
01596       dfield_get_type(field),
01597       types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
01598 
01599     ibuf_dummy_index_add_col(index, dfield_get_type(field), len);
01600   }
01601 
01602   /* Prevent an ut_ad() failure in page_zip_write_rec() by
01603   adding system columns to the dummy table pointed to by the
01604   dummy secondary index.  The insert buffer is only used for
01605   secondary indexes, whose records never contain any system
01606   columns, such as DB_TRX_ID. */
01607   ut_d(dict_table_add_system_columns(index->table, index->table->heap));
01608 
01609   *pindex = index;
01610 
01611   return(tuple);
01612 }
01613 
01614 /******************************************************************/
01617 UNIV_INLINE
01618 ulint
01619 ibuf_rec_get_size(
01620 /*==============*/
01621   const rec_t*  rec,      
01622   const byte* types,      
01623   ulint   n_fields,   
01624   ibool   pre_4_1,    
01626   ulint   comp)     
01628 {
01629   ulint i;
01630   ulint field_offset;
01631   ulint types_offset;
01632   ulint size = 0;
01633 
01634   if (pre_4_1) {
01635     field_offset = 2;
01636     types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE;
01637   } else {
01638     field_offset = 4;
01639     types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
01640   }
01641 
01642   for (i = 0; i < n_fields; i++) {
01643     ulint   len;
01644     dtype_t   dtype;
01645 
01646     rec_get_nth_field_offs_old(rec, i + field_offset, &len);
01647 
01648     if (len != UNIV_SQL_NULL) {
01649       size += len;
01650     } else if (pre_4_1) {
01651       dtype_read_for_order_and_null_size(&dtype, types);
01652 
01653       size += dtype_get_sql_null_size(&dtype, comp);
01654     } else {
01655       dtype_new_read_for_order_and_null_size(&dtype, types);
01656 
01657       size += dtype_get_sql_null_size(&dtype, comp);
01658     }
01659 
01660     types += types_offset;
01661   }
01662 
01663   return(size);
01664 }
01665 
01666 /********************************************************************/
01671 static
01672 ulint
01673 ibuf_rec_get_volume(
01674 /*================*/
01675   const rec_t*  ibuf_rec)
01676 {
01677   ulint   len;
01678   const byte* data;
01679   const byte* types;
01680   ulint   n_fields;
01681   ulint   data_size;
01682   ibool   pre_4_1;
01683   ulint   comp;
01684 
01685   ut_ad(ibuf_inside());
01686   ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
01687 
01688   data = rec_get_nth_field_old(ibuf_rec, 1, &len);
01689   pre_4_1 = (len > 1);
01690 
01691   if (pre_4_1) {
01692     /* < 4.1.x format record */
01693 
01694     ut_a(trx_doublewrite_must_reset_space_ids);
01695     ut_a(!trx_sys_multiple_tablespace_format);
01696 
01697     n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
01698 
01699     types = rec_get_nth_field_old(ibuf_rec, 1, &len);
01700 
01701     ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
01702     comp = 0;
01703   } else {
01704     /* >= 4.1.x format record */
01705     ibuf_op_t op;
01706     ulint   info_len;
01707 
01708     ut_a(trx_sys_multiple_tablespace_format);
01709     ut_a(*data == 0);
01710 
01711     types = rec_get_nth_field_old(ibuf_rec, 3, &len);
01712 
01713     ibuf_rec_get_info(ibuf_rec, &op, &comp, &info_len, NULL);
01714 
01715     if (op == IBUF_OP_DELETE_MARK || op == IBUF_OP_DELETE) {
01716       /* Delete-marking a record doesn't take any
01717       additional space, and while deleting a record
01718       actually frees up space, we have to play it safe and
01719       pretend it takes no additional space (the record
01720       might not exist, etc.).  */
01721 
01722       return(0);
01723     } else if (comp) {
01724       dtuple_t* entry;
01725       ulint   volume;
01726       dict_index_t* dummy_index;
01727       mem_heap_t* heap = mem_heap_create(500);
01728 
01729       entry = ibuf_build_entry_from_ibuf_rec(
01730         ibuf_rec, heap, &dummy_index);
01731 
01732       volume = rec_get_converted_size(dummy_index, entry, 0);
01733 
01734       ibuf_dummy_index_free(dummy_index);
01735       mem_heap_free(heap);
01736 
01737       return(volume + page_dir_calc_reserved_space(1));
01738     }
01739 
01740     types += info_len;
01741     n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
01742   }
01743 
01744   data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp);
01745 
01746   return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0)
01747          + page_dir_calc_reserved_space(1));
01748 }
01749 
01750 /*********************************************************************/
01758 static
01759 dtuple_t*
01760 ibuf_entry_build(
01761 /*=============*/
01762   ibuf_op_t op, 
01763   dict_index_t* index,  
01764   const dtuple_t* entry,  
01765   ulint   space,  
01766   ulint   page_no,
01768   ulint   counter,
01770   mem_heap_t* heap) 
01771 {
01772   dtuple_t* tuple;
01773   dfield_t* field;
01774   const dfield_t* entry_field;
01775   ulint   n_fields;
01776   byte*   buf;
01777   byte*   ti;
01778   byte*   type_info;
01779   ulint   i;
01780 
01781   ut_ad(counter != ULINT_UNDEFINED || op == IBUF_OP_INSERT);
01782   ut_ad(counter == ULINT_UNDEFINED || counter <= 0xFFFF);
01783   ut_ad(op < IBUF_OP_COUNT);
01784 
01785   /* We have to build a tuple with the following fields:
01786 
01787   1-4) These are described at the top of this file.
01788 
01789   5) The rest of the fields are copied from the entry.
01790 
01791   All fields in the tuple are ordered like the type binary in our
01792   insert buffer tree. */
01793 
01794   n_fields = dtuple_get_n_fields(entry);
01795 
01796   tuple = dtuple_create(heap, n_fields + 4);
01797 
01798   /* 1) Space Id */
01799 
01800   field = dtuple_get_nth_field(tuple, 0);
01801 
01802   buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
01803 
01804   mach_write_to_4(buf, space);
01805 
01806   dfield_set_data(field, buf, 4);
01807 
01808   /* 2) Marker byte */
01809 
01810   field = dtuple_get_nth_field(tuple, 1);
01811 
01812   buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
01813 
01814   /* We set the marker byte zero */
01815 
01816   mach_write_to_1(buf, 0);
01817 
01818   dfield_set_data(field, buf, 1);
01819 
01820   /* 3) Page number */
01821 
01822   field = dtuple_get_nth_field(tuple, 2);
01823 
01824   buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
01825 
01826   mach_write_to_4(buf, page_no);
01827 
01828   dfield_set_data(field, buf, 4);
01829 
01830   /* 4) Type info, part #1 */
01831 
01832   if (counter == ULINT_UNDEFINED) {
01833     i = dict_table_is_comp(index->table) ? 1 : 0;
01834   } else {
01835     ut_ad(counter <= 0xFFFF);
01836     i = IBUF_REC_INFO_SIZE;
01837   }
01838 
01839   ti = type_info = static_cast<byte *>(mem_heap_alloc(heap, i + n_fields
01840           * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE));
01841 
01842   switch (i) {
01843   default:
01844     ut_error;
01845     break;
01846   case 1:
01847     /* set the flag for ROW_FORMAT=COMPACT */
01848     *ti++ = 0;
01849     /* fall through */
01850   case 0:
01851     /* the old format does not allow delete buffering */
01852     ut_ad(op == IBUF_OP_INSERT);
01853     break;
01854   case IBUF_REC_INFO_SIZE:
01855     mach_write_to_2(ti + IBUF_REC_OFFSET_COUNTER, counter);
01856 
01857     ti[IBUF_REC_OFFSET_TYPE] = (byte) op;
01858     ti[IBUF_REC_OFFSET_FLAGS] = dict_table_is_comp(index->table)
01859       ? IBUF_REC_COMPACT : 0;
01860     ti += IBUF_REC_INFO_SIZE;
01861     break;
01862   }
01863 
01864   /* 5+) Fields from the entry */
01865 
01866   for (i = 0; i < n_fields; i++) {
01867     ulint     fixed_len;
01868     const dict_field_t* ifield;
01869 
01870     /* We add 4 below because we have the 4 extra fields at the
01871     start of an ibuf record */
01872 
01873     field = dtuple_get_nth_field(tuple, i + 4);
01874     entry_field = dtuple_get_nth_field(entry, i);
01875     dfield_copy(field, entry_field);
01876 
01877     ifield = dict_index_get_nth_field(index, i);
01878     /* Prefix index columns of fixed-length columns are of
01879     fixed length.  However, in the function call below,
01880     dfield_get_type(entry_field) contains the fixed length
01881     of the column in the clustered index.  Replace it with
01882     the fixed length of the secondary index column. */
01883     fixed_len = ifield->fixed_len;
01884 
01885 #ifdef UNIV_DEBUG
01886     if (fixed_len) {
01887       /* dict_index_add_col() should guarantee these */
01888       ut_ad(fixed_len <= (ulint)
01889             dfield_get_type(entry_field)->len);
01890       if (ifield->prefix_len) {
01891         ut_ad(ifield->prefix_len == fixed_len);
01892       } else {
01893         ut_ad(fixed_len == (ulint)
01894               dfield_get_type(entry_field)->len);
01895       }
01896     }
01897 #endif /* UNIV_DEBUG */
01898 
01899     dtype_new_store_for_order_and_null_size(
01900       ti, dfield_get_type(entry_field), fixed_len);
01901     ti += DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
01902   }
01903 
01904   /* 4) Type info, part #2 */
01905 
01906   field = dtuple_get_nth_field(tuple, 3);
01907 
01908   dfield_set_data(field, type_info, ti - type_info);
01909 
01910   /* Set all the types in the new tuple binary */
01911 
01912   dtuple_set_types_binary(tuple, n_fields + 4);
01913 
01914   return(tuple);
01915 }
01916 
01917 /*********************************************************************/
01921 static
01922 dtuple_t*
01923 ibuf_search_tuple_build(
01924 /*====================*/
01925   ulint   space,  
01926   ulint   page_no,
01927   mem_heap_t* heap) 
01928 {
01929   dtuple_t* tuple;
01930   dfield_t* field;
01931   byte*   buf;
01932 
01933   ut_a(space == 0);
01934   ut_a(trx_doublewrite_must_reset_space_ids);
01935   ut_a(!trx_sys_multiple_tablespace_format);
01936 
01937   tuple = dtuple_create(heap, 1);
01938 
01939   /* Store the page number in tuple */
01940 
01941   field = dtuple_get_nth_field(tuple, 0);
01942 
01943   buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
01944 
01945   mach_write_to_4(buf, page_no);
01946 
01947   dfield_set_data(field, buf, 4);
01948 
01949   dtuple_set_types_binary(tuple, 1);
01950 
01951   return(tuple);
01952 }
01953 
01954 /*********************************************************************/
01958 static
01959 dtuple_t*
01960 ibuf_new_search_tuple_build(
01961 /*========================*/
01962   ulint   space,  
01963   ulint   page_no,
01964   mem_heap_t* heap) 
01965 {
01966   dtuple_t* tuple;
01967   dfield_t* field;
01968   byte*   buf;
01969 
01970   ut_a(trx_sys_multiple_tablespace_format);
01971 
01972   tuple = dtuple_create(heap, 3);
01973 
01974   /* Store the space id in tuple */
01975 
01976   field = dtuple_get_nth_field(tuple, 0);
01977 
01978   buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
01979 
01980   mach_write_to_4(buf, space);
01981 
01982   dfield_set_data(field, buf, 4);
01983 
01984   /* Store the new format record marker byte */
01985 
01986   field = dtuple_get_nth_field(tuple, 1);
01987 
01988   buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
01989 
01990   mach_write_to_1(buf, 0);
01991 
01992   dfield_set_data(field, buf, 1);
01993 
01994   /* Store the page number in tuple */
01995 
01996   field = dtuple_get_nth_field(tuple, 2);
01997 
01998   buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
01999 
02000   mach_write_to_4(buf, page_no);
02001 
02002   dfield_set_data(field, buf, 4);
02003 
02004   dtuple_set_types_binary(tuple, 3);
02005 
02006   return(tuple);
02007 }
02008 
02009 /*********************************************************************/
02013 UNIV_INLINE
02014 ibool
02015 ibuf_data_enough_free_for_insert(void)
02016 /*==================================*/
02017 {
02018   ut_ad(mutex_own(&ibuf_mutex));
02019 
02020   /* We want a big margin of free pages, because a B-tree can sometimes
02021   grow in size also if records are deleted from it, as the node pointers
02022   can change, and we must make sure that we are able to delete the
02023   inserts buffered for pages that we read to the buffer pool, without
02024   any risk of running out of free space in the insert buffer. */
02025 
02026   return(ibuf->free_list_len >= (ibuf->size / 2) + 3 * ibuf->height);
02027 }
02028 
02029 /*********************************************************************/
02033 UNIV_INLINE
02034 ibool
02035 ibuf_data_too_much_free(void)
02036 /*=========================*/
02037 {
02038   ut_ad(mutex_own(&ibuf_mutex));
02039 
02040   return(ibuf->free_list_len >= 3 + (ibuf->size / 2) + 3 * ibuf->height);
02041 }
02042 
02043 /*********************************************************************/
02047 static
02048 ibool
02049 ibuf_add_free_page(void)
02050 /*====================*/
02051 {
02052   mtr_t mtr;
02053   page_t* header_page;
02054   ulint flags;
02055   ulint zip_size;
02056   ulint page_no;
02057   page_t* page;
02058   page_t* root;
02059   page_t* bitmap_page;
02060 
02061   mtr_start(&mtr);
02062 
02063   /* Acquire the fsp latch before the ibuf header, obeying the latching
02064   order */
02065   mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, &flags), &mtr);
02066   zip_size = dict_table_flags_to_zip_size(flags);
02067 
02068   header_page = ibuf_header_page_get(&mtr);
02069 
02070   /* Allocate a new page: NOTE that if the page has been a part of a
02071   non-clustered index which has subsequently been dropped, then the
02072   page may have buffered inserts in the insert buffer, and these
02073   should be deleted from there. These get deleted when the page
02074   allocation creates the page in buffer. Thus the call below may end
02075   up calling the insert buffer routines and, as we yet have no latches
02076   to insert buffer tree pages, these routines can run without a risk
02077   of a deadlock. This is the reason why we created a special ibuf
02078   header page apart from the ibuf tree. */
02079 
02080   page_no = fseg_alloc_free_page(
02081     header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
02082     &mtr);
02083 
02084   if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
02085     mtr_commit(&mtr);
02086 
02087     return(FALSE);
02088   }
02089 
02090   {
02091     buf_block_t*  block;
02092 
02093     block = buf_page_get(
02094       IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
02095 
02096     buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
02097 
02098 
02099     page = buf_block_get_frame(block);
02100   }
02101 
02102   ibuf_enter();
02103 
02104   mutex_enter(&ibuf_mutex);
02105 
02106   root = ibuf_tree_root_get(&mtr);
02107 
02108   /* Add the page to the free list and update the ibuf size data */
02109 
02110   flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
02111           page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
02112 
02113   mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_IBUF_FREE_LIST,
02114        MLOG_2BYTES, &mtr);
02115 
02116   ibuf->seg_size++;
02117   ibuf->free_list_len++;
02118 
02119   /* Set the bit indicating that this page is now an ibuf tree page
02120   (level 2 page) */
02121 
02122   bitmap_page = ibuf_bitmap_get_map_page(
02123     IBUF_SPACE_ID, page_no, zip_size, &mtr);
02124 
02125   mutex_exit(&ibuf_mutex);
02126 
02127   ibuf_bitmap_page_set_bits(
02128     bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
02129 
02130   mtr_commit(&mtr);
02131 
02132   ibuf_exit();
02133 
02134   return(TRUE);
02135 }
02136 
02137 /*********************************************************************/
02139 static
02140 void
02141 ibuf_remove_free_page(void)
02142 /*=======================*/
02143 {
02144   mtr_t mtr;
02145   mtr_t mtr2;
02146   page_t* header_page;
02147   ulint flags;
02148   ulint zip_size;
02149   ulint page_no;
02150   page_t* page;
02151   page_t* root;
02152   page_t* bitmap_page;
02153 
02154   mtr_start(&mtr);
02155 
02156   /* Acquire the fsp latch before the ibuf header, obeying the latching
02157   order */
02158   mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, &flags), &mtr);
02159   zip_size = dict_table_flags_to_zip_size(flags);
02160 
02161   header_page = ibuf_header_page_get(&mtr);
02162 
02163   /* Prevent pessimistic inserts to insert buffer trees for a while */
02164   ibuf_enter();
02165   mutex_enter(&ibuf_pessimistic_insert_mutex);
02166   mutex_enter(&ibuf_mutex);
02167 
02168   if (!ibuf_data_too_much_free()) {
02169 
02170     mutex_exit(&ibuf_mutex);
02171     mutex_exit(&ibuf_pessimistic_insert_mutex);
02172 
02173     ibuf_exit();
02174 
02175     mtr_commit(&mtr);
02176 
02177     return;
02178   }
02179 
02180   mtr_start(&mtr2);
02181 
02182   root = ibuf_tree_root_get(&mtr2);
02183 
02184   mutex_exit(&ibuf_mutex);
02185 
02186   page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
02187         &mtr2).page;
02188 
02189   /* NOTE that we must release the latch on the ibuf tree root
02190   because in fseg_free_page we access level 1 pages, and the root
02191   is a level 2 page. */
02192 
02193   mtr_commit(&mtr2);
02194 
02195   ibuf_exit();
02196 
02197   /* Since pessimistic inserts were prevented, we know that the
02198   page is still in the free list. NOTE that also deletes may take
02199   pages from the free list, but they take them from the start, and
02200   the free list was so long that they cannot have taken the last
02201   page from it. */
02202 
02203   fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
02204            IBUF_SPACE_ID, page_no, &mtr);
02205 
02206 #ifdef UNIV_DEBUG_FILE_ACCESSES
02207   buf_page_reset_file_page_was_freed(IBUF_SPACE_ID, page_no);
02208 #endif
02209 
02210   ibuf_enter();
02211 
02212   mutex_enter(&ibuf_mutex);
02213 
02214   root = ibuf_tree_root_get(&mtr);
02215 
02216   ut_ad(page_no == flst_get_last(root + PAGE_HEADER
02217                + PAGE_BTR_IBUF_FREE_LIST, &mtr).page);
02218 
02219   {
02220     buf_block_t*  block;
02221 
02222     block = buf_page_get(
02223       IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
02224 
02225     buf_block_dbg_add_level(block, SYNC_TREE_NODE);
02226 
02227 
02228     page = buf_block_get_frame(block);
02229   }
02230 
02231   /* Remove the page from the free list and update the ibuf size data */
02232 
02233   flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
02234         page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
02235 
02236   mutex_exit(&ibuf_pessimistic_insert_mutex);
02237 
02238   ibuf->seg_size--;
02239   ibuf->free_list_len--;
02240 
02241   /* Set the bit indicating that this page is no more an ibuf tree page
02242   (level 2 page) */
02243 
02244   bitmap_page = ibuf_bitmap_get_map_page(
02245     IBUF_SPACE_ID, page_no, zip_size, &mtr);
02246 
02247   mutex_exit(&ibuf_mutex);
02248 
02249   ibuf_bitmap_page_set_bits(
02250     bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr);
02251 
02252 #ifdef UNIV_DEBUG_FILE_ACCESSES
02253   buf_page_set_file_page_was_freed(IBUF_SPACE_ID, page_no);
02254 #endif
02255   mtr_commit(&mtr);
02256 
02257   ibuf_exit();
02258 }
02259 
02260 /***********************************************************************/
02264 UNIV_INTERN
02265 void
02266 ibuf_free_excess_pages(void)
02267 /*========================*/
02268 {
02269   ulint   i;
02270 
02271 #ifdef UNIV_SYNC_DEBUG
02272   ut_ad(rw_lock_own(fil_space_get_latch(IBUF_SPACE_ID, NULL),
02273         RW_LOCK_EX));
02274 #endif /* UNIV_SYNC_DEBUG */
02275 
02276   ut_ad(rw_lock_get_x_lock_count(
02277     fil_space_get_latch(IBUF_SPACE_ID, NULL)) == 1);
02278 
02279   ut_ad(!ibuf_inside());
02280 
02281   /* NOTE: We require that the thread did not own the latch before,
02282   because then we know that we can obey the correct latching order
02283   for ibuf latches */
02284 
02285   if (!ibuf) {
02286     /* Not yet initialized; not sure if this is possible, but
02287     does no harm to check for it. */
02288 
02289     return;
02290   }
02291 
02292   /* Free at most a few pages at a time, so that we do not delay the
02293   requested service too much */
02294 
02295   for (i = 0; i < 4; i++) {
02296 
02297     ibool too_much_free;
02298 
02299     mutex_enter(&ibuf_mutex);
02300     too_much_free = ibuf_data_too_much_free();
02301     mutex_exit(&ibuf_mutex);
02302 
02303     if (!too_much_free) {
02304       return;
02305     }
02306 
02307     ibuf_remove_free_page();
02308   }
02309 }
02310 
02311 /*********************************************************************/
02315 static
02316 ulint
02317 ibuf_get_merge_page_nos(
02318 /*====================*/
02319   ibool   contract,
02323   rec_t*    rec,  
02325   ulint*    space_ids,
02326   ib_int64_t* space_versions,
02329   ulint*    page_nos,
02332   ulint*    n_stored)
02334 {
02335   ulint prev_page_no;
02336   ulint prev_space_id;
02337   ulint first_page_no;
02338   ulint first_space_id;
02339   ulint rec_page_no;
02340   ulint rec_space_id;
02341   ulint sum_volumes;
02342   ulint volume_for_page;
02343   ulint rec_volume;
02344   ulint limit;
02345   ulint n_pages;
02346 
02347   *n_stored = 0;
02348 
02349   limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4);
02350 
02351   if (page_rec_is_supremum(rec)) {
02352 
02353     rec = page_rec_get_prev(rec);
02354   }
02355 
02356   if (page_rec_is_infimum(rec)) {
02357 
02358     rec = page_rec_get_next(rec);
02359   }
02360 
02361   if (page_rec_is_supremum(rec)) {
02362 
02363     return(0);
02364   }
02365 
02366   first_page_no = ibuf_rec_get_page_no(rec);
02367   first_space_id = ibuf_rec_get_space(rec);
02368   n_pages = 0;
02369   prev_page_no = 0;
02370   prev_space_id = 0;
02371 
02372   /* Go backwards from the first rec until we reach the border of the
02373   'merge area', or the page start or the limit of storeable pages is
02374   reached */
02375 
02376   while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) {
02377 
02378     rec_page_no = ibuf_rec_get_page_no(rec);
02379     rec_space_id = ibuf_rec_get_space(rec);
02380 
02381     if (rec_space_id != first_space_id
02382         || (rec_page_no / IBUF_MERGE_AREA)
02383         != (first_page_no / IBUF_MERGE_AREA)) {
02384 
02385       break;
02386     }
02387 
02388     if (rec_page_no != prev_page_no
02389         || rec_space_id != prev_space_id) {
02390       n_pages++;
02391     }
02392 
02393     prev_page_no = rec_page_no;
02394     prev_space_id = rec_space_id;
02395 
02396     rec = page_rec_get_prev(rec);
02397   }
02398 
02399   rec = page_rec_get_next(rec);
02400 
02401   /* At the loop start there is no prev page; we mark this with a pair
02402   of space id, page no (0, 0) for which there can never be entries in
02403   the insert buffer */
02404 
02405   prev_page_no = 0;
02406   prev_space_id = 0;
02407   sum_volumes = 0;
02408   volume_for_page = 0;
02409 
02410   while (*n_stored < limit) {
02411     if (page_rec_is_supremum(rec)) {
02412       /* When no more records available, mark this with
02413       another 'impossible' pair of space id, page no */
02414       rec_page_no = 1;
02415       rec_space_id = 0;
02416     } else {
02417       rec_page_no = ibuf_rec_get_page_no(rec);
02418       rec_space_id = ibuf_rec_get_space(rec);
02419       ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
02420     }
02421 
02422 #ifdef UNIV_IBUF_DEBUG
02423     ut_a(*n_stored < IBUF_MAX_N_PAGES_MERGED);
02424 #endif
02425     if ((rec_space_id != prev_space_id
02426          || rec_page_no != prev_page_no)
02427         && (prev_space_id != 0 || prev_page_no != 0)) {
02428 
02429       if ((prev_page_no == first_page_no
02430            && prev_space_id == first_space_id)
02431           || contract
02432           || (volume_for_page
02433         > ((IBUF_MERGE_THRESHOLD - 1)
02434            * 4 * UNIV_PAGE_SIZE
02435            / IBUF_PAGE_SIZE_PER_FREE_SPACE)
02436         / IBUF_MERGE_THRESHOLD)) {
02437 
02438         space_ids[*n_stored] = prev_space_id;
02439         space_versions[*n_stored]
02440           = fil_space_get_version(prev_space_id);
02441         page_nos[*n_stored] = prev_page_no;
02442 
02443         (*n_stored)++;
02444 
02445         sum_volumes += volume_for_page;
02446       }
02447 
02448       if (rec_space_id != first_space_id
02449           || rec_page_no / IBUF_MERGE_AREA
02450           != first_page_no / IBUF_MERGE_AREA) {
02451 
02452         break;
02453       }
02454 
02455       volume_for_page = 0;
02456     }
02457 
02458     if (rec_page_no == 1 && rec_space_id == 0) {
02459       /* Supremum record */
02460 
02461       break;
02462     }
02463 
02464     rec_volume = ibuf_rec_get_volume(rec);
02465 
02466     volume_for_page += rec_volume;
02467 
02468     prev_page_no = rec_page_no;
02469     prev_space_id = rec_space_id;
02470 
02471     rec = page_rec_get_next(rec);
02472   }
02473 
02474 #ifdef UNIV_IBUF_DEBUG
02475   ut_a(*n_stored <= IBUF_MAX_N_PAGES_MERGED);
02476 #endif
02477 #if 0
02478   fprintf(stderr, "Ibuf merge batch %lu pages %lu volume\n",
02479     *n_stored, sum_volumes);
02480 #endif
02481   return(sum_volumes);
02482 }
02483 
02484 /*********************************************************************/
02489 static
02490 ulint
02491 ibuf_contract_ext(
02492 /*==============*/
02493   ulint*  n_pages,
02494   ibool sync) 
02497 {
02498   btr_pcur_t  pcur;
02499   ulint   page_nos[IBUF_MAX_N_PAGES_MERGED];
02500   ulint   space_ids[IBUF_MAX_N_PAGES_MERGED];
02501   ib_int64_t  space_versions[IBUF_MAX_N_PAGES_MERGED];
02502   ulint   sum_sizes;
02503   mtr_t   mtr;
02504 
02505   *n_pages = 0;
02506   ut_ad(!ibuf_inside());
02507 
02508   /* We perform a dirty read of ibuf->empty, without latching
02509   the insert buffer root page. We trust this dirty read except
02510   when a slow shutdown is being executed. During a slow
02511   shutdown, the insert buffer merge must be completed. */
02512 
02513   if (UNIV_UNLIKELY(ibuf->empty)
02514       && UNIV_LIKELY(!srv_shutdown_state)) {
02515 ibuf_is_empty:
02516 
02517 #if 0 /* TODO */
02518     if (srv_shutdown_state) {
02519       /* If the insert buffer becomes empty during
02520       shutdown, note it in the system tablespace. */
02521 
02522       trx_sys_set_ibuf_format(TRX_SYS_IBUF_EMPTY);
02523     }
02524 
02525     /* TO DO: call trx_sys_set_ibuf_format() at startup
02526     and whenever ibuf_use is changed to allow buffered
02527     delete-marking or deleting.  Never downgrade the
02528     stamped format except when the insert buffer becomes
02529     empty. */
02530 #endif
02531 
02532     return(0);
02533   }
02534 
02535   mtr_start(&mtr);
02536 
02537   ibuf_enter();
02538 
02539   /* Open a cursor to a randomly chosen leaf of the tree, at a random
02540   position within the leaf */
02541 
02542   btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr);
02543 
02544   ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
02545 
02546   if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
02547     /* If a B-tree page is empty, it must be the root page
02548     and the whole B-tree must be empty. InnoDB does not
02549     allow empty B-tree pages other than the root. */
02550     ut_ad(ibuf->empty);
02551     ut_ad(page_get_space_id(btr_pcur_get_page(&pcur))
02552           == IBUF_SPACE_ID);
02553     ut_ad(page_get_page_no(btr_pcur_get_page(&pcur))
02554           == FSP_IBUF_TREE_ROOT_PAGE_NO);
02555 
02556     ibuf_exit();
02557 
02558     mtr_commit(&mtr);
02559     btr_pcur_close(&pcur);
02560 
02561     goto ibuf_is_empty;
02562   }
02563 
02564   sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
02565               space_ids, space_versions,
02566               page_nos, n_pages);
02567 #if 0 /* defined UNIV_IBUF_DEBUG */
02568   fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
02569     sync, *n_pages, sum_sizes);
02570 #endif
02571   ibuf_exit();
02572 
02573   mtr_commit(&mtr);
02574   btr_pcur_close(&pcur);
02575 
02576   buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos,
02577           *n_pages);
02578 
02579   return(sum_sizes + 1);
02580 }
02581 
02582 /*********************************************************************/
02587 UNIV_INTERN
02588 ulint
02589 ibuf_contract(
02590 /*==========*/
02591   ibool sync) 
02594 {
02595   ulint n_pages;
02596 
02597   return(ibuf_contract_ext(&n_pages, sync));
02598 }
02599 
02600 /*********************************************************************/
02605 UNIV_INTERN
02606 ulint
02607 ibuf_contract_for_n_pages(
02608 /*======================*/
02609   ibool sync, 
02612   ulint n_pages)
02615 {
02616   ulint sum_bytes = 0;
02617   ulint sum_pages = 0;
02618   ulint n_bytes;
02619   ulint n_pag2;
02620 
02621         if (srv_fake_write)
02622           return(0);
02623 
02624   while (sum_pages < n_pages) {
02625     n_bytes = ibuf_contract_ext(&n_pag2, sync);
02626 
02627     if (n_bytes == 0) {
02628       return(sum_bytes);
02629     }
02630 
02631     sum_bytes += n_bytes;
02632     sum_pages += n_pag2;
02633   }
02634 
02635   return(sum_bytes);
02636 }
02637 
02638 /*********************************************************************/
02640 UNIV_INLINE
02641 void
02642 ibuf_contract_after_insert(
02643 /*=======================*/
02644   ulint entry_size) 
02646 {
02647   ibool sync;
02648   ulint sum_sizes;
02649   ulint size;
02650   ulint max_size;
02651 
02652   /* Perform dirty reads of ibuf->size and ibuf->max_size, to
02653   reduce ibuf_mutex contention. ibuf->max_size remains constant
02654   after ibuf_init_at_db_start(), but ibuf->size should be
02655   protected by ibuf_mutex. Given that ibuf->size fits in a
02656   machine word, this should be OK; at worst we are doing some
02657   excessive ibuf_contract() or occasionally skipping a
02658   ibuf_contract(). */
02659   size = ibuf->size;
02660   max_size = ibuf->max_size;
02661 
02662   if (srv_ibuf_active_contract == false
02663       && size < max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
02664     return;
02665   }
02666 
02667   sync = (size >= max_size + IBUF_CONTRACT_ON_INSERT_SYNC);
02668 
02669   /* Contract at least entry_size many bytes */
02670   sum_sizes = 0;
02671   size = 1;
02672 
02673   do {
02674 
02675     size = ibuf_contract(sync);
02676     sum_sizes += size;
02677   } while (size > 0 && sum_sizes < entry_size);
02678 }
02679 
02680 /*********************************************************************/
02683 static
02684 ibool
02685 ibuf_get_volume_buffered_hash(
02686 /*==========================*/
02687   const rec_t*  rec,  
02688   const byte* types,  
02689   const byte* data, 
02690   ulint   comp, 
02692   ulint*    hash, 
02693   ulint   size) 
02694 {
02695   ulint   len;
02696   ulint   fold;
02697   ulint   bitmask;
02698 
02699   len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4,
02700         FALSE, comp);
02701   fold = ut_fold_binary(data, len);
02702 
02703   hash += (fold / (8 * sizeof *hash)) % size; // 8 = bits in byte
02704   bitmask = 1 << (fold % (8 * sizeof *hash));
02705 
02706   if (*hash & bitmask) {
02707 
02708     return(FALSE);
02709   }
02710 
02711   /* We have not seen this record yet.  Insert it. */
02712   *hash |= bitmask;
02713 
02714   return(TRUE);
02715 }
02716 
02717 /*********************************************************************/
02722 static
02723 ulint
02724 ibuf_get_volume_buffered_count(
02725 /*===========================*/
02726   const rec_t*  rec,  
02727   ulint*    hash, 
02728   ulint   size, 
02729   lint*   n_recs) 
02731 {
02732   ulint   len;
02733   ibuf_op_t ibuf_op;
02734   const byte* types;
02735   ulint   n_fields  = rec_get_n_fields_old(rec);
02736 
02737   ut_ad(ibuf_inside());
02738   ut_ad(n_fields > 4);
02739   n_fields -= 4;
02740 
02741   rec_get_nth_field_offs_old(rec, 1, &len);
02742   /* This function is only invoked when buffering new
02743   operations.  All pre-4.1 records should have been merged
02744   when the database was started up. */
02745   ut_a(len == 1);
02746   ut_ad(trx_sys_multiple_tablespace_format);
02747 
02748   types = rec_get_nth_field_old(rec, 3, &len);
02749 
02750   switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
02751           IBUF_REC_INFO_SIZE)) {
02752   default:
02753     ut_error;
02754   case 0:
02755     /* This ROW_TYPE=REDUNDANT record does not include an
02756     operation counter.  Exclude it from the *n_recs,
02757     because deletes cannot be buffered if there are
02758     old-style inserts buffered for the page. */
02759 
02760     len = ibuf_rec_get_size(rec, types, n_fields, FALSE, 0);
02761 
02762     return(len
02763            + rec_get_converted_extra_size(len, n_fields, 0)
02764            + page_dir_calc_reserved_space(1));
02765   case 1:
02766     /* This ROW_TYPE=COMPACT record does not include an
02767     operation counter.  Exclude it from the *n_recs,
02768     because deletes cannot be buffered if there are
02769     old-style inserts buffered for the page. */
02770     goto get_volume_comp;
02771 
02772   case IBUF_REC_INFO_SIZE:
02773     ibuf_op = (ibuf_op_t) types[IBUF_REC_OFFSET_TYPE];
02774     break;
02775   }
02776 
02777   switch (ibuf_op) {
02778   case IBUF_OP_INSERT:
02779     /* Inserts can be done by updating a delete-marked record.
02780     Because delete-mark and insert operations can be pointing to
02781     the same records, we must not count duplicates. */
02782   case IBUF_OP_DELETE_MARK:
02783     /* There must be a record to delete-mark.
02784     See if this record has been already buffered. */
02785     if (n_recs && ibuf_get_volume_buffered_hash(
02786           rec, types + IBUF_REC_INFO_SIZE,
02787           types + len,
02788           types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT,
02789           hash, size)) {
02790       (*n_recs)++;
02791     }
02792 
02793     if (ibuf_op == IBUF_OP_DELETE_MARK) {
02794       /* Setting the delete-mark flag does not
02795       affect the available space on the page. */
02796       return(0);
02797     }
02798     break;
02799   case IBUF_OP_DELETE:
02800     /* A record will be removed from the page. */
02801     if (n_recs) {
02802       (*n_recs)--;
02803     }
02804     /* While deleting a record actually frees up space,
02805     we have to play it safe and pretend that it takes no
02806     additional space (the record might not exist, etc.). */
02807     return(0);
02808   default:
02809     ut_error;
02810   }
02811 
02812   ut_ad(ibuf_op == IBUF_OP_INSERT);
02813 
02814 get_volume_comp:
02815   {
02816     dtuple_t* entry;
02817     ulint   volume;
02818     dict_index_t* dummy_index;
02819     mem_heap_t* heap = mem_heap_create(500);
02820 
02821     entry = ibuf_build_entry_from_ibuf_rec(
02822       rec, heap, &dummy_index);
02823 
02824     volume = rec_get_converted_size(dummy_index, entry, 0);
02825 
02826     ibuf_dummy_index_free(dummy_index);
02827     mem_heap_free(heap);
02828 
02829     return(volume + page_dir_calc_reserved_space(1));
02830   }
02831 }
02832 
02833 /*********************************************************************/
02839 static
02840 ulint
02841 ibuf_get_volume_buffered(
02842 /*=====================*/
02843   btr_pcur_t* pcur, 
02848   ulint   space,  
02849   ulint   page_no,
02850   lint*   n_recs, 
02853   mtr_t*    mtr)  
02854 {
02855   ulint volume;
02856   rec_t*  rec;
02857   page_t* page;
02858   ulint prev_page_no;
02859   page_t* prev_page;
02860   ulint next_page_no;
02861   page_t* next_page;
02862   ulint hash_bitmap[128 / sizeof(ulint)]; /* bitmap of buffered recs */
02863 
02864   ut_a(trx_sys_multiple_tablespace_format);
02865 
02866   ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
02867         || (pcur->latch_mode == BTR_MODIFY_TREE));
02868 
02869   /* Count the volume of inserts earlier in the alphabetical order than
02870   pcur */
02871 
02872   volume = 0;
02873 
02874   if (n_recs) {
02875     memset(hash_bitmap, 0, sizeof hash_bitmap);
02876   }
02877 
02878   rec = btr_pcur_get_rec(pcur);
02879   page = page_align(rec);
02880   ut_ad(page_validate(page, ibuf->index));
02881 
02882   if (page_rec_is_supremum(rec)) {
02883     rec = page_rec_get_prev(rec);
02884   }
02885 
02886   for (;;) {
02887     if (page_rec_is_infimum(rec)) {
02888 
02889       break;
02890     }
02891 
02892     if (page_no != ibuf_rec_get_page_no(rec)
02893         || space != ibuf_rec_get_space(rec)) {
02894 
02895       goto count_later;
02896     }
02897 
02898     volume += ibuf_get_volume_buffered_count(
02899       rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
02900 
02901     rec = page_rec_get_prev(rec);
02902     ut_ad(page_align(rec) == page);
02903   }
02904 
02905   /* Look at the previous page */
02906 
02907   prev_page_no = btr_page_get_prev(page, mtr);
02908 
02909   if (prev_page_no == FIL_NULL) {
02910 
02911     goto count_later;
02912   }
02913 
02914   {
02915     buf_block_t*  block;
02916 
02917     block = buf_page_get(
02918       IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr);
02919 
02920     buf_block_dbg_add_level(block, SYNC_TREE_NODE);
02921 
02922 
02923     prev_page = buf_block_get_frame(block);
02924     ut_ad(page_validate(prev_page, ibuf->index));
02925   }
02926 
02927 #ifdef UNIV_BTR_DEBUG
02928   ut_a(btr_page_get_next(prev_page, mtr)
02929        == page_get_page_no(page));
02930 #endif /* UNIV_BTR_DEBUG */
02931 
02932   rec = page_get_supremum_rec(prev_page);
02933   rec = page_rec_get_prev(rec);
02934 
02935   for (;;) {
02936     if (page_rec_is_infimum(rec)) {
02937 
02938       /* We cannot go to yet a previous page, because we
02939       do not have the x-latch on it, and cannot acquire one
02940       because of the latching order: we have to give up */
02941 
02942       return(UNIV_PAGE_SIZE);
02943     }
02944 
02945     if (page_no != ibuf_rec_get_page_no(rec)
02946         || space != ibuf_rec_get_space(rec)) {
02947 
02948       goto count_later;
02949     }
02950 
02951     volume += ibuf_get_volume_buffered_count(
02952       rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
02953 
02954     rec = page_rec_get_prev(rec);
02955     ut_ad(page_align(rec) == prev_page);
02956   }
02957 
02958 count_later:
02959   rec = btr_pcur_get_rec(pcur);
02960 
02961   if (!page_rec_is_supremum(rec)) {
02962     rec = page_rec_get_next(rec);
02963   }
02964 
02965   for (;;) {
02966     if (page_rec_is_supremum(rec)) {
02967 
02968       break;
02969     }
02970 
02971     if (page_no != ibuf_rec_get_page_no(rec)
02972         || space != ibuf_rec_get_space(rec)) {
02973 
02974       return(volume);
02975     }
02976 
02977     volume += ibuf_get_volume_buffered_count(
02978       rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
02979 
02980     rec = page_rec_get_next(rec);
02981   }
02982 
02983   /* Look at the next page */
02984 
02985   next_page_no = btr_page_get_next(page, mtr);
02986 
02987   if (next_page_no == FIL_NULL) {
02988 
02989     return(volume);
02990   }
02991 
02992   {
02993     buf_block_t*  block;
02994 
02995     block = buf_page_get(
02996       IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr);
02997 
02998     buf_block_dbg_add_level(block, SYNC_TREE_NODE);
02999 
03000 
03001     next_page = buf_block_get_frame(block);
03002     ut_ad(page_validate(next_page, ibuf->index));
03003   }
03004 
03005 #ifdef UNIV_BTR_DEBUG
03006   ut_a(btr_page_get_prev(next_page, mtr) == page_get_page_no(page));
03007 #endif /* UNIV_BTR_DEBUG */
03008 
03009   rec = page_get_infimum_rec(next_page);
03010   rec = page_rec_get_next(rec);
03011 
03012   for (;;) {
03013     if (page_rec_is_supremum(rec)) {
03014 
03015       /* We give up */
03016 
03017       return(UNIV_PAGE_SIZE);
03018     }
03019 
03020     if (page_no != ibuf_rec_get_page_no(rec)
03021         || space != ibuf_rec_get_space(rec)) {
03022 
03023       return(volume);
03024     }
03025 
03026     volume += ibuf_get_volume_buffered_count(
03027       rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
03028 
03029     rec = page_rec_get_next(rec);
03030     ut_ad(page_align(rec) == next_page);
03031   }
03032 }
03033 
03034 /*********************************************************************/
03037 UNIV_INTERN
03038 void
03039 ibuf_update_max_tablespace_id(void)
03040 /*===============================*/
03041 {
03042   ulint   max_space_id;
03043   const rec_t*  rec;
03044   const byte* field;
03045   ulint   len;
03046   btr_pcur_t  pcur;
03047   mtr_t   mtr;
03048 
03049   ut_a(!dict_table_is_comp(ibuf->index->table));
03050 
03051   ibuf_enter();
03052 
03053   mtr_start(&mtr);
03054 
03055   btr_pcur_open_at_index_side(
03056     FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
03057 
03058   ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
03059 
03060   btr_pcur_move_to_prev(&pcur, &mtr);
03061 
03062   if (btr_pcur_is_before_first_on_page(&pcur)) {
03063     /* The tree is empty */
03064 
03065     max_space_id = 0;
03066   } else {
03067     rec = btr_pcur_get_rec(&pcur);
03068 
03069     field = rec_get_nth_field_old(rec, 0, &len);
03070 
03071     ut_a(len == 4);
03072 
03073     max_space_id = mach_read_from_4(field);
03074   }
03075 
03076   mtr_commit(&mtr);
03077   ibuf_exit();
03078 
03079   /* printf("Maximum space id in insert buffer %lu\n", max_space_id); */
03080 
03081   fil_set_max_space_id_if_bigger(max_space_id);
03082 }
03083 
03084 /****************************************************************/
03089 static
03090 ulint
03091 ibuf_get_entry_counter_low(
03092 /*=======================*/
03093   const rec_t*  rec,    
03094   ulint   space,    
03095   ulint   page_no)  
03096 {
03097   ulint   counter;
03098   const byte* field;
03099   ulint   len;
03100 
03101   ut_ad(ibuf_inside());
03102   ut_ad(rec_get_n_fields_old(rec) > 2);
03103 
03104   field = rec_get_nth_field_old(rec, 1, &len);
03105 
03106   if (UNIV_UNLIKELY(len != 1)) {
03107     /* pre-4.1 format */
03108     ut_a(trx_doublewrite_must_reset_space_ids);
03109     ut_a(!trx_sys_multiple_tablespace_format);
03110 
03111     return(ULINT_UNDEFINED);
03112   }
03113 
03114   ut_a(trx_sys_multiple_tablespace_format);
03115 
03116   /* Check the tablespace identifier. */
03117   field = rec_get_nth_field_old(rec, 0, &len);
03118   ut_a(len == 4);
03119 
03120   if (mach_read_from_4(field) != space) {
03121 
03122     return(0);
03123   }
03124 
03125   /* Check the page offset. */
03126   field = rec_get_nth_field_old(rec, 2, &len);
03127   ut_a(len == 4);
03128 
03129   if (mach_read_from_4(field) != page_no) {
03130 
03131     return(0);
03132   }
03133 
03134   /* Check if the record contains a counter field. */
03135   field = rec_get_nth_field_old(rec, 3, &len);
03136 
03137   switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
03138   default:
03139     ut_error;
03140   case 0: /* ROW_FORMAT=REDUNDANT */
03141   case 1: /* ROW_FORMAT=COMPACT */
03142     return(ULINT_UNDEFINED);
03143 
03144   case IBUF_REC_INFO_SIZE:
03145     counter = mach_read_from_2(field + IBUF_REC_OFFSET_COUNTER);
03146     ut_a(counter < 0xFFFF);
03147     return(counter + 1);
03148   }
03149 }
03150 
03151 /****************************************************************/
03155 static
03156 ibool
03157 ibuf_set_entry_counter(
03158 /*===================*/
03159   dtuple_t* entry,    
03160   ulint   space,    
03161   ulint   page_no,  
03162   btr_pcur_t* pcur,   
03165   ibool   is_optimistic,  
03166   mtr_t*    mtr)    
03167 {
03168   dfield_t* field;
03169   byte*   data;
03170   ulint   counter = 0;
03171 
03172   /* pcur points to either a user rec or to a page's infimum record. */
03173   ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index));
03174 
03175   if (btr_pcur_is_on_user_rec(pcur)) {
03176 
03177     counter = ibuf_get_entry_counter_low(
03178       btr_pcur_get_rec(pcur), space, page_no);
03179 
03180     if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
03181       /* The record lacks a counter field.
03182       Such old records must be merged before
03183       new records can be buffered. */
03184 
03185       return(FALSE);
03186     }
03187   } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) {
03188     /* Ibuf tree is either completely empty, or the insert
03189     position is at the very first record of a non-empty tree. In
03190     either case we have no previous records for (space,
03191     page_no). */
03192 
03193     counter = 0;
03194   } else if (btr_pcur_is_before_first_on_page(pcur)) {
03195     btr_cur_t*  cursor = btr_pcur_get_btr_cur(pcur);
03196 
03197     if (cursor->low_match < 3) {
03198       /* If low_match < 3, we know that the father node
03199       pointer did not contain the searched for (space,
03200       page_no), which means that the search ended on the
03201       right page regardless of the counter value, and
03202       since we're at the infimum record, there are no
03203       existing records. */
03204 
03205       counter = 0;
03206     } else {
03207       rec_t*    rec;
03208       const page_t* page;
03209       buf_block_t*  block;
03210       page_t*   prev_page;
03211       ulint   prev_page_no;
03212 
03213       ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED);
03214 
03215       page = btr_pcur_get_page(pcur);
03216       prev_page_no = btr_page_get_prev(page, mtr);
03217 
03218       ut_a(prev_page_no != FIL_NULL);
03219 
03220       block = buf_page_get(
03221         IBUF_SPACE_ID, 0, prev_page_no,
03222         RW_X_LATCH, mtr);
03223 
03224       buf_block_dbg_add_level(block, SYNC_TREE_NODE);
03225 
03226       prev_page = buf_block_get_frame(block);
03227 
03228       rec = page_rec_get_prev(
03229         page_get_supremum_rec(prev_page));
03230 
03231       ut_ad(page_rec_is_user_rec(rec));
03232 
03233       counter = ibuf_get_entry_counter_low(
03234         rec, space, page_no);
03235 
03236       if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
03237         /* The record lacks a counter field.
03238         Such old records must be merged before
03239         new records can be buffered. */
03240 
03241         return(FALSE);
03242       }
03243 
03244       if (counter < cursor->ibuf_cnt) {
03245         /* Search ended on the wrong page. */
03246 
03247         if (is_optimistic) {
03248           /* In an optimistic insert, we can
03249           shift the insert position to the left
03250           page, since it only needs an X-latch
03251           on the page itself, which the
03252           original search acquired for us. */
03253 
03254           btr_cur_position(
03255             ibuf->index, rec, block,
03256             btr_pcur_get_btr_cur(pcur));
03257         } else {
03258           /* We can't shift the insert
03259           position to the left page in a
03260           pessimistic insert since it would
03261           require an X-latch on the left
03262           page's left page, so we have to
03263           abort. */
03264 
03265           return(FALSE);
03266         }
03267       } else {
03268         /* The counter field in the father node is
03269         the same as we would insert; we don't know
03270         whether the insert should go to this page or
03271         the left page (the later fields can differ),
03272         so refuse the insert. */
03273 
03274         return(FALSE);
03275       }
03276     }
03277   } else {
03278     /* The cursor is not positioned at or before a user record. */
03279     return(FALSE);
03280   }
03281 
03282   /* Patch counter value in already built entry. */
03283   field = dtuple_get_nth_field(entry, 3);
03284   data = static_cast<byte *>(dfield_get_data(field));
03285 
03286   mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter);
03287 
03288   return(TRUE);
03289 }
03290 
03291 /*********************************************************************/
03295 static
03296 ulint
03297 ibuf_insert_low(
03298 /*============*/
03299   ulint   mode, 
03300   ibuf_op_t op, 
03301   ibool   no_counter,
03304   const dtuple_t* entry,  
03305   ulint   entry_size,
03307   dict_index_t* index,  
03309   ulint   space,  
03310   ulint   zip_size,
03311   ulint   page_no,
03312   que_thr_t*  thr)  
03313 {
03314   big_rec_t*  dummy_big_rec;
03315   btr_pcur_t  pcur;
03316   btr_cur_t*  cursor;
03317   dtuple_t* ibuf_entry;
03318   mem_heap_t* heap;
03319   ulint   buffered;
03320   lint    min_n_recs;
03321   rec_t*    ins_rec;
03322   ibool   old_bit_value;
03323   page_t*   bitmap_page;
03324   buf_block_t*  block;
03325   page_t*   root;
03326   ulint   err;
03327   ibool   do_merge;
03328   ulint   space_ids[IBUF_MAX_N_PAGES_MERGED];
03329   ib_int64_t  space_versions[IBUF_MAX_N_PAGES_MERGED];
03330   ulint   page_nos[IBUF_MAX_N_PAGES_MERGED];
03331   ulint   n_stored;
03332   mtr_t   mtr;
03333   mtr_t   bitmap_mtr;
03334 
03335   ut_a(!dict_index_is_clust(index));
03336   ut_ad(dtuple_check_typed(entry));
03337   ut_ad(ut_is_2pow(zip_size));
03338   ut_ad(!no_counter || op == IBUF_OP_INSERT);
03339   ut_a(op < IBUF_OP_COUNT);
03340 
03341   ut_a(trx_sys_multiple_tablespace_format);
03342 
03343   do_merge = FALSE;
03344 
03345   /* Perform dirty reads of ibuf->size and ibuf->max_size, to
03346   reduce ibuf_mutex contention. ibuf->max_size remains constant
03347   after ibuf_init_at_db_start(), but ibuf->size should be
03348   protected by ibuf_mutex. Given that ibuf->size fits in a
03349   machine word, this should be OK; at worst we are doing some
03350   excessive ibuf_contract() or occasionally skipping a
03351   ibuf_contract(). */
03352   if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
03353     /* Insert buffer is now too big, contract it but do not try
03354     to insert */
03355 
03356 
03357 #ifdef UNIV_IBUF_DEBUG
03358     fputs("Ibuf too big\n", stderr);
03359 #endif
03360     /* Use synchronous contract (== TRUE) */
03361     ibuf_contract(TRUE);
03362 
03363     return(DB_STRONG_FAIL);
03364   }
03365 
03366   heap = mem_heap_create(512);
03367 
03368   /* Build the entry which contains the space id and the page number
03369   as the first fields and the type information for other fields, and
03370   which will be inserted to the insert buffer. Using a counter value
03371   of 0xFFFF we find the last record for (space, page_no), from which
03372   we can then read the counter value N and use N + 1 in the record we
03373   insert. (We patch the ibuf_entry's counter field to the correct
03374   value just before actually inserting the entry.) */
03375 
03376   ibuf_entry = ibuf_entry_build(
03377     op, index, entry, space, page_no,
03378     no_counter ? ULINT_UNDEFINED : 0xFFFF, heap);
03379 
03380   /* Open a cursor to the insert buffer tree to calculate if we can add
03381   the new entry to it without exceeding the free space limit for the
03382   page. */
03383 
03384   if (mode == BTR_MODIFY_TREE) {
03385     for (;;) {
03386       ibuf_enter();
03387       mutex_enter(&ibuf_pessimistic_insert_mutex);
03388       mutex_enter(&ibuf_mutex);
03389 
03390       if (UNIV_LIKELY(ibuf_data_enough_free_for_insert())) {
03391 
03392         break;
03393       }
03394 
03395       mutex_exit(&ibuf_mutex);
03396       mutex_exit(&ibuf_pessimistic_insert_mutex);
03397       ibuf_exit();
03398 
03399       if (UNIV_UNLIKELY(!ibuf_add_free_page())) {
03400 
03401         mem_heap_free(heap);
03402         return(DB_STRONG_FAIL);
03403       }
03404     }
03405   } else {
03406     ibuf_enter();
03407   }
03408 
03409   mtr_start(&mtr);
03410 
03411   btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
03412   ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
03413 
03414   /* Find out the volume of already buffered inserts for the same index
03415   page */
03416   min_n_recs = 0;
03417   buffered = ibuf_get_volume_buffered(&pcur, space, page_no,
03418               op == IBUF_OP_DELETE
03419               ? &min_n_recs
03420               : NULL, &mtr);
03421 
03422   if (op == IBUF_OP_DELETE
03423       && (min_n_recs < 2
03424     || buf_pool_watch_occurred(space, page_no))) {
03425     /* The page could become empty after the record is
03426     deleted, or the page has been read in to the buffer
03427     pool.  Refuse to buffer the operation. */
03428 
03429     /* The buffer pool watch is needed for IBUF_OP_DELETE
03430     because of latching order considerations.  We can
03431     check buf_pool_watch_occurred() only after latching
03432     the insert buffer B-tree pages that contain buffered
03433     changes for the page.  We never buffer IBUF_OP_DELETE,
03434     unless some IBUF_OP_INSERT or IBUF_OP_DELETE_MARK have
03435     been previously buffered for the page.  Because there
03436     are buffered operations for the page, the insert
03437     buffer B-tree page latches held by mtr will guarantee
03438     that no changes for the user page will be merged
03439     before mtr_commit(&mtr).  We must not mtr_commit(&mtr)
03440     until after the IBUF_OP_DELETE has been buffered. */
03441 
03442 fail_exit:
03443     if (mode == BTR_MODIFY_TREE) {
03444       mutex_exit(&ibuf_mutex);
03445       mutex_exit(&ibuf_pessimistic_insert_mutex);
03446     }
03447 
03448     err = DB_STRONG_FAIL;
03449     goto func_exit;
03450   }
03451 
03452   /* After this point, the page could still be loaded to the
03453   buffer pool, but we do not have to care about it, since we are
03454   holding a latch on the insert buffer leaf page that contains
03455   buffered changes for (space, page_no).  If the page enters the
03456   buffer pool, buf_page_io_complete() for (space, page_no) will
03457   have to acquire a latch on the same insert buffer leaf page,
03458   which it cannot do until we have buffered the IBUF_OP_DELETE
03459   and done mtr_commit(&mtr) to release the latch. */
03460 
03461 #ifdef UNIV_IBUF_COUNT_DEBUG
03462   ut_a((buffered == 0) || ibuf_count_get(space, page_no));
03463 #endif
03464   mtr_start(&bitmap_mtr);
03465 
03466   bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
03467                  zip_size, &bitmap_mtr);
03468 
03469   /* We check if the index page is suitable for buffered entries */
03470 
03471   if (buf_page_peek(space, page_no)
03472       || lock_rec_expl_exist_on_page(space, page_no)) {
03473 
03474     goto bitmap_fail;
03475   }
03476 
03477   if (op == IBUF_OP_INSERT) {
03478     ulint bits = ibuf_bitmap_page_get_bits(
03479       bitmap_page, page_no, zip_size, IBUF_BITMAP_FREE,
03480       &bitmap_mtr);
03481 
03482     if (buffered + entry_size + page_dir_calc_reserved_space(1)
03483         > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
03484       /* Release the bitmap page latch early. */
03485       mtr_commit(&bitmap_mtr);
03486 
03487       /* It may not fit */
03488       do_merge = TRUE;
03489 
03490       ibuf_get_merge_page_nos(
03491         FALSE, btr_pcur_get_rec(&pcur),
03492         space_ids, space_versions,
03493         page_nos, &n_stored);
03494 
03495       goto fail_exit;
03496     }
03497   }
03498 
03499   /* Patch correct counter value to the entry to insert. This can
03500   change the insert position, which can result in the need to abort in
03501   some cases. */
03502   if (!no_counter
03503       && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur,
03504                mode == BTR_MODIFY_PREV, &mtr)) {
03505 bitmap_fail:
03506     mtr_commit(&bitmap_mtr);
03507 
03508     goto fail_exit;
03509   }
03510 
03511   /* Set the bitmap bit denoting that the insert buffer contains
03512   buffered entries for this index page, if the bit is not set yet */
03513 
03514   old_bit_value = ibuf_bitmap_page_get_bits(
03515     bitmap_page, page_no, zip_size,
03516     IBUF_BITMAP_BUFFERED, &bitmap_mtr);
03517 
03518   if (!old_bit_value) {
03519     ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
03520             IBUF_BITMAP_BUFFERED, TRUE,
03521             &bitmap_mtr);
03522   }
03523 
03524   mtr_commit(&bitmap_mtr);
03525 
03526   cursor = btr_pcur_get_btr_cur(&pcur);
03527 
03528   if (mode == BTR_MODIFY_PREV) {
03529     err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
03530             ibuf_entry, &ins_rec,
03531             &dummy_big_rec, 0, thr, &mtr);
03532     block = btr_cur_get_block(cursor);
03533     ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
03534 
03535     /* If this is the root page, update ibuf->empty. */
03536     if (UNIV_UNLIKELY(buf_block_get_page_no(block)
03537           == FSP_IBUF_TREE_ROOT_PAGE_NO)) {
03538       const page_t* page_root = buf_block_get_frame(block);
03539 
03540       ut_ad(page_get_space_id(page_root) == IBUF_SPACE_ID);
03541       ut_ad(page_get_page_no(page_root)
03542             == FSP_IBUF_TREE_ROOT_PAGE_NO);
03543 
03544       ibuf->empty = (page_get_n_recs(page_root) == 0);
03545     }
03546   } else {
03547     ut_ad(mode == BTR_MODIFY_TREE);
03548 
03549     /* We acquire an x-latch to the root page before the insert,
03550     because a pessimistic insert releases the tree x-latch,
03551     which would cause the x-latching of the root after that to
03552     break the latching order. */
03553 
03554     root = ibuf_tree_root_get(&mtr);
03555 
03556     err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
03557              | BTR_NO_UNDO_LOG_FLAG,
03558              cursor,
03559              ibuf_entry, &ins_rec,
03560              &dummy_big_rec, 0, thr, &mtr);
03561     mutex_exit(&ibuf_pessimistic_insert_mutex);
03562     ibuf_size_update(root, &mtr);
03563     mutex_exit(&ibuf_mutex);
03564     ibuf->empty = (page_get_n_recs(root) == 0);
03565 
03566     block = btr_cur_get_block(cursor);
03567     ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
03568   }
03569 
03570   if (err == DB_SUCCESS && op != IBUF_OP_DELETE) {
03571     /* Update the page max trx id field */
03572     page_update_max_trx_id(block, NULL,
03573                thr_get_trx(thr)->id, &mtr);
03574   }
03575 
03576 func_exit:
03577 #ifdef UNIV_IBUF_COUNT_DEBUG
03578   if (err == DB_SUCCESS) {
03579     fprintf(stderr,
03580       "Incrementing ibuf count of space %lu page %lu\n"
03581       "from %lu by 1\n", space, page_no,
03582       ibuf_count_get(space, page_no));
03583 
03584     ibuf_count_set(space, page_no,
03585              ibuf_count_get(space, page_no) + 1);
03586   }
03587 #endif
03588 
03589   mtr_commit(&mtr);
03590   btr_pcur_close(&pcur);
03591   ibuf_exit();
03592 
03593   mem_heap_free(heap);
03594 
03595   if (err == DB_SUCCESS && mode == BTR_MODIFY_TREE) {
03596     ibuf_contract_after_insert(entry_size);
03597   }
03598 
03599   if (do_merge) {
03600 #ifdef UNIV_IBUF_DEBUG
03601     ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
03602 #endif
03603     buf_read_ibuf_merge_pages(FALSE, space_ids, space_versions,
03604             page_nos, n_stored);
03605   }
03606 
03607   return(err);
03608 }
03609 
03610 /*********************************************************************/
03615 UNIV_INTERN
03616 ibool
03617 ibuf_insert(
03618 /*========*/
03619   ibuf_op_t op, 
03620   const dtuple_t* entry,  
03621   dict_index_t* index,  
03622   ulint   space,  
03623   ulint   zip_size,
03624   ulint   page_no,
03625   que_thr_t*  thr)  
03626 {
03627   ulint   err;
03628   ulint   entry_size;
03629   ibool   no_counter;
03630   /* Read the settable global variable ibuf_use only once in
03631   this function, so that we will have a consistent view of it. */
03632   ibuf_use_t  use   = ibuf_use;
03633 
03634   ut_a(trx_sys_multiple_tablespace_format);
03635   ut_ad(dtuple_check_typed(entry));
03636   ut_ad(ut_is_2pow(zip_size));
03637 
03638   ut_a(!dict_index_is_clust(index));
03639 
03640   no_counter = use <= IBUF_USE_INSERT;
03641 
03642   switch (op) {
03643   case IBUF_OP_INSERT:
03644     switch (use) {
03645     case IBUF_USE_NONE:
03646     case IBUF_USE_DELETE:
03647     case IBUF_USE_DELETE_MARK:
03648       return(FALSE);
03649     case IBUF_USE_INSERT:
03650     case IBUF_USE_INSERT_DELETE_MARK:
03651     case IBUF_USE_ALL:
03652       goto check_watch;
03653     case IBUF_USE_COUNT:
03654       break;
03655     }
03656     break;
03657   case IBUF_OP_DELETE_MARK:
03658     switch (use) {
03659     case IBUF_USE_NONE:
03660     case IBUF_USE_INSERT:
03661       return(FALSE);
03662     case IBUF_USE_DELETE_MARK:
03663     case IBUF_USE_DELETE:
03664     case IBUF_USE_INSERT_DELETE_MARK:
03665     case IBUF_USE_ALL:
03666       ut_ad(!no_counter);
03667       goto check_watch;
03668     case IBUF_USE_COUNT:
03669       break;
03670     }
03671     break;
03672   case IBUF_OP_DELETE:
03673     switch (use) {
03674     case IBUF_USE_NONE:
03675     case IBUF_USE_INSERT:
03676     case IBUF_USE_INSERT_DELETE_MARK:
03677       return(FALSE);
03678     case IBUF_USE_DELETE_MARK:
03679     case IBUF_USE_DELETE:
03680     case IBUF_USE_ALL:
03681       ut_ad(!no_counter);
03682       goto skip_watch;
03683     case IBUF_USE_COUNT:
03684       break;
03685     }
03686     break;
03687   case IBUF_OP_COUNT:
03688     break;
03689   }
03690 
03691   /* unknown op or use */
03692   ut_error;
03693 
03694 check_watch:
03695   /* If a thread attempts to buffer an insert on a page while a
03696   purge is in progress on the same page, the purge must not be
03697   buffered, because it could remove a record that was
03698   re-inserted later.  For simplicity, we block the buffering of
03699   all operations on a page that has a purge pending.
03700 
03701   We do not check this in the IBUF_OP_DELETE case, because that
03702   would always trigger the buffer pool watch during purge and
03703   thus prevent the buffering of delete operations.  We assume
03704   that the issuer of IBUF_OP_DELETE has called
03705   buf_pool_watch_set(space, page_no). */
03706 
03707   {
03708     buf_page_t* bpage;
03709     ulint   fold = buf_page_address_fold(space, page_no);
03710     buf_pool_t* buf_pool = buf_pool_get(space, page_no);
03711 
03712     buf_pool_mutex_enter(buf_pool);
03713     bpage = buf_page_hash_get_low(buf_pool, space, page_no, fold);
03714     buf_pool_mutex_exit(buf_pool);
03715 
03716     if (UNIV_LIKELY_NULL(bpage)) {
03717       /* A buffer pool watch has been set or the
03718       page has been read into the buffer pool.
03719       Do not buffer the request.  If a purge operation
03720       is being buffered, have this request executed
03721       directly on the page in the buffer pool after the
03722       buffered entries for this page have been merged. */
03723       return(FALSE);
03724     }
03725   }
03726 
03727 skip_watch:
03728   entry_size = rec_get_converted_size(index, entry, 0);
03729 
03730   if (entry_size
03731       >= page_get_free_space_of_empty(dict_table_is_comp(index->table))
03732       / 2) {
03733 
03734     return(FALSE);
03735   }
03736 
03737   err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter,
03738             entry, entry_size,
03739             index, space, zip_size, page_no, thr);
03740   if (err == DB_FAIL) {
03741     err = ibuf_insert_low(BTR_MODIFY_TREE, op, no_counter,
03742               entry, entry_size,
03743               index, space, zip_size, page_no, thr);
03744   }
03745 
03746   if (err == DB_SUCCESS) {
03747 #ifdef UNIV_IBUF_DEBUG
03748     /* fprintf(stderr, "Ibuf insert for page no %lu of index %s\n",
03749     page_no, index->name); */
03750 #endif
03751     return(TRUE);
03752 
03753   } else {
03754     ut_a(err == DB_STRONG_FAIL);
03755 
03756     return(FALSE);
03757   }
03758 }
03759 
03760 /********************************************************************/
03763 static
03764 void
03765 ibuf_insert_to_index_page_low(
03766 /*==========================*/
03767   const dtuple_t* entry,  
03768   buf_block_t*  block,  
03770   dict_index_t* index,  
03771   mtr_t*    mtr,  
03772   page_cur_t* page_cur)
03774 {
03775   const page_t* page;
03776   ulint   space;
03777   ulint   page_no;
03778   ulint   zip_size;
03779   const page_t* bitmap_page;
03780   ulint   old_bits;
03781 
03782   if (UNIV_LIKELY
03783       (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
03784     return;
03785   }
03786 
03787   /* If the record did not fit, reorganize */
03788 
03789   btr_page_reorganize(block, index, mtr);
03790   page_cur_search(block, index, entry, PAGE_CUR_LE, page_cur);
03791 
03792   /* This time the record must fit */
03793 
03794   if (UNIV_LIKELY
03795       (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
03796     return;
03797   }
03798 
03799   page = buf_block_get_frame(block);
03800 
03801   ut_print_timestamp(stderr);
03802 
03803   fprintf(stderr,
03804     "  InnoDB: Error: Insert buffer insert fails;"
03805     " page free %lu, dtuple size %lu\n",
03806     (ulong) page_get_max_insert_size(page, 1),
03807     (ulong) rec_get_converted_size(index, entry, 0));
03808   fputs("InnoDB: Cannot insert index record ", stderr);
03809   dtuple_print(stderr, entry);
03810   fputs("\nInnoDB: The table where this index record belongs\n"
03811         "InnoDB: is now probably corrupt. Please run CHECK TABLE on\n"
03812         "InnoDB: that table.\n", stderr);
03813 
03814   space = page_get_space_id(page);
03815   zip_size = buf_block_get_zip_size(block);
03816   page_no = page_get_page_no(page);
03817 
03818   bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
03819   old_bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
03820                IBUF_BITMAP_FREE, mtr);
03821 
03822   fprintf(stderr,
03823     "InnoDB: space %lu, page %lu, zip_size %lu, bitmap bits %lu\n",
03824     (ulong) space, (ulong) page_no,
03825     (ulong) zip_size, (ulong) old_bits);
03826 
03827   fputs("InnoDB: Submit a detailed bug report"
03828         " to http://bugs.mysql.com\n", stderr);
03829 }
03830 
03831 /************************************************************************
03832 During merge, inserts to an index page a secondary index entry extracted
03833 from the insert buffer. */
03834 static
03835 void
03836 ibuf_insert_to_index_page(
03837 /*======================*/
03838   const dtuple_t* entry,  
03839   buf_block_t*  block,  
03841   dict_index_t* index,  
03842   mtr_t*    mtr)  
03843 {
03844   page_cur_t  page_cur;
03845   ulint   low_match;
03846   page_t*   page    = buf_block_get_frame(block);
03847   rec_t*    rec;
03848 
03849   ut_ad(ibuf_inside());
03850   ut_ad(dtuple_check_typed(entry));
03851   ut_ad(!buf_block_align(page)->is_hashed);
03852 
03853   if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
03854         != (ibool)!!page_is_comp(page))) {
03855     fputs("InnoDB: Trying to insert a record from"
03856           " the insert buffer to an index page\n"
03857           "InnoDB: but the 'compact' flag does not match!\n",
03858           stderr);
03859     goto dump;
03860   }
03861 
03862   rec = page_rec_get_next(page_get_infimum_rec(page));
03863 
03864   if (page_rec_is_supremum(rec)) {
03865     fputs("InnoDB: Trying to insert a record from"
03866           " the insert buffer to an index page\n"
03867           "InnoDB: but the index page is empty!\n",
03868           stderr);
03869     goto dump;
03870   }
03871 
03872   if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
03873         != dtuple_get_n_fields(entry))) {
03874     fputs("InnoDB: Trying to insert a record from"
03875           " the insert buffer to an index page\n"
03876           "InnoDB: but the number of fields does not match!\n",
03877           stderr);
03878 dump:
03879     buf_page_print(page, 0);
03880 
03881     dtuple_print(stderr, entry);
03882 
03883     fputs("InnoDB: The table where where"
03884           " this index record belongs\n"
03885           "InnoDB: is now probably corrupt."
03886           " Please run CHECK TABLE on\n"
03887           "InnoDB: your tables.\n"
03888           "InnoDB: Submit a detailed bug report to"
03889           " http://bugs.mysql.com!\n", stderr);
03890 
03891     return;
03892   }
03893 
03894   low_match = page_cur_search(block, index, entry,
03895             PAGE_CUR_LE, &page_cur);
03896 
03897   if (UNIV_UNLIKELY(low_match == dtuple_get_n_fields(entry))) {
03898     mem_heap_t* heap;
03899     upd_t*    update;
03900     ulint*    offsets;
03901     page_zip_des_t* page_zip;
03902 
03903     rec = page_cur_get_rec(&page_cur);
03904 
03905     /* This is based on
03906     row_ins_sec_index_entry_by_modify(BTR_MODIFY_LEAF). */
03907     ut_ad(rec_get_deleted_flag(rec, page_is_comp(page)));
03908 
03909     heap = mem_heap_create(1024);
03910 
03911     offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED,
03912             &heap);
03913     update = row_upd_build_sec_rec_difference_binary(
03914       index, entry, rec, NULL, heap);
03915 
03916     page_zip = buf_block_get_page_zip(block);
03917 
03918     if (update->n_fields == 0) {
03919       /* The records only differ in the delete-mark.
03920       Clear the delete-mark, like we did before
03921       Bug #56680 was fixed. */
03922       btr_cur_set_deleted_flag_for_ibuf(
03923         rec, page_zip, FALSE, mtr);
03924 updated_in_place:
03925       mem_heap_free(heap);
03926       return;
03927     }
03928 
03929     /* Copy the info bits. Clear the delete-mark. */
03930     update->info_bits = rec_get_info_bits(rec, page_is_comp(page));
03931     update->info_bits &= ~REC_INFO_DELETED_FLAG;
03932 
03933     /* We cannot invoke btr_cur_optimistic_update() here,
03934     because we do not have a btr_cur_t or que_thr_t,
03935     as the insert buffer merge occurs at a very low level. */
03936     if (!row_upd_changes_field_size_or_external(index, offsets,
03937                   update)
03938         && (!page_zip || btr_cur_update_alloc_zip(
03939         page_zip, block, index,
03940         rec_offs_size(offsets), FALSE, mtr))) {
03941       /* This is the easy case. Do something similar
03942       to btr_cur_update_in_place(). */
03943       row_upd_rec_in_place(rec, index, offsets,
03944                update, page_zip);
03945       goto updated_in_place;
03946     }
03947 
03948     /* A collation may identify values that differ in
03949     storage length.
03950     Some examples (1 or 2 bytes):
03951     utf8_turkish_ci: I = U+0131 LATIN SMALL LETTER DOTLESS I
03952     utf8_general_ci: S = U+00DF LATIN SMALL LETTER SHARP S
03953     utf8_general_ci: A = U+00E4 LATIN SMALL LETTER A WITH DIAERESIS
03954 
03955     latin1_german2_ci: SS = U+00DF LATIN SMALL LETTER SHARP S
03956 
03957     Examples of a character (3-byte UTF-8 sequence)
03958     identified with 2 or 4 characters (1-byte UTF-8 sequences):
03959 
03960     utf8_unicode_ci: 'II' = U+2171 SMALL ROMAN NUMERAL TWO
03961     utf8_unicode_ci: '(10)' = U+247D PARENTHESIZED NUMBER TEN
03962     */
03963 
03964     /* Delete the different-length record, and insert the
03965     buffered one. */
03966 
03967     lock_rec_store_on_page_infimum(block, rec);
03968     page_cur_delete_rec(&page_cur, index, offsets, mtr);
03969     page_cur_move_to_prev(&page_cur);
03970     mem_heap_free(heap);
03971 
03972     ibuf_insert_to_index_page_low(entry, block, index, mtr,
03973                 &page_cur);
03974     lock_rec_restore_from_page_infimum(block, rec, block);
03975   } else {
03976     ibuf_insert_to_index_page_low(entry, block, index, mtr,
03977                 &page_cur);
03978   }
03979 }
03980 
03981 /****************************************************************/
03984 static
03985 void
03986 ibuf_set_del_mark(
03987 /*==============*/
03988   const dtuple_t*   entry,  
03989   buf_block_t*    block,  
03990   const dict_index_t* index,  
03991   mtr_t*      mtr)  
03992 {
03993   page_cur_t  page_cur;
03994   ulint   low_match;
03995 
03996   ut_ad(ibuf_inside());
03997   ut_ad(dtuple_check_typed(entry));
03998 
03999   low_match = page_cur_search(
04000     block, index, entry, PAGE_CUR_LE, &page_cur);
04001 
04002   if (low_match == dtuple_get_n_fields(entry)) {
04003     rec_t*    rec;
04004     page_zip_des_t* page_zip;
04005 
04006     rec = page_cur_get_rec(&page_cur);
04007     page_zip = page_cur_get_page_zip(&page_cur);
04008 
04009     /* Delete mark the old index record. According to a
04010     comment in row_upd_sec_index_entry(), it can already
04011     have been delete marked if a lock wait occurred in
04012     row_ins_index_entry() in a previous invocation of
04013     row_upd_sec_index_entry(). */
04014 
04015     if (UNIV_LIKELY
04016         (!rec_get_deleted_flag(
04017           rec, dict_table_is_comp(index->table)))) {
04018       btr_cur_set_deleted_flag_for_ibuf(rec, page_zip,
04019                 TRUE, mtr);
04020     }
04021   } else {
04022     ut_print_timestamp(stderr);
04023     fputs("  InnoDB: unable to find a record to delete-mark\n",
04024           stderr);
04025     fputs("InnoDB: tuple ", stderr);
04026     dtuple_print(stderr, entry);
04027     fputs("\n"
04028           "InnoDB: record ", stderr);
04029     rec_print(stderr, page_cur_get_rec(&page_cur), index);
04030     putc('\n', stderr);
04031     fputs("\n"
04032           "InnoDB: Submit a detailed bug report"
04033           " to http://bugs.mysql.com\n", stderr);
04034     ut_ad(0);
04035   }
04036 }
04037 
04038 /****************************************************************/
04040 static
04041 void
04042 ibuf_delete(
04043 /*========*/
04044   const dtuple_t* entry,  
04045   buf_block_t*  block,  
04046   dict_index_t* index,  
04047   mtr_t*    mtr)  
04049 {
04050   page_cur_t  page_cur;
04051   ulint   low_match;
04052 
04053   ut_ad(ibuf_inside());
04054   ut_ad(dtuple_check_typed(entry));
04055 
04056   low_match = page_cur_search(
04057     block, index, entry, PAGE_CUR_LE, &page_cur);
04058 
04059   if (low_match == dtuple_get_n_fields(entry)) {
04060     page_zip_des_t* page_zip= buf_block_get_page_zip(block);
04061     page_t*   page  = buf_block_get_frame(block);
04062     rec_t*    rec = page_cur_get_rec(&page_cur);
04063 
04064     /* TODO: the below should probably be a separate function,
04065     it's a bastardized version of btr_cur_optimistic_delete. */
04066 
04067     ulint   offsets_[REC_OFFS_NORMAL_SIZE];
04068     ulint*    offsets = offsets_;
04069     mem_heap_t* heap = NULL;
04070     ulint   max_ins_size;
04071 
04072     rec_offs_init(offsets_);
04073 
04074     offsets = rec_get_offsets(
04075       rec, index, offsets, ULINT_UNDEFINED, &heap);
04076 
04077     /* Refuse to delete the last record. */
04078     ut_a(page_get_n_recs(page) > 1);
04079 
04080     /* The record should have been marked for deletion. */
04081     ut_ad(REC_INFO_DELETED_FLAG
04082           & rec_get_info_bits(rec, page_is_comp(page)));
04083 
04084     lock_update_delete(block, rec);
04085 
04086     if (!page_zip) {
04087       max_ins_size
04088         = page_get_max_insert_size_after_reorganize(
04089           page, 1);
04090     }
04091 #ifdef UNIV_ZIP_DEBUG
04092     ut_a(!page_zip || page_zip_validate(page_zip, page));
04093 #endif /* UNIV_ZIP_DEBUG */
04094     page_cur_delete_rec(&page_cur, index, offsets, mtr);
04095 #ifdef UNIV_ZIP_DEBUG
04096     ut_a(!page_zip || page_zip_validate(page_zip, page));
04097 #endif /* UNIV_ZIP_DEBUG */
04098 
04099     if (page_zip) {
04100       ibuf_update_free_bits_zip(block, mtr);
04101     } else {
04102       ibuf_update_free_bits_low(block, max_ins_size, mtr);
04103     }
04104 
04105     if (UNIV_LIKELY_NULL(heap)) {
04106       mem_heap_free(heap);
04107     }
04108   } else {
04109     /* The record must have been purged already. */
04110   }
04111 }
04112 
04113 /*********************************************************************/
04116 static __attribute__((nonnull))
04117 ibool
04118 ibuf_restore_pos(
04119 /*=============*/
04120   ulint   space,  
04121   ulint   page_no,
04123   const dtuple_t* search_tuple,
04125   ulint   mode, 
04126   btr_pcur_t* pcur, 
04128   mtr_t*    mtr)  
04129 {
04130   ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE);
04131 
04132   if (btr_pcur_restore_position(mode, pcur, mtr)) {
04133 
04134     return(TRUE);
04135   }
04136 
04137   if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
04138     /* The tablespace has been dropped.  It is possible
04139     that another thread has deleted the insert buffer
04140     entry.  Do not complain. */
04141     btr_pcur_commit_specify_mtr(pcur, mtr);
04142   } else {
04143     fprintf(stderr,
04144       "InnoDB: ERROR: Submit the output to"
04145       " http://bugs.mysql.com\n"
04146       "InnoDB: ibuf cursor restoration fails!\n"
04147       "InnoDB: ibuf record inserted to page %lu:%lu\n",
04148       (ulong) space, (ulong) page_no);
04149     fflush(stderr);
04150 
04151     rec_print_old(stderr, btr_pcur_get_rec(pcur));
04152     rec_print_old(stderr, pcur->old_rec);
04153     dtuple_print(stderr, search_tuple);
04154 
04155     rec_print_old(stderr,
04156             page_rec_get_next(btr_pcur_get_rec(pcur)));
04157     fflush(stderr);
04158 
04159     btr_pcur_commit_specify_mtr(pcur, mtr);
04160 
04161     fputs("InnoDB: Validating insert buffer tree:\n", stderr);
04162     if (!btr_validate_index(ibuf->index, NULL)) {
04163       ut_error;
04164     }
04165 
04166     fprintf(stderr, "InnoDB: ibuf tree ok\n");
04167     fflush(stderr);
04168   }
04169 
04170   return(FALSE);
04171 }
04172 
04173 /*********************************************************************/
04178 static
04179 ibool
04180 ibuf_delete_rec(
04181 /*============*/
04182   ulint   space,  
04183   ulint   page_no,
04185   btr_pcur_t* pcur, 
04187   const dtuple_t* search_tuple,
04189   mtr_t*    mtr)  
04190 {
04191   ibool   success;
04192   page_t*   root;
04193   ulint   err;
04194 
04195   ut_ad(ibuf_inside());
04196   ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur)));
04197   ut_ad(ibuf_rec_get_page_no(btr_pcur_get_rec(pcur)) == page_no);
04198   ut_ad(ibuf_rec_get_space(btr_pcur_get_rec(pcur)) == space);
04199 
04200   success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
04201 
04202   if (success) {
04203     if (UNIV_UNLIKELY(!page_get_n_recs(btr_pcur_get_page(pcur)))) {
04204       /* If a B-tree page is empty, it must be the root page
04205       and the whole B-tree must be empty. InnoDB does not
04206       allow empty B-tree pages other than the root. */
04207       root = btr_pcur_get_page(pcur);
04208 
04209       ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
04210       ut_ad(page_get_page_no(root)
04211             == FSP_IBUF_TREE_ROOT_PAGE_NO);
04212 
04213       /* ibuf->empty is protected by the root page latch.
04214       Before the deletion, it had to be FALSE. */
04215       ut_ad(!ibuf->empty);
04216       ibuf->empty = TRUE;
04217     }
04218 
04219 #ifdef UNIV_IBUF_COUNT_DEBUG
04220     fprintf(stderr,
04221       "Decrementing ibuf count of space %lu page %lu\n"
04222       "from %lu by 1\n", space, page_no,
04223       ibuf_count_get(space, page_no));
04224     ibuf_count_set(space, page_no,
04225              ibuf_count_get(space, page_no) - 1);
04226 #endif
04227     return(FALSE);
04228   }
04229 
04230   ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur)));
04231   ut_ad(ibuf_rec_get_page_no(btr_pcur_get_rec(pcur)) == page_no);
04232   ut_ad(ibuf_rec_get_space(btr_pcur_get_rec(pcur)) == space);
04233 
04234   /* We have to resort to a pessimistic delete from ibuf */
04235   btr_pcur_store_position(pcur, mtr);
04236 
04237   btr_pcur_commit_specify_mtr(pcur, mtr);
04238 
04239   mutex_enter(&ibuf_mutex);
04240 
04241   mtr_start(mtr);
04242 
04243   if (!ibuf_restore_pos(space, page_no, search_tuple,
04244             BTR_MODIFY_TREE, pcur, mtr)) {
04245 
04246     mutex_exit(&ibuf_mutex);
04247     goto func_exit;
04248   }
04249 
04250   root = ibuf_tree_root_get(mtr);
04251 
04252   btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur),
04253            RB_NONE, mtr);
04254   ut_a(err == DB_SUCCESS);
04255 
04256 #ifdef UNIV_IBUF_COUNT_DEBUG
04257   ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
04258 #endif
04259   ibuf_size_update(root, mtr);
04260   mutex_exit(&ibuf_mutex);
04261 
04262   ibuf->empty = (page_get_n_recs(root) == 0);
04263   btr_pcur_commit_specify_mtr(pcur, mtr);
04264 
04265 func_exit:
04266   btr_pcur_close(pcur);
04267 
04268   return(TRUE);
04269 }
04270 
04271 /*********************************************************************/
04278 UNIV_INTERN
04279 void
04280 ibuf_merge_or_delete_for_page(
04281 /*==========================*/
04282   buf_block_t*  block,  
04285   ulint   space,  
04286   ulint   page_no,
04287   ulint   zip_size,
04289   ibool   update_ibuf_bitmap)
04294 {
04295   mem_heap_t* heap;
04296   btr_pcur_t  pcur;
04297   dtuple_t* search_tuple;
04298 #ifdef UNIV_IBUF_DEBUG
04299   ulint   volume      = 0;
04300 #endif
04301   page_zip_des_t* page_zip    = NULL;
04302   ibool   tablespace_being_deleted = FALSE;
04303   ibool   corruption_noticed  = FALSE;
04304   mtr_t   mtr;
04305 
04306   /* Counts for merged & discarded operations. */
04307   ulint   mops[IBUF_OP_COUNT];
04308   ulint   dops[IBUF_OP_COUNT];
04309 
04310   ut_ad(!block || buf_block_get_space(block) == space);
04311   ut_ad(!block || buf_block_get_page_no(block) == page_no);
04312   ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
04313 
04314   if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE
04315       || trx_sys_hdr_page(space, page_no)) {
04316     return;
04317   }
04318 
04319   /* We cannot refer to zip_size in the following, because
04320   zip_size is passed as ULINT_UNDEFINED (it is unknown) when
04321   buf_read_ibuf_merge_pages() is merging (discarding) changes
04322   for a dropped tablespace.  When block != NULL or
04323   update_ibuf_bitmap is specified, the zip_size must be known.
04324   That is why we will repeat the check below, with zip_size in
04325   place of 0.  Passing zip_size as 0 assumes that the
04326   uncompressed page size always is a power-of-2 multiple of the
04327   compressed page size. */
04328 
04329   if (ibuf_fixed_addr_page(space, 0, page_no)
04330       || fsp_descr_page(0, page_no)) {
04331     return;
04332   }
04333 
04334   if (UNIV_LIKELY(update_ibuf_bitmap)) {
04335     ut_a(ut_is_2pow(zip_size));
04336 
04337     if (ibuf_fixed_addr_page(space, zip_size, page_no)
04338         || fsp_descr_page(zip_size, page_no)) {
04339       return;
04340     }
04341 
04342     /* If the following returns FALSE, we get the counter
04343     incremented, and must decrement it when we leave this
04344     function. When the counter is > 0, that prevents tablespace
04345     from being dropped. */
04346 
04347     tablespace_being_deleted = fil_inc_pending_ibuf_merges(space);
04348 
04349     if (UNIV_UNLIKELY(tablespace_being_deleted)) {
04350       /* Do not try to read the bitmap page from space;
04351       just delete the ibuf records for the page */
04352 
04353       block = NULL;
04354       update_ibuf_bitmap = FALSE;
04355     } else {
04356       page_t* bitmap_page;
04357 
04358       mtr_start(&mtr);
04359 
04360       bitmap_page = ibuf_bitmap_get_map_page(
04361         space, page_no, zip_size, &mtr);
04362 
04363       if (!ibuf_bitmap_page_get_bits(bitmap_page, page_no,
04364                    zip_size,
04365                    IBUF_BITMAP_BUFFERED,
04366                    &mtr)) {
04367         /* No inserts buffered for this page */
04368         mtr_commit(&mtr);
04369 
04370         if (!tablespace_being_deleted) {
04371           fil_decr_pending_ibuf_merges(space);
04372         }
04373 
04374         return;
04375       }
04376       mtr_commit(&mtr);
04377     }
04378   } else if (block
04379        && (ibuf_fixed_addr_page(space, zip_size, page_no)
04380           || fsp_descr_page(zip_size, page_no))) {
04381 
04382     return;
04383   }
04384 
04385   ibuf_enter();
04386 
04387   heap = mem_heap_create(512);
04388 
04389   if (!trx_sys_multiple_tablespace_format) {
04390     ut_a(trx_doublewrite_must_reset_space_ids);
04391     search_tuple = ibuf_search_tuple_build(space, page_no, heap);
04392   } else {
04393     search_tuple = ibuf_new_search_tuple_build(space, page_no,
04394                  heap);
04395   }
04396 
04397   if (block) {
04398     /* Move the ownership of the x-latch on the page to this OS
04399     thread, so that we can acquire a second x-latch on it. This
04400     is needed for the insert operations to the index page to pass
04401     the debug checks. */
04402 
04403     rw_lock_x_lock_move_ownership(&(block->lock));
04404     page_zip = buf_block_get_page_zip(block);
04405 
04406     if (UNIV_UNLIKELY(fil_page_get_type(block->frame)
04407           != FIL_PAGE_INDEX)
04408         || UNIV_UNLIKELY(!page_is_leaf(block->frame))) {
04409 
04410       page_t* bitmap_page;
04411 
04412       corruption_noticed = TRUE;
04413 
04414       ut_print_timestamp(stderr);
04415 
04416       mtr_start(&mtr);
04417 
04418       fputs("  InnoDB: Dump of the ibuf bitmap page:\n",
04419             stderr);
04420 
04421       bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
04422                      zip_size, &mtr);
04423       buf_page_print(bitmap_page, 0);
04424 
04425       mtr_commit(&mtr);
04426 
04427       fputs("\nInnoDB: Dump of the page:\n", stderr);
04428 
04429       buf_page_print(block->frame, 0);
04430 
04431       fprintf(stderr,
04432         "InnoDB: Error: corruption in the tablespace."
04433         " Bitmap shows insert\n"
04434         "InnoDB: buffer records to page n:o %lu"
04435         " though the page\n"
04436         "InnoDB: type is %lu, which is"
04437         " not an index leaf page!\n"
04438         "InnoDB: We try to resolve the problem"
04439         " by skipping the insert buffer\n"
04440         "InnoDB: merge for this page."
04441         " Please run CHECK TABLE on your tables\n"
04442         "InnoDB: to determine if they are corrupt"
04443         " after this.\n\n"
04444         "InnoDB: Please submit a detailed bug report"
04445         " to http://bugs.mysql.com\n\n",
04446         (ulong) page_no,
04447         (ulong)
04448         fil_page_get_type(block->frame));
04449     }
04450   }
04451 
04452   memset(mops, 0, sizeof(mops));
04453   memset(dops, 0, sizeof(dops));
04454 
04455 loop:
04456   mtr_start(&mtr);
04457 
04458   if (block) {
04459     ibool success;
04460 
04461     success = buf_page_get_known_nowait(
04462       RW_X_LATCH, block,
04463       BUF_KEEP_OLD, __FILE__, __LINE__, &mtr);
04464 
04465     ut_a(success);
04466 
04467     buf_block_dbg_add_level(block, SYNC_TREE_NODE);
04468   }
04469 
04470   /* Position pcur in the insert buffer at the first entry for this
04471   index page */
04472   btr_pcur_open_on_user_rec(
04473     ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
04474     &pcur, &mtr);
04475 
04476   if (!btr_pcur_is_on_user_rec(&pcur)) {
04477     ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
04478 
04479     goto reset_bit;
04480   }
04481 
04482   for (;;) {
04483     rec_t*  rec;
04484 
04485     ut_ad(btr_pcur_is_on_user_rec(&pcur));
04486 
04487     rec = btr_pcur_get_rec(&pcur);
04488 
04489     /* Check if the entry is for this index page */
04490     if (ibuf_rec_get_page_no(rec) != page_no
04491         || ibuf_rec_get_space(rec) != space) {
04492 
04493       if (block) {
04494         page_header_reset_last_insert(
04495           block->frame, page_zip, &mtr);
04496       }
04497 
04498       goto reset_bit;
04499     }
04500 
04501     if (UNIV_UNLIKELY(corruption_noticed)) {
04502       fputs("InnoDB: Discarding record\n ", stderr);
04503       rec_print_old(stderr, rec);
04504       fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
04505     } else if (block) {
04506       /* Now we have at pcur a record which should be
04507       applied on the index page; NOTE that the call below
04508       copies pointers to fields in rec, and we must
04509       keep the latch to the rec page until the
04510       insertion is finished! */
04511       dtuple_t* entry;
04512       trx_id_t  max_trx_id;
04513       dict_index_t* dummy_index;
04514       ibuf_op_t op = ibuf_rec_get_op_type(rec);
04515 
04516       max_trx_id = page_get_max_trx_id(page_align(rec));
04517       page_update_max_trx_id(block, page_zip, max_trx_id,
04518                  &mtr);
04519 
04520       ut_ad(page_validate(page_align(rec), ibuf->index));
04521 
04522       entry = ibuf_build_entry_from_ibuf_rec(
04523         rec, heap, &dummy_index);
04524 
04525       ut_ad(page_validate(block->frame, dummy_index));
04526 
04527       switch (op) {
04528         ibool success;
04529       case IBUF_OP_INSERT:
04530 #ifdef UNIV_IBUF_DEBUG
04531         volume += rec_get_converted_size(
04532           dummy_index, entry, 0);
04533 
04534         volume += page_dir_calc_reserved_space(1);
04535 
04536         ut_a(volume <= 4 * UNIV_PAGE_SIZE
04537           / IBUF_PAGE_SIZE_PER_FREE_SPACE);
04538 #endif
04539         ibuf_insert_to_index_page(
04540           entry, block, dummy_index, &mtr);
04541         break;
04542 
04543       case IBUF_OP_DELETE_MARK:
04544         ibuf_set_del_mark(
04545           entry, block, dummy_index, &mtr);
04546         break;
04547 
04548       case IBUF_OP_DELETE:
04549         ibuf_delete(entry, block, dummy_index, &mtr);
04550         /* Because ibuf_delete() will latch an
04551         insert buffer bitmap page, commit mtr
04552         before latching any further pages.
04553         Store and restore the cursor position. */
04554         ut_ad(rec == btr_pcur_get_rec(&pcur));
04555         ut_ad(page_rec_is_user_rec(rec));
04556         ut_ad(ibuf_rec_get_page_no(rec) == page_no);
04557         ut_ad(ibuf_rec_get_space(rec) == space);
04558 
04559         btr_pcur_store_position(&pcur, &mtr);
04560         btr_pcur_commit_specify_mtr(&pcur, &mtr);
04561 
04562         mtr_start(&mtr);
04563 
04564         success = buf_page_get_known_nowait(
04565           RW_X_LATCH, block,
04566           BUF_KEEP_OLD,
04567           __FILE__, __LINE__, &mtr);
04568         ut_a(success);
04569 
04570         buf_block_dbg_add_level(block, SYNC_TREE_NODE);
04571 
04572         if (!ibuf_restore_pos(space, page_no,
04573                   search_tuple,
04574                   BTR_MODIFY_LEAF,
04575                   &pcur, &mtr)) {
04576 
04577           mtr_commit(&mtr);
04578           mops[op]++;
04579           ibuf_dummy_index_free(dummy_index);
04580           goto loop;
04581         }
04582 
04583         break;
04584       default:
04585         ut_error;
04586       }
04587 
04588       mops[op]++;
04589 
04590       ibuf_dummy_index_free(dummy_index);
04591     } else {
04592       dops[ibuf_rec_get_op_type(rec)]++;
04593     }
04594 
04595     /* Delete the record from ibuf */
04596     if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
04597             &mtr)) {
04598       /* Deletion was pessimistic and mtr was committed:
04599       we start from the beginning again */
04600 
04601       goto loop;
04602     } else if (btr_pcur_is_after_last_on_page(&pcur)) {
04603       mtr_commit(&mtr);
04604       btr_pcur_close(&pcur);
04605 
04606       goto loop;
04607     }
04608   }
04609 
04610 reset_bit:
04611   if (UNIV_LIKELY(update_ibuf_bitmap)) {
04612     page_t* bitmap_page;
04613 
04614     bitmap_page = ibuf_bitmap_get_map_page(
04615       space, page_no, zip_size, &mtr);
04616 
04617     ibuf_bitmap_page_set_bits(
04618       bitmap_page, page_no, zip_size,
04619       IBUF_BITMAP_BUFFERED, FALSE, &mtr);
04620 
04621     if (block) {
04622       ulint old_bits = ibuf_bitmap_page_get_bits(
04623         bitmap_page, page_no, zip_size,
04624         IBUF_BITMAP_FREE, &mtr);
04625 
04626       ulint new_bits = ibuf_index_page_calc_free(
04627         zip_size, block);
04628 
04629       if (old_bits != new_bits) {
04630         ibuf_bitmap_page_set_bits(
04631           bitmap_page, page_no, zip_size,
04632           IBUF_BITMAP_FREE, new_bits, &mtr);
04633       }
04634     }
04635   }
04636 
04637   mtr_commit(&mtr);
04638   btr_pcur_close(&pcur);
04639   mem_heap_free(heap);
04640 
04641 #ifdef HAVE_ATOMIC_BUILTINS
04642   os_atomic_increment_ulint(&ibuf->n_merges, 1);
04643   ibuf_add_ops(ibuf->n_merged_ops, mops);
04644   ibuf_add_ops(ibuf->n_discarded_ops, dops);
04645 #else /* HAVE_ATOMIC_BUILTINS */
04646   /* Protect our statistics keeping from race conditions */
04647   mutex_enter(&ibuf_mutex);
04648 
04649   ibuf->n_merges++;
04650   ibuf_add_ops(ibuf->n_merged_ops, mops);
04651   ibuf_add_ops(ibuf->n_discarded_ops, dops);
04652 
04653   mutex_exit(&ibuf_mutex);
04654 #endif /* HAVE_ATOMIC_BUILTINS */
04655 
04656   if (update_ibuf_bitmap && !tablespace_being_deleted) {
04657 
04658     fil_decr_pending_ibuf_merges(space);
04659   }
04660 
04661   ibuf_exit();
04662 
04663 #ifdef UNIV_IBUF_COUNT_DEBUG
04664   ut_a(ibuf_count_get(space, page_no) == 0);
04665 #endif
04666 }
04667 
04668 /*********************************************************************/
04673 UNIV_INTERN
04674 void
04675 ibuf_delete_for_discarded_space(
04676 /*============================*/
04677   ulint space)  
04678 {
04679   mem_heap_t* heap;
04680   btr_pcur_t  pcur;
04681   dtuple_t* search_tuple;
04682   rec_t*    ibuf_rec;
04683   ulint   page_no;
04684   ibool   closed;
04685   mtr_t   mtr;
04686 
04687   /* Counts for discarded operations. */
04688   ulint   dops[IBUF_OP_COUNT];
04689 
04690   heap = mem_heap_create(512);
04691 
04692   /* Use page number 0 to build the search tuple so that we get the
04693   cursor positioned at the first entry for this space id */
04694 
04695   search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
04696 
04697   memset(dops, 0, sizeof(dops));
04698 loop:
04699   ibuf_enter();
04700 
04701   mtr_start(&mtr);
04702 
04703   /* Position pcur in the insert buffer at the first entry for the
04704   space */
04705   btr_pcur_open_on_user_rec(
04706     ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
04707     &pcur, &mtr);
04708 
04709   if (!btr_pcur_is_on_user_rec(&pcur)) {
04710     ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
04711 
04712     goto leave_loop;
04713   }
04714 
04715   for (;;) {
04716     ut_ad(btr_pcur_is_on_user_rec(&pcur));
04717 
04718     ibuf_rec = btr_pcur_get_rec(&pcur);
04719 
04720     /* Check if the entry is for this space */
04721     if (ibuf_rec_get_space(ibuf_rec) != space) {
04722 
04723       goto leave_loop;
04724     }
04725 
04726     page_no = ibuf_rec_get_page_no(ibuf_rec);
04727 
04728     dops[ibuf_rec_get_op_type(ibuf_rec)]++;
04729 
04730     /* Delete the record from ibuf */
04731     closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
04732            &mtr);
04733     if (closed) {
04734       /* Deletion was pessimistic and mtr was committed:
04735       we start from the beginning again */
04736 
04737       ibuf_exit();
04738 
04739       goto loop;
04740     }
04741 
04742     if (btr_pcur_is_after_last_on_page(&pcur)) {
04743       mtr_commit(&mtr);
04744       btr_pcur_close(&pcur);
04745 
04746       ibuf_exit();
04747 
04748       goto loop;
04749     }
04750   }
04751 
04752 leave_loop:
04753   mtr_commit(&mtr);
04754   btr_pcur_close(&pcur);
04755 
04756 #ifdef HAVE_ATOMIC_BUILTINS
04757   ibuf_add_ops(ibuf->n_discarded_ops, dops);
04758 #else /* HAVE_ATOMIC_BUILTINS */
04759   /* Protect our statistics keeping from race conditions */
04760   mutex_enter(&ibuf_mutex);
04761   ibuf_add_ops(ibuf->n_discarded_ops, dops);
04762   mutex_exit(&ibuf_mutex);
04763 #endif /* HAVE_ATOMIC_BUILTINS */
04764 
04765   ibuf_exit();
04766 
04767   mem_heap_free(heap);
04768 }
04769 
04770 /******************************************************************/
04773 UNIV_INTERN
04774 ibool
04775 ibuf_is_empty(void)
04776 /*===============*/
04777 {
04778   ibool   is_empty;
04779   const page_t* root;
04780   mtr_t   mtr;
04781 
04782   ibuf_enter();
04783   mtr_start(&mtr);
04784 
04785   mutex_enter(&ibuf_mutex);
04786   root = ibuf_tree_root_get(&mtr);
04787   mutex_exit(&ibuf_mutex);
04788 
04789   is_empty = (page_get_n_recs(root) == 0);
04790   mtr_commit(&mtr);
04791   ibuf_exit();
04792 
04793   ut_a(is_empty == ibuf->empty);
04794 
04795   return(is_empty);
04796 }
04797 
04798 /******************************************************************/
04800 UNIV_INTERN
04801 void
04802 ibuf_print(
04803 /*=======*/
04804   FILE* file) 
04805 {
04806 #ifdef UNIV_IBUF_COUNT_DEBUG
04807   ulint   i;
04808   ulint   j;
04809 #endif
04810 
04811   mutex_enter(&ibuf_mutex);
04812 
04813   fprintf(file,
04814     "Ibuf: size %lu, free list len %lu,"
04815     " seg size %lu, %lu merges\n",
04816     (ulong) ibuf->size,
04817     (ulong) ibuf->free_list_len,
04818     (ulong) ibuf->seg_size,
04819     (ulong) ibuf->n_merges);
04820 
04821   fputs("merged operations:\n ", file);
04822   ibuf_print_ops(ibuf->n_merged_ops, file);
04823 
04824   fputs("discarded operations:\n ", file);
04825   ibuf_print_ops(ibuf->n_discarded_ops, file);
04826 
04827 #ifdef UNIV_IBUF_COUNT_DEBUG
04828   for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
04829     for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {
04830       ulint count = ibuf_count_get(i, j);
04831 
04832       if (count > 0) {
04833         fprintf(stderr,
04834           "Ibuf count for space/page %lu/%lu"
04835           " is %lu\n",
04836           (ulong) i, (ulong) j, (ulong) count);
04837       }
04838     }
04839   }
04840 #endif /* UNIV_IBUF_COUNT_DEBUG */
04841 
04842   mutex_exit(&ibuf_mutex);
04843 }
04844 #endif /* !UNIV_HOTBACKUP */