Drizzled Public API Documentation

ibuf0ibuf.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "ibuf0ibuf.h"
27 
29 #define IBUF_BITS_PER_PAGE 4
30 #if IBUF_BITS_PER_PAGE % 2
31 # error "IBUF_BITS_PER_PAGE must be an even number!"
32 #endif
33 
34 #define IBUF_BITMAP PAGE_DATA
35 
36 #ifdef UNIV_NONINL
37 #include "ibuf0ibuf.ic"
38 #endif
39 
40 #ifndef UNIV_HOTBACKUP
41 
42 #include "buf0buf.h"
43 #include "buf0rea.h"
44 #include "fsp0fsp.h"
45 #include "trx0sys.h"
46 #include "fil0fil.h"
47 #include "rem0rec.h"
48 #include "btr0cur.h"
49 #include "btr0pcur.h"
50 #include "btr0btr.h"
51 #include "row0upd.h"
52 #include "sync0sync.h"
53 #include "dict0boot.h"
54 #include "fut0lst.h"
55 #include "lock0lock.h"
56 #include "log0recv.h"
57 #include "que0que.h"
58 #include "srv0start.h" /* srv_shutdown_state */
59 
60 /* STRUCTURE OF AN INSERT BUFFER RECORD
61 
62 In versions < 4.1.x:
63 
64 1. The first field is the page number.
65 2. The second field is an array which stores type info for each subsequent
66  field. We store the information which affects the ordering of records, and
67  also the physical storage size of an SQL NULL value. E.g., for CHAR(10) it
68  is 10 bytes.
69 3. Next we have the fields of the actual index record.
70 
71 In versions >= 4.1.x:
72 
73 Note that contary to what we planned in the 1990's, there will only be one
74 insert buffer tree, and that is in the system tablespace of InnoDB.
75 
76 1. The first field is the space id.
77 2. The second field is a one-byte marker (0) which differentiates records from
78  the < 4.1.x storage format.
79 3. The third field is the page number.
80 4. The fourth field contains the type info, where we have also added 2 bytes to
81  store the charset. In the compressed table format of 5.0.x we must add more
82  information here so that we can build a dummy 'index' struct which 5.0.x
83  can use in the binary search on the index page in the ibuf merge phase.
84 5. The rest of the fields contain the fields of the actual index record.
85 
86 In versions >= 5.0.3:
87 
88 The first byte of the fourth field is an additional marker (0) if the record
89 is in the compact format. The presence of this marker can be detected by
90 looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
91 
92 The high-order bit of the character set field in the type info is the
93 "nullable" flag for the field.
94 
95 In versions >= 5.5:
96 
97 The optional marker byte at the start of the fourth field is replaced by
98 mandatory 3 fields, totaling 4 bytes:
99 
100  1. 2 bytes: Counter field, used to sort records within a (space id, page
101  no) in the order they were added. This is needed so that for example the
102  sequence of operations "INSERT x, DEL MARK x, INSERT x" is handled
103  correctly.
104 
105  2. 1 byte: Operation type (see ibuf_op_t).
106 
107  3. 1 byte: Flags. Currently only one flag exists, IBUF_REC_COMPACT.
108 
109 To ensure older records, which do not have counters to enforce correct
110 sorting, are merged before any new records, ibuf_insert checks if we're
111 trying to insert to a position that contains old-style records, and if so,
112 refuses the insert. Thus, ibuf pages are gradually converted to the new
113 format as their corresponding buffer pool pages are read into memory.
114 */
115 
116 
117 /* PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
118 
119 If an OS thread performs any operation that brings in disk pages from
120 non-system tablespaces into the buffer pool, or creates such a page there,
121 then the operation may have as a side effect an insert buffer index tree
122 compression. Thus, the tree latch of the insert buffer tree may be acquired
123 in the x-mode, and also the file space latch of the system tablespace may
124 be acquired in the x-mode.
125 
126 Also, an insert to an index in a non-system tablespace can have the same
127 effect. How do we know this cannot lead to a deadlock of OS threads? There
128 is a problem with the i\o-handler threads: they break the latching order
129 because they own x-latches to pages which are on a lower level than the
130 insert buffer tree latch, its page latches, and the tablespace latch an
131 insert buffer operation can reserve.
132 
133 The solution is the following: Let all the tree and page latches connected
134 with the insert buffer be later in the latching order than the fsp latch and
135 fsp page latches.
136 
137 Insert buffer pages must be such that the insert buffer is never invoked
138 when these pages are accessed as this would result in a recursion violating
139 the latching order. We let a special i/o-handler thread take care of i/o to
140 the insert buffer pages and the ibuf bitmap pages, as well as the fsp bitmap
141 pages and the first inode page, which contains the inode of the ibuf tree: let
142 us call all these ibuf pages. To prevent deadlocks, we do not let a read-ahead
143 access both non-ibuf and ibuf pages.
144 
145 Then an i/o-handler for the insert buffer never needs to access recursively the
146 insert buffer tree and thus obeys the latching order. On the other hand, other
147 i/o-handlers for other tablespaces may require access to the insert buffer,
148 but because all kinds of latches they need to access there are later in the
149 latching order, no violation of the latching order occurs in this case,
150 either.
151 
152 A problem is how to grow and contract an insert buffer tree. As it is later
153 in the latching order than the fsp management, we have to reserve the fsp
154 latch first, before adding or removing pages from the insert buffer tree.
155 We let the insert buffer tree have its own file space management: a free
156 list of pages linked to the tree root. To prevent recursive using of the
157 insert buffer when adding pages to the tree, we must first load these pages
158 to memory, obtaining a latch on them, and only after that add them to the
159 free list of the insert buffer tree. More difficult is removing of pages
160 from the free list. If there is an excess of pages in the free list of the
161 ibuf tree, they might be needed if some thread reserves the fsp latch,
162 intending to allocate more file space. So we do the following: if a thread
163 reserves the fsp latch, we check the writer count field of the latch. If
164 this field has value 1, it means that the thread did not own the latch
165 before entering the fsp system, and the mtr of the thread contains no
166 modifications to the fsp pages. Now we are free to reserve the ibuf latch,
167 and check if there is an excess of pages in the free list. We can then, in a
168 separate mini-transaction, take them out of the free list and free them to
169 the fsp system.
170 
171 To avoid deadlocks in the ibuf system, we divide file pages into three levels:
172 
173 (1) non-ibuf pages,
174 (2) ibuf tree pages and the pages in the ibuf tree free list, and
175 (3) ibuf bitmap pages.
176 
177 No OS thread is allowed to access higher level pages if it has latches to
178 lower level pages; even if the thread owns a B-tree latch it must not access
179 the B-tree non-leaf pages if it has latches on lower level pages. Read-ahead
180 is only allowed for level 1 and 2 pages. Dedicated i/o-handler threads handle
181 exclusively level 1 i/o. A dedicated i/o handler thread handles exclusively
182 level 2 i/o. However, if an OS thread does the i/o handling for itself, i.e.,
183 it uses synchronous aio, it can access any pages, as long as it obeys the
184 access order rules. */
185 
187 #define IBUF_POOL_SIZE_PER_MAX_SIZE 2
188 
190 #define IBUF_TABLE_NAME "SYS_IBUF_TABLE"
191 
193 UNIV_INTERN ibuf_use_t ibuf_use = IBUF_USE_ALL;
194 
195 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
196 
197 UNIV_INTERN uint ibuf_debug;
198 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
199 
201 UNIV_INTERN ibuf_t* ibuf = NULL;
202 
204 UNIV_INTERN ulint ibuf_flush_count = 0;
205 
206 #ifdef UNIV_PFS_MUTEX
207 UNIV_INTERN mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key;
208 UNIV_INTERN mysql_pfs_key_t ibuf_mutex_key;
209 UNIV_INTERN mysql_pfs_key_t ibuf_bitmap_mutex_key;
210 #endif /* UNIV_PFS_MUTEX */
211 
212 #ifdef UNIV_IBUF_COUNT_DEBUG
213 
214 #define IBUF_COUNT_N_SPACES 4
215 
216 #define IBUF_COUNT_N_PAGES 130000
217 
219 static ulint ibuf_counts[IBUF_COUNT_N_SPACES][IBUF_COUNT_N_PAGES];
220 
221 /******************************************************************/
223 UNIV_INLINE
224 void
225 ibuf_count_check(
226 /*=============*/
227  ulint space_id,
228  ulint page_no)
229 {
230  if (space_id < IBUF_COUNT_N_SPACES && page_no < IBUF_COUNT_N_PAGES) {
231  return;
232  }
233 
234  fprintf(stderr,
235  "InnoDB: UNIV_IBUF_COUNT_DEBUG limits space_id and page_no\n"
236  "InnoDB: and breaks crash recovery.\n"
237  "InnoDB: space_id=%lu, should be 0<=space_id<%lu\n"
238  "InnoDB: page_no=%lu, should be 0<=page_no<%lu\n",
239  (ulint) space_id, (ulint) IBUF_COUNT_N_SPACES,
240  (ulint) page_no, (ulint) IBUF_COUNT_N_PAGES);
241  ut_error;
242 }
243 #endif
244 
246 /* @{ */
247 #define IBUF_BITMAP_FREE 0
249 #define IBUF_BITMAP_BUFFERED 2
251 #define IBUF_BITMAP_IBUF 3
255 /* @} */
256 
257 /* Various constants for checking the type of an ibuf record and extracting
258 data from it. For details, see the description of the record format at the
259 top of this file. */
260 
264 /* @{ */
265 #define IBUF_REC_INFO_SIZE 4
267 #if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
268 # error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
269 #endif
270 
271 /* Offsets for the fields at the beginning of the fourth field */
272 #define IBUF_REC_OFFSET_COUNTER 0
273 #define IBUF_REC_OFFSET_TYPE 2
274 #define IBUF_REC_OFFSET_FLAGS 3
276 /* Record flag masks */
277 #define IBUF_REC_COMPACT 0x1
284 static mutex_t ibuf_pessimistic_insert_mutex;
285 
287 static mutex_t ibuf_mutex;
288 
290 static mutex_t ibuf_bitmap_mutex;
291 
293 #define IBUF_MERGE_AREA 8
294 
298 #define IBUF_MERGE_THRESHOLD 4
299 
302 #define IBUF_MAX_N_PAGES_MERGED IBUF_MERGE_AREA
303 
307 #define IBUF_CONTRACT_ON_INSERT_NON_SYNC 0
308 
312 #define IBUF_CONTRACT_ON_INSERT_SYNC 5
313 
317 #define IBUF_CONTRACT_DO_NOT_INSERT 10
318 
319 /* TODO: how to cope with drop table if there are records in the insert
320 buffer for the indexes of the table? Is there actually any problem,
321 because ibuf merge is done to a page when it is read in, and it is
322 still physically like the index page even if the index would have been
323 dropped! So, there seems to be no problem. */
324 
325 /******************************************************************/
328 UNIV_INLINE
329 void
330 ibuf_enter(
331 /*=======*/
332  mtr_t* mtr)
333 {
334  ut_ad(!mtr->inside_ibuf);
335  mtr->inside_ibuf = TRUE;
336 }
337 
338 /******************************************************************/
341 UNIV_INLINE
342 void
343 ibuf_exit(
344 /*======*/
345  mtr_t* mtr)
346 {
347  ut_ad(mtr->inside_ibuf);
348  mtr->inside_ibuf = FALSE;
349 }
350 
351 /**************************************************************/
354 UNIV_INLINE
355 void
356 ibuf_btr_pcur_commit_specify_mtr(
357 /*=============================*/
358  btr_pcur_t* pcur,
359  mtr_t* mtr)
360 {
361  ut_d(ibuf_exit(mtr));
362  btr_pcur_commit_specify_mtr(pcur, mtr);
363 }
364 
365 /******************************************************************/
368 static
369 page_t*
370 ibuf_header_page_get(
371 /*=================*/
372  mtr_t* mtr)
373 {
374  buf_block_t* block;
375 
376  ut_ad(!ibuf_inside(mtr));
377 
378  block = buf_page_get(
379  IBUF_SPACE_ID, 0, FSP_IBUF_HEADER_PAGE_NO, RW_X_LATCH, mtr);
380  buf_block_dbg_add_level(block, SYNC_IBUF_HEADER);
381 
382  return(buf_block_get_frame(block));
383 }
384 
385 /******************************************************************/
388 static
389 page_t*
390 ibuf_tree_root_get(
391 /*===============*/
392  mtr_t* mtr)
393 {
394  buf_block_t* block;
395  page_t* root;
396 
397  ut_ad(ibuf_inside(mtr));
398  ut_ad(mutex_own(&ibuf_mutex));
399 
400  mtr_x_lock(dict_index_get_lock(ibuf->index), mtr);
401 
402  block = buf_page_get(
403  IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr);
404 
405  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
406 
407  root = buf_block_get_frame(block);
408 
409  ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
410  ut_ad(page_get_page_no(root) == FSP_IBUF_TREE_ROOT_PAGE_NO);
411  ut_ad(ibuf->empty == (page_get_n_recs(root) == 0));
412 
413  return(root);
414 }
415 
416 #ifdef UNIV_IBUF_COUNT_DEBUG
417 /******************************************************************/
421 UNIV_INTERN
422 ulint
423 ibuf_count_get(
424 /*===========*/
425  ulint space,
426  ulint page_no)
427 {
428  ibuf_count_check(space, page_no);
429 
430  return(ibuf_counts[space][page_no]);
431 }
432 
433 /******************************************************************/
435 static
436 void
437 ibuf_count_set(
438 /*===========*/
439  ulint space,
440  ulint page_no,
441  ulint val)
442 {
443  ibuf_count_check(space, page_no);
444  ut_a(val < UNIV_PAGE_SIZE);
445 
446  ibuf_counts[space][page_no] = val;
447 }
448 #endif
449 
450 /******************************************************************/
452 UNIV_INTERN
453 void
454 ibuf_close(void)
455 /*============*/
456 {
457  mutex_free(&ibuf_pessimistic_insert_mutex);
458  memset(&ibuf_pessimistic_insert_mutex,
459  0x0, sizeof(ibuf_pessimistic_insert_mutex));
460 
461  mutex_free(&ibuf_mutex);
462  memset(&ibuf_mutex, 0x0, sizeof(ibuf_mutex));
464  mutex_free(&ibuf_bitmap_mutex);
465  memset(&ibuf_bitmap_mutex, 0x0, sizeof(ibuf_mutex));
466 
467  mem_free(ibuf);
468  ibuf = NULL;
469 }
470 
471 /******************************************************************/
474 static
475 void
476 ibuf_size_update(
477 /*=============*/
478  const page_t* root,
479  mtr_t* mtr)
480 {
481  ut_ad(mutex_own(&ibuf_mutex));
482 
483  ibuf->free_list_len = flst_get_len(root + PAGE_HEADER
484  + PAGE_BTR_IBUF_FREE_LIST, mtr);
485 
486  ibuf->height = 1 + btr_page_get_level(root, mtr);
487 
488  /* the '1 +' is the ibuf header page */
489  ibuf->size = ibuf->seg_size - (1 + ibuf->free_list_len);
490 }
491 
492 /******************************************************************/
495 UNIV_INTERN
496 void
498 /*=======================*/
499 {
500  page_t* root;
501  mtr_t mtr;
502  dict_table_t* table;
503  mem_heap_t* heap;
504  dict_index_t* index;
505  ulint n_used;
506  page_t* header_page;
507  ulint error;
508 
509  ibuf = static_cast<ibuf_t *>(mem_alloc(sizeof(ibuf_t)));
510 
511  memset(ibuf, 0, sizeof(*ibuf));
512 
513  /* Note that also a pessimistic delete can sometimes make a B-tree
514  grow in size, as the references on the upper levels of the tree can
515  change */
516 
517  ibuf->max_size = ut_min(buf_pool_get_curr_size() / UNIV_PAGE_SIZE
518  / IBUF_POOL_SIZE_PER_MAX_SIZE,
519  srv_ibuf_max_size / UNIV_PAGE_SIZE);
520  srv_ibuf_max_size = ibuf->max_size * UNIV_PAGE_SIZE;
521 
522  mutex_create(ibuf_pessimistic_insert_mutex_key,
523  &ibuf_pessimistic_insert_mutex,
524  SYNC_IBUF_PESS_INSERT_MUTEX);
525 
526  mutex_create(ibuf_mutex_key,
527  &ibuf_mutex, SYNC_IBUF_MUTEX);
528 
529  mutex_create(ibuf_bitmap_mutex_key,
530  &ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
531 
532  mtr_start(&mtr);
533 
534  mutex_enter(&ibuf_mutex);
535 
536  mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, NULL), &mtr);
537 
538  header_page = ibuf_header_page_get(&mtr);
539 
540  fseg_n_reserved_pages(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
541  &n_used, &mtr);
542  ibuf_enter(&mtr);
543 
544  ut_ad(n_used >= 2);
545 
546  ibuf->seg_size = n_used;
547 
548  {
549  buf_block_t* block;
550 
551  block = buf_page_get(
552  IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO,
553  RW_X_LATCH, &mtr);
554  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
555 
556  root = buf_block_get_frame(block);
557  }
558 
559  ibuf_size_update(root, &mtr);
560  mutex_exit(&ibuf_mutex);
561 
562  ibuf->empty = (page_get_n_recs(root) == 0);
563  ibuf_mtr_commit(&mtr);
564 
565  heap = mem_heap_create(450);
566 
567  /* Use old-style record format for the insert buffer. */
568  table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0);
569 
570  dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
571 
572  table->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
573 
574  dict_table_add_to_cache(table, heap);
575  mem_heap_free(heap);
576 
577  index = dict_mem_index_create(
578  IBUF_TABLE_NAME, "CLUST_IND",
579  IBUF_SPACE_ID, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 1);
580 
581  dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
582 
583  index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
584 
585  error = dict_index_add_to_cache(table, index,
586  FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
587  ut_a(error == DB_SUCCESS);
588 
589  ibuf->index = dict_table_get_first_index(table);
590 }
591 #endif /* !UNIV_HOTBACKUP */
592 /*********************************************************************/
594 UNIV_INTERN
595 void
597 /*==================*/
598  buf_block_t* block,
599  mtr_t* mtr)
600 {
601  page_t* page;
602  ulint byte_offset;
603  ulint zip_size = buf_block_get_zip_size(block);
604 
605  ut_a(ut_is_2pow(zip_size));
606 
607  page = buf_block_get_frame(block);
609 
610  /* Write all zeros to the bitmap */
611 
612  if (!zip_size) {
613  byte_offset = UT_BITS_IN_BYTES(UNIV_PAGE_SIZE
614  * IBUF_BITS_PER_PAGE);
615  } else {
616  byte_offset = UT_BITS_IN_BYTES(zip_size * IBUF_BITS_PER_PAGE);
617  }
618 
619  memset(page + IBUF_BITMAP, 0, byte_offset);
620 
621  /* The remaining area (up to the page trailer) is uninitialized. */
622 
623 #ifndef UNIV_HOTBACKUP
625 #endif /* !UNIV_HOTBACKUP */
626 }
627 
628 /*********************************************************************/
631 UNIV_INTERN
632 byte*
634 /*===================*/
635  byte* ptr,
636  byte* /*end_ptr __attribute__((unused))*/,
637  buf_block_t* block,
638  mtr_t* mtr)
639 {
640  ut_ad(ptr && end_ptr);
641 
642  if (block) {
643  ibuf_bitmap_page_init(block, mtr);
644  }
645 
646  return(ptr);
647 }
648 #ifndef UNIV_HOTBACKUP
649 # ifdef UNIV_DEBUG
650 
657 # define ibuf_bitmap_page_get_bits(page, offset, zs, bit, mtr) \
658  ibuf_bitmap_page_get_bits_low(page, offset, zs, \
659  MTR_MEMO_PAGE_X_FIX, mtr, bit)
660 # else /* UNIV_DEBUG */
661 
668 # define ibuf_bitmap_page_get_bits(page, offset, zs, bit, mtr) \
669  ibuf_bitmap_page_get_bits_low(page, offset, zs, bit)
670 # endif /* UNIV_DEBUG */
671 
672 /********************************************************************/
675 UNIV_INLINE
676 ulint
677 ibuf_bitmap_page_get_bits_low(
678 /*==========================*/
679  const page_t* page,
680  ulint page_no,
681  ulint zip_size,
683 #ifdef UNIV_DEBUG
684  ulint latch_type,
687  mtr_t* mtr,
689 #endif /* UNIV_DEBUG */
690  ulint bit)
693 {
694  ulint byte_offset;
695  ulint bit_offset;
696  ulint map_byte;
697  ulint value;
698 
699  ut_ad(bit < IBUF_BITS_PER_PAGE);
700 #if IBUF_BITS_PER_PAGE % 2
701 # error "IBUF_BITS_PER_PAGE % 2 != 0"
702 #endif
703  ut_ad(ut_is_2pow(zip_size));
704  ut_ad(mtr_memo_contains_page(mtr, page, latch_type));
705 
706  if (!zip_size) {
707  bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE
708  + bit;
709  } else {
710  bit_offset = (page_no & (zip_size - 1)) * IBUF_BITS_PER_PAGE
711  + bit;
712  }
713 
714  byte_offset = bit_offset / 8;
715  bit_offset = bit_offset % 8;
716 
717  ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
718 
719  map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
720 
721  value = ut_bit_get_nth(map_byte, bit_offset);
722 
723  if (bit == IBUF_BITMAP_FREE) {
724  ut_ad(bit_offset + 1 < 8);
725 
726  value = value * 2 + ut_bit_get_nth(map_byte, bit_offset + 1);
727  }
728 
729  return(value);
730 }
731 
732 /********************************************************************/
734 static
735 void
736 ibuf_bitmap_page_set_bits(
737 /*======================*/
738  page_t* page,
739  ulint page_no,
740  ulint zip_size,
742  ulint bit,
743  ulint val,
744  mtr_t* mtr)
745 {
746  ulint byte_offset;
747  ulint bit_offset;
748  ulint map_byte;
749 
750  ut_ad(bit < IBUF_BITS_PER_PAGE);
751 #if IBUF_BITS_PER_PAGE % 2
752 # error "IBUF_BITS_PER_PAGE % 2 != 0"
753 #endif
754  ut_ad(ut_is_2pow(zip_size));
755  ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
756 #ifdef UNIV_IBUF_COUNT_DEBUG
757  ut_a((bit != IBUF_BITMAP_BUFFERED) || (val != FALSE)
758  || (0 == ibuf_count_get(page_get_space_id(page),
759  page_no)));
760 #endif
761  if (!zip_size) {
762  bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE
763  + bit;
764  } else {
765  bit_offset = (page_no & (zip_size - 1)) * IBUF_BITS_PER_PAGE
766  + bit;
767  }
768 
769  byte_offset = bit_offset / 8;
770  bit_offset = bit_offset % 8;
771 
772  ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
773 
774  map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
775 
776  if (bit == IBUF_BITMAP_FREE) {
777  ut_ad(bit_offset + 1 < 8);
778  ut_ad(val <= 3);
779 
780  map_byte = ut_bit_set_nth(map_byte, bit_offset, val / 2);
781  map_byte = ut_bit_set_nth(map_byte, bit_offset + 1, val % 2);
782  } else {
783  ut_ad(val <= 1);
784  map_byte = ut_bit_set_nth(map_byte, bit_offset, val);
785  }
786 
787  mlog_write_ulint(page + IBUF_BITMAP + byte_offset, map_byte,
788  MLOG_1BYTE, mtr);
789 }
790 
791 /********************************************************************/
794 UNIV_INLINE
795 ulint
796 ibuf_bitmap_page_no_calc(
797 /*=====================*/
798  ulint zip_size,
800  ulint page_no)
801 {
802  ut_ad(ut_is_2pow(zip_size));
803 
804  if (!zip_size) {
805  return(FSP_IBUF_BITMAP_OFFSET
806  + (page_no & ~(UNIV_PAGE_SIZE - 1)));
807  } else {
808  return(FSP_IBUF_BITMAP_OFFSET
809  + (page_no & ~(zip_size - 1)));
810  }
811 }
812 
813 /********************************************************************/
819 static
820 page_t*
821 ibuf_bitmap_get_map_page_func(
822 /*==========================*/
823  ulint space,
824  ulint page_no,
825  ulint zip_size,
827  const char* file,
828  ulint line,
829  mtr_t* mtr)
830 {
831  buf_block_t* block;
832 
833  block = buf_page_get_gen(space, zip_size,
834  ibuf_bitmap_page_no_calc(zip_size, page_no),
835  RW_X_LATCH, NULL, BUF_GET,
836  file, line, mtr);
837  buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
838 
839  return(buf_block_get_frame(block));
840 }
841 
842 /********************************************************************/
852 #define ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr) \
853  ibuf_bitmap_get_map_page_func(space, page_no, zip_size, \
854  __FILE__, __LINE__, mtr)
855 
856 /************************************************************************/
861 UNIV_INLINE
862 void
863 ibuf_set_free_bits_low(
864 /*===================*/
865  ulint zip_size,
867  const buf_block_t* block,
870  ulint val,
871  mtr_t* mtr)
872 {
873  page_t* bitmap_page;
874  ulint space;
875  ulint page_no;
876 
877  if (!page_is_leaf(buf_block_get_frame(block))) {
878 
879  return;
880  }
881 
882  space = buf_block_get_space(block);
883  page_no = buf_block_get_page_no(block);
884  bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
885 #ifdef UNIV_IBUF_DEBUG
886 # if 0
887  fprintf(stderr,
888  "Setting space %lu page %lu free bits to %lu should be %lu\n",
889  space, page_no, val,
890  ibuf_index_page_calc_free(zip_size, block));
891 # endif
892 
893  ut_a(val <= ibuf_index_page_calc_free(zip_size, block));
894 #endif /* UNIV_IBUF_DEBUG */
895  ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
896  IBUF_BITMAP_FREE, val, mtr);
897 }
898 
899 /************************************************************************/
904 UNIV_INTERN
905 void
906 ibuf_set_free_bits_func(
907 /*====================*/
908  buf_block_t* block,
910 #ifdef UNIV_IBUF_DEBUG
911  ulint max_val,
914 #endif /* UNIV_IBUF_DEBUG */
915  ulint val)
916 {
917  mtr_t mtr;
918  page_t* page;
919  page_t* bitmap_page;
920  ulint space;
921  ulint page_no;
922  ulint zip_size;
923 
924  page = buf_block_get_frame(block);
925 
926  if (!page_is_leaf(page)) {
927 
928  return;
929  }
930 
931  mtr_start(&mtr);
932 
933  space = buf_block_get_space(block);
934  page_no = buf_block_get_page_no(block);
935  zip_size = buf_block_get_zip_size(block);
936  bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, &mtr);
937 
938 #ifdef UNIV_IBUF_DEBUG
939  if (max_val != ULINT_UNDEFINED) {
940  ulint old_val;
941 
942  old_val = ibuf_bitmap_page_get_bits(
943  bitmap_page, page_no, zip_size,
944  IBUF_BITMAP_FREE, &mtr);
945 # if 0
946  if (old_val != max_val) {
947  fprintf(stderr,
948  "Ibuf: page %lu old val %lu max val %lu\n",
949  page_get_page_no(page),
950  old_val, max_val);
951  }
952 # endif
953 
954  ut_a(old_val <= max_val);
955  }
956 # if 0
957  fprintf(stderr, "Setting page no %lu free bits to %lu should be %lu\n",
958  page_get_page_no(page), val,
959  ibuf_index_page_calc_free(zip_size, block));
960 # endif
961 
962  ut_a(val <= ibuf_index_page_calc_free(zip_size, block));
963 #endif /* UNIV_IBUF_DEBUG */
964  ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
965  IBUF_BITMAP_FREE, val, &mtr);
966  mtr_commit(&mtr);
967 }
968 
969 /************************************************************************/
978 UNIV_INTERN
979 void
981 /*=================*/
982  buf_block_t* block)
985 {
986  ibuf_set_free_bits(block, 0, ULINT_UNDEFINED);
987 }
988 
989 /**********************************************************************/
997 UNIV_INTERN
998 void
1000 /*======================*/
1001  const buf_block_t* block,
1002  ulint max_ins_size,
1007  mtr_t* mtr)
1009  ulint before;
1010  ulint after;
1011 
1012  ut_a(!buf_block_get_page_zip(block));
1013 
1014  before = ibuf_index_page_calc_free_bits(0, max_ins_size);
1015 
1016  after = ibuf_index_page_calc_free(0, block);
1017 
1018  /* This approach cannot be used on compressed pages, since the
1019  computed value of "before" often does not match the current
1020  state of the bitmap. This is because the free space may
1021  increase or decrease when a compressed page is reorganized. */
1022  if (before != after) {
1023  ibuf_set_free_bits_low(0, block, after, mtr);
1024  }
1025 }
1026 
1027 /**********************************************************************/
1035 UNIV_INTERN
1036 void
1038 /*======================*/
1039  buf_block_t* block,
1040  mtr_t* mtr)
1041 {
1042  page_t* bitmap_page;
1043  ulint space;
1044  ulint page_no;
1045  ulint zip_size;
1046  ulint after;
1047 
1048  space = buf_block_get_space(block);
1049  page_no = buf_block_get_page_no(block);
1050  zip_size = buf_block_get_zip_size(block);
1051 
1052  ut_a(page_is_leaf(buf_block_get_frame(block)));
1053  ut_a(zip_size);
1054 
1055  bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
1056 
1057  after = ibuf_index_page_calc_free_zip(zip_size, block);
1058 
1059  if (after == 0) {
1060  /* We move the page to the front of the buffer pool LRU list:
1061  the purpose of this is to prevent those pages to which we
1062  cannot make inserts using the insert buffer from slipping
1063  out of the buffer pool */
1064 
1065  buf_page_make_young(&block->page);
1066  }
1067 
1068  ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
1069  IBUF_BITMAP_FREE, after, mtr);
1070 }
1071 
1072 /**********************************************************************/
1079 UNIV_INTERN
1080 void
1082 /*====================================*/
1083  ulint zip_size,
1085  buf_block_t* block1,
1086  buf_block_t* block2,
1087  mtr_t* mtr)
1088 {
1089  ulint state;
1091  /* As we have to x-latch two random bitmap pages, we have to acquire
1092  the bitmap mutex to prevent a deadlock with a similar operation
1093  performed by another OS thread. */
1094 
1095  mutex_enter(&ibuf_bitmap_mutex);
1096 
1097  state = ibuf_index_page_calc_free(zip_size, block1);
1098 
1099  ibuf_set_free_bits_low(zip_size, block1, state, mtr);
1100 
1101  state = ibuf_index_page_calc_free(zip_size, block2);
1102 
1103  ibuf_set_free_bits_low(zip_size, block2, state, mtr);
1104 
1105  mutex_exit(&ibuf_bitmap_mutex);
1106 }
1107 
1108 /**********************************************************************/
1111 UNIV_INLINE
1112 ibool
1113 ibuf_fixed_addr_page(
1114 /*=================*/
1115  ulint space,
1116  ulint zip_size,
1118  ulint page_no)
1119 {
1120  return((space == IBUF_SPACE_ID && page_no == IBUF_TREE_ROOT_PAGE_NO)
1121  || ibuf_bitmap_page(zip_size, page_no));
1122 }
1123 
1124 /***********************************************************************/
1128 UNIV_INTERN
1129 ibool
1131 /*==========*/
1132  ulint space,
1133  ulint zip_size,
1134  ulint page_no,
1135 #ifdef UNIV_DEBUG
1136  ibool x_latch,
1138 #endif /* UNIV_DEBUG */
1139  const char* file,
1140  ulint line,
1141  mtr_t* mtr)
1146 {
1147  ibool ret;
1148  mtr_t local_mtr;
1149  page_t* bitmap_page;
1150 
1152  ut_ad(x_latch || mtr == NULL);
1153 
1154  if (srv_fake_write)
1155  return(FALSE);
1156 
1157  if (ibuf_fixed_addr_page(space, zip_size, page_no)) {
1158 
1159  return(TRUE);
1160  } else if (space != IBUF_SPACE_ID) {
1161 
1162  return(FALSE);
1163  }
1164 
1165  ut_ad(fil_space_get_type(IBUF_SPACE_ID) == FIL_TABLESPACE);
1166 
1167 #ifdef UNIV_DEBUG
1168  if (!x_latch) {
1169  mtr_start(&local_mtr);
1170 
1171  /* Get the bitmap page without a page latch, so that
1172  we will not be violating the latching order when
1173  another bitmap page has already been latched by this
1174  thread. The page will be buffer-fixed, and thus it
1175  cannot be removed or relocated while we are looking at
1176  it. The contents of the page could change, but the
1177  IBUF_BITMAP_IBUF bit that we are interested in should
1178  not be modified by any other thread. Nobody should be
1179  calling ibuf_add_free_page() or ibuf_remove_free_page()
1180  while the page is linked to the insert buffer b-tree. */
1181 
1182  bitmap_page = buf_block_get_frame(
1184  space, zip_size,
1185  ibuf_bitmap_page_no_calc(zip_size, page_no),
1186  RW_NO_LATCH, NULL, BUF_GET_NO_LATCH,
1187  file, line, &local_mtr));
1188 # ifdef UNIV_SYNC_DEBUG
1189  /* This is for tracking Bug #58212. This check and message can
1190  be removed once it has been established that our assumptions
1191  about this condition are correct. The bug was only a one-time
1192  occurrence, unable to repeat since then. */
1193  void* latch = sync_thread_levels_contains(SYNC_IBUF_BITMAP);
1194  if (latch) {
1195  fprintf(stderr, "Bug#58212 UNIV_SYNC_DEBUG"
1196  " levels %p (%u,%u)\n",
1197  latch, (unsigned) space, (unsigned) page_no);
1198  }
1199 # endif /* UNIV_SYNC_DEBUG */
1200  ret = ibuf_bitmap_page_get_bits_low(
1201  bitmap_page, page_no, zip_size,
1202  MTR_MEMO_BUF_FIX, &local_mtr, IBUF_BITMAP_IBUF);
1203 
1204  mtr_commit(&local_mtr);
1205  return(ret);
1206  }
1207 #endif /* UNIV_DEBUG */
1208 
1209  if (mtr == NULL) {
1210  mtr = &local_mtr;
1211  mtr_start(mtr);
1212  }
1213 
1214  bitmap_page = ibuf_bitmap_get_map_page_func(space, page_no, zip_size,
1215  file, line, mtr);
1216 
1217  ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
1218  IBUF_BITMAP_IBUF, mtr);
1219 
1220  if (mtr == &local_mtr) {
1221  mtr_commit(mtr);
1222  }
1223 
1224  return(ret);
1225 }
1226 
1227 #ifdef UNIV_DEBUG
1228 # define ibuf_rec_get_page_no(mtr,rec) ibuf_rec_get_page_no_func(mtr,rec)
1229 #else /* UNIV_DEBUG */
1230 # define ibuf_rec_get_page_no(mtr,rec) ibuf_rec_get_page_no_func(rec)
1231 #endif /* UNIV_DEBUG */
1232 
1233 /********************************************************************/
1236 static
1237 ulint
1238 ibuf_rec_get_page_no_func(
1239 /*======================*/
1240 #ifdef UNIV_DEBUG
1241  mtr_t* mtr,
1242 #endif /* UNIV_DEBUG */
1243  const rec_t* rec)
1244 {
1245  const byte* field;
1246  ulint len;
1247 
1248  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
1249  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
1250  ut_ad(ibuf_inside(mtr));
1251  ut_ad(rec_get_n_fields_old(rec) > 2);
1252 
1253  field = rec_get_nth_field_old(rec, 1, &len);
1254 
1255  if (len == 1) {
1256  /* This is of the >= 4.1.x record format */
1258 
1259  field = rec_get_nth_field_old(rec, 2, &len);
1260  } else {
1263 
1264  field = rec_get_nth_field_old(rec, 0, &len);
1265  }
1266 
1267  ut_a(len == 4);
1268 
1269  return(mach_read_from_4(field));
1270 }
1271 
1272 #ifdef UNIV_DEBUG
1273 # define ibuf_rec_get_space(mtr,rec) ibuf_rec_get_space_func(mtr,rec)
1274 #else /* UNIV_DEBUG */
1275 # define ibuf_rec_get_space(mtr,rec) ibuf_rec_get_space_func(rec)
1276 #endif /* UNIV_DEBUG */
1277 
1278 /********************************************************************/
1282 static
1283 ulint
1284 ibuf_rec_get_space_func(
1285 /*====================*/
1286 #ifdef UNIV_DEBUG
1287  mtr_t* mtr,
1288 #endif /* UNIV_DEBUG */
1289  const rec_t* rec)
1290 {
1291  const byte* field;
1292  ulint len;
1293 
1294  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
1295  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
1296  ut_ad(ibuf_inside(mtr));
1297  ut_ad(rec_get_n_fields_old(rec) > 2);
1298 
1299  field = rec_get_nth_field_old(rec, 1, &len);
1300 
1301  if (len == 1) {
1302  /* This is of the >= 4.1.x record format */
1303 
1305  field = rec_get_nth_field_old(rec, 0, &len);
1306  ut_a(len == 4);
1307 
1308  return(mach_read_from_4(field));
1309  }
1310 
1313 
1314  return(0);
1315 }
1316 
1317 #ifdef UNIV_DEBUG
1318 # define ibuf_rec_get_info(mtr,rec,op,comp,info_len,counter) \
1319  ibuf_rec_get_info_func(mtr,rec,op,comp,info_len,counter)
1320 #else /* UNIV_DEBUG */
1321 # define ibuf_rec_get_info(mtr,rec,op,comp,info_len,counter) \
1322  ibuf_rec_get_info_func(rec,op,comp,info_len,counter)
1323 #endif
1324 /****************************************************************/
1326 static
1327 void
1328 ibuf_rec_get_info_func(
1329 /*===================*/
1330 #ifdef UNIV_DEBUG
1331  mtr_t* mtr,
1332 #endif /* UNIV_DEBUG */
1333  const rec_t* rec,
1334  ibuf_op_t* op,
1335  ibool* comp,
1336  ulint* info_len,
1339  ulint* counter)
1340 {
1341  const byte* types;
1342  ulint fields;
1343  ulint len;
1344 
1345  /* Local variables to shadow arguments. */
1346  ibuf_op_t op_local;
1347  ibool comp_local;
1348  ulint info_len_local;
1349  ulint counter_local;
1350 
1351  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
1352  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
1353  ut_ad(ibuf_inside(mtr));
1354  fields = rec_get_n_fields_old(rec);
1355  ut_a(fields > 4);
1356 
1357  types = rec_get_nth_field_old(rec, 3, &len);
1358 
1359  info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1360 
1361  switch (info_len_local) {
1362  case 0:
1363  case 1:
1364  op_local = IBUF_OP_INSERT;
1365  comp_local = info_len_local;
1366  ut_ad(!counter);
1367  counter_local = ULINT_UNDEFINED;
1368  break;
1369 
1370  case IBUF_REC_INFO_SIZE:
1371  op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE];
1372  comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT;
1373  counter_local = mach_read_from_2(
1374  types + IBUF_REC_OFFSET_COUNTER);
1375  break;
1376 
1377  default:
1378  ut_error;
1379  }
1380 
1381  ut_a(op_local < IBUF_OP_COUNT);
1382  ut_a((len - info_len_local) ==
1383  (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1384 
1385  if (op) {
1386  *op = op_local;
1387  }
1388 
1389  if (comp) {
1390  *comp = comp_local;
1391  }
1392 
1393  if (info_len) {
1394  *info_len = info_len_local;
1395  }
1396 
1397  if (counter) {
1398  *counter = counter_local;
1399  }
1400 }
1401 
1402 #ifdef UNIV_DEBUG
1403 # define ibuf_rec_get_op_type(mtr,rec) ibuf_rec_get_op_type_func(mtr,rec)
1404 #else /* UNIV_DEBUG */
1405 # define ibuf_rec_get_op_type(mtr,rec) ibuf_rec_get_op_type_func(rec)
1406 #endif
1407 
1408 /****************************************************************/
1411 static
1412 ibuf_op_t
1413 ibuf_rec_get_op_type_func(
1414 /*======================*/
1415 #ifdef UNIV_DEBUG
1416  mtr_t* mtr,
1417 #endif /* UNIV_DEBUG */
1418  const rec_t* rec)
1419 {
1420  ulint len;
1421 
1422  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
1423  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
1424  ut_ad(ibuf_inside(mtr));
1425  ut_ad(rec_get_n_fields_old(rec) > 2);
1426 
1427  (void) rec_get_nth_field_old(rec, 1, &len);
1428 
1429  if (len > 1) {
1430  /* This is a < 4.1.x format record */
1431 
1432  return(IBUF_OP_INSERT);
1433  } else {
1434  ibuf_op_t op;
1435 
1436  ibuf_rec_get_info(mtr, rec, &op, NULL, NULL, NULL);
1437 
1438  return(op);
1439  }
1440 }
1441 
1442 /****************************************************************/
1447 UNIV_INTERN
1448 ulint
1450 /*=================*/
1451  const rec_t* rec)
1452 {
1453  const byte* ptr;
1454  ulint len;
1455 
1456  if (rec_get_n_fields_old(rec) < 4) {
1457 
1458  return(ULINT_UNDEFINED);
1459  }
1460 
1461  ptr = rec_get_nth_field_old(rec, 3, &len);
1462 
1463  if (len >= 2) {
1464 
1465  return(mach_read_from_2(ptr));
1466  } else {
1467 
1468  return(ULINT_UNDEFINED);
1469  }
1470 }
1471 
1472 /****************************************************************/
1475 static
1476 void
1477 ibuf_add_ops(
1478 /*=========*/
1479  ulint* arr,
1480  const ulint* ops)
1482 {
1483  ulint i;
1484 
1485 #ifndef HAVE_ATOMIC_BUILTINS
1486  ut_ad(mutex_own(&ibuf_mutex));
1487 #endif /* !HAVE_ATOMIC_BUILTINS */
1488 
1489  for (i = 0; i < IBUF_OP_COUNT; i++) {
1490 #ifdef HAVE_ATOMIC_BUILTINS
1491  os_atomic_increment_ulint(&arr[i], ops[i]);
1492 #else /* HAVE_ATOMIC_BUILTINS */
1493  arr[i] += ops[i];
1494 #endif /* HAVE_ATOMIC_BUILTINS */
1495  }
1496 }
1497 
1498 /****************************************************************/
1500 static
1501 void
1502 ibuf_print_ops(
1503 /*===========*/
1504  const ulint* ops,
1505  FILE* file)
1506 {
1507  static const char* op_names[] = {
1508  "insert",
1509  "delete mark",
1510  "delete"
1511  };
1512  ulint i;
1513 
1514  ut_a(UT_ARR_SIZE(op_names) == IBUF_OP_COUNT);
1515 
1516  for (i = 0; i < IBUF_OP_COUNT; i++) {
1517  fprintf(file, "%s %lu%s", op_names[i],
1518  (ulong) ops[i], (i < (IBUF_OP_COUNT - 1)) ? ", " : "");
1519  }
1520 
1521  putc('\n', file);
1522 }
1523 
1524 /********************************************************************/
1527 static
1528 dict_index_t*
1529 ibuf_dummy_index_create(
1530 /*====================*/
1531  ulint n,
1532  ibool comp)
1533 {
1534  dict_table_t* table;
1535  dict_index_t* index;
1536 
1537  table = dict_mem_table_create("IBUF_DUMMY",
1538  DICT_HDR_SPACE, n,
1539  comp ? DICT_TF_COMPACT : 0);
1540 
1541  index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY",
1542  DICT_HDR_SPACE, 0, n);
1543 
1544  index->table = table;
1545 
1546  /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
1547  index->cached = TRUE;
1548 
1549  return(index);
1550 }
1551 /********************************************************************/
1553 static
1554 void
1555 ibuf_dummy_index_add_col(
1556 /*=====================*/
1557  dict_index_t* index,
1558  const dtype_t* type,
1559  ulint len)
1560 {
1561  ulint i = index->table->n_def;
1562  dict_mem_table_add_col(index->table, NULL, NULL,
1563  dtype_get_mtype(type),
1564  dtype_get_prtype(type),
1565  dtype_get_len(type));
1566  dict_index_add_col(index, index->table,
1567  dict_table_get_nth_col(index->table, i), len);
1568 }
1569 /********************************************************************/
1571 static
1572 void
1573 ibuf_dummy_index_free(
1574 /*==================*/
1575  dict_index_t* index)
1576 {
1577  dict_table_t* table = index->table;
1578 
1579  dict_mem_index_free(index);
1580  dict_mem_table_free(table);
1581 }
1582 
1583 /*********************************************************************/
1591 UNIV_INLINE
1592 dtuple_t*
1593 ibuf_build_entry_pre_4_1_x(
1594 /*=======================*/
1595  const rec_t* ibuf_rec,
1596  mem_heap_t* heap,
1597  dict_index_t** pindex)
1599 {
1600  ulint i;
1601  ulint len;
1602  const byte* types;
1603  dtuple_t* tuple;
1604  ulint n_fields;
1605 
1608 
1609  n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
1610  tuple = dtuple_create(heap, n_fields);
1611  types = rec_get_nth_field_old(ibuf_rec, 1, &len);
1612 
1613  ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1614 
1615  for (i = 0; i < n_fields; i++) {
1616  const byte* data;
1617  dfield_t* field;
1618 
1619  field = dtuple_get_nth_field(tuple, i);
1620 
1621  data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1622 
1623  dfield_set_data(field, data, len);
1624 
1626  dfield_get_type(field),
1627  types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1628  }
1629 
1630  *pindex = ibuf_dummy_index_create(n_fields, FALSE);
1631 
1632  return(tuple);
1633 }
1634 
1635 #ifdef UNIV_DEBUG
1636 # define ibuf_build_entry_from_ibuf_rec(mtr,ibuf_rec,heap,pindex) \
1637  ibuf_build_entry_from_ibuf_rec_func(mtr,ibuf_rec,heap,pindex)
1638 #else /* UNIV_DEBUG */
1639 # define ibuf_build_entry_from_ibuf_rec(mtr,ibuf_rec,heap,pindex) \
1640  ibuf_build_entry_from_ibuf_rec_func(ibuf_rec,heap,pindex)
1641 #endif
1642 
1643 /*********************************************************************/
1659 static
1660 dtuple_t*
1661 ibuf_build_entry_from_ibuf_rec_func(
1662 /*================================*/
1663 #ifdef UNIV_DEBUG
1664  mtr_t* mtr,
1665 #endif /* UNIV_DEBUG */
1666  const rec_t* ibuf_rec,
1667  mem_heap_t* heap,
1668  dict_index_t** pindex)
1670 {
1671  dtuple_t* tuple;
1672  dfield_t* field;
1673  ulint n_fields;
1674  const byte* types;
1675  const byte* data;
1676  ulint len;
1677  ulint info_len;
1678  ulint i;
1679  ulint comp;
1680  dict_index_t* index;
1681 
1682  ut_ad(mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_X_FIX)
1683  || mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_S_FIX));
1684  ut_ad(ibuf_inside(mtr));
1685 
1686  data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1687 
1688  if (len > 1) {
1689  /* This a < 4.1.x format record */
1690 
1691  return(ibuf_build_entry_pre_4_1_x(ibuf_rec, heap, pindex));
1692  }
1693 
1694  /* This a >= 4.1.x format record */
1695 
1697  ut_a(*data == 0);
1698  ut_a(rec_get_n_fields_old(ibuf_rec) > 4);
1699 
1700  n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1701 
1702  tuple = dtuple_create(heap, n_fields);
1703 
1704  types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1705 
1706  ibuf_rec_get_info(mtr, ibuf_rec, NULL, &comp, &info_len, NULL);
1707 
1708  index = ibuf_dummy_index_create(n_fields, comp);
1709 
1710  len -= info_len;
1711  types += info_len;
1712 
1713  ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1714 
1715  for (i = 0; i < n_fields; i++) {
1716  field = dtuple_get_nth_field(tuple, i);
1717 
1718  data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1719 
1720  dfield_set_data(field, data, len);
1721 
1723  dfield_get_type(field),
1724  types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1725 
1726  ibuf_dummy_index_add_col(index, dfield_get_type(field), len);
1727  }
1728 
1729  /* Prevent an ut_ad() failure in page_zip_write_rec() by
1730  adding system columns to the dummy table pointed to by the
1731  dummy secondary index. The insert buffer is only used for
1732  secondary indexes, whose records never contain any system
1733  columns, such as DB_TRX_ID. */
1735 
1736  *pindex = index;
1737 
1738  return(tuple);
1739 }
1740 
1741 /******************************************************************/
1744 UNIV_INLINE
1745 ulint
1746 ibuf_rec_get_size(
1747 /*==============*/
1748  const rec_t* rec,
1749  const byte* types,
1750  ulint n_fields,
1751  ibool pre_4_1,
1753  ulint comp)
1755 {
1756  ulint i;
1757  ulint field_offset;
1758  ulint types_offset;
1759  ulint size = 0;
1760 
1761  if (pre_4_1) {
1762  field_offset = 2;
1763  types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE;
1764  } else {
1765  field_offset = 4;
1766  types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1767  }
1768 
1769  for (i = 0; i < n_fields; i++) {
1770  ulint len;
1771  dtype_t dtype;
1772 
1773  rec_get_nth_field_offs_old(rec, i + field_offset, &len);
1774 
1775  if (len != UNIV_SQL_NULL) {
1776  size += len;
1777  } else if (pre_4_1) {
1778  dtype_read_for_order_and_null_size(&dtype, types);
1779 
1780  size += dtype_get_sql_null_size(&dtype, comp);
1781  } else {
1783 
1784  size += dtype_get_sql_null_size(&dtype, comp);
1785  }
1786 
1787  types += types_offset;
1788  }
1789 
1790  return(size);
1791 }
1792 
1793 #ifdef UNIV_DEBUG
1794 # define ibuf_rec_get_volume(mtr,rec) ibuf_rec_get_volume_func(mtr,rec)
1795 #else /* UNIV_DEBUG */
1796 # define ibuf_rec_get_volume(mtr,rec) ibuf_rec_get_volume_func(rec)
1797 #endif
1798 
1799 /********************************************************************/
1804 static
1805 ulint
1806 ibuf_rec_get_volume_func(
1807 /*=====================*/
1808 #ifdef UNIV_DEBUG
1809  mtr_t* mtr,
1810 #endif /* UNIV_DEBUG */
1811  const rec_t* ibuf_rec)
1812 {
1813  ulint len;
1814  const byte* data;
1815  const byte* types;
1816  ulint n_fields;
1817  ulint data_size;
1818  ibool pre_4_1;
1819  ulint comp;
1820 
1821  ut_ad(mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_X_FIX)
1822  || mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_S_FIX));
1823  ut_ad(ibuf_inside(mtr));
1824  ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
1825 
1826  data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1827  pre_4_1 = (len > 1);
1828 
1829  if (pre_4_1) {
1830  /* < 4.1.x format record */
1831 
1834 
1835  n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
1836 
1837  types = rec_get_nth_field_old(ibuf_rec, 1, &len);
1838 
1839  ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1840  comp = 0;
1841  } else {
1842  /* >= 4.1.x format record */
1843  ibuf_op_t op;
1844  ulint info_len;
1845 
1847  ut_a(*data == 0);
1848 
1849  types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1850 
1851  ibuf_rec_get_info(mtr, ibuf_rec, &op, &comp, &info_len, NULL);
1852 
1853  if (op == IBUF_OP_DELETE_MARK || op == IBUF_OP_DELETE) {
1854  /* Delete-marking a record doesn't take any
1855  additional space, and while deleting a record
1856  actually frees up space, we have to play it safe and
1857  pretend it takes no additional space (the record
1858  might not exist, etc.). */
1859 
1860  return(0);
1861  } else if (comp) {
1862  dtuple_t* entry;
1863  ulint volume;
1864  dict_index_t* dummy_index;
1865  mem_heap_t* heap = mem_heap_create(500);
1866 
1867  entry = ibuf_build_entry_from_ibuf_rec(
1868  mtr, ibuf_rec, heap, &dummy_index);
1869 
1870  volume = rec_get_converted_size(dummy_index, entry, 0);
1871 
1872  ibuf_dummy_index_free(dummy_index);
1873  mem_heap_free(heap);
1874 
1875  return(volume + page_dir_calc_reserved_space(1));
1876  }
1877 
1878  types += info_len;
1879  n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1880  }
1881 
1882  data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp);
1883 
1884  return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0)
1886 }
1887 
1888 /*********************************************************************/
1896 static
1897 dtuple_t*
1898 ibuf_entry_build(
1899 /*=============*/
1900  ibuf_op_t op,
1901  dict_index_t* index,
1902  const dtuple_t* entry,
1903  ulint space,
1904  ulint page_no,
1906  ulint counter,
1908  mem_heap_t* heap)
1909 {
1910  dtuple_t* tuple;
1911  dfield_t* field;
1912  const dfield_t* entry_field;
1913  ulint n_fields;
1914  byte* buf;
1915  byte* ti;
1916  byte* type_info;
1917  ulint i;
1918 
1919  ut_ad(counter != ULINT_UNDEFINED || op == IBUF_OP_INSERT);
1920  ut_ad(counter == ULINT_UNDEFINED || counter <= 0xFFFF);
1921  ut_ad(op < IBUF_OP_COUNT);
1922 
1923  /* We have to build a tuple with the following fields:
1924 
1925  1-4) These are described at the top of this file.
1926 
1927  5) The rest of the fields are copied from the entry.
1928 
1929  All fields in the tuple are ordered like the type binary in our
1930  insert buffer tree. */
1931 
1932  n_fields = dtuple_get_n_fields(entry);
1933 
1934  tuple = dtuple_create(heap, n_fields + 4);
1935 
1936  /* 1) Space Id */
1937 
1938  field = dtuple_get_nth_field(tuple, 0);
1939 
1940  buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1941 
1942  mach_write_to_4(buf, space);
1943 
1944  dfield_set_data(field, buf, 4);
1945 
1946  /* 2) Marker byte */
1947 
1948  field = dtuple_get_nth_field(tuple, 1);
1949 
1950  buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
1951 
1952  /* We set the marker byte zero */
1953 
1954  mach_write_to_1(buf, 0);
1955 
1956  dfield_set_data(field, buf, 1);
1957 
1958  /* 3) Page number */
1959 
1960  field = dtuple_get_nth_field(tuple, 2);
1961 
1962  buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1963 
1964  mach_write_to_4(buf, page_no);
1965 
1966  dfield_set_data(field, buf, 4);
1967 
1968  /* 4) Type info, part #1 */
1969 
1970  if (counter == ULINT_UNDEFINED) {
1971  i = dict_table_is_comp(index->table) ? 1 : 0;
1972  } else {
1973  ut_ad(counter <= 0xFFFF);
1974  i = IBUF_REC_INFO_SIZE;
1975  }
1976 
1977  ti = type_info = static_cast<byte *>(mem_heap_alloc(heap, i + n_fields
1978  * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE));
1979 
1980  switch (i) {
1981  default:
1982  ut_error;
1983  break;
1984  case 1:
1985  /* set the flag for ROW_FORMAT=COMPACT */
1986  *ti++ = 0;
1987  /* fall through */
1988  case 0:
1989  /* the old format does not allow delete buffering */
1990  ut_ad(op == IBUF_OP_INSERT);
1991  break;
1992  case IBUF_REC_INFO_SIZE:
1993  mach_write_to_2(ti + IBUF_REC_OFFSET_COUNTER, counter);
1994 
1995  ti[IBUF_REC_OFFSET_TYPE] = (byte) op;
1996  ti[IBUF_REC_OFFSET_FLAGS] = dict_table_is_comp(index->table)
1997  ? IBUF_REC_COMPACT : 0;
1998  ti += IBUF_REC_INFO_SIZE;
1999  break;
2000  }
2001 
2002  /* 5+) Fields from the entry */
2003 
2004  for (i = 0; i < n_fields; i++) {
2005  ulint fixed_len;
2006  const dict_field_t* ifield;
2007 
2008  /* We add 4 below because we have the 4 extra fields at the
2009  start of an ibuf record */
2010 
2011  field = dtuple_get_nth_field(tuple, i + 4);
2012  entry_field = dtuple_get_nth_field(entry, i);
2013  dfield_copy(field, entry_field);
2014 
2015  ifield = dict_index_get_nth_field(index, i);
2016  /* Prefix index columns of fixed-length columns are of
2017  fixed length. However, in the function call below,
2018  dfield_get_type(entry_field) contains the fixed length
2019  of the column in the clustered index. Replace it with
2020  the fixed length of the secondary index column. */
2021  fixed_len = ifield->fixed_len;
2022 
2023 #ifdef UNIV_DEBUG
2024  if (fixed_len) {
2025  /* dict_index_add_col() should guarantee these */
2026  ut_ad(fixed_len <= (ulint)
2027  dfield_get_type(entry_field)->len);
2028  if (ifield->prefix_len) {
2029  ut_ad(ifield->prefix_len == fixed_len);
2030  } else {
2031  ut_ad(fixed_len == (ulint)
2032  dfield_get_type(entry_field)->len);
2033  }
2034  }
2035 #endif /* UNIV_DEBUG */
2036 
2038  ti, dfield_get_type(entry_field), fixed_len);
2039  ti += DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
2040  }
2041 
2042  /* 4) Type info, part #2 */
2043 
2044  field = dtuple_get_nth_field(tuple, 3);
2045 
2046  dfield_set_data(field, type_info, ti - type_info);
2047 
2048  /* Set all the types in the new tuple binary */
2049 
2050  dtuple_set_types_binary(tuple, n_fields + 4);
2051 
2052  return(tuple);
2053 }
2054 
2055 /*********************************************************************/
2059 static
2060 dtuple_t*
2061 ibuf_search_tuple_build(
2062 /*====================*/
2063  ulint space,
2064  ulint page_no,
2065  mem_heap_t* heap)
2066 {
2067  dtuple_t* tuple;
2068  dfield_t* field;
2069  byte* buf;
2070 
2071  ut_a(space == 0);
2074 
2075  tuple = dtuple_create(heap, 1);
2076 
2077  /* Store the page number in tuple */
2078 
2079  field = dtuple_get_nth_field(tuple, 0);
2080 
2081  buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
2082 
2083  mach_write_to_4(buf, page_no);
2084 
2085  dfield_set_data(field, buf, 4);
2086 
2087  dtuple_set_types_binary(tuple, 1);
2088 
2089  return(tuple);
2090 }
2091 
2092 /*********************************************************************/
2096 static
2097 dtuple_t*
2098 ibuf_new_search_tuple_build(
2099 /*========================*/
2100  ulint space,
2101  ulint page_no,
2102  mem_heap_t* heap)
2103 {
2104  dtuple_t* tuple;
2105  dfield_t* field;
2106  byte* buf;
2107 
2109 
2110  tuple = dtuple_create(heap, 3);
2111 
2112  /* Store the space id in tuple */
2113 
2114  field = dtuple_get_nth_field(tuple, 0);
2115 
2116  buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
2117 
2118  mach_write_to_4(buf, space);
2119 
2120  dfield_set_data(field, buf, 4);
2121 
2122  /* Store the new format record marker byte */
2123 
2124  field = dtuple_get_nth_field(tuple, 1);
2125 
2126  buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
2127 
2128  mach_write_to_1(buf, 0);
2129 
2130  dfield_set_data(field, buf, 1);
2131 
2132  /* Store the page number in tuple */
2133 
2134  field = dtuple_get_nth_field(tuple, 2);
2135 
2136  buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
2137 
2138  mach_write_to_4(buf, page_no);
2139 
2140  dfield_set_data(field, buf, 4);
2141 
2142  dtuple_set_types_binary(tuple, 3);
2143 
2144  return(tuple);
2145 }
2146 
2147 /*********************************************************************/
2151 UNIV_INLINE
2152 ibool
2153 ibuf_data_enough_free_for_insert(void)
2154 /*==================================*/
2155 {
2156  ut_ad(mutex_own(&ibuf_mutex));
2157 
2158  /* We want a big margin of free pages, because a B-tree can sometimes
2159  grow in size also if records are deleted from it, as the node pointers
2160  can change, and we must make sure that we are able to delete the
2161  inserts buffered for pages that we read to the buffer pool, without
2162  any risk of running out of free space in the insert buffer. */
2163 
2164  return(ibuf->free_list_len >= (ibuf->size / 2) + 3 * ibuf->height);
2165 }
2166 
2167 /*********************************************************************/
2171 UNIV_INLINE
2172 ibool
2173 ibuf_data_too_much_free(void)
2174 /*=========================*/
2175 {
2176  ut_ad(mutex_own(&ibuf_mutex));
2177 
2178  return(ibuf->free_list_len >= 3 + (ibuf->size / 2) + 3 * ibuf->height);
2179 }
2180 
2181 /*********************************************************************/
2185 static
2186 ibool
2187 ibuf_add_free_page(void)
2188 /*====================*/
2189 {
2190  mtr_t mtr;
2191  page_t* header_page;
2192  ulint flags;
2193  ulint zip_size;
2194  ulint page_no;
2195  page_t* page;
2196  page_t* root;
2197  page_t* bitmap_page;
2198 
2199  mtr_start(&mtr);
2200 
2201  /* Acquire the fsp latch before the ibuf header, obeying the latching
2202  order */
2203  mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, &flags), &mtr);
2204  zip_size = dict_table_flags_to_zip_size(flags);
2205 
2206  header_page = ibuf_header_page_get(&mtr);
2207 
2208  /* Allocate a new page: NOTE that if the page has been a part of a
2209  non-clustered index which has subsequently been dropped, then the
2210  page may have buffered inserts in the insert buffer, and these
2211  should be deleted from there. These get deleted when the page
2212  allocation creates the page in buffer. Thus the call below may end
2213  up calling the insert buffer routines and, as we yet have no latches
2214  to insert buffer tree pages, these routines can run without a risk
2215  of a deadlock. This is the reason why we created a special ibuf
2216  header page apart from the ibuf tree. */
2217 
2218  page_no = fseg_alloc_free_page(
2219  header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
2220  &mtr);
2221 
2222  if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
2223  mtr_commit(&mtr);
2224 
2225  return(FALSE);
2226  } else {
2227  buf_block_t* block = buf_page_get(
2228  IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
2229  buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
2230 
2231  page = buf_block_get_frame(block);
2232  }
2233 
2234  ibuf_enter(&mtr);
2235 
2236  mutex_enter(&ibuf_mutex);
2237 
2238  root = ibuf_tree_root_get(&mtr);
2239 
2240  /* Add the page to the free list and update the ibuf size data */
2241 
2242  flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
2243  page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
2244 
2246  MLOG_2BYTES, &mtr);
2247 
2248  ibuf->seg_size++;
2249  ibuf->free_list_len++;
2250 
2251  /* Set the bit indicating that this page is now an ibuf tree page
2252  (level 2 page) */
2253 
2254  bitmap_page = ibuf_bitmap_get_map_page(
2255  IBUF_SPACE_ID, page_no, zip_size, &mtr);
2256 
2257  mutex_exit(&ibuf_mutex);
2258 
2259  ibuf_bitmap_page_set_bits(
2260  bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
2261 
2262  ibuf_mtr_commit(&mtr);
2263 
2264  return(TRUE);
2265 }
2266 
2267 /*********************************************************************/
2269 static
2270 void
2271 ibuf_remove_free_page(void)
2272 /*=======================*/
2273 {
2274  mtr_t mtr;
2275  mtr_t mtr2;
2276  page_t* header_page;
2277  ulint flags;
2278  ulint zip_size;
2279  ulint page_no;
2280  page_t* page;
2281  page_t* root;
2282  page_t* bitmap_page;
2283 
2284  mtr_start(&mtr);
2285 
2286  /* Acquire the fsp latch before the ibuf header, obeying the latching
2287  order */
2288  mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, &flags), &mtr);
2289  zip_size = dict_table_flags_to_zip_size(flags);
2290 
2291  header_page = ibuf_header_page_get(&mtr);
2292 
2293  /* Prevent pessimistic inserts to insert buffer trees for a while */
2294  ibuf_enter(&mtr);
2295  mutex_enter(&ibuf_pessimistic_insert_mutex);
2296  mutex_enter(&ibuf_mutex);
2297 
2298  if (!ibuf_data_too_much_free()) {
2299 
2300  mutex_exit(&ibuf_mutex);
2301  mutex_exit(&ibuf_pessimistic_insert_mutex);
2302 
2303  ibuf_mtr_commit(&mtr);
2304 
2305  return;
2306  }
2307 
2308  ibuf_mtr_start(&mtr2);
2309 
2310  root = ibuf_tree_root_get(&mtr2);
2311 
2312  mutex_exit(&ibuf_mutex);
2313 
2314  page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
2315  &mtr2).page;
2316 
2317  /* NOTE that we must release the latch on the ibuf tree root
2318  because in fseg_free_page we access level 1 pages, and the root
2319  is a level 2 page. */
2320 
2321  ibuf_mtr_commit(&mtr2);
2322  ibuf_exit(&mtr);
2323 
2324  /* Since pessimistic inserts were prevented, we know that the
2325  page is still in the free list. NOTE that also deletes may take
2326  pages from the free list, but they take them from the start, and
2327  the free list was so long that they cannot have taken the last
2328  page from it. */
2329 
2330  fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
2331  IBUF_SPACE_ID, page_no, &mtr);
2332 
2333 #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
2334  buf_page_reset_file_page_was_freed(IBUF_SPACE_ID, page_no);
2335 #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
2336 
2337  ibuf_enter(&mtr);
2338 
2339  mutex_enter(&ibuf_mutex);
2340 
2341  root = ibuf_tree_root_get(&mtr);
2342 
2343  ut_ad(page_no == flst_get_last(root + PAGE_HEADER
2344  + PAGE_BTR_IBUF_FREE_LIST, &mtr).page);
2345 
2346  {
2347  buf_block_t* block;
2348 
2349  block = buf_page_get(
2350  IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
2351 
2352  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
2353 
2354 
2355  page = buf_block_get_frame(block);
2356  }
2357 
2358  /* Remove the page from the free list and update the ibuf size data */
2359 
2360  flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
2361  page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
2362 
2363  mutex_exit(&ibuf_pessimistic_insert_mutex);
2364 
2365  ibuf->seg_size--;
2366  ibuf->free_list_len--;
2367 
2368  /* Set the bit indicating that this page is no more an ibuf tree page
2369  (level 2 page) */
2370 
2371  bitmap_page = ibuf_bitmap_get_map_page(
2372  IBUF_SPACE_ID, page_no, zip_size, &mtr);
2373 
2374  mutex_exit(&ibuf_mutex);
2375 
2376  ibuf_bitmap_page_set_bits(
2377  bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr);
2378 
2379 #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
2380  buf_page_set_file_page_was_freed(IBUF_SPACE_ID, page_no);
2381 #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
2382  ibuf_mtr_commit(&mtr);
2383 }
2384 
2385 /***********************************************************************/
2389 UNIV_INTERN
2390 void
2392 /*========================*/
2393 {
2394  ulint i;
2395 
2396 #ifdef UNIV_SYNC_DEBUG
2397  ut_ad(rw_lock_own(fil_space_get_latch(IBUF_SPACE_ID, NULL),
2398  RW_LOCK_EX));
2399 #endif /* UNIV_SYNC_DEBUG */
2402  fil_space_get_latch(IBUF_SPACE_ID, NULL)) == 1);
2403 
2404  /* NOTE: We require that the thread did not own the latch before,
2405  because then we know that we can obey the correct latching order
2406  for ibuf latches */
2407 
2408  if (!ibuf) {
2409  /* Not yet initialized; not sure if this is possible, but
2410  does no harm to check for it. */
2411 
2412  return;
2413  }
2414 
2415  /* Free at most a few pages at a time, so that we do not delay the
2416  requested service too much */
2417 
2418  for (i = 0; i < 4; i++) {
2419 
2420  ibool too_much_free;
2421 
2422  mutex_enter(&ibuf_mutex);
2423  too_much_free = ibuf_data_too_much_free();
2424  mutex_exit(&ibuf_mutex);
2425 
2426  if (!too_much_free) {
2427  return;
2428  }
2429 
2430  ibuf_remove_free_page();
2431  }
2432 }
2433 
2434 #ifdef UNIV_DEBUG
2435 # define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \
2436  ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,vers,pages,n_stored)
2437 #else /* UNIV_DEBUG */
2438 # define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \
2439  ibuf_get_merge_page_nos_func(contract,rec,ids,vers,pages,n_stored)
2440 #endif /* UNIV_DEBUG */
2441 
2442 /*********************************************************************/
2446 static
2447 ulint
2448 ibuf_get_merge_page_nos_func(
2449 /*=========================*/
2450  ibool contract,
2454  const rec_t* rec,
2455 #ifdef UNIV_DEBUG
2456  mtr_t* mtr,
2457 #endif /* UNIV_DEBUG */
2458  ulint* space_ids,
2459  ib_int64_t* space_versions,
2462  ulint* page_nos,
2465  ulint* n_stored)
2467 {
2468  ulint prev_page_no;
2469  ulint prev_space_id;
2470  ulint first_page_no;
2471  ulint first_space_id;
2472  ulint rec_page_no;
2473  ulint rec_space_id;
2474  ulint sum_volumes;
2475  ulint volume_for_page;
2476  ulint rec_volume;
2477  ulint limit;
2478  ulint n_pages;
2479 
2480  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
2481  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
2482  ut_ad(ibuf_inside(mtr));
2483 
2484  *n_stored = 0;
2485 
2486  limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4);
2487 
2488  if (page_rec_is_supremum(rec)) {
2489 
2490  rec = page_rec_get_prev_const(rec);
2491  }
2492 
2493  if (page_rec_is_infimum(rec)) {
2494 
2495  rec = page_rec_get_next_const(rec);
2496  }
2497 
2498  if (page_rec_is_supremum(rec)) {
2499 
2500  return(0);
2501  }
2502 
2503  first_page_no = ibuf_rec_get_page_no(mtr, rec);
2504  first_space_id = ibuf_rec_get_space(mtr, rec);
2505  n_pages = 0;
2506  prev_page_no = 0;
2507  prev_space_id = 0;
2508 
2509  /* Go backwards from the first rec until we reach the border of the
2510  'merge area', or the page start or the limit of storeable pages is
2511  reached */
2512 
2513  while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) {
2514 
2515  rec_page_no = ibuf_rec_get_page_no(mtr, rec);
2516  rec_space_id = ibuf_rec_get_space(mtr, rec);
2517 
2518  if (rec_space_id != first_space_id
2519  || (rec_page_no / IBUF_MERGE_AREA)
2520  != (first_page_no / IBUF_MERGE_AREA)) {
2521 
2522  break;
2523  }
2524 
2525  if (rec_page_no != prev_page_no
2526  || rec_space_id != prev_space_id) {
2527  n_pages++;
2528  }
2529 
2530  prev_page_no = rec_page_no;
2531  prev_space_id = rec_space_id;
2532 
2533  rec = page_rec_get_prev_const(rec);
2534  }
2535 
2536  rec = page_rec_get_next_const(rec);
2537 
2538  /* At the loop start there is no prev page; we mark this with a pair
2539  of space id, page no (0, 0) for which there can never be entries in
2540  the insert buffer */
2541 
2542  prev_page_no = 0;
2543  prev_space_id = 0;
2544  sum_volumes = 0;
2545  volume_for_page = 0;
2546 
2547  while (*n_stored < limit) {
2548  if (page_rec_is_supremum(rec)) {
2549  /* When no more records available, mark this with
2550  another 'impossible' pair of space id, page no */
2551  rec_page_no = 1;
2552  rec_space_id = 0;
2553  } else {
2554  rec_page_no = ibuf_rec_get_page_no(mtr, rec);
2555  rec_space_id = ibuf_rec_get_space(mtr, rec);
2556  ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
2557  }
2558 
2559 #ifdef UNIV_IBUF_DEBUG
2560  ut_a(*n_stored < IBUF_MAX_N_PAGES_MERGED);
2561 #endif
2562  if ((rec_space_id != prev_space_id
2563  || rec_page_no != prev_page_no)
2564  && (prev_space_id != 0 || prev_page_no != 0)) {
2565 
2566  if (contract
2567  || (prev_page_no == first_page_no
2568  && prev_space_id == first_space_id)
2569  || (volume_for_page
2570  > ((IBUF_MERGE_THRESHOLD - 1)
2571  * 4 * UNIV_PAGE_SIZE
2572  / IBUF_PAGE_SIZE_PER_FREE_SPACE)
2573  / IBUF_MERGE_THRESHOLD)) {
2574 
2575  space_ids[*n_stored] = prev_space_id;
2576  space_versions[*n_stored]
2577  = fil_space_get_version(prev_space_id);
2578  page_nos[*n_stored] = prev_page_no;
2579 
2580  (*n_stored)++;
2581 
2582  sum_volumes += volume_for_page;
2583  }
2584 
2585  if (rec_space_id != first_space_id
2586  || rec_page_no / IBUF_MERGE_AREA
2587  != first_page_no / IBUF_MERGE_AREA) {
2588 
2589  break;
2590  }
2591 
2592  volume_for_page = 0;
2593  }
2594 
2595  if (rec_page_no == 1 && rec_space_id == 0) {
2596  /* Supremum record */
2597 
2598  break;
2599  }
2600 
2601  rec_volume = ibuf_rec_get_volume(mtr, rec);
2602 
2603  volume_for_page += rec_volume;
2604 
2605  prev_page_no = rec_page_no;
2606  prev_space_id = rec_space_id;
2607 
2608  rec = page_rec_get_next_const(rec);
2609  }
2610 
2611 #ifdef UNIV_IBUF_DEBUG
2612  ut_a(*n_stored <= IBUF_MAX_N_PAGES_MERGED);
2613 #endif
2614 #if 0
2615  fprintf(stderr, "Ibuf merge batch %lu pages %lu volume\n",
2616  *n_stored, sum_volumes);
2617 #endif
2618  return(sum_volumes);
2619 }
2620 
2621 /*********************************************************************/
2626 static
2627 ulint
2628 ibuf_contract_ext(
2629 /*==============*/
2630  ulint* n_pages,
2631  ibool sync)
2634 {
2635  btr_pcur_t pcur;
2636  ulint page_nos[IBUF_MAX_N_PAGES_MERGED];
2637  ulint space_ids[IBUF_MAX_N_PAGES_MERGED];
2638  ib_int64_t space_versions[IBUF_MAX_N_PAGES_MERGED];
2639  ulint sum_sizes;
2640  mtr_t mtr;
2641 
2642  *n_pages = 0;
2643 
2644  /* We perform a dirty read of ibuf->empty, without latching
2645  the insert buffer root page. We trust this dirty read except
2646  when a slow shutdown is being executed. During a slow
2647  shutdown, the insert buffer merge must be completed. */
2648 
2649  if (UNIV_UNLIKELY(ibuf->empty)
2650  && UNIV_LIKELY(!srv_shutdown_state)) {
2651  return(0);
2652  }
2653 
2654  ibuf_mtr_start(&mtr);
2655 
2656  /* Open a cursor to a randomly chosen leaf of the tree, at a random
2657  position within the leaf */
2658 
2659  btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr);
2660 
2661  ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
2662 
2663  if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
2664  /* If a B-tree page is empty, it must be the root page
2665  and the whole B-tree must be empty. InnoDB does not
2666  allow empty B-tree pages other than the root. */
2667  ut_ad(ibuf->empty);
2668  ut_ad(page_get_space_id(btr_pcur_get_page(&pcur))
2669  == IBUF_SPACE_ID);
2670  ut_ad(page_get_page_no(btr_pcur_get_page(&pcur))
2671  == FSP_IBUF_TREE_ROOT_PAGE_NO);
2672 
2673  ibuf_mtr_commit(&mtr);
2674  btr_pcur_close(&pcur);
2675 
2676  return(0);
2677  }
2678 
2679  sum_sizes = ibuf_get_merge_page_nos(TRUE,
2680  btr_pcur_get_rec(&pcur), &mtr,
2681  space_ids, space_versions,
2682  page_nos, n_pages);
2683 #if 0 /* defined UNIV_IBUF_DEBUG */
2684  fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
2685  sync, *n_pages, sum_sizes);
2686 #endif
2687  ibuf_mtr_commit(&mtr);
2688  btr_pcur_close(&pcur);
2689 
2690  buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos,
2691  *n_pages);
2692 
2693  return(sum_sizes + 1);
2694 }
2695 
2696 /*********************************************************************/
2701 UNIV_INTERN
2702 ulint
2704 /*==========*/
2705  ibool sync)
2708 {
2709  ulint n_pages;
2710 
2711  return(ibuf_contract_ext(&n_pages, sync));
2713 
2714 /*********************************************************************/
2719 UNIV_INTERN
2720 ulint
2722 /*======================*/
2723  ibool sync,
2726  ulint n_pages)
2729 {
2730  ulint sum_bytes = 0;
2731  ulint sum_pages = 0;
2732  ulint n_bytes;
2733  ulint n_pag2;
2734 
2735  if (srv_fake_write)
2736  return(0);
2737 
2738  while (sum_pages < n_pages) {
2739  n_bytes = ibuf_contract_ext(&n_pag2, sync);
2740 
2741  if (n_bytes == 0) {
2742  return(sum_bytes);
2743  }
2744 
2745  sum_bytes += n_bytes;
2746  sum_pages += n_pag2;
2747  }
2748 
2749  return(sum_bytes);
2750 }
2751 
2752 /*********************************************************************/
2754 UNIV_INLINE
2755 void
2756 ibuf_contract_after_insert(
2757 /*=======================*/
2758  ulint entry_size)
2760 {
2761  ibool sync;
2762  ulint sum_sizes;
2763  ulint size;
2764  ulint max_size;
2765 
2766  /* Perform dirty reads of ibuf->size and ibuf->max_size, to
2767  reduce ibuf_mutex contention. ibuf->max_size remains constant
2768  after ibuf_init_at_db_start(), but ibuf->size should be
2769  protected by ibuf_mutex. Given that ibuf->size fits in a
2770  machine word, this should be OK; at worst we are doing some
2771  excessive ibuf_contract() or occasionally skipping a
2772  ibuf_contract(). */
2773  size = ibuf->size;
2774  max_size = ibuf->max_size;
2775 
2776  if (srv_ibuf_active_contract == false
2777  && size < max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
2778  return;
2779  }
2780 
2781  sync = (size >= max_size + IBUF_CONTRACT_ON_INSERT_SYNC);
2782 
2783  /* Contract at least entry_size many bytes */
2784  sum_sizes = 0;
2785  size = 1;
2786 
2787  do {
2788 
2789  size = ibuf_contract(sync);
2790  sum_sizes += size;
2791  } while (size > 0 && sum_sizes < entry_size);
2792 }
2793 
2794 /*********************************************************************/
2797 static
2798 ibool
2799 ibuf_get_volume_buffered_hash(
2800 /*==========================*/
2801  const rec_t* rec,
2802  const byte* types,
2803  const byte* data,
2804  ulint comp,
2806  ulint* hash,
2807  ulint size)
2808 {
2809  ulint len;
2810  ulint fold;
2811  ulint bitmask;
2812 
2813  len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4,
2814  FALSE, comp);
2815  fold = ut_fold_binary(data, len);
2816 
2817  hash += (fold / (8 * sizeof *hash)) % size; // 8 = bits in byte
2818  bitmask = 1 << (fold % (8 * sizeof *hash));
2819 
2820  if (*hash & bitmask) {
2821 
2822  return(FALSE);
2823  }
2824 
2825  /* We have not seen this record yet. Insert it. */
2826  *hash |= bitmask;
2827 
2828  return(TRUE);
2829 }
2830 
2831 #ifdef UNIV_DEBUG
2832 # define ibuf_get_volume_buffered_count(mtr,rec,hash,size,n_recs) \
2833  ibuf_get_volume_buffered_count_func(mtr,rec,hash,size,n_recs)
2834 #else /* UNIV_DEBUG */
2835 # define ibuf_get_volume_buffered_count(mtr,rec,hash,size,n_recs) \
2836  ibuf_get_volume_buffered_count_func(rec,hash,size,n_recs)
2837 #endif
2838 /*********************************************************************/
2843 static
2844 ulint
2845 ibuf_get_volume_buffered_count_func(
2846 /*================================*/
2847 #ifdef UNIV_DEBUG
2848  mtr_t* mtr,
2849 #endif /* UNIV_DEBUG */
2850  const rec_t* rec,
2851  ulint* hash,
2852  ulint size,
2853  lint* n_recs)
2855 {
2856  ulint len;
2857  ibuf_op_t ibuf_op;
2858  const byte* types;
2859  ulint n_fields;
2860 
2861  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
2862  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
2863  ut_ad(ibuf_inside(mtr));
2864 
2865  n_fields = rec_get_n_fields_old(rec);
2866  ut_ad(n_fields > 4);
2867  n_fields -= 4;
2868 
2869  rec_get_nth_field_offs_old(rec, 1, &len);
2870  /* This function is only invoked when buffering new
2871  operations. All pre-4.1 records should have been merged
2872  when the database was started up. */
2873  ut_a(len == 1);
2875 
2876  types = rec_get_nth_field_old(rec, 3, &len);
2877 
2878  switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
2879  IBUF_REC_INFO_SIZE)) {
2880  default:
2881  ut_error;
2882  case 0:
2883  /* This ROW_TYPE=REDUNDANT record does not include an
2884  operation counter. Exclude it from the *n_recs,
2885  because deletes cannot be buffered if there are
2886  old-style inserts buffered for the page. */
2887 
2888  len = ibuf_rec_get_size(rec, types, n_fields, FALSE, 0);
2889 
2890  return(len
2891  + rec_get_converted_extra_size(len, n_fields, 0)
2893  case 1:
2894  /* This ROW_TYPE=COMPACT record does not include an
2895  operation counter. Exclude it from the *n_recs,
2896  because deletes cannot be buffered if there are
2897  old-style inserts buffered for the page. */
2898  goto get_volume_comp;
2899 
2900  case IBUF_REC_INFO_SIZE:
2901  ibuf_op = (ibuf_op_t) types[IBUF_REC_OFFSET_TYPE];
2902  break;
2903  }
2904 
2905  switch (ibuf_op) {
2906  case IBUF_OP_INSERT:
2907  /* Inserts can be done by updating a delete-marked record.
2908  Because delete-mark and insert operations can be pointing to
2909  the same records, we must not count duplicates. */
2910  case IBUF_OP_DELETE_MARK:
2911  /* There must be a record to delete-mark.
2912  See if this record has been already buffered. */
2913  if (n_recs && ibuf_get_volume_buffered_hash(
2914  rec, types + IBUF_REC_INFO_SIZE,
2915  types + len,
2916  types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT,
2917  hash, size)) {
2918  (*n_recs)++;
2919  }
2920 
2921  if (ibuf_op == IBUF_OP_DELETE_MARK) {
2922  /* Setting the delete-mark flag does not
2923  affect the available space on the page. */
2924  return(0);
2925  }
2926  break;
2927  case IBUF_OP_DELETE:
2928  /* A record will be removed from the page. */
2929  if (n_recs) {
2930  (*n_recs)--;
2931  }
2932  /* While deleting a record actually frees up space,
2933  we have to play it safe and pretend that it takes no
2934  additional space (the record might not exist, etc.). */
2935  return(0);
2936  default:
2937  ut_error;
2938  }
2939 
2940  ut_ad(ibuf_op == IBUF_OP_INSERT);
2941 
2942 get_volume_comp:
2943  {
2944  dtuple_t* entry;
2945  ulint volume;
2946  dict_index_t* dummy_index;
2947  mem_heap_t* heap = mem_heap_create(500);
2948 
2949  entry = ibuf_build_entry_from_ibuf_rec(
2950  mtr, rec, heap, &dummy_index);
2951 
2952  volume = rec_get_converted_size(dummy_index, entry, 0);
2953 
2954  ibuf_dummy_index_free(dummy_index);
2955  mem_heap_free(heap);
2956 
2957  return(volume + page_dir_calc_reserved_space(1));
2958  }
2959 }
2960 
2961 /*********************************************************************/
2967 static
2968 ulint
2969 ibuf_get_volume_buffered(
2970 /*=====================*/
2971  const btr_pcur_t*pcur,
2976  ulint space,
2977  ulint page_no,
2978  lint* n_recs,
2981  mtr_t* mtr)
2982 {
2983  ulint volume;
2984  const rec_t* rec;
2985  const page_t* page;
2986  ulint prev_page_no;
2987  const page_t* prev_page;
2988  ulint next_page_no;
2989  const page_t* next_page;
2990  /* bitmap of buffered recs */
2991  ulint hash_bitmap[128 / sizeof(ulint)];
2992 
2994 
2995  ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
2996  || (pcur->latch_mode == BTR_MODIFY_TREE));
2997 
2998  /* Count the volume of inserts earlier in the alphabetical order than
2999  pcur */
3000 
3001  volume = 0;
3002 
3003  if (n_recs) {
3004  memset(hash_bitmap, 0, sizeof hash_bitmap);
3005  }
3006 
3007  rec = btr_pcur_get_rec(pcur);
3008  page = page_align(rec);
3009  ut_ad(page_validate(page, ibuf->index));
3010 
3011  if (page_rec_is_supremum(rec)) {
3012  rec = page_rec_get_prev_const(rec);
3013  }
3014 
3015  for (; !page_rec_is_infimum(rec);
3016  rec = page_rec_get_prev_const(rec)) {
3017  ut_ad(page_align(rec) == page);
3018 
3019  if (page_no != ibuf_rec_get_page_no(mtr, rec)
3020  || space != ibuf_rec_get_space(mtr, rec)) {
3021 
3022  goto count_later;
3023  }
3024 
3025  volume += ibuf_get_volume_buffered_count(
3026  mtr, rec,
3027  hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
3028  }
3029 
3030  /* Look at the previous page */
3031 
3032  prev_page_no = btr_page_get_prev(page, mtr);
3033 
3034  if (prev_page_no == FIL_NULL) {
3035 
3036  goto count_later;
3037  }
3038 
3039  {
3040  buf_block_t* block;
3041 
3042  block = buf_page_get(
3043  IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH,
3044  mtr);
3045 
3046  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
3047 
3048 
3049  prev_page = buf_block_get_frame(block);
3050  ut_ad(page_validate(prev_page, ibuf->index));
3051  }
3052 
3053 #ifdef UNIV_BTR_DEBUG
3054  ut_a(btr_page_get_next(prev_page, mtr) == page_get_page_no(page));
3055 #endif /* UNIV_BTR_DEBUG */
3056 
3057  rec = page_get_supremum_rec(prev_page);
3058  rec = page_rec_get_prev_const(rec);
3059 
3060  for (;; rec = page_rec_get_prev_const(rec)) {
3061  ut_ad(page_align(rec) == prev_page);
3062 
3063  if (page_rec_is_infimum(rec)) {
3064 
3065  /* We cannot go to yet a previous page, because we
3066  do not have the x-latch on it, and cannot acquire one
3067  because of the latching order: we have to give up */
3068 
3069  return(UNIV_PAGE_SIZE);
3070  }
3071 
3072  if (page_no != ibuf_rec_get_page_no(mtr, rec)
3073  || space != ibuf_rec_get_space(mtr, rec)) {
3074 
3075  goto count_later;
3076  }
3077 
3078  volume += ibuf_get_volume_buffered_count(
3079  mtr, rec,
3080  hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
3081  }
3082 
3083 count_later:
3084  rec = btr_pcur_get_rec(pcur);
3085 
3086  if (!page_rec_is_supremum(rec)) {
3087  rec = page_rec_get_next_const(rec);
3088  }
3089 
3090  for (; !page_rec_is_supremum(rec);
3091  rec = page_rec_get_next_const(rec)) {
3092  if (page_no != ibuf_rec_get_page_no(mtr, rec)
3093  || space != ibuf_rec_get_space(mtr, rec)) {
3094 
3095  return(volume);
3096  }
3097 
3098  volume += ibuf_get_volume_buffered_count(
3099  mtr, rec,
3100  hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
3101  }
3102 
3103  /* Look at the next page */
3104 
3105  next_page_no = btr_page_get_next(page, mtr);
3106 
3107  if (next_page_no == FIL_NULL) {
3108 
3109  return(volume);
3110  }
3111 
3112  {
3113  buf_block_t* block;
3114 
3115  block = buf_page_get(
3116  IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH,
3117  mtr);
3118 
3119  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
3120 
3121 
3122  next_page = buf_block_get_frame(block);
3123  ut_ad(page_validate(next_page, ibuf->index));
3124  }
3125 
3126 #ifdef UNIV_BTR_DEBUG
3127  ut_a(btr_page_get_prev(next_page, mtr) == page_get_page_no(page));
3128 #endif /* UNIV_BTR_DEBUG */
3129 
3130  rec = page_get_infimum_rec(next_page);
3131  rec = page_rec_get_next_const(rec);
3132 
3133  for (;; rec = page_rec_get_next_const(rec)) {
3134  ut_ad(page_align(rec) == next_page);
3135 
3136  if (page_rec_is_supremum(rec)) {
3137 
3138  /* We give up */
3139 
3140  return(UNIV_PAGE_SIZE);
3141  }
3142 
3143  if (page_no != ibuf_rec_get_page_no(mtr, rec)
3144  || space != ibuf_rec_get_space(mtr, rec)) {
3145 
3146  return(volume);
3147  }
3148 
3149  volume += ibuf_get_volume_buffered_count(
3150  mtr, rec,
3151  hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
3152  }
3153 }
3154 
3155 /*********************************************************************/
3158 UNIV_INTERN
3159 void
3161 /*===============================*/
3162 {
3163  ulint max_space_id;
3164  const rec_t* rec;
3165  const byte* field;
3166  ulint len;
3167  btr_pcur_t pcur;
3168  mtr_t mtr;
3170  ut_a(!dict_table_is_comp(ibuf->index->table));
3171 
3172  ibuf_mtr_start(&mtr);
3173 
3175  FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3176 
3177  ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
3178 
3179  btr_pcur_move_to_prev(&pcur, &mtr);
3180 
3181  if (btr_pcur_is_before_first_on_page(&pcur)) {
3182  /* The tree is empty */
3183 
3184  max_space_id = 0;
3185  } else {
3186  rec = btr_pcur_get_rec(&pcur);
3187 
3188  field = rec_get_nth_field_old(rec, 0, &len);
3189 
3190  ut_a(len == 4);
3191 
3192  max_space_id = mach_read_from_4(field);
3193  }
3194 
3195  ibuf_mtr_commit(&mtr);
3196 
3197  /* printf("Maximum space id in insert buffer %lu\n", max_space_id); */
3198 
3199  fil_set_max_space_id_if_bigger(max_space_id);
3200 }
3201 
3202 #ifdef UNIV_DEBUG
3203 # define ibuf_get_entry_counter_low(mtr,rec,space,page_no) \
3204  ibuf_get_entry_counter_low_func(mtr,rec,space,page_no)
3205 #else /* UNIV_DEBUG */
3206 # define ibuf_get_entry_counter_low(mtr,rec,space,page_no) \
3207  ibuf_get_entry_counter_low_func(rec,space,page_no)
3208 #endif
3209 /****************************************************************/
3214 static
3215 ulint
3216 ibuf_get_entry_counter_low_func(
3217 /*============================*/
3218 #ifdef UNIV_DEBUG
3219  mtr_t* mtr,
3220 #endif /* UNIV_DEBUG */
3221  const rec_t* rec,
3222  ulint space,
3223  ulint page_no)
3224 {
3225  ulint counter;
3226  const byte* field;
3227  ulint len;
3228 
3229  ut_ad(ibuf_inside(mtr));
3230  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX)
3231  || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
3232  ut_ad(rec_get_n_fields_old(rec) > 2);
3233 
3234  field = rec_get_nth_field_old(rec, 1, &len);
3235 
3236  if (UNIV_UNLIKELY(len != 1)) {
3237  /* pre-4.1 format */
3240 
3241  return(ULINT_UNDEFINED);
3242  }
3243 
3245 
3246  /* Check the tablespace identifier. */
3247  field = rec_get_nth_field_old(rec, 0, &len);
3248  ut_a(len == 4);
3249 
3250  if (mach_read_from_4(field) != space) {
3251 
3252  return(0);
3253  }
3254 
3255  /* Check the page offset. */
3256  field = rec_get_nth_field_old(rec, 2, &len);
3257  ut_a(len == 4);
3258 
3259  if (mach_read_from_4(field) != page_no) {
3260 
3261  return(0);
3262  }
3263 
3264  /* Check if the record contains a counter field. */
3265  field = rec_get_nth_field_old(rec, 3, &len);
3266 
3267  switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
3268  default:
3269  ut_error;
3270  case 0: /* ROW_FORMAT=REDUNDANT */
3271  case 1: /* ROW_FORMAT=COMPACT */
3272  return(ULINT_UNDEFINED);
3273 
3274  case IBUF_REC_INFO_SIZE:
3275  counter = mach_read_from_2(field + IBUF_REC_OFFSET_COUNTER);
3276  ut_a(counter < 0xFFFF);
3277  return(counter + 1);
3278  }
3279 }
3280 
3281 /****************************************************************/
3285 static
3286 ibool
3287 ibuf_set_entry_counter(
3288 /*===================*/
3289  dtuple_t* entry,
3290  ulint space,
3291  ulint page_no,
3292  btr_pcur_t* pcur,
3295  ibool is_optimistic,
3296  mtr_t* mtr)
3297 {
3298  dfield_t* field;
3299  byte* data;
3300  ulint counter = 0;
3301 
3302  /* pcur points to either a user rec or to a page's infimum record. */
3303  ut_ad(ibuf_inside(mtr));
3304  ut_ad(mtr_memo_contains(mtr, btr_pcur_get_block(pcur),
3305  MTR_MEMO_PAGE_X_FIX));
3306  ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index));
3307 
3308  if (btr_pcur_is_on_user_rec(pcur)) {
3309 
3310  counter = ibuf_get_entry_counter_low(
3311  mtr, btr_pcur_get_rec(pcur), space, page_no);
3312 
3313  if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
3314  /* The record lacks a counter field.
3315  Such old records must be merged before
3316  new records can be buffered. */
3317 
3318  return(FALSE);
3319  }
3320  } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) {
3321  /* Ibuf tree is either completely empty, or the insert
3322  position is at the very first record of a non-empty tree. In
3323  either case we have no previous records for (space,
3324  page_no). */
3325 
3326  counter = 0;
3327  } else if (btr_pcur_is_before_first_on_page(pcur)) {
3328  btr_cur_t* cursor = btr_pcur_get_btr_cur(pcur);
3329 
3330  if (cursor->low_match < 3) {
3331  /* If low_match < 3, we know that the father node
3332  pointer did not contain the searched for (space,
3333  page_no), which means that the search ended on the
3334  right page regardless of the counter value, and
3335  since we're at the infimum record, there are no
3336  existing records. */
3337 
3338  counter = 0;
3339  } else {
3340  rec_t* rec;
3341  const page_t* page;
3342  buf_block_t* block;
3343  page_t* prev_page;
3344  ulint prev_page_no;
3345 
3346  ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED);
3347 
3348  page = btr_pcur_get_page(pcur);
3349  prev_page_no = btr_page_get_prev(page, mtr);
3350 
3351  ut_a(prev_page_no != FIL_NULL);
3352 
3353  block = buf_page_get(
3354  IBUF_SPACE_ID, 0, prev_page_no,
3355  RW_X_LATCH, mtr);
3356 
3357  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
3358 
3359  prev_page = buf_block_get_frame(block);
3360 
3361  rec = page_rec_get_prev(
3362  page_get_supremum_rec(prev_page));
3363 
3365 
3366  counter = ibuf_get_entry_counter_low(
3367  mtr, rec, space, page_no);
3368 
3369  if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
3370  /* The record lacks a counter field.
3371  Such old records must be merged before
3372  new records can be buffered. */
3373 
3374  return(FALSE);
3375  }
3376 
3377  if (counter < cursor->ibuf_cnt) {
3378  /* Search ended on the wrong page. */
3379 
3380  if (is_optimistic) {
3381  /* In an optimistic insert, we can
3382  shift the insert position to the left
3383  page, since it only needs an X-latch
3384  on the page itself, which the
3385  original search acquired for us. */
3386 
3388  ibuf->index, rec, block,
3389  btr_pcur_get_btr_cur(pcur));
3390  } else {
3391  /* We can't shift the insert
3392  position to the left page in a
3393  pessimistic insert since it would
3394  require an X-latch on the left
3395  page's left page, so we have to
3396  abort. */
3397 
3398  return(FALSE);
3399  }
3400  } else {
3401  /* The counter field in the father node is
3402  the same as we would insert; we don't know
3403  whether the insert should go to this page or
3404  the left page (the later fields can differ),
3405  so refuse the insert. */
3406 
3407  return(FALSE);
3408  }
3409  }
3410  } else {
3411  /* The cursor is not positioned at or before a user record. */
3412  return(FALSE);
3413  }
3414 
3415  /* Patch counter value in already built entry. */
3416  field = dtuple_get_nth_field(entry, 3);
3417  data = static_cast<byte *>(dfield_get_data(field));
3418 
3419  mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter);
3420 
3421  return(TRUE);
3422 }
3423 
3424 /*********************************************************************/
3428 static
3429 ulint
3430 ibuf_insert_low(
3431 /*============*/
3432  ulint mode,
3433  ibuf_op_t op,
3434  ibool no_counter,
3437  const dtuple_t* entry,
3438  ulint entry_size,
3440  dict_index_t* index,
3442  ulint space,
3443  ulint zip_size,
3444  ulint page_no,
3445  que_thr_t* thr)
3446 {
3447  big_rec_t* dummy_big_rec;
3448  btr_pcur_t pcur;
3449  btr_cur_t* cursor;
3450  dtuple_t* ibuf_entry;
3451  mem_heap_t* heap;
3452  ulint buffered;
3453  lint min_n_recs;
3454  rec_t* ins_rec;
3455  ibool old_bit_value;
3456  page_t* bitmap_page;
3457  buf_block_t* block;
3458  page_t* root;
3459  ulint err;
3460  ibool do_merge;
3461  ulint space_ids[IBUF_MAX_N_PAGES_MERGED];
3462  ib_int64_t space_versions[IBUF_MAX_N_PAGES_MERGED];
3463  ulint page_nos[IBUF_MAX_N_PAGES_MERGED];
3464  ulint n_stored;
3465  mtr_t mtr;
3466  mtr_t bitmap_mtr;
3467 
3468  ut_a(!dict_index_is_clust(index));
3469  ut_ad(dtuple_check_typed(entry));
3470  ut_ad(ut_is_2pow(zip_size));
3471  ut_ad(!no_counter || op == IBUF_OP_INSERT);
3472  ut_a(op < IBUF_OP_COUNT);
3473 
3475 
3476  do_merge = FALSE;
3477 
3478  /* Perform dirty reads of ibuf->size and ibuf->max_size, to
3479  reduce ibuf_mutex contention. ibuf->max_size remains constant
3480  after ibuf_init_at_db_start(), but ibuf->size should be
3481  protected by ibuf_mutex. Given that ibuf->size fits in a
3482  machine word, this should be OK; at worst we are doing some
3483  excessive ibuf_contract() or occasionally skipping a
3484  ibuf_contract(). */
3485  if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
3486  /* Insert buffer is now too big, contract it but do not try
3487  to insert */
3488 
3489 
3490 #ifdef UNIV_IBUF_DEBUG
3491  fputs("Ibuf too big\n", stderr);
3492 #endif
3493  /* Use synchronous contract (== TRUE) */
3494  ibuf_contract(TRUE);
3495 
3496  return(DB_STRONG_FAIL);
3497  }
3498 
3499  heap = mem_heap_create(512);
3500 
3501  /* Build the entry which contains the space id and the page number
3502  as the first fields and the type information for other fields, and
3503  which will be inserted to the insert buffer. Using a counter value
3504  of 0xFFFF we find the last record for (space, page_no), from which
3505  we can then read the counter value N and use N + 1 in the record we
3506  insert. (We patch the ibuf_entry's counter field to the correct
3507  value just before actually inserting the entry.) */
3508 
3509  ibuf_entry = ibuf_entry_build(
3510  op, index, entry, space, page_no,
3511  no_counter ? ULINT_UNDEFINED : 0xFFFF, heap);
3512 
3513  /* Open a cursor to the insert buffer tree to calculate if we can add
3514  the new entry to it without exceeding the free space limit for the
3515  page. */
3516 
3517  if (mode == BTR_MODIFY_TREE) {
3518  for (;;) {
3519  mutex_enter(&ibuf_pessimistic_insert_mutex);
3520  mutex_enter(&ibuf_mutex);
3521 
3522  if (UNIV_LIKELY(ibuf_data_enough_free_for_insert())) {
3523 
3524  break;
3525  }
3526 
3527  mutex_exit(&ibuf_mutex);
3528  mutex_exit(&ibuf_pessimistic_insert_mutex);
3529 
3530  if (UNIV_UNLIKELY(!ibuf_add_free_page())) {
3531 
3532  mem_heap_free(heap);
3533  return(DB_STRONG_FAIL);
3534  }
3535  }
3536  }
3537 
3538  ibuf_mtr_start(&mtr);
3539 
3540  btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
3541  ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
3542 
3543  /* Find out the volume of already buffered inserts for the same index
3544  page */
3545  min_n_recs = 0;
3546  buffered = ibuf_get_volume_buffered(&pcur, space, page_no,
3547  op == IBUF_OP_DELETE
3548  ? &min_n_recs
3549  : NULL, &mtr);
3550 
3551  if (op == IBUF_OP_DELETE
3552  && (min_n_recs < 2
3553  || buf_pool_watch_occurred(space, page_no))) {
3554  /* The page could become empty after the record is
3555  deleted, or the page has been read in to the buffer
3556  pool. Refuse to buffer the operation. */
3557 
3558  /* The buffer pool watch is needed for IBUF_OP_DELETE
3559  because of latching order considerations. We can
3560  check buf_pool_watch_occurred() only after latching
3561  the insert buffer B-tree pages that contain buffered
3562  changes for the page. We never buffer IBUF_OP_DELETE,
3563  unless some IBUF_OP_INSERT or IBUF_OP_DELETE_MARK have
3564  been previously buffered for the page. Because there
3565  are buffered operations for the page, the insert
3566  buffer B-tree page latches held by mtr will guarantee
3567  that no changes for the user page will be merged
3568  before mtr_commit(&mtr). We must not mtr_commit(&mtr)
3569  until after the IBUF_OP_DELETE has been buffered. */
3570 
3571 fail_exit:
3572  if (mode == BTR_MODIFY_TREE) {
3573  mutex_exit(&ibuf_mutex);
3574  mutex_exit(&ibuf_pessimistic_insert_mutex);
3575  }
3576 
3577  err = DB_STRONG_FAIL;
3578  goto func_exit;
3579  }
3580 
3581  /* After this point, the page could still be loaded to the
3582  buffer pool, but we do not have to care about it, since we are
3583  holding a latch on the insert buffer leaf page that contains
3584  buffered changes for (space, page_no). If the page enters the
3585  buffer pool, buf_page_io_complete() for (space, page_no) will
3586  have to acquire a latch on the same insert buffer leaf page,
3587  which it cannot do until we have buffered the IBUF_OP_DELETE
3588  and done mtr_commit(&mtr) to release the latch. */
3589 
3590 #ifdef UNIV_IBUF_COUNT_DEBUG
3591  ut_a((buffered == 0) || ibuf_count_get(space, page_no));
3592 #endif
3593  ibuf_mtr_start(&bitmap_mtr);
3594 
3595  bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
3596  zip_size, &bitmap_mtr);
3597 
3598  /* We check if the index page is suitable for buffered entries */
3599 
3600  if (buf_page_peek(space, page_no)
3601  || lock_rec_expl_exist_on_page(space, page_no)) {
3602 
3603  goto bitmap_fail;
3604  }
3605 
3606  if (op == IBUF_OP_INSERT) {
3607  ulint bits = ibuf_bitmap_page_get_bits(
3608  bitmap_page, page_no, zip_size, IBUF_BITMAP_FREE,
3609  &bitmap_mtr);
3610 
3611  if (buffered + entry_size + page_dir_calc_reserved_space(1)
3612  > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
3613  /* Release the bitmap page latch early. */
3614  ibuf_mtr_commit(&bitmap_mtr);
3615 
3616  /* It may not fit */
3617  do_merge = TRUE;
3618 
3619  ibuf_get_merge_page_nos(FALSE,
3620  btr_pcur_get_rec(&pcur), &mtr,
3621  space_ids, space_versions,
3622  page_nos, &n_stored);
3623 
3624  goto fail_exit;
3625  }
3626  }
3627 
3628  /* Patch correct counter value to the entry to insert. This can
3629  change the insert position, which can result in the need to abort in
3630  some cases. */
3631  if (!no_counter
3632  && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur,
3633  mode == BTR_MODIFY_PREV, &mtr)) {
3634 bitmap_fail:
3635  ibuf_mtr_commit(&bitmap_mtr);
3636 
3637  goto fail_exit;
3638  }
3639 
3640  /* Set the bitmap bit denoting that the insert buffer contains
3641  buffered entries for this index page, if the bit is not set yet */
3642 
3643  old_bit_value = ibuf_bitmap_page_get_bits(
3644  bitmap_page, page_no, zip_size,
3645  IBUF_BITMAP_BUFFERED, &bitmap_mtr);
3646 
3647  if (!old_bit_value) {
3648  ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
3649  IBUF_BITMAP_BUFFERED, TRUE,
3650  &bitmap_mtr);
3651  }
3652 
3653  ibuf_mtr_commit(&bitmap_mtr);
3654 
3655  cursor = btr_pcur_get_btr_cur(&pcur);
3656 
3657  if (mode == BTR_MODIFY_PREV) {
3658  err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
3659  ibuf_entry, &ins_rec,
3660  &dummy_big_rec, 0, thr, &mtr);
3661  block = btr_cur_get_block(cursor);
3662  ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
3663 
3664  /* If this is the root page, update ibuf->empty. */
3665  if (UNIV_UNLIKELY(buf_block_get_page_no(block)
3666  == FSP_IBUF_TREE_ROOT_PAGE_NO)) {
3667  const page_t* page_root = buf_block_get_frame(block);
3668 
3669  ut_ad(page_get_space_id(page_root) == IBUF_SPACE_ID);
3670  ut_ad(page_get_page_no(page_root)
3671  == FSP_IBUF_TREE_ROOT_PAGE_NO);
3672 
3673  ibuf->empty = (page_get_n_recs(page_root) == 0);
3674  }
3675  } else {
3676  ut_ad(mode == BTR_MODIFY_TREE);
3677 
3678  /* We acquire an x-latch to the root page before the insert,
3679  because a pessimistic insert releases the tree x-latch,
3680  which would cause the x-latching of the root after that to
3681  break the latching order. */
3682 
3683  root = ibuf_tree_root_get(&mtr);
3684 
3685  err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
3686  | BTR_NO_UNDO_LOG_FLAG,
3687  cursor,
3688  ibuf_entry, &ins_rec,
3689  &dummy_big_rec, 0, thr, &mtr);
3690  mutex_exit(&ibuf_pessimistic_insert_mutex);
3691  ibuf_size_update(root, &mtr);
3692  mutex_exit(&ibuf_mutex);
3693  ibuf->empty = (page_get_n_recs(root) == 0);
3694 
3695  block = btr_cur_get_block(cursor);
3696  ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
3697  }
3698 
3699  if (err == DB_SUCCESS && op != IBUF_OP_DELETE) {
3700  /* Update the page max trx id field */
3701  page_update_max_trx_id(block, NULL,
3702  thr_get_trx(thr)->id, &mtr);
3703  }
3704 
3705 func_exit:
3706 #ifdef UNIV_IBUF_COUNT_DEBUG
3707  if (err == DB_SUCCESS) {
3708  fprintf(stderr,
3709  "Incrementing ibuf count of space %lu page %lu\n"
3710  "from %lu by 1\n", space, page_no,
3711  ibuf_count_get(space, page_no));
3712 
3713  ibuf_count_set(space, page_no,
3714  ibuf_count_get(space, page_no) + 1);
3715  }
3716 #endif
3717 
3718  ibuf_mtr_commit(&mtr);
3719  btr_pcur_close(&pcur);
3720 
3721  mem_heap_free(heap);
3722 
3723  if (err == DB_SUCCESS && mode == BTR_MODIFY_TREE) {
3724  ibuf_contract_after_insert(entry_size);
3725  }
3726 
3727  if (do_merge) {
3728 #ifdef UNIV_IBUF_DEBUG
3729  ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
3730 #endif
3731  buf_read_ibuf_merge_pages(FALSE, space_ids, space_versions,
3732  page_nos, n_stored);
3733  }
3734 
3735  return(err);
3736 }
3737 
3738 /*********************************************************************/
3743 UNIV_INTERN
3744 ibool
3745 ibuf_insert(
3746 /*========*/
3747  ibuf_op_t op,
3748  const dtuple_t* entry,
3749  dict_index_t* index,
3750  ulint space,
3751  ulint zip_size,
3752  ulint page_no,
3753  que_thr_t* thr)
3755  ulint err;
3756  ulint entry_size;
3757  ibool no_counter;
3758  /* Read the settable global variable ibuf_use only once in
3759  this function, so that we will have a consistent view of it. */
3760  ibuf_use_t use = ibuf_use;
3761 
3763  ut_ad(dtuple_check_typed(entry));
3764  ut_ad(ut_is_2pow(zip_size));
3765 
3766  ut_a(!dict_index_is_clust(index));
3767 
3768  no_counter = use <= IBUF_USE_INSERT;
3769 
3770  switch (op) {
3771  case IBUF_OP_INSERT:
3772  switch (use) {
3773  case IBUF_USE_NONE:
3774  case IBUF_USE_DELETE:
3775  case IBUF_USE_DELETE_MARK:
3776  return(FALSE);
3777  case IBUF_USE_INSERT:
3778  case IBUF_USE_INSERT_DELETE_MARK:
3779  case IBUF_USE_ALL:
3780  goto check_watch;
3781  case IBUF_USE_COUNT:
3782  break;
3783  }
3784  break;
3785  case IBUF_OP_DELETE_MARK:
3786  switch (use) {
3787  case IBUF_USE_NONE:
3788  case IBUF_USE_INSERT:
3789  return(FALSE);
3790  case IBUF_USE_DELETE_MARK:
3791  case IBUF_USE_DELETE:
3792  case IBUF_USE_INSERT_DELETE_MARK:
3793  case IBUF_USE_ALL:
3794  ut_ad(!no_counter);
3795  goto check_watch;
3796  case IBUF_USE_COUNT:
3797  break;
3798  }
3799  break;
3800  case IBUF_OP_DELETE:
3801  switch (use) {
3802  case IBUF_USE_NONE:
3803  case IBUF_USE_INSERT:
3804  case IBUF_USE_INSERT_DELETE_MARK:
3805  return(FALSE);
3806  case IBUF_USE_DELETE_MARK:
3807  case IBUF_USE_DELETE:
3808  case IBUF_USE_ALL:
3809  ut_ad(!no_counter);
3810  goto skip_watch;
3811  case IBUF_USE_COUNT:
3812  break;
3813  }
3814  break;
3815  case IBUF_OP_COUNT:
3816  break;
3817  }
3818 
3819  /* unknown op or use */
3820  ut_error;
3821 
3822 check_watch:
3823  /* If a thread attempts to buffer an insert on a page while a
3824  purge is in progress on the same page, the purge must not be
3825  buffered, because it could remove a record that was
3826  re-inserted later. For simplicity, we block the buffering of
3827  all operations on a page that has a purge pending.
3828 
3829  We do not check this in the IBUF_OP_DELETE case, because that
3830  would always trigger the buffer pool watch during purge and
3831  thus prevent the buffering of delete operations. We assume
3832  that the issuer of IBUF_OP_DELETE has called
3833  buf_pool_watch_set(space, page_no). */
3834 
3835  {
3836  buf_page_t* bpage;
3837  ulint fold = buf_page_address_fold(space, page_no);
3838  buf_pool_t* buf_pool = buf_pool_get(space, page_no);
3839 
3840  buf_pool_mutex_enter(buf_pool);
3841  bpage = buf_page_hash_get_low(buf_pool, space, page_no, fold);
3842  buf_pool_mutex_exit(buf_pool);
3843 
3844  if (UNIV_LIKELY_NULL(bpage)) {
3845  /* A buffer pool watch has been set or the
3846  page has been read into the buffer pool.
3847  Do not buffer the request. If a purge operation
3848  is being buffered, have this request executed
3849  directly on the page in the buffer pool after the
3850  buffered entries for this page have been merged. */
3851  return(FALSE);
3852  }
3853  }
3854 
3855 skip_watch:
3856  entry_size = rec_get_converted_size(index, entry, 0);
3857 
3858  if (entry_size
3860  / 2) {
3861 
3862  return(FALSE);
3863  }
3864 
3865  err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter,
3866  entry, entry_size,
3867  index, space, zip_size, page_no, thr);
3868  if (err == DB_FAIL) {
3869  err = ibuf_insert_low(BTR_MODIFY_TREE, op, no_counter,
3870  entry, entry_size,
3871  index, space, zip_size, page_no, thr);
3872  }
3873 
3874  if (err == DB_SUCCESS) {
3875 #ifdef UNIV_IBUF_DEBUG
3876  /* fprintf(stderr, "Ibuf insert for page no %lu of index %s\n",
3877  page_no, index->name); */
3878 #endif
3879  return(TRUE);
3880 
3881  } else {
3882  ut_a(err == DB_STRONG_FAIL);
3883 
3884  return(FALSE);
3885  }
3886 }
3887 
3888 /********************************************************************/
3891 static
3892 void
3893 ibuf_insert_to_index_page_low(
3894 /*==========================*/
3895  const dtuple_t* entry,
3896  buf_block_t* block,
3898  dict_index_t* index,
3899  mtr_t* mtr,
3900  page_cur_t* page_cur)
3902 {
3903  const page_t* page;
3904  ulint space;
3905  ulint page_no;
3906  ulint zip_size;
3907  const page_t* bitmap_page;
3908  ulint old_bits;
3909 
3910  if (UNIV_LIKELY
3911  (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
3912  return;
3913  }
3914 
3915  /* If the record did not fit, reorganize */
3916 
3917  btr_page_reorganize(block, index, mtr);
3918  page_cur_search(block, index, entry, PAGE_CUR_LE, page_cur);
3919 
3920  /* This time the record must fit */
3921 
3922  if (UNIV_LIKELY
3923  (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
3924  return;
3925  }
3926 
3927  page = buf_block_get_frame(block);
3928 
3929  ut_print_timestamp(stderr);
3930 
3931  fprintf(stderr,
3932  " InnoDB: Error: Insert buffer insert fails;"
3933  " page free %lu, dtuple size %lu\n",
3934  (ulong) page_get_max_insert_size(page, 1),
3935  (ulong) rec_get_converted_size(index, entry, 0));
3936  fputs("InnoDB: Cannot insert index record ", stderr);
3937  dtuple_print(stderr, entry);
3938  fputs("\nInnoDB: The table where this index record belongs\n"
3939  "InnoDB: is now probably corrupt. Please run CHECK TABLE on\n"
3940  "InnoDB: that table.\n", stderr);
3941 
3942  space = page_get_space_id(page);
3943  zip_size = buf_block_get_zip_size(block);
3944  page_no = page_get_page_no(page);
3945 
3946  bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
3947  old_bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
3948  IBUF_BITMAP_FREE, mtr);
3949 
3950  fprintf(stderr,
3951  "InnoDB: space %lu, page %lu, zip_size %lu, bitmap bits %lu\n",
3952  (ulong) space, (ulong) page_no,
3953  (ulong) zip_size, (ulong) old_bits);
3954 
3955  fputs("InnoDB: Submit a detailed bug report"
3956  " to http://bugs.mysql.com\n", stderr);
3957 }
3958 
3959 /************************************************************************
3960 During merge, inserts to an index page a secondary index entry extracted
3961 from the insert buffer. */
3962 static
3963 void
3964 ibuf_insert_to_index_page(
3965 /*======================*/
3966  const dtuple_t* entry,
3967  buf_block_t* block,
3969  dict_index_t* index,
3970  mtr_t* mtr)
3971 {
3972  page_cur_t page_cur;
3973  ulint low_match;
3974  page_t* page = buf_block_get_frame(block);
3975  rec_t* rec;
3976 
3977  ut_ad(ibuf_inside(mtr));
3978  ut_ad(dtuple_check_typed(entry));
3979  ut_ad(!buf_block_align(page)->is_hashed);
3980 
3981  if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
3982  != (ibool)!!page_is_comp(page))) {
3983  fputs("InnoDB: Trying to insert a record from"
3984  " the insert buffer to an index page\n"
3985  "InnoDB: but the 'compact' flag does not match!\n",
3986  stderr);
3987  goto dump;
3988  }
3989 
3990  rec = page_rec_get_next(page_get_infimum_rec(page));
3991 
3992  if (page_rec_is_supremum(rec)) {
3993  fputs("InnoDB: Trying to insert a record from"
3994  " the insert buffer to an index page\n"
3995  "InnoDB: but the index page is empty!\n",
3996  stderr);
3997  goto dump;
3998  }
3999 
4000  if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
4001  != dtuple_get_n_fields(entry))) {
4002  fputs("InnoDB: Trying to insert a record from"
4003  " the insert buffer to an index page\n"
4004  "InnoDB: but the number of fields does not match!\n",
4005  stderr);
4006 dump:
4007  buf_page_print(page, 0);
4008 
4009  dtuple_print(stderr, entry);
4010 
4011  fputs("InnoDB: The table where where"
4012  " this index record belongs\n"
4013  "InnoDB: is now probably corrupt."
4014  " Please run CHECK TABLE on\n"
4015  "InnoDB: your tables.\n"
4016  "InnoDB: Submit a detailed bug report to"
4017  " http://bugs.mysql.com!\n", stderr);
4018 
4019  return;
4020  }
4021 
4022  low_match = page_cur_search(block, index, entry,
4023  PAGE_CUR_LE, &page_cur);
4024 
4025  if (UNIV_UNLIKELY(low_match == dtuple_get_n_fields(entry))) {
4026  mem_heap_t* heap;
4027  upd_t* update;
4028  ulint* offsets;
4029  page_zip_des_t* page_zip;
4030 
4031  rec = page_cur_get_rec(&page_cur);
4032 
4033  /* This is based on
4034  row_ins_sec_index_entry_by_modify(BTR_MODIFY_LEAF). */
4036 
4037  heap = mem_heap_create(1024);
4038 
4039  offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED,
4040  &heap);
4042  index, entry, rec, NULL, heap);
4043 
4044  page_zip = buf_block_get_page_zip(block);
4045 
4046  if (update->n_fields == 0) {
4047  /* The records only differ in the delete-mark.
4048  Clear the delete-mark, like we did before
4049  Bug #56680 was fixed. */
4051  rec, page_zip, FALSE, mtr);
4052 updated_in_place:
4053  mem_heap_free(heap);
4054  return;
4055  }
4056 
4057  /* Copy the info bits. Clear the delete-mark. */
4058  update->info_bits = rec_get_info_bits(rec, page_is_comp(page));
4059  update->info_bits &= ~REC_INFO_DELETED_FLAG;
4060 
4061  /* We cannot invoke btr_cur_optimistic_update() here,
4062  because we do not have a btr_cur_t or que_thr_t,
4063  as the insert buffer merge occurs at a very low level. */
4064  if (!row_upd_changes_field_size_or_external(index, offsets,
4065  update)
4066  && (!page_zip || btr_cur_update_alloc_zip(
4067  page_zip, block, index,
4068  rec_offs_size(offsets), FALSE, mtr))) {
4069  /* This is the easy case. Do something similar
4070  to btr_cur_update_in_place(). */
4071  row_upd_rec_in_place(rec, index, offsets,
4072  update, page_zip);
4073  goto updated_in_place;
4074  }
4075 
4076  /* A collation may identify values that differ in
4077  storage length.
4078  Some examples (1 or 2 bytes):
4079  utf8_turkish_ci: I = U+0131 LATIN SMALL LETTER DOTLESS I
4080  utf8_general_ci: S = U+00DF LATIN SMALL LETTER SHARP S
4081  utf8_general_ci: A = U+00E4 LATIN SMALL LETTER A WITH DIAERESIS
4082 
4083  latin1_german2_ci: SS = U+00DF LATIN SMALL LETTER SHARP S
4084 
4085  Examples of a character (3-byte UTF-8 sequence)
4086  identified with 2 or 4 characters (1-byte UTF-8 sequences):
4087 
4088  utf8_unicode_ci: 'II' = U+2171 SMALL ROMAN NUMERAL TWO
4089  utf8_unicode_ci: '(10)' = U+247D PARENTHESIZED NUMBER TEN
4090  */
4091 
4092  /* Delete the different-length record, and insert the
4093  buffered one. */
4094 
4095  lock_rec_store_on_page_infimum(block, rec);
4096  page_cur_delete_rec(&page_cur, index, offsets, mtr);
4097  page_cur_move_to_prev(&page_cur);
4098  mem_heap_free(heap);
4099 
4100  ibuf_insert_to_index_page_low(entry, block, index, mtr,
4101  &page_cur);
4102  lock_rec_restore_from_page_infimum(block, rec, block);
4103  } else {
4104  ibuf_insert_to_index_page_low(entry, block, index, mtr,
4105  &page_cur);
4106  }
4107 }
4108 
4109 /****************************************************************/
4112 static
4113 void
4114 ibuf_set_del_mark(
4115 /*==============*/
4116  const dtuple_t* entry,
4117  buf_block_t* block,
4118  const dict_index_t* index,
4119  mtr_t* mtr)
4120 {
4121  page_cur_t page_cur;
4122  ulint low_match;
4123 
4124  ut_ad(ibuf_inside(mtr));
4125  ut_ad(dtuple_check_typed(entry));
4126 
4127  low_match = page_cur_search(
4128  block, index, entry, PAGE_CUR_LE, &page_cur);
4129 
4130  if (low_match == dtuple_get_n_fields(entry)) {
4131  rec_t* rec;
4132  page_zip_des_t* page_zip;
4133 
4134  rec = page_cur_get_rec(&page_cur);
4135  page_zip = page_cur_get_page_zip(&page_cur);
4136 
4137  /* Delete mark the old index record. According to a
4138  comment in row_upd_sec_index_entry(), it can already
4139  have been delete marked if a lock wait occurred in
4140  row_ins_index_entry() in a previous invocation of
4141  row_upd_sec_index_entry(). */
4142 
4143  if (UNIV_LIKELY
4145  rec, dict_table_is_comp(index->table)))) {
4146  btr_cur_set_deleted_flag_for_ibuf(rec, page_zip,
4147  TRUE, mtr);
4148  }
4149  } else {
4150  ut_print_timestamp(stderr);
4151  fputs(" InnoDB: unable to find a record to delete-mark\n",
4152  stderr);
4153  fputs("InnoDB: tuple ", stderr);
4154  dtuple_print(stderr, entry);
4155  fputs("\n"
4156  "InnoDB: record ", stderr);
4157  rec_print(stderr, page_cur_get_rec(&page_cur), index);
4158  putc('\n', stderr);
4159  fputs("\n"
4160  "InnoDB: Submit a detailed bug report"
4161  " to http://bugs.mysql.com\n", stderr);
4162  ut_ad(0);
4163  }
4164 }
4165 
4166 /****************************************************************/
4168 static
4169 void
4170 ibuf_delete(
4171 /*========*/
4172  const dtuple_t* entry,
4173  buf_block_t* block,
4174  dict_index_t* index,
4175  mtr_t* mtr)
4177 {
4178  page_cur_t page_cur;
4179  ulint low_match;
4180 
4181  ut_ad(ibuf_inside(mtr));
4182  ut_ad(dtuple_check_typed(entry));
4183 
4184  low_match = page_cur_search(
4185  block, index, entry, PAGE_CUR_LE, &page_cur);
4186 
4187  if (low_match == dtuple_get_n_fields(entry)) {
4188  page_zip_des_t* page_zip= buf_block_get_page_zip(block);
4189  page_t* page = buf_block_get_frame(block);
4190  rec_t* rec = page_cur_get_rec(&page_cur);
4191 
4192  /* TODO: the below should probably be a separate function,
4193  it's a bastardized version of btr_cur_optimistic_delete. */
4194 
4195  ulint offsets_[REC_OFFS_NORMAL_SIZE];
4196  ulint* offsets = offsets_;
4197  mem_heap_t* heap = NULL;
4198  ulint max_ins_size;
4199 
4200  rec_offs_init(offsets_);
4201 
4202  offsets = rec_get_offsets(
4203  rec, index, offsets, ULINT_UNDEFINED, &heap);
4204 
4205  /* Refuse to delete the last record. */
4206  ut_a(page_get_n_recs(page) > 1);
4207 
4208  /* The record should have been marked for deletion. */
4209  ut_ad(REC_INFO_DELETED_FLAG
4210  & rec_get_info_bits(rec, page_is_comp(page)));
4211 
4212  lock_update_delete(block, rec);
4213 
4214  if (!page_zip) {
4215  max_ins_size
4217  page, 1);
4218  }
4219 #ifdef UNIV_ZIP_DEBUG
4220  ut_a(!page_zip || page_zip_validate(page_zip, page));
4221 #endif /* UNIV_ZIP_DEBUG */
4222  page_cur_delete_rec(&page_cur, index, offsets, mtr);
4223 #ifdef UNIV_ZIP_DEBUG
4224  ut_a(!page_zip || page_zip_validate(page_zip, page));
4225 #endif /* UNIV_ZIP_DEBUG */
4226 
4227  if (page_zip) {
4228  ibuf_update_free_bits_zip(block, mtr);
4229  } else {
4230  ibuf_update_free_bits_low(block, max_ins_size, mtr);
4231  }
4232 
4233  if (UNIV_LIKELY_NULL(heap)) {
4234  mem_heap_free(heap);
4235  }
4236  } else {
4237  /* The record must have been purged already. */
4238  }
4239 }
4240 
4241 /*********************************************************************/
4244 static __attribute__((nonnull))
4245 ibool
4246 ibuf_restore_pos(
4247 /*=============*/
4248  ulint space,
4249  ulint page_no,
4251  const dtuple_t* search_tuple,
4253  ulint mode,
4254  btr_pcur_t* pcur,
4256  mtr_t* mtr)
4257 {
4258  ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE);
4259 
4260  if (btr_pcur_restore_position(mode, pcur, mtr)) {
4261 
4262  return(TRUE);
4263  }
4264 
4265  if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
4266  /* The tablespace has been dropped. It is possible
4267  that another thread has deleted the insert buffer
4268  entry. Do not complain. */
4269  ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
4270  } else {
4271  fprintf(stderr,
4272  "InnoDB: ERROR: Submit the output to"
4273  " http://bugs.mysql.com\n"
4274  "InnoDB: ibuf cursor restoration fails!\n"
4275  "InnoDB: ibuf record inserted to page %lu:%lu\n",
4276  (ulong) space, (ulong) page_no);
4277  fflush(stderr);
4278 
4279  rec_print_old(stderr, btr_pcur_get_rec(pcur));
4280  rec_print_old(stderr, pcur->old_rec);
4281  dtuple_print(stderr, search_tuple);
4282 
4283  rec_print_old(stderr,
4284  page_rec_get_next(btr_pcur_get_rec(pcur)));
4285  fflush(stderr);
4286 
4287  ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
4288 
4289  fputs("InnoDB: Validating insert buffer tree:\n", stderr);
4290  if (!btr_validate_index(ibuf->index, NULL)) {
4291  ut_error;
4292  }
4293 
4294  fprintf(stderr, "InnoDB: ibuf tree ok\n");
4295  fflush(stderr);
4296  }
4297 
4298  return(FALSE);
4299 }
4300 
4301 /*********************************************************************/
4306 static
4307 ibool
4308 ibuf_delete_rec(
4309 /*============*/
4310  ulint space,
4311  ulint page_no,
4313  btr_pcur_t* pcur,
4315  const dtuple_t* search_tuple,
4317  mtr_t* mtr)
4318 {
4319  ibool success;
4320  page_t* root;
4321  ulint err;
4322 
4323  ut_ad(ibuf_inside(mtr));
4324  ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur)));
4325  ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no);
4326  ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space);
4327 
4328  success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
4329 
4330  if (success) {
4331  if (UNIV_UNLIKELY(!page_get_n_recs(btr_pcur_get_page(pcur)))) {
4332  /* If a B-tree page is empty, it must be the root page
4333  and the whole B-tree must be empty. InnoDB does not
4334  allow empty B-tree pages other than the root. */
4335  root = btr_pcur_get_page(pcur);
4336 
4337  ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
4338  ut_ad(page_get_page_no(root)
4339  == FSP_IBUF_TREE_ROOT_PAGE_NO);
4340 
4341  /* ibuf->empty is protected by the root page latch.
4342  Before the deletion, it had to be FALSE. */
4343  ut_ad(!ibuf->empty);
4344  ibuf->empty = TRUE;
4345  }
4346 
4347 #ifdef UNIV_IBUF_COUNT_DEBUG
4348  fprintf(stderr,
4349  "Decrementing ibuf count of space %lu page %lu\n"
4350  "from %lu by 1\n", space, page_no,
4351  ibuf_count_get(space, page_no));
4352  ibuf_count_set(space, page_no,
4353  ibuf_count_get(space, page_no) - 1);
4354 #endif
4355  return(FALSE);
4356  }
4357 
4358  ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur)));
4359  ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no);
4360  ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space);
4361 
4362  /* We have to resort to a pessimistic delete from ibuf */
4363  btr_pcur_store_position(pcur, mtr);
4364  ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
4365 
4366  ibuf_mtr_start(mtr);
4367  mutex_enter(&ibuf_mutex);
4368 
4369  if (!ibuf_restore_pos(space, page_no, search_tuple,
4370  BTR_MODIFY_TREE, pcur, mtr)) {
4371 
4372  mutex_exit(&ibuf_mutex);
4373  ut_ad(!ibuf_inside(mtr));
4374  ut_ad(mtr->state == MTR_COMMITTED);
4375  goto func_exit;
4376  }
4377 
4378  root = ibuf_tree_root_get(mtr);
4379 
4380  btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur),
4381  RB_NONE, mtr);
4382  ut_a(err == DB_SUCCESS);
4383 
4384 #ifdef UNIV_IBUF_COUNT_DEBUG
4385  ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
4386 #endif
4387  ibuf_size_update(root, mtr);
4388  mutex_exit(&ibuf_mutex);
4389 
4390  ibuf->empty = (page_get_n_recs(root) == 0);
4391  ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
4392 
4393 func_exit:
4394  ut_ad(!ibuf_inside(mtr));
4395  ut_ad(mtr->state == MTR_COMMITTED);
4396  btr_pcur_close(pcur);
4397 
4398  return(TRUE);
4399 }
4400 
4401 /*********************************************************************/
4408 UNIV_INTERN
4409 void
4411 /*==========================*/
4412  buf_block_t* block,
4415  ulint space,
4416  ulint page_no,
4417  ulint zip_size,
4419  ibool update_ibuf_bitmap)
4424 {
4425  mem_heap_t* heap;
4426  btr_pcur_t pcur;
4427  dtuple_t* search_tuple;
4428 #ifdef UNIV_IBUF_DEBUG
4429  ulint volume = 0;
4430 #endif
4431  page_zip_des_t* page_zip = NULL;
4432  ibool tablespace_being_deleted = FALSE;
4433  ibool corruption_noticed = FALSE;
4434  mtr_t mtr;
4435 
4436  /* Counts for merged & discarded operations. */
4437  ulint mops[IBUF_OP_COUNT];
4438  ulint dops[IBUF_OP_COUNT];
4439 
4440  ut_ad(!block || buf_block_get_space(block) == space);
4441  ut_ad(!block || buf_block_get_page_no(block) == page_no);
4442  ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
4443 
4444  if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE
4445  || trx_sys_hdr_page(space, page_no)) {
4446  return;
4447  }
4448 
4449  /* We cannot refer to zip_size in the following, because
4450  zip_size is passed as ULINT_UNDEFINED (it is unknown) when
4451  buf_read_ibuf_merge_pages() is merging (discarding) changes
4452  for a dropped tablespace. When block != NULL or
4453  update_ibuf_bitmap is specified, the zip_size must be known.
4454  That is why we will repeat the check below, with zip_size in
4455  place of 0. Passing zip_size as 0 assumes that the
4456  uncompressed page size always is a power-of-2 multiple of the
4457  compressed page size. */
4458 
4459  if (ibuf_fixed_addr_page(space, 0, page_no)
4460  || fsp_descr_page(0, page_no)) {
4461  return;
4462  }
4463 
4464  if (UNIV_LIKELY(update_ibuf_bitmap)) {
4465  ut_a(ut_is_2pow(zip_size));
4466 
4467  if (ibuf_fixed_addr_page(space, zip_size, page_no)
4468  || fsp_descr_page(zip_size, page_no)) {
4469  return;
4470  }
4471 
4472  /* If the following returns FALSE, we get the counter
4473  incremented, and must decrement it when we leave this
4474  function. When the counter is > 0, that prevents tablespace
4475  from being dropped. */
4476 
4477  tablespace_being_deleted = fil_inc_pending_ibuf_merges(space);
4478 
4479  if (UNIV_UNLIKELY(tablespace_being_deleted)) {
4480  /* Do not try to read the bitmap page from space;
4481  just delete the ibuf records for the page */
4482 
4483  block = NULL;
4484  update_ibuf_bitmap = FALSE;
4485  } else {
4486  page_t* bitmap_page;
4487  ulint bitmap_bits;
4488 
4489  ibuf_mtr_start(&mtr);
4490 
4491  bitmap_page = ibuf_bitmap_get_map_page(
4492  space, page_no, zip_size, &mtr);
4493  bitmap_bits = ibuf_bitmap_page_get_bits(
4494  bitmap_page, page_no, zip_size,
4495  IBUF_BITMAP_BUFFERED, &mtr);
4496 
4497  ibuf_mtr_commit(&mtr);
4498 
4499  if (!bitmap_bits) {
4500  /* No inserts buffered for this page */
4501 
4502  if (!tablespace_being_deleted) {
4504  }
4505 
4506  return;
4507  }
4508  }
4509  } else if (block
4510  && (ibuf_fixed_addr_page(space, zip_size, page_no)
4511  || fsp_descr_page(zip_size, page_no))) {
4512 
4513  return;
4514  }
4515 
4516  heap = mem_heap_create(512);
4517 
4518  if (UNIV_UNLIKELY(!trx_sys_multiple_tablespace_format)) {
4520  search_tuple = ibuf_search_tuple_build(space, page_no, heap);
4521  } else {
4522  search_tuple = ibuf_new_search_tuple_build(space, page_no,
4523  heap);
4524  }
4525 
4526  if (block) {
4527  /* Move the ownership of the x-latch on the page to this OS
4528  thread, so that we can acquire a second x-latch on it. This
4529  is needed for the insert operations to the index page to pass
4530  the debug checks. */
4531 
4533  page_zip = buf_block_get_page_zip(block);
4534 
4535  if (UNIV_UNLIKELY(fil_page_get_type(block->frame)
4536  != FIL_PAGE_INDEX)
4537  || UNIV_UNLIKELY(!page_is_leaf(block->frame))) {
4538 
4539  page_t* bitmap_page;
4540 
4541  corruption_noticed = TRUE;
4542 
4543  ut_print_timestamp(stderr);
4544 
4545  ibuf_mtr_start(&mtr);
4546 
4547  fputs(" InnoDB: Dump of the ibuf bitmap page:\n",
4548  stderr);
4549 
4550  bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
4551  zip_size, &mtr);
4552  buf_page_print(bitmap_page, 0);
4553  ibuf_mtr_commit(&mtr);
4554 
4555  fputs("\nInnoDB: Dump of the page:\n", stderr);
4556 
4557  buf_page_print(block->frame, 0);
4558 
4559  fprintf(stderr,
4560  "InnoDB: Error: corruption in the tablespace."
4561  " Bitmap shows insert\n"
4562  "InnoDB: buffer records to page n:o %lu"
4563  " though the page\n"
4564  "InnoDB: type is %lu, which is"
4565  " not an index leaf page!\n"
4566  "InnoDB: We try to resolve the problem"
4567  " by skipping the insert buffer\n"
4568  "InnoDB: merge for this page."
4569  " Please run CHECK TABLE on your tables\n"
4570  "InnoDB: to determine if they are corrupt"
4571  " after this.\n\n"
4572  "InnoDB: Please submit a detailed bug report"
4573  " to http://bugs.mysql.com\n\n",
4574  (ulong) page_no,
4575  (ulong)
4576  fil_page_get_type(block->frame));
4577  }
4578  }
4579 
4580  memset(mops, 0, sizeof(mops));
4581  memset(dops, 0, sizeof(dops));
4582 
4583 loop:
4584  ibuf_mtr_start(&mtr);
4585 
4586  if (block) {
4587  ibool success;
4588 
4589  success = buf_page_get_known_nowait(
4590  RW_X_LATCH, block,
4591  BUF_KEEP_OLD, __FILE__, __LINE__, &mtr);
4592 
4593  ut_a(success);
4594 
4595  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
4596  }
4597 
4598  /* Position pcur in the insert buffer at the first entry for this
4599  index page */
4600  btr_pcur_open_on_user_rec(
4601  ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
4602  &pcur, &mtr);
4603 
4604  if (!btr_pcur_is_on_user_rec(&pcur)) {
4605  ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
4606 
4607  goto reset_bit;
4608  }
4609 
4610  for (;;) {
4611  rec_t* rec;
4612 
4614 
4615  rec = btr_pcur_get_rec(&pcur);
4616 
4617  /* Check if the entry is for this index page */
4618  if (ibuf_rec_get_page_no(&mtr, rec) != page_no
4619  || ibuf_rec_get_space(&mtr, rec) != space) {
4620 
4621  if (block) {
4623  block->frame, page_zip, &mtr);
4624  }
4625 
4626  goto reset_bit;
4627  }
4628 
4629  if (UNIV_UNLIKELY(corruption_noticed)) {
4630  fputs("InnoDB: Discarding record\n ", stderr);
4631  rec_print_old(stderr, rec);
4632  fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
4633  } else if (block) {
4634  /* Now we have at pcur a record which should be
4635  applied on the index page; NOTE that the call below
4636  copies pointers to fields in rec, and we must
4637  keep the latch to the rec page until the
4638  insertion is finished! */
4639  dtuple_t* entry;
4640  trx_id_t max_trx_id;
4641  dict_index_t* dummy_index;
4642  ibuf_op_t op = ibuf_rec_get_op_type(&mtr, rec);
4643 
4644  max_trx_id = page_get_max_trx_id(page_align(rec));
4645  page_update_max_trx_id(block, page_zip, max_trx_id,
4646  &mtr);
4647 
4648  ut_ad(page_validate(page_align(rec), ibuf->index));
4649 
4650  entry = ibuf_build_entry_from_ibuf_rec(
4651  &mtr, rec, heap, &dummy_index);
4652 
4653  ut_ad(page_validate(block->frame, dummy_index));
4654 
4655  switch (op) {
4656  ibool success;
4657  case IBUF_OP_INSERT:
4658 #ifdef UNIV_IBUF_DEBUG
4659  volume += rec_get_converted_size(
4660  dummy_index, entry, 0);
4661 
4662  volume += page_dir_calc_reserved_space(1);
4663 
4664  ut_a(volume <= 4 * UNIV_PAGE_SIZE
4665  / IBUF_PAGE_SIZE_PER_FREE_SPACE);
4666 #endif
4667  ibuf_insert_to_index_page(
4668  entry, block, dummy_index, &mtr);
4669  break;
4670 
4671  case IBUF_OP_DELETE_MARK:
4672  ibuf_set_del_mark(
4673  entry, block, dummy_index, &mtr);
4674  break;
4675 
4676  case IBUF_OP_DELETE:
4677  ibuf_delete(entry, block, dummy_index, &mtr);
4678  /* Because ibuf_delete() will latch an
4679  insert buffer bitmap page, commit mtr
4680  before latching any further pages.
4681  Store and restore the cursor position. */
4682  ut_ad(rec == btr_pcur_get_rec(&pcur));
4684  ut_ad(ibuf_rec_get_page_no(&mtr, rec)
4685  == page_no);
4686  ut_ad(ibuf_rec_get_space(&mtr, rec) == space);
4687 
4688  btr_pcur_store_position(&pcur, &mtr);
4689  ibuf_btr_pcur_commit_specify_mtr(&pcur, &mtr);
4690 
4691  ibuf_mtr_start(&mtr);
4692 
4693  success = buf_page_get_known_nowait(
4694  RW_X_LATCH, block,
4695  BUF_KEEP_OLD,
4696  __FILE__, __LINE__, &mtr);
4697  ut_a(success);
4698 
4699  buf_block_dbg_add_level(block, SYNC_TREE_NODE);
4700 
4701  if (!ibuf_restore_pos(space, page_no,
4702  search_tuple,
4704  &pcur, &mtr)) {
4705 
4706  ut_ad(!ibuf_inside(&mtr));
4707  ut_ad(mtr.state == MTR_COMMITTED);
4708  mops[op]++;
4709  ibuf_dummy_index_free(dummy_index);
4710  goto loop;
4711  }
4712 
4713  break;
4714  default:
4715  ut_error;
4716  }
4717 
4718  mops[op]++;
4719 
4720  ibuf_dummy_index_free(dummy_index);
4721  } else {
4722  dops[ibuf_rec_get_op_type(&mtr, rec)]++;
4723  }
4724 
4725  /* Delete the record from ibuf */
4726  if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
4727  &mtr)) {
4728  /* Deletion was pessimistic and mtr was committed:
4729  we start from the beginning again */
4730 
4731  goto loop;
4732  } else if (btr_pcur_is_after_last_on_page(&pcur)) {
4733  ibuf_mtr_commit(&mtr);
4734  btr_pcur_close(&pcur);
4735 
4736  goto loop;
4737  }
4738  }
4739 
4740 reset_bit:
4741  if (UNIV_LIKELY(update_ibuf_bitmap)) {
4742  page_t* bitmap_page;
4743 
4744  bitmap_page = ibuf_bitmap_get_map_page(
4745  space, page_no, zip_size, &mtr);
4746 
4747  ibuf_bitmap_page_set_bits(
4748  bitmap_page, page_no, zip_size,
4749  IBUF_BITMAP_BUFFERED, FALSE, &mtr);
4750 
4751  if (block) {
4752  ulint old_bits = ibuf_bitmap_page_get_bits(
4753  bitmap_page, page_no, zip_size,
4754  IBUF_BITMAP_FREE, &mtr);
4755 
4756  ulint new_bits = ibuf_index_page_calc_free(
4757  zip_size, block);
4758 
4759  if (old_bits != new_bits) {
4760  ibuf_bitmap_page_set_bits(
4761  bitmap_page, page_no, zip_size,
4762  IBUF_BITMAP_FREE, new_bits, &mtr);
4763  }
4764  }
4765  }
4766 
4767  ibuf_mtr_commit(&mtr);
4768  btr_pcur_close(&pcur);
4769  mem_heap_free(heap);
4770 
4771 #ifdef HAVE_ATOMIC_BUILTINS
4772  os_atomic_increment_ulint(&ibuf->n_merges, 1);
4773  ibuf_add_ops(ibuf->n_merged_ops, mops);
4774  ibuf_add_ops(ibuf->n_discarded_ops, dops);
4775 #else /* HAVE_ATOMIC_BUILTINS */
4776  /* Protect our statistics keeping from race conditions */
4777  mutex_enter(&ibuf_mutex);
4778 
4779  ibuf->n_merges++;
4780  ibuf_add_ops(ibuf->n_merged_ops, mops);
4781  ibuf_add_ops(ibuf->n_discarded_ops, dops);
4782 
4783  mutex_exit(&ibuf_mutex);
4784 #endif /* HAVE_ATOMIC_BUILTINS */
4785 
4786  if (update_ibuf_bitmap && !tablespace_being_deleted) {
4787 
4789  }
4790 
4791 #ifdef UNIV_IBUF_COUNT_DEBUG
4792  ut_a(ibuf_count_get(space, page_no) == 0);
4793 #endif
4794 }
4795 
4796 /*********************************************************************/
4801 UNIV_INTERN
4802 void
4804 /*============================*/
4805  ulint space)
4806 {
4807  mem_heap_t* heap;
4808  btr_pcur_t pcur;
4809  dtuple_t* search_tuple;
4810  const rec_t* ibuf_rec;
4811  ulint page_no;
4812  mtr_t mtr;
4813 
4814  /* Counts for discarded operations. */
4815  ulint dops[IBUF_OP_COUNT];
4816 
4817  heap = mem_heap_create(512);
4818 
4819  /* Use page number 0 to build the search tuple so that we get the
4820  cursor positioned at the first entry for this space id */
4821 
4822  search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
4823 
4824  memset(dops, 0, sizeof(dops));
4825 loop:
4826  ibuf_mtr_start(&mtr);
4827 
4828  /* Position pcur in the insert buffer at the first entry for the
4829  space */
4830  btr_pcur_open_on_user_rec(
4831  ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
4832  &pcur, &mtr);
4833 
4834  if (!btr_pcur_is_on_user_rec(&pcur)) {
4835  ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
4836 
4837  goto leave_loop;
4838  }
4839 
4840  for (;;) {
4842 
4843  ibuf_rec = btr_pcur_get_rec(&pcur);
4844 
4845  /* Check if the entry is for this space */
4846  if (ibuf_rec_get_space(&mtr, ibuf_rec) != space) {
4847 
4848  goto leave_loop;
4849  }
4850 
4851  page_no = ibuf_rec_get_page_no(&mtr, ibuf_rec);
4852 
4853  dops[ibuf_rec_get_op_type(&mtr, ibuf_rec)]++;
4854 
4855  /* Delete the record from ibuf */
4856  if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
4857  &mtr)) {
4858  /* Deletion was pessimistic and mtr was committed:
4859  we start from the beginning again */
4860 
4861  goto loop;
4862  }
4863 
4864  if (btr_pcur_is_after_last_on_page(&pcur)) {
4865  ibuf_mtr_commit(&mtr);
4866  btr_pcur_close(&pcur);
4867 
4868  goto loop;
4869  }
4870  }
4871 
4872 leave_loop:
4873  ibuf_mtr_commit(&mtr);
4874  btr_pcur_close(&pcur);
4875 
4876 #ifdef HAVE_ATOMIC_BUILTINS
4877  ibuf_add_ops(ibuf->n_discarded_ops, dops);
4878 #else /* HAVE_ATOMIC_BUILTINS */
4879  /* Protect our statistics keeping from race conditions */
4880  mutex_enter(&ibuf_mutex);
4881  ibuf_add_ops(ibuf->n_discarded_ops, dops);
4882  mutex_exit(&ibuf_mutex);
4883 #endif /* HAVE_ATOMIC_BUILTINS */
4884 
4885  mem_heap_free(heap);
4886 }
4887 
4888 /******************************************************************/
4891 UNIV_INTERN
4892 ibool
4893 ibuf_is_empty(void)
4894 /*===============*/
4895 {
4896  ibool is_empty;
4897  const page_t* root;
4898  mtr_t mtr;
4899 
4900  ibuf_mtr_start(&mtr);
4901 
4902  mutex_enter(&ibuf_mutex);
4903  root = ibuf_tree_root_get(&mtr);
4904  mutex_exit(&ibuf_mutex);
4905 
4906  is_empty = (page_get_n_recs(root) == 0);
4907  ut_a(is_empty == ibuf->empty);
4908  ibuf_mtr_commit(&mtr);
4909 
4910  return(is_empty);
4911 }
4912 
4913 /******************************************************************/
4915 UNIV_INTERN
4916 void
4917 ibuf_print(
4918 /*=======*/
4919  FILE* file)
4920 {
4921 #ifdef UNIV_IBUF_COUNT_DEBUG
4922  ulint i;
4923  ulint j;
4924 #endif
4925 
4926  mutex_enter(&ibuf_mutex);
4927 
4928  fprintf(file,
4929  "Ibuf: size %lu, free list len %lu,"
4930  " seg size %lu, %lu merges\n",
4931  (ulong) ibuf->size,
4932  (ulong) ibuf->free_list_len,
4933  (ulong) ibuf->seg_size,
4934  (ulong) ibuf->n_merges);
4935 
4936  fputs("merged operations:\n ", file);
4937  ibuf_print_ops(ibuf->n_merged_ops, file);
4938 
4939  fputs("discarded operations:\n ", file);
4940  ibuf_print_ops(ibuf->n_discarded_ops, file);
4941 
4942 #ifdef UNIV_IBUF_COUNT_DEBUG
4943  for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
4944  for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {
4945  ulint count = ibuf_count_get(i, j);
4946 
4947  if (count > 0) {
4948  fprintf(stderr,
4949  "Ibuf count for space/page %lu/%lu"
4950  " is %lu\n",
4951  (ulong) i, (ulong) j, (ulong) count);
4952  }
4953  }
4954  }
4955 #endif /* UNIV_IBUF_COUNT_DEBUG */
4956 
4957  mutex_exit(&ibuf_mutex);
4958 }
4959 #endif /* !UNIV_HOTBACKUP */
UNIV_INLINE ibool fsp_descr_page(ulint zip_size, ulint page_no)
UNIV_INTERN ibool ibuf_page_low(ulint space, ulint zip_size, ulint page_no, const char *file, ulint line, mtr_t *mtr) __attribute__((warn_unused_result))
Definition: ibuf0ibuf.cc:1139
#define BUF_GET_NO_LATCH
Definition: buf0buf.h:48
UNIV_INLINE rec_t * page_cur_tuple_insert(page_cur_t *cursor, const dtuple_t *tuple, dict_index_t *index, ulint n_ext, mtr_t *mtr)
UNIV_INLINE ulint rec_get_converted_extra_size(ulint data_size, ulint n_fields, ulint n_ext) __attribute__((const ))
rw_lock_t lock
Definition: buf0buf.h:1458
#define buf_pool_mutex_enter(b)
Definition: buf0buf.h:1765
UNIV_INLINE ulint page_is_comp(const page_t *page)
UNIV_INTERN void dict_mem_index_add_field(dict_index_t *index, const char *name, ulint prefix_len)
Definition: dict0mem.cc:356
UNIV_INTERN void ibuf_update_free_bits_zip(buf_block_t *block, mtr_t *mtr)
Definition: ibuf0ibuf.cc:1046
UNIV_INLINE ulint rw_lock_get_x_lock_count(const rw_lock_t *lock)
UNIV_INTERN void dict_table_add_to_cache(dict_table_t *table, mem_heap_t *heap)
Definition: dict0dict.cc:827
UNIV_INLINE ibool ut_bit_get_nth(ulint a, ulint n)
UNIV_INLINE ulint page_get_space_id(const page_t *page)
ulint n_fields
Definition: row0upd.h:392
UNIV_INLINE void dtype_read_for_order_and_null_size(dtype_t *type, const byte *buf)
UNIV_INLINE ibool trx_sys_hdr_page(ulint space, ulint page_no)
UNIV_INLINE ibool btr_pcur_is_on_user_rec(const btr_pcur_t *cursor)
UNIV_INLINE fil_addr_t flst_get_last(const flst_base_node_t *base, mtr_t *mtr)
#define FIL_PAGE_IBUF_FREE_LIST
Definition: fil0fil.h:176
#define FIL_PAGE_INDEX
Definition: fil0fil.h:173
UNIV_INLINE page_t * page_align(const void *ptr) __attribute__((const ))
ibuf_t * ibuf
Definition: ibuf0ibuf.cc:201
unsigned n_def
Definition: dict0mem.h:502
UNIV_INLINE void mach_write_to_4(byte *b, ulint n)
UNIV_INTERN ibool btr_cur_optimistic_delete(btr_cur_t *cursor, mtr_t *mtr)
Definition: btr0cur.cc:2906
UNIV_INLINE ulint page_get_page_no(const page_t *page)
UNIV_INLINE ulint page_cur_search(const buf_block_t *block, const dict_index_t *index, const dtuple_t *tuple, ulint mode, page_cur_t *cursor)
UNIV_INTERN void ibuf_update_free_bits_for_two_pages_low(ulint zip_size, buf_block_t *block1, buf_block_t *block2, mtr_t *mtr)
Definition: ibuf0ibuf.cc:1090
ibool trx_sys_multiple_tablespace_format
Definition: trx0sys.cc:74
UNIV_INTERN ulint rec_get_nth_field_offs_old(const rec_t *rec, ulint n, ulint *len)
Definition: rem0rec.cc:718
UNIV_INLINE ulint buf_block_get_zip_size(const buf_block_t *block) __attribute__((pure))
UNIV_INLINE dtuple_t * dtuple_create(mem_heap_t *heap, ulint n_fields)
UNIV_INTERN ibool btr_cur_update_alloc_zip(page_zip_des_t *page_zip, buf_block_t *block, dict_index_t *index, ulint length, ibool create, mtr_t *mtr) UNIV_WARN_UNUSED_RESULT_NONNULL
Definition: btr0cur.cc:1764
UNIV_INLINE ulint rec_get_n_fields_old(const rec_t *rec)
UNIV_INLINE ulint page_get_n_recs(const page_t *page)
UNIV_INTERN void buf_page_print(const byte *read_buf, ulint zip_size)
Definition: buf0buf.cc:601
ibuf_use_t ibuf_use
Definition: ibuf0ibuf.cc:193
#define BUF_GET
Definition: buf0buf.h:43
UNIV_INTERN void flst_add_last(flst_base_node_t *base, flst_node_t *node, mtr_t *mtr)
Definition: fut0lst.cc:75
UNIV_INTERN void ibuf_bitmap_page_init(buf_block_t *block, mtr_t *mtr)
Definition: ibuf0ibuf.cc:605
UNIV_INTERN ibool btr_validate_index(dict_index_t *index, trx_t *trx)
Definition: btr0btr.cc:4300
#define mem_free(PTR)
Definition: mem0mem.h:249
UNIV_INTERN void page_cur_delete_rec(page_cur_t *cursor, dict_index_t *index, const ulint *offsets, mtr_t *mtr)
Definition: page0cur.cc:1858
UNIV_INLINE ibool buf_page_peek(ulint space, ulint offset)
UNIV_INLINE ibool ibuf_inside(const mtr_t *mtr) __attribute__((nonnull
#define MLOG_1BYTE
Definition: mtr0mtr.h:73
UNIV_INLINE trx_id_t page_get_max_trx_id(const page_t *page)
UNIV_INTERN ib_int64_t fil_space_get_version(ulint id)
Definition: fil0fil.cc:488
UNIV_INTERN ulint fseg_n_reserved_pages(fseg_header_t *header, ulint *used, mtr_t *mtr)
Definition: fsp0fsp.cc:2401
UNIV_INLINE ibool dict_table_is_comp(const dict_table_t *table)
UNIV_INLINE ulint dtype_get_mtype(const dtype_t *type)
#define FIL_PAGE_TYPE
Definition: fil0fil.h:118
UNIV_INLINE void dtype_new_read_for_order_and_null_size(dtype_t *type, const byte *buf)
UNIV_INTERN ulint btr_cur_pessimistic_insert(ulint flags, btr_cur_t *cursor, dtuple_t *entry, rec_t **rec, big_rec_t **big_rec, ulint n_ext, que_thr_t *thr, mtr_t *mtr)
Definition: btr0cur.cc:1429
UNIV_INTERN void ibuf_init_at_db_start(void)
Definition: ibuf0ibuf.cc:506
UNIV_INTERN void mlog_write_ulint(byte *ptr, ulint val, byte type, mtr_t *mtr)
Definition: mtr0log.cc:247
UNIV_INTERN void dict_index_add_col(dict_index_t *index, const dict_table_t *table, dict_col_t *col, ulint prefix_len)
Definition: dict0dict.cc:1859
UNIV_INTERN dict_index_t * dict_mem_index_create(const char *table_name, const char *index_name, ulint space, ulint type, ulint n_fields)
Definition: dict0mem.cc:251
UNIV_INTERN void dict_mem_table_free(dict_table_t *table)
Definition: dict0mem.cc:111
UNIV_INLINE ulint dict_table_flags_to_zip_size(ulint flags) __attribute__((const ))
ibool trx_doublewrite_must_reset_space_ids
Definition: trx0sys.cc:67
UNIV_INLINE buf_page_t * buf_page_hash_get_low(buf_pool_t *buf_pool, ulint space, ulint offset, ulint fold)
UNIV_INLINE rec_t * page_rec_get_next(rec_t *rec)
UNIV_INLINE ulint page_dir_calc_reserved_space(ulint n_recs)
#define ut_d(EXPR)
Definition: ut0dbg.h:129
UNIV_INTERN void rec_print(FILE *file, const rec_t *rec, const dict_index_t *index)
Definition: rem0rec.cc:1750
UNIV_INTERN void ibuf_print(FILE *file)
Definition: ibuf0ibuf.cc:4926
UNIV_INLINE ibool btr_pcur_is_before_first_on_page(const btr_pcur_t *cursor)
#define mem_heap_free(heap)
Definition: mem0mem.h:117
UNIV_INTERN void flst_remove(flst_base_node_t *base, flst_node_t *node2, mtr_t *mtr)
Definition: fut0lst.cc:270
mem_heap_t * heap
Definition: dict0mem.h:478
buf_page_t page
Definition: buf0buf.h:1433
UNIV_INLINE ulint btr_page_get_prev(const page_t *page, mtr_t *mtr)
#define DICT_IBUF
Definition: dict0mem.h:56
UNIV_INTERN void ibuf_free_excess_pages(void)
Definition: ibuf0ibuf.cc:2400
UNIV_INLINE void page_header_reset_last_insert(page_t *page, page_zip_des_t *page_zip, mtr_t *mtr)
UNIV_INLINE void dfield_copy(dfield_t *field1, const dfield_t *field2)
UNIV_INLINE ulint dtype_get_sql_null_size(const dtype_t *type, ulint comp)
UNIV_INLINE void dtype_new_store_for_order_and_null_size(byte *buf, const dtype_t *type, ulint prefix_len)
UNIV_INTERN ibool lock_rec_expl_exist_on_page(ulint space, ulint page_no)
Definition: lock0lock.cc:1168
UNIV_INTERN ulint fseg_alloc_free_page(fseg_header_t *seg_header, ulint hint, byte direction, mtr_t *mtr)
Definition: fsp0fsp.cc:2873
UNIV_INTERN void dtuple_print(FILE *f, const dtuple_t *tuple)
Definition: data0data.cc:532
#define MLOG_IBUF_BITMAP_INIT
Definition: mtr0mtr.h:130
UNIV_INLINE void ibuf_mtr_start(mtr_t *mtr) __attribute__((nonnull))
UNIV_INLINE ibool btr_pcur_is_before_first_in_tree(btr_pcur_t *cursor, mtr_t *mtr)
UNIV_INLINE ulint btr_page_get_level(const page_t *page, mtr_t *mtr)
UNIV_INTERN ulint fil_space_get_type(ulint id)
Definition: fil0fil.cc:544
UNIV_INTERN void fseg_free_page(fseg_header_t *seg_header, ulint space, ulint page, mtr_t *mtr)
Definition: fsp0fsp.cc:3403
UNIV_INLINE ulint dtuple_get_n_fields(const dtuple_t *tuple)
UNIV_INTERN rw_lock_t * fil_space_get_latch(ulint id, ulint *zip_size)
Definition: fil0fil.cc:515
#define FIL_TABLESPACE
Definition: fil0fil.h:190
UNIV_INLINE ulint btr_page_get_next(const page_t *page, mtr_t *mtr)
UNIV_INLINE void btr_pcur_close(btr_pcur_t *cursor)
UNIV_INLINE rec_t * page_rec_get_prev(rec_t *rec)
UNIV_INTERN void row_upd_rec_in_place(rec_t *rec, dict_index_t *index, const ulint *offsets, const upd_t *update, page_zip_des_t *page_zip)
Definition: row0upd.cc:486
UNIV_INLINE ulint buf_page_address_fold(ulint space, ulint offset) __attribute__((const ))
ibuf_use_t
Definition: ibuf0ibuf.h:53
UNIV_INLINE ibool btr_pcur_is_after_last_in_tree(btr_pcur_t *cursor, mtr_t *mtr)
The buffer pool structure.
Definition: buf0buf.h:1607
UNIV_INLINE ulint ut_min(ulint n1, ulint n2)
UNIV_INTERN void ibuf_merge_or_delete_for_page(buf_block_t *block, ulint space, ulint page_no, ulint zip_size, ibool update_ibuf_bitmap)
Definition: ibuf0ibuf.cc:4419
UNIV_INTERN ibool ibuf_insert(ibuf_op_t op, const dtuple_t *entry, dict_index_t *index, ulint space, ulint zip_size, ulint page_no, que_thr_t *thr)
Definition: ibuf0ibuf.cc:3754
UNIV_INLINE ulint rec_get_deleted_flag(const rec_t *rec, ulint comp)
UNIV_INTERN ulint btr_cur_optimistic_insert(ulint flags, btr_cur_t *cursor, dtuple_t *entry, rec_t **rec, big_rec_t **big_rec, ulint n_ext, que_thr_t *thr, mtr_t *mtr)
Definition: btr0cur.cc:1167
UNIV_INLINE void page_update_max_trx_id(buf_block_t *block, page_zip_des_t *page_zip, trx_id_t trx_id, mtr_t *mtr)
UNIV_INTERN byte * ibuf_parse_bitmap_init(byte *ptr, byte *end_ptr, buf_block_t *block, mtr_t *mtr)
Definition: ibuf0ibuf.cc:642
UNIV_INTERN ulint ibuf_rec_get_counter(const rec_t *rec)
Definition: ibuf0ibuf.cc:1458
UNIV_INTERN ibool row_upd_changes_field_size_or_external(dict_index_t *index, const ulint *offsets, const upd_t *update)
Definition: row0upd.cc:418
UNIV_INLINE ulint buf_block_get_page_no(const buf_block_t *block) __attribute__((pure))
UNIV_INLINE const rec_t * page_rec_get_prev_const(const rec_t *rec)
UNIV_INTERN void mtr_commit(mtr_t *mtr) __attribute__((nonnull))
Definition: mtr0mtr.cc:247
UNIV_INLINE void dfield_set_data(dfield_t *field, const void *data, ulint len)
UNIV_INLINE void ibuf_mtr_commit(mtr_t *mtr) __attribute__((nonnull))
UNIV_INTERN void lock_update_delete(const buf_block_t *block, const rec_t *rec)
Definition: lock0lock.cc:3162
UNIV_INLINE ulint dtype_get_len(const dtype_t *type)
UNIV_INLINE ulint page_get_max_insert_size(const page_t *page, ulint n_recs)
#define DICT_CLUSTERED
Definition: dict0mem.h:51
UNIV_INLINE ibool page_is_leaf(const page_t *page) __attribute__((nonnull
UNIV_INLINE ulint page_get_max_insert_size_after_reorganize(const page_t *page, ulint n_recs)
UNIV_INTERN void fil_page_set_type(byte *page, ulint type)
Definition: fil0fil.cc:4899
UNIV_INTERN void btr_cur_set_deleted_flag_for_ibuf(rec_t *rec, page_zip_des_t *page_zip, ibool val, mtr_t *mtr)
Definition: btr0cur.cc:2853
UNIV_INTERN ibool buf_page_get_known_nowait(ulint rw_latch, buf_block_t *block, ulint mode, const char *file, ulint line, mtr_t *mtr)
Definition: buf0buf.cc:3267
unsigned prefix_len
Definition: dict0mem.h:322
UNIV_INTERN dict_table_t * dict_mem_table_create(const char *name, ulint space, ulint n_cols, ulint flags)
Definition: dict0mem.cc:59
table_id_t id
Definition: dict0mem.h:477
UNIV_INTERN ibool fil_inc_pending_ibuf_merges(ulint id)
Definition: fil0fil.cc:1872
UNIV_INTERN ulint fil_space_get_flags(ulint id)
Definition: fil0fil.cc:1483
UNIV_INTERN ibool page_validate(const page_t *page, dict_index_t *index)
Definition: page0page.cc:2307
UNIV_INLINE ulint dict_index_is_clust(const dict_index_t *index) __attribute__((pure))
UNIV_INTERN void lock_rec_store_on_page_infimum(const buf_block_t *block, const rec_t *rec)
Definition: lock0lock.cc:3207
#define MLOG_2BYTES
Definition: mtr0mtr.h:74
UNIV_INTERN ibool dtuple_check_typed(const dtuple_t *tuple)
UNIV_INLINE rw_lock_t * dict_index_get_lock(dict_index_t *index)
UNIV_INTERN void btr_pcur_store_position(btr_pcur_t *cursor, mtr_t *mtr)
Definition: btr0pcur.cc:89
UNIV_INTERN void lock_rec_restore_from_page_infimum(const buf_block_t *block, const rec_t *rec, const buf_block_t *donator)
Definition: lock0lock.cc:3232
unsigned cached
Definition: dict0mem.h:363
#define buf_block_get_page_zip(block)
Definition: buf0buf.h:1034
#define ut_is_2pow(n)
Definition: ut0ut.h:162
#define ut_a(EXPR)
Definition: ut0dbg.h:105
UNIV_INTERN void dict_table_add_system_columns(dict_table_t *table, mem_heap_t *heap)
Definition: dict0dict.cc:780
UNIV_INLINE void * mem_heap_alloc(mem_heap_t *heap, ulint n)
#define mem_heap_create(N)
Definition: mem0mem.h:97
UNIV_INLINE ibool page_rec_is_supremum(const rec_t *rec) __attribute__((const ))
dict_table_t * table
Definition: dict0mem.h:341
UNIV_INTERN void rw_lock_x_lock_move_ownership(rw_lock_t *lock)
Definition: sync0rw.cc:473
ulint info_bits
Definition: row0upd.h:390
UNIV_INTERN void fil_set_max_space_id_if_bigger(ulint max_id)
Definition: fil0fil.cc:1696
UNIV_INTERN ulint fil_page_get_type(const byte *page)
Definition: fil0fil.cc:4915
UNIV_INTERN ibool btr_page_reorganize(buf_block_t *block, dict_index_t *index, mtr_t *mtr)
Definition: btr0btr.cc:1671
UNIV_INTERN void dict_mem_table_add_col(dict_table_t *table, mem_heap_t *heap, const char *name, ulint mtype, ulint prtype, ulint len)
Definition: dict0mem.cc:178
UNIV_INLINE void mach_write_to_1(byte *b, ulint n)
UNIV_INTERN ibool ibuf_is_empty(void)
Definition: ibuf0ibuf.cc:4902
UNIV_INTERN buf_block_t * buf_page_get_gen(ulint space, ulint zip_size, ulint offset, ulint rw_latch, buf_block_t *guess, ulint mode, const char *file, ulint line, mtr_t *mtr)
Definition: buf0buf.cc:2712
UNIV_INTERN ulint dict_index_add_to_cache(dict_table_t *table, dict_index_t *index, ulint page_no, ibool strict)
Definition: dict0dict.cc:1567
UNIV_INTERN void mlog_write_initial_log_record(const byte *ptr, byte type, mtr_t *mtr)
Definition: mtr0log.cc:68
#define DICT_UNIVERSAL
Definition: dict0mem.h:53
UNIV_INLINE ulint ut_fold_binary(const byte *str, ulint len) __attribute__((pure))
UNIV_INTERN void ibuf_reset_free_bits(buf_block_t *block)
Definition: ibuf0ibuf.cc:989
UNIV_INTERN void dict_mem_index_free(dict_index_t *index)
Definition: dict0mem.cc:381
UNIV_INTERN ibool btr_cur_pessimistic_delete(ulint *err, ibool has_reserved_extents, btr_cur_t *cursor, enum trx_rb_ctx rb_ctx, mtr_t *mtr)
Definition: btr0cur.cc:2995
index_id_t id
Definition: dict0mem.h:337
#define ut_ad(EXPR)
Definition: ut0dbg.h:127
#define mtr_x_lock(B, MTR)
Definition: mtr0mtr.h:340
#define DICT_TF_COMPACT
Definition: dict0mem.h:69
ib_id_t trx_id_t
Definition: trx0types.h:85
UNIV_INLINE ulint rec_get_converted_size(dict_index_t *index, const dtuple_t *dtuple, ulint n_ext)
#define ut_error
Definition: ut0dbg.h:115
#define BUF_KEEP_OLD
Definition: buf0buf.h:75
#define FIL_NULL
Definition: fil0fil.h:48
UNIV_INLINE const rec_t * page_rec_get_next_const(const rec_t *rec)
UNIV_INLINE ulint buf_block_get_space(const buf_block_t *block) __attribute__((pure))
ibool recv_no_ibuf_operations
Definition: log0recv.cc:116
ibool inside_ibuf
Definition: mtr0mtr.h:447
UNIV_INLINE ibool page_rec_is_user_rec(const rec_t *rec) __attribute__((const ))
UNIV_INLINE ulint mach_read_from_4(const byte *b) __attribute__((nonnull
UNIV_INLINE void btr_cur_position(dict_index_t *index, rec_t *rec, buf_block_t *block, btr_cur_t *cursor)
UNIV_INTERN void ibuf_update_free_bits_low(const buf_block_t *block, ulint max_ins_size, mtr_t *mtr)
Definition: ibuf0ibuf.cc:1008
UNIV_INTERN void ut_print_timestamp(FILE *file)
Definition: ut0ut.cc:247
UNIV_INLINE ulint rec_get_n_fields(const rec_t *rec, const dict_index_t *index)
UNIV_INLINE void mach_write_to_2(byte *b, ulint n)
UNIV_INTERN ibool buf_pool_watch_occurred(ulint space, ulint offset) UNIV_WARN_UNUSED_RESULT
Definition: buf0buf.cc:2099
UNIV_INTERN ulint ibuf_contract_for_n_pages(ibool sync, ulint n_pages)
Definition: ibuf0ibuf.cc:2730
UNIV_INLINE trx_t * thr_get_trx(que_thr_t *thr)
UNIV_INLINE buf_block_t * btr_cur_get_block(btr_cur_t *cursor)
UNIV_INTERN upd_t * row_upd_build_sec_rec_difference_binary(dict_index_t *index, const dtuple_t *entry, const rec_t *rec, trx_t *trx, mem_heap_t *heap)
Definition: row0upd.cc:786
byte page_t
Definition: page0types.h:37
srv_shutdown_state
Definition: srv0start.h:113
UNIV_INTERN void rec_print_old(FILE *file, const rec_t *rec)
Definition: rem0rec.cc:1630
UNIV_INLINE void dtuple_set_types_binary(dtuple_t *tuple, ulint n)
UNIV_INTERN void ibuf_update_max_tablespace_id(void)
Definition: ibuf0ibuf.cc:3169
UNIV_INLINE buf_pool_t * buf_pool_get(ulint space, ulint offset)
ulint page
Definition: fil0fil.h:67
UNIV_INTERN buf_block_t * buf_block_align(const byte *ptr)
Definition: buf0buf.cc:2610
UNIV_INLINE void mtr_start(mtr_t *mtr) __attribute__((nonnull))
UNIV_INLINE ulint ut_bit_set_nth(ulint a, ulint n, ibool val)
UNIV_INTERN void buf_page_make_young(buf_page_t *bpage)
Definition: buf0buf.cc:2127
UNIV_INLINE ulint rec_get_info_bits(const rec_t *rec, ulint comp)
UNIV_INLINE ibool page_rec_is_infimum(const rec_t *rec) __attribute__((const ))
UNIV_INLINE ulint mach_read_from_1(const byte *b) __attribute__((nonnull
UNIV_INLINE ibool btr_pcur_is_after_last_on_page(const btr_pcur_t *cursor)
UNIV_INLINE ulint rec_offs_size(const ulint *offsets)
UNIV_INLINE ulint mach_read_from_2(const byte *b) __attribute__((nonnull
UNIV_INLINE ulint page_get_free_space_of_empty(ulint comp) __attribute__((const ))
UNIV_INLINE void page_cur_move_to_prev(page_cur_t *cur)
UNIV_INTERN void ibuf_delete_for_discarded_space(ulint space)
Definition: ibuf0ibuf.cc:4812
UNIV_INLINE void btr_pcur_open_at_index_side(ibool from_left, dict_index_t *index, ulint latch_mode, btr_pcur_t *pcur, ibool do_init, mtr_t *mtr)
ulint latch_mode
Definition: btr0pcur.h:460
#define FIL_PAGE_IBUF_BITMAP
Definition: fil0fil.h:179
UNIV_INTERN void ibuf_close(void)
Definition: ibuf0ibuf.cc:463
UNIV_INLINE ulint flst_get_len(const flst_base_node_t *base, mtr_t *mtr)
UNIV_INTERN ulint ibuf_contract(ibool sync)
Definition: ibuf0ibuf.cc:2712
#define UT_BITS_IN_BYTES(b)
Definition: ut0ut.h:219
#define buf_pool_mutex_exit(b)
Definition: buf0buf.h:1807
UNIV_INTERN void fil_decr_pending_ibuf_merges(ulint id)
Definition: fil0fil.cc:1906
UNIV_INLINE ibool ibuf_bitmap_page(ulint zip_size, ulint page_no)
ulint low_match
Definition: btr0cur.h:729
UNIV_INTERN void buf_read_ibuf_merge_pages(ibool sync, const ulint *space_ids, const ib_int64_t *space_versions, const ulint *page_nos, ulint n_stored)
Definition: buf0rea.cc:497
UNIV_INTERN ibool btr_pcur_move_to_prev(btr_pcur_t *cursor, mtr_t *mtr)
Definition: btr0pcur.cc:525
UNIV_INLINE void btr_pcur_commit_specify_mtr(btr_pcur_t *pcur, mtr_t *mtr)
UNIV_INLINE ulint buf_pool_get_curr_size(void)
UNIV_INLINE ulint dtype_get_prtype(const dtype_t *type)
#define buf_page_get(SP, ZS, OF, LA, MTR)
Definition: buf0buf.h:316
unsigned fixed_len
Definition: dict0mem.h:329