mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / ibuf / ibuf0ibuf.c
blobae6c5f6636f142b3f8a12eef5b1042f01cc5d0ef
1 /*****************************************************************************
3 Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
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.
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.
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.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 *****************************************************************************/
19 /******************************************************
20 Insert buffer
22 (c) 1997 Innobase Oy
24 Created 7/19/1997 Heikki Tuuri
25 *******************************************************/
27 #include "ibuf0ibuf.h"
29 #ifdef UNIV_NONINL
30 #include "ibuf0ibuf.ic"
31 #endif
33 #include "buf0buf.h"
34 #include "buf0rea.h"
35 #include "fsp0fsp.h"
36 #include "trx0sys.h"
37 #include "fil0fil.h"
38 #include "thr0loc.h"
39 #include "rem0rec.h"
40 #include "btr0cur.h"
41 #include "btr0pcur.h"
42 #include "btr0btr.h"
43 #include "row0upd.h"
44 #include "sync0sync.h"
45 #include "dict0boot.h"
46 #include "fut0lst.h"
47 #include "lock0lock.h"
48 #include "log0recv.h"
49 #include "que0que.h"
50 #include "rem0cmp.h"
52 /* STRUCTURE OF AN INSERT BUFFER RECORD
54 In versions < 4.1.x:
56 1. The first field is the page number.
57 2. The second field is an array which stores type info for each subsequent
58 field. We store the information which affects the ordering of records, and
59 also the physical storage size of an SQL NULL value. E.g., for CHAR(10) it
60 is 10 bytes.
61 3. Next we have the fields of the actual index record.
63 In versions >= 4.1.x:
65 Note that contary to what we planned in the 1990's, there will only be one
66 insert buffer tree, and that is in the system tablespace of InnoDB.
68 1. The first field is the space id.
69 2. The second field is a one-byte marker (0) which differentiates records from
70 the < 4.1.x storage format.
71 3. The third field is the page number.
72 4. The fourth field contains the type info, where we have also added 2 bytes to
73 store the charset. In the compressed table format of 5.0.x we must add more
74 information here so that we can build a dummy 'index' struct which 5.0.x
75 can use in the binary search on the index page in the ibuf merge phase.
76 5. The rest of the fields contain the fields of the actual index record.
78 In versions >= 5.0.3:
80 The first byte of the fourth field is an additional marker (0) if the record
81 is in the compact format. The presence of this marker can be detected by
82 looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
84 The high-order bit of the character set field in the type info is the
85 "nullable" flag for the field. */
88 /* PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
90 If an OS thread performs any operation that brings in disk pages from
91 non-system tablespaces into the buffer pool, or creates such a page there,
92 then the operation may have as a side effect an insert buffer index tree
93 compression. Thus, the tree latch of the insert buffer tree may be acquired
94 in the x-mode, and also the file space latch of the system tablespace may
95 be acquired in the x-mode.
97 Also, an insert to an index in a non-system tablespace can have the same
98 effect. How do we know this cannot lead to a deadlock of OS threads? There
99 is a problem with the i\o-handler threads: they break the latching order
100 because they own x-latches to pages which are on a lower level than the
101 insert buffer tree latch, its page latches, and the tablespace latch an
102 insert buffer operation can reserve.
104 The solution is the following: Let all the tree and page latches connected
105 with the insert buffer be later in the latching order than the fsp latch and
106 fsp page latches.
108 Insert buffer pages must be such that the insert buffer is never invoked
109 when these pages are accessed as this would result in a recursion violating
110 the latching order. We let a special i/o-handler thread take care of i/o to
111 the insert buffer pages and the ibuf bitmap pages, as well as the fsp bitmap
112 pages and the first inode page, which contains the inode of the ibuf tree: let
113 us call all these ibuf pages. To prevent deadlocks, we do not let a read-ahead
114 access both non-ibuf and ibuf pages.
116 Then an i/o-handler for the insert buffer never needs to access recursively the
117 insert buffer tree and thus obeys the latching order. On the other hand, other
118 i/o-handlers for other tablespaces may require access to the insert buffer,
119 but because all kinds of latches they need to access there are later in the
120 latching order, no violation of the latching order occurs in this case,
121 either.
123 A problem is how to grow and contract an insert buffer tree. As it is later
124 in the latching order than the fsp management, we have to reserve the fsp
125 latch first, before adding or removing pages from the insert buffer tree.
126 We let the insert buffer tree have its own file space management: a free
127 list of pages linked to the tree root. To prevent recursive using of the
128 insert buffer when adding pages to the tree, we must first load these pages
129 to memory, obtaining a latch on them, and only after that add them to the
130 free list of the insert buffer tree. More difficult is removing of pages
131 from the free list. If there is an excess of pages in the free list of the
132 ibuf tree, they might be needed if some thread reserves the fsp latch,
133 intending to allocate more file space. So we do the following: if a thread
134 reserves the fsp latch, we check the writer count field of the latch. If
135 this field has value 1, it means that the thread did not own the latch
136 before entering the fsp system, and the mtr of the thread contains no
137 modifications to the fsp pages. Now we are free to reserve the ibuf latch,
138 and check if there is an excess of pages in the free list. We can then, in a
139 separate mini-transaction, take them out of the free list and free them to
140 the fsp system.
142 To avoid deadlocks in the ibuf system, we divide file pages into three levels:
144 (1) non-ibuf pages,
145 (2) ibuf tree pages and the pages in the ibuf tree free list, and
146 (3) ibuf bitmap pages.
148 No OS thread is allowed to access higher level pages if it has latches to
149 lower level pages; even if the thread owns a B-tree latch it must not access
150 the B-tree non-leaf pages if it has latches on lower level pages. Read-ahead
151 is only allowed for level 1 and 2 pages. Dedicated i/o-handler threads handle
152 exclusively level 1 i/o. A dedicated i/o handler thread handles exclusively
153 level 2 i/o. However, if an OS thread does the i/o handling for itself, i.e.,
154 it uses synchronous aio, it can access any pages, as long as it obeys the
155 access order rules. */
157 /* Buffer pool size per the maximum insert buffer size */
158 #define IBUF_POOL_SIZE_PER_MAX_SIZE 2
160 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
161 /* Flag to control insert buffer debugging. */
162 uint ibuf_debug;
163 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
165 /* The insert buffer control structure */
166 ibuf_t* ibuf = NULL;
168 static ulint ibuf_rnd = 986058871;
170 ulint ibuf_flush_count = 0;
172 #ifdef UNIV_IBUF_DEBUG
173 /* Dimensions for the ibuf_count array */
174 #define IBUF_COUNT_N_SPACES 500
175 #define IBUF_COUNT_N_PAGES 2000
177 /* Buffered entry counts for file pages, used in debugging */
178 static ulint ibuf_counts[IBUF_COUNT_N_SPACES][IBUF_COUNT_N_PAGES];
180 /**********************************************************************
181 Checks that the indexes to ibuf_counts[][] are within limits. */
182 UNIV_INLINE
183 void
184 ibuf_count_check(
185 /*=============*/
186 ulint space_id, /* in: space identifier */
187 ulint page_no) /* in: page number */
189 if (space_id < IBUF_COUNT_N_SPACES && page_no < IBUF_COUNT_N_PAGES) {
190 return;
193 fprintf(stderr,
194 "InnoDB: UNIV_IBUF_DEBUG limits space_id and page_no\n"
195 "InnoDB: and breaks crash recovery.\n"
196 "InnoDB: space_id=%lu, should be 0<=space_id<%lu\n"
197 "InnoDB: page_no=%lu, should be 0<=page_no<%lu\n",
198 (ulint) space_id, (ulint) IBUF_COUNT_N_SPACES,
199 (ulint) page_no, (ulint) IBUF_COUNT_N_PAGES);
200 ut_error;
202 #endif
204 /* The start address for an insert buffer bitmap page bitmap */
205 #define IBUF_BITMAP PAGE_DATA
207 /* Offsets in bits for the bits describing a single page in the bitmap */
208 #define IBUF_BITMAP_FREE 0
209 #define IBUF_BITMAP_BUFFERED 2
210 #define IBUF_BITMAP_IBUF 3 /* TRUE if page is a part of the ibuf
211 tree, excluding the root page, or is
212 in the free list of the ibuf */
214 /* Number of bits describing a single page */
215 #define IBUF_BITS_PER_PAGE 4
216 #if IBUF_BITS_PER_PAGE % 2
217 # error "IBUF_BITS_PER_PAGE must be an even number!"
218 #endif
220 /* The mutex used to block pessimistic inserts to ibuf trees */
221 static mutex_t ibuf_pessimistic_insert_mutex;
223 /* The mutex protecting the insert buffer structs */
224 static mutex_t ibuf_mutex;
226 /* The mutex protecting the insert buffer bitmaps */
227 static mutex_t ibuf_bitmap_mutex;
229 /* The area in pages from which contract looks for page numbers for merge */
230 #define IBUF_MERGE_AREA 8
232 /* Inside the merge area, pages which have at most 1 per this number less
233 buffered entries compared to maximum volume that can buffered for a single
234 page are merged along with the page whose buffer became full */
235 #define IBUF_MERGE_THRESHOLD 4
237 /* In ibuf_contract at most this number of pages is read to memory in one
238 batch, in order to merge the entries for them in the insert buffer */
239 #define IBUF_MAX_N_PAGES_MERGED IBUF_MERGE_AREA
241 /* If the combined size of the ibuf trees exceeds ibuf->max_size by this
242 many pages, we start to contract it in connection to inserts there, using
243 non-synchronous contract */
244 #define IBUF_CONTRACT_ON_INSERT_NON_SYNC 0
246 /* Same as above, but use synchronous contract */
247 #define IBUF_CONTRACT_ON_INSERT_SYNC 5
249 /* Same as above, but no insert is done, only contract is called */
250 #define IBUF_CONTRACT_DO_NOT_INSERT 10
252 /* TODO: how to cope with drop table if there are records in the insert
253 buffer for the indexes of the table? Is there actually any problem,
254 because ibuf merge is done to a page when it is read in, and it is
255 still physically like the index page even if the index would have been
256 dropped! So, there seems to be no problem. */
258 /**********************************************************************
259 Validates the ibuf data structures when the caller owns ibuf_mutex. */
261 ibool
262 ibuf_validate_low(void);
263 /*===================*/
264 /* out: TRUE if ok */
266 /**********************************************************************
267 Sets the flag in the current OS thread local storage denoting that it is
268 inside an insert buffer routine. */
269 UNIV_INLINE
270 void
271 ibuf_enter(void)
272 /*============*/
274 ibool* ptr;
276 ptr = thr_local_get_in_ibuf_field();
278 ut_ad(*ptr == FALSE);
280 *ptr = TRUE;
283 /**********************************************************************
284 Sets the flag in the current OS thread local storage denoting that it is
285 exiting an insert buffer routine. */
286 UNIV_INLINE
287 void
288 ibuf_exit(void)
289 /*===========*/
291 ibool* ptr;
293 ptr = thr_local_get_in_ibuf_field();
295 ut_ad(*ptr == TRUE);
297 *ptr = FALSE;
300 /**********************************************************************
301 Returns TRUE if the current OS thread is performing an insert buffer
302 routine. */
304 ibool
305 ibuf_inside(void)
306 /*=============*/
307 /* out: TRUE if inside an insert buffer routine: for instance,
308 a read-ahead of non-ibuf pages is then forbidden */
310 return(*thr_local_get_in_ibuf_field());
313 /**********************************************************************
314 Gets the ibuf header page and x-latches it. */
315 static
316 page_t*
317 ibuf_header_page_get(
318 /*=================*/
319 /* out: insert buffer header page */
320 ulint space, /* in: space id */
321 mtr_t* mtr) /* in: mtr */
323 page_t* page;
325 ut_a(space == 0);
327 ut_ad(!ibuf_inside());
329 page = buf_page_get(space, FSP_IBUF_HEADER_PAGE_NO, RW_X_LATCH, mtr);
331 #ifdef UNIV_SYNC_DEBUG
332 buf_page_dbg_add_level(page, SYNC_IBUF_HEADER);
333 #endif /* UNIV_SYNC_DEBUG */
335 return(page);
338 /**********************************************************************
339 Gets the root page and x-latches it. */
340 static
341 page_t*
342 ibuf_tree_root_get(
343 /*===============*/
344 /* out: insert buffer tree root page */
345 ibuf_data_t* data, /* in: ibuf data */
346 ulint space, /* in: space id */
347 mtr_t* mtr) /* in: mtr */
349 page_t* page;
351 ut_a(space == 0);
352 ut_ad(ibuf_inside());
354 mtr_x_lock(dict_index_get_lock(data->index), mtr);
356 page = buf_page_get(space, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH,
357 mtr);
358 #ifdef UNIV_SYNC_DEBUG
359 buf_page_dbg_add_level(page, SYNC_TREE_NODE);
360 #endif /* UNIV_SYNC_DEBUG */
362 return(page);
365 #ifdef UNIV_IBUF_DEBUG
366 /**********************************************************************
367 Gets the ibuf count for a given page. */
369 ulint
370 ibuf_count_get(
371 /*===========*/
372 /* out: number of entries in the insert buffer
373 currently buffered for this page */
374 ulint space, /* in: space id */
375 ulint page_no)/* in: page number */
377 ibuf_count_check(space, page_no);
379 return(ibuf_counts[space][page_no]);
382 /**********************************************************************
383 Sets the ibuf count for a given page. */
384 static
385 void
386 ibuf_count_set(
387 /*===========*/
388 ulint space, /* in: space id */
389 ulint page_no,/* in: page number */
390 ulint val) /* in: value to set */
392 ibuf_count_check(space, page_no);
393 ut_a(val < UNIV_PAGE_SIZE);
395 ibuf_counts[space][page_no] = val;
397 #endif
399 /**********************************************************************
400 Creates the insert buffer data structure at a database startup and initializes
401 the data structures for the insert buffer. */
403 void
404 ibuf_init_at_db_start(void)
405 /*=======================*/
407 ibuf = mem_alloc(sizeof(ibuf_t));
409 /* Note that also a pessimistic delete can sometimes make a B-tree
410 grow in size, as the references on the upper levels of the tree can
411 change */
413 ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE
414 / IBUF_POOL_SIZE_PER_MAX_SIZE;
416 UT_LIST_INIT(ibuf->data_list);
418 ibuf->size = 0;
420 mutex_create(&ibuf_pessimistic_insert_mutex,
421 SYNC_IBUF_PESS_INSERT_MUTEX);
423 mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX);
425 mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
427 fil_ibuf_init_at_db_start();
430 /**********************************************************************
431 Updates the size information in an ibuf data, assuming the segment size has
432 not changed. */
433 static
434 void
435 ibuf_data_sizes_update(
436 /*===================*/
437 ibuf_data_t* data, /* in: ibuf data struct */
438 page_t* root, /* in: ibuf tree root */
439 mtr_t* mtr) /* in: mtr */
441 ulint old_size;
443 ut_ad(mutex_own(&ibuf_mutex));
445 old_size = data->size;
447 data->free_list_len = flst_get_len(root + PAGE_HEADER
448 + PAGE_BTR_IBUF_FREE_LIST, mtr);
450 data->height = 1 + btr_page_get_level(root, mtr);
452 data->size = data->seg_size - (1 + data->free_list_len);
453 /* the '1 +' is the ibuf header page */
454 ut_ad(data->size < data->seg_size);
456 if (page_get_n_recs(root) == 0) {
458 data->empty = TRUE;
459 } else {
460 data->empty = FALSE;
463 ut_ad(ibuf->size + data->size >= old_size);
465 ibuf->size = ibuf->size + data->size - old_size;
467 #if 0
468 fprintf(stderr, "ibuf size %lu, space ibuf size %lu\n",
469 ibuf->size, data->size);
470 #endif
473 /**********************************************************************
474 Creates the insert buffer data struct for a single tablespace. Reads the
475 root page of the insert buffer tree in the tablespace. This function can
476 be called only after the dictionary system has been initialized, as this
477 creates also the insert buffer table and index into this tablespace. */
479 ibuf_data_t*
480 ibuf_data_init_for_space(
481 /*=====================*/
482 /* out, own: ibuf data struct, linked to the list
483 in ibuf control structure */
484 ulint space) /* in: space id */
486 ibuf_data_t* data;
487 page_t* root;
488 page_t* header_page;
489 mtr_t mtr;
490 char* buf;
491 mem_heap_t* heap;
492 dict_table_t* table;
493 dict_index_t* index;
494 ulint n_used;
496 ut_a(space == 0);
498 data = mem_alloc(sizeof(ibuf_data_t));
500 data->space = space;
502 mtr_start(&mtr);
504 mutex_enter(&ibuf_mutex);
506 mtr_x_lock(fil_space_get_latch(space), &mtr);
508 header_page = ibuf_header_page_get(space, &mtr);
510 fseg_n_reserved_pages(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
511 &n_used, &mtr);
512 ibuf_enter();
514 ut_ad(n_used >= 2);
516 data->seg_size = n_used;
518 root = buf_page_get(space, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH,
519 &mtr);
520 #ifdef UNIV_SYNC_DEBUG
521 buf_page_dbg_add_level(root, SYNC_TREE_NODE);
522 #endif /* UNIV_SYNC_DEBUG */
524 data->size = 0;
525 data->n_inserts = 0;
526 data->n_merges = 0;
527 data->n_merged_recs = 0;
529 ibuf_data_sizes_update(data, root, &mtr);
531 if (!data->empty) {
532 fprintf(stderr,
533 "InnoDB: index entries found in the insert buffer\n");
534 } else {
535 fprintf(stderr,
536 "InnoDB: insert buffer empty\n");
539 mutex_exit(&ibuf_mutex);
541 mtr_commit(&mtr);
543 ibuf_exit();
545 heap = mem_heap_create(450);
546 buf = mem_heap_alloc(heap, 50);
548 sprintf(buf, "SYS_IBUF_TABLE_%lu", (ulong) space);
549 /* use old-style record format for the insert buffer */
550 table = dict_mem_table_create(buf, space, 2, 0);
552 dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_BINARY, 0, 0);
553 dict_mem_table_add_col(table, heap, "TYPES", DATA_BINARY, 0, 0);
555 table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
557 dict_table_add_to_cache(table, heap);
558 mem_heap_free(heap);
560 index = dict_mem_index_create(
561 buf, "CLUST_IND", space,
562 DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 2);
564 dict_mem_index_add_field(index, "PAGE_NO", 0);
565 dict_mem_index_add_field(index, "TYPES", 0);
567 index->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
569 dict_index_add_to_cache(table, index, FSP_IBUF_TREE_ROOT_PAGE_NO);
571 data->index = dict_table_get_first_index(table);
573 mutex_enter(&ibuf_mutex);
575 UT_LIST_ADD_LAST(data_list, ibuf->data_list, data);
577 mutex_exit(&ibuf_mutex);
579 return(data);
582 /*************************************************************************
583 Initializes an ibuf bitmap page. */
585 void
586 ibuf_bitmap_page_init(
587 /*==================*/
588 page_t* page, /* in: bitmap page */
589 mtr_t* mtr) /* in: mtr */
591 ulint bit_offset;
592 ulint byte_offset;
594 /* Write all zeros to the bitmap */
596 bit_offset = XDES_DESCRIBED_PER_PAGE * IBUF_BITS_PER_PAGE;
598 byte_offset = bit_offset / 8 + 1;
599 /* better: byte_offset = UT_BITS_IN_BYTES(bit_offset); */
601 fil_page_set_type(page, FIL_PAGE_IBUF_BITMAP);
603 memset(page + IBUF_BITMAP, 0, byte_offset);
605 /* The remaining area (up to the page trailer) is uninitialized. */
607 mlog_write_initial_log_record(page, MLOG_IBUF_BITMAP_INIT, mtr);
610 /*************************************************************************
611 Parses a redo log record of an ibuf bitmap page init. */
613 byte*
614 ibuf_parse_bitmap_init(
615 /*===================*/
616 /* out: end of log record or NULL */
617 byte* ptr, /* in: buffer */
618 byte* end_ptr __attribute__((unused)), /* in: buffer end */
619 page_t* page, /* in: page or NULL */
620 mtr_t* mtr) /* in: mtr or NULL */
622 ut_ad(ptr && end_ptr);
624 if (page) {
625 ibuf_bitmap_page_init(page, mtr);
628 return(ptr);
631 /************************************************************************
632 Gets the desired bits for a given page from a bitmap page. */
633 UNIV_INLINE
634 ulint
635 ibuf_bitmap_page_get_bits(
636 /*======================*/
637 /* out: value of bits */
638 page_t* page, /* in: bitmap page */
639 ulint page_no,/* in: page whose bits to get */
640 ulint bit, /* in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */
641 mtr_t* mtr __attribute__((unused))) /* in: mtr containing an
642 x-latch to the bitmap
643 page */
645 ulint byte_offset;
646 ulint bit_offset;
647 ulint map_byte;
648 ulint value;
650 ut_ad(bit < IBUF_BITS_PER_PAGE);
651 #if IBUF_BITS_PER_PAGE % 2
652 # error "IBUF_BITS_PER_PAGE % 2 != 0"
653 #endif
654 ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
655 MTR_MEMO_PAGE_X_FIX));
657 bit_offset = (page_no % XDES_DESCRIBED_PER_PAGE) * IBUF_BITS_PER_PAGE
658 + bit;
660 byte_offset = bit_offset / 8;
661 bit_offset = bit_offset % 8;
663 ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
665 map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
667 value = ut_bit_get_nth(map_byte, bit_offset);
669 if (bit == IBUF_BITMAP_FREE) {
670 ut_ad(bit_offset + 1 < 8);
672 value = value * 2 + ut_bit_get_nth(map_byte, bit_offset + 1);
675 return(value);
678 /************************************************************************
679 Sets the desired bit for a given page in a bitmap page. */
680 static
681 void
682 ibuf_bitmap_page_set_bits(
683 /*======================*/
684 page_t* page, /* in: bitmap page */
685 ulint page_no,/* in: page whose bits to set */
686 ulint bit, /* in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */
687 ulint val, /* in: value to set */
688 mtr_t* mtr) /* in: mtr containing an x-latch to the bitmap page */
690 ulint byte_offset;
691 ulint bit_offset;
692 ulint map_byte;
694 ut_ad(bit < IBUF_BITS_PER_PAGE);
695 #if IBUF_BITS_PER_PAGE % 2
696 # error "IBUF_BITS_PER_PAGE % 2 != 0"
697 #endif
698 ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
699 MTR_MEMO_PAGE_X_FIX));
700 #ifdef UNIV_IBUF_DEBUG
701 ut_a((bit != IBUF_BITMAP_BUFFERED) || (val != FALSE)
702 || (0 == ibuf_count_get(buf_frame_get_space_id(page),
703 page_no)));
704 #endif
705 bit_offset = (page_no % XDES_DESCRIBED_PER_PAGE) * IBUF_BITS_PER_PAGE
706 + bit;
708 byte_offset = bit_offset / 8;
709 bit_offset = bit_offset % 8;
711 ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
713 map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
715 if (bit == IBUF_BITMAP_FREE) {
716 ut_ad(bit_offset + 1 < 8);
717 ut_ad(val <= 3);
719 map_byte = ut_bit_set_nth(map_byte, bit_offset, val / 2);
720 map_byte = ut_bit_set_nth(map_byte, bit_offset + 1, val % 2);
721 } else {
722 ut_ad(val <= 1);
723 map_byte = ut_bit_set_nth(map_byte, bit_offset, val);
726 mlog_write_ulint(page + IBUF_BITMAP + byte_offset, map_byte,
727 MLOG_1BYTE, mtr);
730 /************************************************************************
731 Calculates the bitmap page number for a given page number. */
732 UNIV_INLINE
733 ulint
734 ibuf_bitmap_page_no_calc(
735 /*=====================*/
736 /* out: the bitmap page number where
737 the file page is mapped */
738 ulint page_no) /* in: tablespace page number */
740 return(FSP_IBUF_BITMAP_OFFSET
741 + XDES_DESCRIBED_PER_PAGE
742 * (page_no / XDES_DESCRIBED_PER_PAGE));
745 /************************************************************************
746 Gets the ibuf bitmap page where the bits describing a given file page are
747 stored. */
748 static
749 page_t*
750 ibuf_bitmap_get_map_page(
751 /*=====================*/
752 /* out: bitmap page where the file page is mapped,
753 that is, the bitmap page containing the descriptor
754 bits for the file page; the bitmap page is
755 x-latched */
756 ulint space, /* in: space id of the file page */
757 ulint page_no,/* in: page number of the file page */
758 mtr_t* mtr) /* in: mtr */
760 page_t* page;
762 page = buf_page_get(space, ibuf_bitmap_page_no_calc(page_no),
763 RW_X_LATCH, mtr);
764 #ifdef UNIV_SYNC_DEBUG
765 buf_page_dbg_add_level(page, SYNC_IBUF_BITMAP);
766 #endif /* UNIV_SYNC_DEBUG */
768 return(page);
771 /****************************************************************************
772 Sets the free bits of the page in the ibuf bitmap. This is done in a separate
773 mini-transaction, hence this operation does not restrict further work to only
774 ibuf bitmap operations, which would result if the latch to the bitmap page
775 were kept. */
776 UNIV_INLINE
777 void
778 ibuf_set_free_bits_low(
779 /*===================*/
780 ulint type, /* in: index type */
781 page_t* page, /* in: index page; free bit is set if the index is
782 non-clustered and page level is 0 */
783 ulint val, /* in: value to set: < 4 */
784 mtr_t* mtr) /* in: mtr */
786 page_t* bitmap_page;
788 if (type & DICT_CLUSTERED) {
790 return;
793 if (btr_page_get_level_low(page) != 0) {
795 return;
798 bitmap_page = ibuf_bitmap_get_map_page(
799 buf_frame_get_space_id(page),
800 buf_frame_get_page_no(page), mtr);
801 #ifdef UNIV_IBUF_DEBUG
802 # if 0
803 fprintf(stderr,
804 "Setting page no %lu free bits to %lu should be %lu\n",
805 buf_frame_get_page_no(page), val,
806 ibuf_index_page_calc_free(page));
807 # endif
809 ut_a(val <= ibuf_index_page_calc_free(page));
810 #endif /* UNIV_IBUF_DEBUG */
811 ibuf_bitmap_page_set_bits(bitmap_page, buf_frame_get_page_no(page),
812 IBUF_BITMAP_FREE, val, mtr);
816 /****************************************************************************
817 Sets the free bit of the page in the ibuf bitmap. This is done in a separate
818 mini-transaction, hence this operation does not restrict further work to only
819 ibuf bitmap operations, which would result if the latch to the bitmap page
820 were kept. */
822 void
823 ibuf_set_free_bits(
824 /*===============*/
825 ulint type, /* in: index type */
826 page_t* page, /* in: index page; free bit is set if the index is
827 non-clustered and page level is 0 */
828 ulint val, /* in: value to set: < 4 */
829 ulint max_val)/* in: ULINT_UNDEFINED or a maximum value which
830 the bits must have before setting; this is for
831 debugging */
833 mtr_t mtr;
834 page_t* bitmap_page;
836 if (type & DICT_CLUSTERED) {
838 return;
841 if (btr_page_get_level_low(page) != 0) {
843 return;
846 mtr_start(&mtr);
848 bitmap_page = ibuf_bitmap_get_map_page(
849 buf_frame_get_space_id(page), buf_frame_get_page_no(page),
850 &mtr);
852 if (max_val != ULINT_UNDEFINED) {
853 #ifdef UNIV_IBUF_DEBUG
854 ulint old_val;
856 old_val = ibuf_bitmap_page_get_bits(
857 bitmap_page, buf_frame_get_page_no(page),
858 IBUF_BITMAP_FREE, &mtr);
859 # if 0
860 if (old_val != max_val) {
861 fprintf(stderr,
862 "Ibuf: page %lu old val %lu max val %lu\n",
863 buf_frame_get_page_no(page),
864 old_val, max_val);
866 # endif
868 ut_a(old_val <= max_val);
869 #endif
871 #ifdef UNIV_IBUF_DEBUG
872 # if 0
873 fprintf(stderr, "Setting page no %lu free bits to %lu should be %lu\n",
874 buf_frame_get_page_no(page), val,
875 ibuf_index_page_calc_free(page));
876 # endif
878 ut_a(val <= ibuf_index_page_calc_free(page));
879 #endif
880 ibuf_bitmap_page_set_bits(bitmap_page, buf_frame_get_page_no(page),
881 IBUF_BITMAP_FREE, val, &mtr);
882 mtr_commit(&mtr);
885 /****************************************************************************
886 Resets the free bits of the page in the ibuf bitmap. This is done in a
887 separate mini-transaction, hence this operation does not restrict further
888 work to only ibuf bitmap operations, which would result if the latch to the
889 bitmap page were kept. */
891 void
892 ibuf_reset_free_bits_with_type(
893 /*===========================*/
894 ulint type, /* in: index type */
895 page_t* page) /* in: index page; free bits are set to 0 if the index
896 is non-clustered and non-unique and the page level is
897 0 */
899 ibuf_set_free_bits(type, page, 0, ULINT_UNDEFINED);
902 /****************************************************************************
903 Resets the free bits of the page in the ibuf bitmap. This is done in a
904 separate mini-transaction, hence this operation does not restrict further
905 work to solely ibuf bitmap operations, which would result if the latch to
906 the bitmap page were kept. */
908 void
909 ibuf_reset_free_bits(
910 /*=================*/
911 dict_index_t* index, /* in: index */
912 page_t* page) /* in: index page; free bits are set to 0 if
913 the index is non-clustered and non-unique and
914 the page level is 0 */
916 ibuf_set_free_bits(index->type, page, 0, ULINT_UNDEFINED);
919 /**************************************************************************
920 Updates the free bits for a page to reflect the present state. Does this
921 in the mtr given, which means that the latching order rules virtually prevent
922 any further operations for this OS thread until mtr is committed. */
924 void
925 ibuf_update_free_bits_low(
926 /*======================*/
927 dict_index_t* index, /* in: index */
928 page_t* page, /* in: index page */
929 ulint max_ins_size, /* in: value of maximum insert size
930 with reorganize before the latest
931 operation performed to the page */
932 mtr_t* mtr) /* in: mtr */
934 ulint before;
935 ulint after;
937 before = ibuf_index_page_calc_free_bits(max_ins_size);
939 after = ibuf_index_page_calc_free(page);
941 if (before != after) {
942 ibuf_set_free_bits_low(index->type, page, after, mtr);
946 /**************************************************************************
947 Updates the free bits for the two pages to reflect the present state. Does
948 this in the mtr given, which means that the latching order rules virtually
949 prevent any further operations until mtr is committed. */
951 void
952 ibuf_update_free_bits_for_two_pages_low(
953 /*====================================*/
954 dict_index_t* index, /* in: index */
955 page_t* page1, /* in: index page */
956 page_t* page2, /* in: index page */
957 mtr_t* mtr) /* in: mtr */
959 ulint state;
961 /* As we have to x-latch two random bitmap pages, we have to acquire
962 the bitmap mutex to prevent a deadlock with a similar operation
963 performed by another OS thread. */
965 mutex_enter(&ibuf_bitmap_mutex);
967 state = ibuf_index_page_calc_free(page1);
969 ibuf_set_free_bits_low(index->type, page1, state, mtr);
971 state = ibuf_index_page_calc_free(page2);
973 ibuf_set_free_bits_low(index->type, page2, state, mtr);
975 mutex_exit(&ibuf_bitmap_mutex);
978 /**************************************************************************
979 Returns TRUE if the page is one of the fixed address ibuf pages. */
980 UNIV_INLINE
981 ibool
982 ibuf_fixed_addr_page(
983 /*=================*/
984 /* out: TRUE if a fixed address ibuf i/o page */
985 ulint space, /* in: space id */
986 ulint page_no)/* in: page number */
988 return((space == 0 && page_no == IBUF_TREE_ROOT_PAGE_NO)
989 || ibuf_bitmap_page(page_no));
992 /***************************************************************************
993 Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */
995 ibool
996 ibuf_page(
997 /*======*/
998 /* out: TRUE if level 2 or level 3 page */
999 ulint space, /* in: space id */
1000 ulint page_no)/* in: page number */
1002 page_t* bitmap_page;
1003 mtr_t mtr;
1004 ibool ret;
1006 if (recv_no_ibuf_operations) {
1007 /* Recovery is running: no ibuf operations should be
1008 performed */
1010 return(FALSE);
1013 if (ibuf_fixed_addr_page(space, page_no)) {
1015 return(TRUE);
1018 if (space != 0) {
1019 /* Currently we only have an ibuf tree in space 0 */
1021 return(FALSE);
1024 ut_ad(fil_space_get_type(space) == FIL_TABLESPACE);
1026 mtr_start(&mtr);
1028 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
1030 ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
1031 &mtr);
1032 mtr_commit(&mtr);
1034 return(ret);
1037 /***************************************************************************
1038 Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */
1040 ibool
1041 ibuf_page_low(
1042 /*==========*/
1043 /* out: TRUE if level 2 or level 3 page */
1044 ulint space, /* in: space id */
1045 ulint page_no,/* in: page number */
1046 mtr_t* mtr) /* in: mtr which will contain an x-latch to the
1047 bitmap page if the page is not one of the fixed
1048 address ibuf pages */
1050 page_t* bitmap_page;
1051 ibool ret;
1053 if (ibuf_fixed_addr_page(space, page_no)) {
1055 return(TRUE);
1058 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, mtr);
1060 ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
1061 mtr);
1062 return(ret);
1065 /************************************************************************
1066 Returns the page number field of an ibuf record. */
1067 static
1068 ulint
1069 ibuf_rec_get_page_no(
1070 /*=================*/
1071 /* out: page number */
1072 rec_t* rec) /* in: ibuf record */
1074 byte* field;
1075 ulint len;
1077 ut_ad(ibuf_inside());
1078 ut_ad(rec_get_n_fields_old(rec) > 2);
1080 field = rec_get_nth_field_old(rec, 1, &len);
1082 if (len == 1) {
1083 /* This is of the >= 4.1.x record format */
1084 ut_a(trx_sys_multiple_tablespace_format);
1086 field = rec_get_nth_field_old(rec, 2, &len);
1087 } else {
1088 ut_a(trx_doublewrite_must_reset_space_ids);
1089 ut_a(!trx_sys_multiple_tablespace_format);
1091 field = rec_get_nth_field_old(rec, 0, &len);
1094 ut_a(len == 4);
1096 return(mach_read_from_4(field));
1099 /************************************************************************
1100 Returns the space id field of an ibuf record. For < 4.1.x format records
1101 returns 0. */
1102 static
1103 ulint
1104 ibuf_rec_get_space(
1105 /*===============*/
1106 /* out: space id */
1107 rec_t* rec) /* in: ibuf record */
1109 byte* field;
1110 ulint len;
1112 ut_ad(ibuf_inside());
1113 ut_ad(rec_get_n_fields_old(rec) > 2);
1115 field = rec_get_nth_field_old(rec, 1, &len);
1117 if (len == 1) {
1118 /* This is of the >= 4.1.x record format */
1120 ut_a(trx_sys_multiple_tablespace_format);
1121 field = rec_get_nth_field_old(rec, 0, &len);
1122 ut_a(len == 4);
1124 return(mach_read_from_4(field));
1127 ut_a(trx_doublewrite_must_reset_space_ids);
1128 ut_a(!trx_sys_multiple_tablespace_format);
1130 return(0);
1133 /************************************************************************
1134 Creates a dummy index for inserting a record to a non-clustered index.
1136 static
1137 dict_index_t*
1138 ibuf_dummy_index_create(
1139 /*====================*/
1140 /* out: dummy index */
1141 ulint n, /* in: number of fields */
1142 ibool comp) /* in: TRUE=use compact record format */
1144 dict_table_t* table;
1145 dict_index_t* index;
1147 table = dict_mem_table_create("IBUF_DUMMY",
1148 DICT_HDR_SPACE, n,
1149 comp ? DICT_TF_COMPACT : 0);
1151 index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY",
1152 DICT_HDR_SPACE, 0, n);
1154 index->table = table;
1156 /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
1157 index->cached = TRUE;
1159 return(index);
1161 /************************************************************************
1162 Add a column to the dummy index */
1163 static
1164 void
1165 ibuf_dummy_index_add_col(
1166 /*=====================*/
1167 dict_index_t* index, /* in: dummy index */
1168 dtype_t* type, /* in: the data type of the column */
1169 ulint len) /* in: length of the column */
1171 ulint i = index->table->n_def;
1172 dict_mem_table_add_col(index->table, NULL, NULL,
1173 dtype_get_mtype(type),
1174 dtype_get_prtype(type),
1175 dtype_get_len(type));
1176 dict_index_add_col(index, index->table, (dict_col_t*)
1177 dict_table_get_nth_col(index->table, i), len);
1179 /************************************************************************
1180 Deallocates a dummy index for inserting a record to a non-clustered index.
1182 static
1183 void
1184 ibuf_dummy_index_free(
1185 /*==================*/
1186 dict_index_t* index) /* in: dummy index */
1188 dict_table_t* table = index->table;
1190 dict_mem_index_free(index);
1191 dict_mem_table_free(table);
1194 /*************************************************************************
1195 Builds the entry to insert into a non-clustered index when we have the
1196 corresponding record in an ibuf index. */
1197 static
1198 dtuple_t*
1199 ibuf_build_entry_from_ibuf_rec(
1200 /*===========================*/
1201 /* out, own: entry to insert to
1202 a non-clustered index; NOTE that
1203 as we copy pointers to fields in
1204 ibuf_rec, the caller must hold a
1205 latch to the ibuf_rec page as long
1206 as the entry is used! */
1207 rec_t* ibuf_rec, /* in: record in an insert buffer */
1208 mem_heap_t* heap, /* in: heap where built */
1209 dict_index_t** pindex) /* out, own: dummy index that
1210 describes the entry */
1212 dtuple_t* tuple;
1213 dfield_t* field;
1214 ulint n_fields;
1215 byte* types;
1216 const byte* data;
1217 ulint len;
1218 ulint i;
1219 dict_index_t* index;
1221 data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1223 if (len > 1) {
1224 /* This a < 4.1.x format record */
1226 ut_a(trx_doublewrite_must_reset_space_ids);
1227 ut_a(!trx_sys_multiple_tablespace_format);
1229 n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
1230 tuple = dtuple_create(heap, n_fields);
1231 types = rec_get_nth_field_old(ibuf_rec, 1, &len);
1233 ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1235 for (i = 0; i < n_fields; i++) {
1236 field = dtuple_get_nth_field(tuple, i);
1238 data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1240 dfield_set_data(field, data, len);
1242 dtype_read_for_order_and_null_size(
1243 dfield_get_type(field),
1244 types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1247 *pindex = ibuf_dummy_index_create(n_fields, FALSE);
1248 return(tuple);
1251 /* This a >= 4.1.x format record */
1253 ut_a(trx_sys_multiple_tablespace_format);
1254 ut_a(*data == 0);
1255 ut_a(rec_get_n_fields_old(ibuf_rec) > 4);
1257 n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1259 tuple = dtuple_create(heap, n_fields);
1261 types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1263 ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
1264 index = ibuf_dummy_index_create(
1265 n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1267 if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
1268 /* compact record format */
1269 len--;
1270 ut_a(*types == 0);
1271 types++;
1274 ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1276 for (i = 0; i < n_fields; i++) {
1277 field = dtuple_get_nth_field(tuple, i);
1279 data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1281 dfield_set_data(field, data, len);
1283 dtype_new_read_for_order_and_null_size(
1284 dfield_get_type(field),
1285 types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1287 ibuf_dummy_index_add_col(index, dfield_get_type(field), len);
1290 *pindex = index;
1291 return(tuple);
1294 /************************************************************************
1295 Returns the space taken by a stored non-clustered index entry if converted to
1296 an index record. */
1297 static
1298 ulint
1299 ibuf_rec_get_volume(
1300 /*================*/
1301 /* out: size of index record in bytes + an upper
1302 limit of the space taken in the page directory */
1303 rec_t* ibuf_rec)/* in: ibuf record */
1305 dtype_t dtype;
1306 ibool new_format = FALSE;
1307 ulint data_size = 0;
1308 ulint n_fields;
1309 byte* types;
1310 byte* data;
1311 ulint len;
1312 ulint i;
1314 ut_ad(ibuf_inside());
1315 ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
1317 data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1319 if (len > 1) {
1320 /* < 4.1.x format record */
1322 ut_a(trx_doublewrite_must_reset_space_ids);
1323 ut_a(!trx_sys_multiple_tablespace_format);
1325 n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
1327 types = rec_get_nth_field_old(ibuf_rec, 1, &len);
1329 ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1330 } else {
1331 /* >= 4.1.x format record */
1333 ut_a(trx_sys_multiple_tablespace_format);
1334 ut_a(*data == 0);
1336 types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1338 ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
1339 if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
1340 /* compact record format */
1341 ulint volume;
1342 dict_index_t* dummy_index;
1343 mem_heap_t* heap = mem_heap_create(500);
1344 dtuple_t* entry = ibuf_build_entry_from_ibuf_rec(
1345 ibuf_rec, heap, &dummy_index);
1346 volume = rec_get_converted_size(dummy_index, entry);
1347 ibuf_dummy_index_free(dummy_index);
1348 mem_heap_free(heap);
1349 return(volume + page_dir_calc_reserved_space(1));
1352 n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1354 new_format = TRUE;
1357 for (i = 0; i < n_fields; i++) {
1358 if (new_format) {
1359 data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1361 dtype_new_read_for_order_and_null_size(
1362 &dtype, types + i
1363 * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1364 } else {
1365 data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1367 dtype_read_for_order_and_null_size(
1368 &dtype, types + i
1369 * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1372 if (len == UNIV_SQL_NULL) {
1373 data_size += dtype_get_sql_null_size(&dtype);
1374 } else {
1375 data_size += len;
1379 return(data_size + rec_get_converted_extra_size(data_size, n_fields)
1380 + page_dir_calc_reserved_space(1));
1383 /*************************************************************************
1384 Builds the tuple to insert to an ibuf tree when we have an entry for a
1385 non-clustered index. */
1386 static
1387 dtuple_t*
1388 ibuf_entry_build(
1389 /*=============*/
1390 /* out, own: entry to insert into an ibuf
1391 index tree; NOTE that the original entry
1392 must be kept because we copy pointers to its
1393 fields */
1394 dict_index_t* index, /* in: non-clustered index */
1395 dtuple_t* entry, /* in: entry for a non-clustered index */
1396 ulint space, /* in: space id */
1397 ulint page_no,/* in: index page number where entry should
1398 be inserted */
1399 mem_heap_t* heap) /* in: heap into which to build */
1401 dtuple_t* tuple;
1402 dfield_t* field;
1403 dfield_t* entry_field;
1404 ulint n_fields;
1405 byte* buf;
1406 byte* buf2;
1407 ulint i;
1409 /* Starting from 4.1.x, we have to build a tuple whose
1410 (1) first field is the space id,
1411 (2) the second field a single marker byte (0) to tell that this
1412 is a new format record,
1413 (3) the third contains the page number, and
1414 (4) the fourth contains the relevent type information of each data
1415 field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is
1416 (a) 0 for b-trees in the old format, and
1417 (b) 1 for b-trees in the compact format, the first byte of the field
1418 being the marker (0);
1419 (5) and the rest of the fields are copied from entry. All fields
1420 in the tuple are ordered like the type binary in our insert buffer
1421 tree. */
1423 n_fields = dtuple_get_n_fields(entry);
1425 tuple = dtuple_create(heap, n_fields + 4);
1427 /* Store the space id in tuple */
1429 field = dtuple_get_nth_field(tuple, 0);
1431 buf = mem_heap_alloc(heap, 4);
1433 mach_write_to_4(buf, space);
1435 dfield_set_data(field, buf, 4);
1437 /* Store the marker byte field in tuple */
1439 field = dtuple_get_nth_field(tuple, 1);
1441 buf = mem_heap_alloc(heap, 1);
1443 /* We set the marker byte zero */
1445 mach_write_to_1(buf, 0);
1447 dfield_set_data(field, buf, 1);
1449 /* Store the page number in tuple */
1451 field = dtuple_get_nth_field(tuple, 2);
1453 buf = mem_heap_alloc(heap, 4);
1455 mach_write_to_4(buf, page_no);
1457 dfield_set_data(field, buf, 4);
1459 /* Store the type info in buf2, and add the fields from entry to
1460 tuple */
1461 buf2 = mem_heap_alloc(heap, n_fields
1462 * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1463 + dict_table_is_comp(index->table));
1464 if (dict_table_is_comp(index->table)) {
1465 *buf2++ = 0; /* write the compact format indicator */
1467 for (i = 0; i < n_fields; i++) {
1468 ulint fixed_len;
1469 const dict_field_t* ifield;
1471 /* We add 4 below because we have the 4 extra fields at the
1472 start of an ibuf record */
1474 field = dtuple_get_nth_field(tuple, i + 4);
1475 entry_field = dtuple_get_nth_field(entry, i);
1476 dfield_copy(field, entry_field);
1478 ifield = dict_index_get_nth_field(index, i);
1479 /* Prefix index columns of fixed-length columns are of
1480 fixed length. However, in the function call below,
1481 dfield_get_type(entry_field) contains the fixed length
1482 of the column in the clustered index. Replace it with
1483 the fixed length of the secondary index column. */
1484 fixed_len = ifield->fixed_len;
1486 #ifdef UNIV_DEBUG
1487 if (fixed_len) {
1488 /* dict_index_add_col() should guarantee these */
1489 ut_ad(fixed_len <= (ulint) entry_field->type.len);
1490 if (ifield->prefix_len) {
1491 ut_ad(ifield->prefix_len == fixed_len);
1492 } else {
1493 ut_ad(fixed_len
1494 == (ulint) entry_field->type.len);
1497 #endif /* UNIV_DEBUG */
1499 dtype_new_store_for_order_and_null_size(
1500 buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
1501 dfield_get_type(entry_field), fixed_len);
1504 /* Store the type info in buf2 to field 3 of tuple */
1506 field = dtuple_get_nth_field(tuple, 3);
1508 if (dict_table_is_comp(index->table)) {
1509 buf2--;
1512 dfield_set_data(field, buf2, n_fields
1513 * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1514 + dict_table_is_comp(index->table));
1515 /* Set all the types in the new tuple binary */
1517 dtuple_set_types_binary(tuple, n_fields + 4);
1519 return(tuple);
1522 /*************************************************************************
1523 Builds a search tuple used to search buffered inserts for an index page.
1524 This is for < 4.1.x format records */
1525 static
1526 dtuple_t*
1527 ibuf_search_tuple_build(
1528 /*====================*/
1529 /* out, own: search tuple */
1530 ulint space, /* in: space id */
1531 ulint page_no,/* in: index page number */
1532 mem_heap_t* heap) /* in: heap into which to build */
1534 dtuple_t* tuple;
1535 dfield_t* field;
1536 byte* buf;
1538 ut_a(space == 0);
1539 ut_a(trx_doublewrite_must_reset_space_ids);
1540 ut_a(!trx_sys_multiple_tablespace_format);
1542 tuple = dtuple_create(heap, 1);
1544 /* Store the page number in tuple */
1546 field = dtuple_get_nth_field(tuple, 0);
1548 buf = mem_heap_alloc(heap, 4);
1550 mach_write_to_4(buf, page_no);
1552 dfield_set_data(field, buf, 4);
1554 dtuple_set_types_binary(tuple, 1);
1556 return(tuple);
1559 /*************************************************************************
1560 Builds a search tuple used to search buffered inserts for an index page.
1561 This is for >= 4.1.x format records. */
1562 static
1563 dtuple_t*
1564 ibuf_new_search_tuple_build(
1565 /*========================*/
1566 /* out, own: search tuple */
1567 ulint space, /* in: space id */
1568 ulint page_no,/* in: index page number */
1569 mem_heap_t* heap) /* in: heap into which to build */
1571 dtuple_t* tuple;
1572 dfield_t* field;
1573 byte* buf;
1575 ut_a(trx_sys_multiple_tablespace_format);
1577 tuple = dtuple_create(heap, 3);
1579 /* Store the space id in tuple */
1581 field = dtuple_get_nth_field(tuple, 0);
1583 buf = mem_heap_alloc(heap, 4);
1585 mach_write_to_4(buf, space);
1587 dfield_set_data(field, buf, 4);
1589 /* Store the new format record marker byte */
1591 field = dtuple_get_nth_field(tuple, 1);
1593 buf = mem_heap_alloc(heap, 1);
1595 mach_write_to_1(buf, 0);
1597 dfield_set_data(field, buf, 1);
1599 /* Store the page number in tuple */
1601 field = dtuple_get_nth_field(tuple, 2);
1603 buf = mem_heap_alloc(heap, 4);
1605 mach_write_to_4(buf, page_no);
1607 dfield_set_data(field, buf, 4);
1609 dtuple_set_types_binary(tuple, 3);
1611 return(tuple);
1614 /*************************************************************************
1615 Checks if there are enough pages in the free list of the ibuf tree that we
1616 dare to start a pessimistic insert to the insert buffer. */
1617 UNIV_INLINE
1618 ibool
1619 ibuf_data_enough_free_for_insert(
1620 /*=============================*/
1621 /* out: TRUE if enough free pages in list */
1622 ibuf_data_t* data) /* in: ibuf data for the space */
1624 ut_ad(mutex_own(&ibuf_mutex));
1626 /* We want a big margin of free pages, because a B-tree can sometimes
1627 grow in size also if records are deleted from it, as the node pointers
1628 can change, and we must make sure that we are able to delete the
1629 inserts buffered for pages that we read to the buffer pool, without
1630 any risk of running out of free space in the insert buffer. */
1632 if (data->free_list_len >= data->size / 2 + 3 * data->height) {
1634 return(TRUE);
1637 return(FALSE);
1640 /*************************************************************************
1641 Checks if there are enough pages in the free list of the ibuf tree that we
1642 should remove them and free to the file space management. */
1643 UNIV_INLINE
1644 ibool
1645 ibuf_data_too_much_free(
1646 /*====================*/
1647 /* out: TRUE if enough free pages in list */
1648 ibuf_data_t* data) /* in: ibuf data for the space */
1650 ut_ad(mutex_own(&ibuf_mutex));
1652 return(data->free_list_len >= 3 + data->size / 2 + 3 * data->height);
1655 /*************************************************************************
1656 Allocates a new page from the ibuf file segment and adds it to the free
1657 list. */
1658 static
1659 ulint
1660 ibuf_add_free_page(
1661 /*===============*/
1662 /* out: DB_SUCCESS, or DB_STRONG_FAIL
1663 if no space left */
1664 ulint space, /* in: space id */
1665 ibuf_data_t* ibuf_data) /* in: ibuf data for the space */
1667 mtr_t mtr;
1668 page_t* header_page;
1669 ulint page_no;
1670 page_t* page;
1671 page_t* root;
1672 page_t* bitmap_page;
1674 ut_a(space == 0);
1676 mtr_start(&mtr);
1678 /* Acquire the fsp latch before the ibuf header, obeying the latching
1679 order */
1680 mtr_x_lock(fil_space_get_latch(space), &mtr);
1682 header_page = ibuf_header_page_get(space, &mtr);
1684 /* Allocate a new page: NOTE that if the page has been a part of a
1685 non-clustered index which has subsequently been dropped, then the
1686 page may have buffered inserts in the insert buffer, and these
1687 should be deleted from there. These get deleted when the page
1688 allocation creates the page in buffer. Thus the call below may end
1689 up calling the insert buffer routines and, as we yet have no latches
1690 to insert buffer tree pages, these routines can run without a risk
1691 of a deadlock. This is the reason why we created a special ibuf
1692 header page apart from the ibuf tree. */
1694 page_no = fseg_alloc_free_page(header_page + IBUF_HEADER
1695 + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
1696 &mtr);
1697 if (page_no == FIL_NULL) {
1698 mtr_commit(&mtr);
1700 return(DB_STRONG_FAIL);
1703 page = buf_page_get(space, page_no, RW_X_LATCH, &mtr);
1705 ibuf_enter();
1707 mutex_enter(&ibuf_mutex);
1709 root = ibuf_tree_root_get(ibuf_data, space, &mtr);
1711 #ifdef UNIV_SYNC_DEBUG
1712 buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW);
1713 #endif /* UNIV_SYNC_DEBUG */
1715 /* Add the page to the free list and update the ibuf size data */
1717 flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1718 page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
1720 mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_IBUF_FREE_LIST,
1721 MLOG_2BYTES, &mtr);
1723 ibuf_data->seg_size++;
1724 ibuf_data->free_list_len++;
1726 /* Set the bit indicating that this page is now an ibuf tree page
1727 (level 2 page) */
1729 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
1731 ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
1732 TRUE, &mtr);
1733 mtr_commit(&mtr);
1735 mutex_exit(&ibuf_mutex);
1737 ibuf_exit();
1739 return(DB_SUCCESS);
1742 /*************************************************************************
1743 Removes a page from the free list and frees it to the fsp system. */
1744 static
1745 void
1746 ibuf_remove_free_page(
1747 /*==================*/
1748 ulint space, /* in: space id */
1749 ibuf_data_t* ibuf_data) /* in: ibuf data for the space */
1751 mtr_t mtr;
1752 mtr_t mtr2;
1753 page_t* header_page;
1754 ulint page_no;
1755 page_t* page;
1756 page_t* root;
1757 page_t* bitmap_page;
1759 ut_a(space == 0);
1761 mtr_start(&mtr);
1763 /* Acquire the fsp latch before the ibuf header, obeying the latching
1764 order */
1765 mtr_x_lock(fil_space_get_latch(space), &mtr);
1767 header_page = ibuf_header_page_get(space, &mtr);
1769 /* Prevent pessimistic inserts to insert buffer trees for a while */
1770 mutex_enter(&ibuf_pessimistic_insert_mutex);
1772 ibuf_enter();
1774 mutex_enter(&ibuf_mutex);
1776 if (!ibuf_data_too_much_free(ibuf_data)) {
1778 mutex_exit(&ibuf_mutex);
1780 ibuf_exit();
1782 mutex_exit(&ibuf_pessimistic_insert_mutex);
1784 mtr_commit(&mtr);
1786 return;
1789 mtr_start(&mtr2);
1791 root = ibuf_tree_root_get(ibuf_data, space, &mtr2);
1793 page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1794 &mtr2)
1795 .page;
1797 /* NOTE that we must release the latch on the ibuf tree root
1798 because in fseg_free_page we access level 1 pages, and the root
1799 is a level 2 page. */
1801 mtr_commit(&mtr2);
1802 mutex_exit(&ibuf_mutex);
1804 ibuf_exit();
1806 /* Since pessimistic inserts were prevented, we know that the
1807 page is still in the free list. NOTE that also deletes may take
1808 pages from the free list, but they take them from the start, and
1809 the free list was so long that they cannot have taken the last
1810 page from it. */
1812 fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
1813 space, page_no, &mtr);
1814 #ifdef UNIV_DEBUG_FILE_ACCESSES
1815 buf_page_reset_file_page_was_freed(space, page_no);
1816 #endif
1817 ibuf_enter();
1819 mutex_enter(&ibuf_mutex);
1821 root = ibuf_tree_root_get(ibuf_data, space, &mtr);
1823 ut_ad(page_no == flst_get_last(root + PAGE_HEADER
1824 + PAGE_BTR_IBUF_FREE_LIST, &mtr)
1825 .page);
1827 page = buf_page_get(space, page_no, RW_X_LATCH, &mtr);
1829 #ifdef UNIV_SYNC_DEBUG
1830 buf_page_dbg_add_level(page, SYNC_TREE_NODE);
1831 #endif /* UNIV_SYNC_DEBUG */
1833 /* Remove the page from the free list and update the ibuf size data */
1835 flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1836 page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
1838 ibuf_data->seg_size--;
1839 ibuf_data->free_list_len--;
1841 mutex_exit(&ibuf_pessimistic_insert_mutex);
1843 /* Set the bit indicating that this page is no more an ibuf tree page
1844 (level 2 page) */
1846 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
1848 ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
1849 FALSE, &mtr);
1850 #ifdef UNIV_DEBUG_FILE_ACCESSES
1851 buf_page_set_file_page_was_freed(space, page_no);
1852 #endif
1853 mtr_commit(&mtr);
1855 mutex_exit(&ibuf_mutex);
1857 ibuf_exit();
1860 /***************************************************************************
1861 Frees excess pages from the ibuf free list. This function is called when an OS
1862 thread calls fsp services to allocate a new file segment, or a new page to a
1863 file segment, and the thread did not own the fsp latch before this call. */
1865 void
1866 ibuf_free_excess_pages(
1867 /*===================*/
1868 ulint space) /* in: space id */
1870 ibuf_data_t* ibuf_data;
1871 ulint i;
1873 if (space != 0) {
1874 fprintf(stderr,
1875 "InnoDB: Error: calling ibuf_free_excess_pages"
1876 " for space %lu\n", (ulong) space);
1877 return;
1880 #ifdef UNIV_SYNC_DEBUG
1881 ut_ad(rw_lock_own(fil_space_get_latch(space), RW_LOCK_EX));
1882 #endif /* UNIV_SYNC_DEBUG */
1883 ut_ad(rw_lock_get_x_lock_count(fil_space_get_latch(space)) == 1);
1884 ut_ad(!ibuf_inside());
1886 /* NOTE: We require that the thread did not own the latch before,
1887 because then we know that we can obey the correct latching order
1888 for ibuf latches */
1890 ibuf_data = fil_space_get_ibuf_data(space);
1892 if (ibuf_data == NULL) {
1893 /* Not yet initialized */
1895 #if 0 /* defined UNIV_DEBUG */
1896 fprintf(stderr,
1897 "Ibuf for space %lu not yet initialized\n", space);
1898 #endif
1900 return;
1903 /* Free at most a few pages at a time, so that we do not delay the
1904 requested service too much */
1906 for (i = 0; i < 4; i++) {
1908 mutex_enter(&ibuf_mutex);
1910 if (!ibuf_data_too_much_free(ibuf_data)) {
1912 mutex_exit(&ibuf_mutex);
1914 return;
1917 mutex_exit(&ibuf_mutex);
1919 ibuf_remove_free_page(space, ibuf_data);
1923 /*************************************************************************
1924 Reads page numbers from a leaf in an ibuf tree. */
1925 static
1926 ulint
1927 ibuf_get_merge_page_nos(
1928 /*====================*/
1929 /* out: a lower limit for the combined volume
1930 of records which will be merged */
1931 ibool contract,/* in: TRUE if this function is called to
1932 contract the tree, FALSE if this is called
1933 when a single page becomes full and we look
1934 if it pays to read also nearby pages */
1935 rec_t* rec, /* in: record from which we read up and down
1936 in the chain of records */
1937 ulint* space_ids,/* in/out: space id's of the pages */
1938 ib_longlong* space_versions,/* in/out: tablespace version
1939 timestamps; used to prevent reading in old
1940 pages after DISCARD + IMPORT tablespace */
1941 ulint* page_nos,/* in/out: buffer for at least
1942 IBUF_MAX_N_PAGES_MERGED many page numbers;
1943 the page numbers are in an ascending order */
1944 ulint* n_stored)/* out: number of page numbers stored to
1945 page_nos in this function */
1947 ulint prev_page_no;
1948 ulint prev_space_id;
1949 ulint first_page_no;
1950 ulint first_space_id;
1951 ulint rec_page_no;
1952 ulint rec_space_id;
1953 ulint sum_volumes;
1954 ulint volume_for_page;
1955 ulint rec_volume;
1956 ulint limit;
1957 ulint n_pages;
1959 *n_stored = 0;
1961 limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
1963 if (page_rec_is_supremum(rec)) {
1965 rec = page_rec_get_prev(rec);
1968 if (page_rec_is_infimum(rec)) {
1970 rec = page_rec_get_next(rec);
1973 if (page_rec_is_supremum(rec)) {
1975 return(0);
1978 first_page_no = ibuf_rec_get_page_no(rec);
1979 first_space_id = ibuf_rec_get_space(rec);
1980 n_pages = 0;
1981 prev_page_no = 0;
1982 prev_space_id = 0;
1984 /* Go backwards from the first rec until we reach the border of the
1985 'merge area', or the page start or the limit of storeable pages is
1986 reached */
1988 while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) {
1990 rec_page_no = ibuf_rec_get_page_no(rec);
1991 rec_space_id = ibuf_rec_get_space(rec);
1993 if (rec_space_id != first_space_id
1994 || rec_page_no / IBUF_MERGE_AREA
1995 != first_page_no / IBUF_MERGE_AREA) {
1997 break;
2000 if (rec_page_no != prev_page_no
2001 || rec_space_id != prev_space_id) {
2002 n_pages++;
2005 prev_page_no = rec_page_no;
2006 prev_space_id = rec_space_id;
2008 rec = page_rec_get_prev(rec);
2011 rec = page_rec_get_next(rec);
2013 /* At the loop start there is no prev page; we mark this with a pair
2014 of space id, page no (0, 0) for which there can never be entries in
2015 the insert buffer */
2017 prev_page_no = 0;
2018 prev_space_id = 0;
2019 sum_volumes = 0;
2020 volume_for_page = 0;
2022 while (*n_stored < limit) {
2023 if (page_rec_is_supremum(rec)) {
2024 /* When no more records available, mark this with
2025 another 'impossible' pair of space id, page no */
2026 rec_page_no = 1;
2027 rec_space_id = 0;
2028 } else {
2029 rec_page_no = ibuf_rec_get_page_no(rec);
2030 rec_space_id = ibuf_rec_get_space(rec);
2031 /* In the system tablespace, the smallest
2032 possible secondary index leaf page number is
2033 bigger than IBUF_TREE_ROOT_PAGE_NO (4). In
2034 other tablespaces, the clustered index tree is
2035 created at page 3, which makes page 4 the
2036 smallest possible secondary index leaf page
2037 (and that only after DROP INDEX). */
2038 ut_ad(rec_page_no
2039 > IBUF_TREE_ROOT_PAGE_NO - (rec_space_id != 0));
2042 #ifdef UNIV_IBUF_DEBUG
2043 ut_a(*n_stored < IBUF_MAX_N_PAGES_MERGED);
2044 #endif
2045 if ((rec_space_id != prev_space_id
2046 || rec_page_no != prev_page_no)
2047 && (prev_space_id != 0 || prev_page_no != 0)) {
2049 if ((prev_page_no == first_page_no
2050 && prev_space_id == first_space_id)
2051 || contract
2052 || (volume_for_page
2053 > ((IBUF_MERGE_THRESHOLD - 1)
2054 * 4 * UNIV_PAGE_SIZE
2055 / IBUF_PAGE_SIZE_PER_FREE_SPACE)
2056 / IBUF_MERGE_THRESHOLD)) {
2058 space_ids[*n_stored] = prev_space_id;
2059 space_versions[*n_stored]
2060 = fil_space_get_version(prev_space_id);
2061 page_nos[*n_stored] = prev_page_no;
2063 (*n_stored)++;
2065 sum_volumes += volume_for_page;
2068 if (rec_space_id != first_space_id
2069 || rec_page_no / IBUF_MERGE_AREA
2070 != first_page_no / IBUF_MERGE_AREA) {
2072 break;
2075 volume_for_page = 0;
2078 if (rec_page_no == 1 && rec_space_id == 0) {
2079 /* Supremum record */
2081 break;
2084 rec_volume = ibuf_rec_get_volume(rec);
2086 volume_for_page += rec_volume;
2088 prev_page_no = rec_page_no;
2089 prev_space_id = rec_space_id;
2091 rec = page_rec_get_next(rec);
2094 #ifdef UNIV_IBUF_DEBUG
2095 ut_a(*n_stored <= IBUF_MAX_N_PAGES_MERGED);
2096 #endif
2097 #if 0
2098 fprintf(stderr, "Ibuf merge batch %lu pages %lu volume\n",
2099 *n_stored, sum_volumes);
2100 #endif
2101 return(sum_volumes);
2104 /*************************************************************************
2105 Contracts insert buffer trees by reading pages to the buffer pool. */
2106 static
2107 ulint
2108 ibuf_contract_ext(
2109 /*==============*/
2110 /* out: a lower limit for the combined size in bytes
2111 of entries which will be merged from ibuf trees to the
2112 pages read, 0 if ibuf is empty */
2113 ulint* n_pages,/* out: number of pages to which merged */
2114 ibool sync) /* in: TRUE if the caller wants to wait for the
2115 issued read with the highest tablespace address
2116 to complete */
2118 ulint rnd_pos;
2119 ibuf_data_t* data;
2120 btr_pcur_t pcur;
2121 ulint space;
2122 ibool all_trees_empty;
2123 ulint page_nos[IBUF_MAX_N_PAGES_MERGED];
2124 ulint space_ids[IBUF_MAX_N_PAGES_MERGED];
2125 ib_longlong space_versions[IBUF_MAX_N_PAGES_MERGED];
2126 ulint n_stored;
2127 ulint sum_sizes;
2128 mtr_t mtr;
2130 *n_pages = 0;
2131 loop:
2132 ut_ad(!ibuf_inside());
2134 mutex_enter(&ibuf_mutex);
2136 ut_ad(ibuf_validate_low());
2138 /* Choose an ibuf tree at random (though there really is only one tree
2139 in the current implementation) */
2140 ibuf_rnd += 865558671;
2142 rnd_pos = ibuf_rnd % ibuf->size;
2144 all_trees_empty = TRUE;
2146 data = UT_LIST_GET_FIRST(ibuf->data_list);
2148 for (;;) {
2149 if (!data->empty) {
2150 all_trees_empty = FALSE;
2152 if (rnd_pos < data->size) {
2154 break;
2157 rnd_pos -= data->size;
2160 data = UT_LIST_GET_NEXT(data_list, data);
2162 if (data == NULL) {
2163 if (all_trees_empty) {
2164 mutex_exit(&ibuf_mutex);
2166 return(0);
2169 data = UT_LIST_GET_FIRST(ibuf->data_list);
2173 ut_ad(data);
2175 space = data->index->space;
2177 ut_a(space == 0); /* We currently only have an ibuf tree in
2178 space 0 */
2179 mtr_start(&mtr);
2181 ibuf_enter();
2183 /* Open a cursor to a randomly chosen leaf of the tree, at a random
2184 position within the leaf */
2186 btr_pcur_open_at_rnd_pos(data->index, BTR_SEARCH_LEAF, &pcur, &mtr);
2188 if (0 == page_get_n_recs(btr_pcur_get_page(&pcur))) {
2190 /* This tree is empty */
2192 data->empty = TRUE;
2194 ibuf_exit();
2196 mtr_commit(&mtr);
2197 btr_pcur_close(&pcur);
2199 mutex_exit(&ibuf_mutex);
2201 goto loop;
2204 mutex_exit(&ibuf_mutex);
2206 sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
2207 space_ids, space_versions,
2208 page_nos, &n_stored);
2209 #if 0 /* defined UNIV_IBUF_DEBUG */
2210 fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
2211 sync, n_stored, sum_sizes);
2212 #endif
2213 ibuf_exit();
2215 mtr_commit(&mtr);
2216 btr_pcur_close(&pcur);
2218 buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos,
2219 n_stored);
2220 *n_pages = n_stored;
2222 return(sum_sizes + 1);
2225 /*************************************************************************
2226 Contracts insert buffer trees by reading pages to the buffer pool. */
2228 ulint
2229 ibuf_contract(
2230 /*==========*/
2231 /* out: a lower limit for the combined size in bytes
2232 of entries which will be merged from ibuf trees to the
2233 pages read, 0 if ibuf is empty */
2234 ibool sync) /* in: TRUE if the caller wants to wait for the
2235 issued read with the highest tablespace address
2236 to complete */
2238 ulint n_pages;
2240 return(ibuf_contract_ext(&n_pages, sync));
2243 /*************************************************************************
2244 Contracts insert buffer trees by reading pages to the buffer pool. */
2246 ulint
2247 ibuf_contract_for_n_pages(
2248 /*======================*/
2249 /* out: a lower limit for the combined size in bytes
2250 of entries which will be merged from ibuf trees to the
2251 pages read, 0 if ibuf is empty */
2252 ibool sync, /* in: TRUE if the caller wants to wait for the
2253 issued read with the highest tablespace address
2254 to complete */
2255 ulint n_pages)/* in: try to read at least this many pages to
2256 the buffer pool and merge the ibuf contents to
2257 them */
2259 ulint sum_bytes = 0;
2260 ulint sum_pages = 0;
2261 ulint n_bytes;
2262 ulint n_pag2;
2264 while (sum_pages < n_pages) {
2265 n_bytes = ibuf_contract_ext(&n_pag2, sync);
2267 if (n_bytes == 0) {
2268 return(sum_bytes);
2271 sum_bytes += n_bytes;
2272 sum_pages += n_pag2;
2275 return(sum_bytes);
2278 /*************************************************************************
2279 Contract insert buffer trees after insert if they are too big. */
2280 UNIV_INLINE
2281 void
2282 ibuf_contract_after_insert(
2283 /*=======================*/
2284 ulint entry_size) /* in: size of a record which was inserted
2285 into an ibuf tree */
2287 ibool sync;
2288 ulint sum_sizes;
2289 ulint size;
2291 mutex_enter(&ibuf_mutex);
2293 if (ibuf->size < ibuf->max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
2294 mutex_exit(&ibuf_mutex);
2296 return;
2299 sync = FALSE;
2301 if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_ON_INSERT_SYNC) {
2303 sync = TRUE;
2306 mutex_exit(&ibuf_mutex);
2308 /* Contract at least entry_size many bytes */
2309 sum_sizes = 0;
2310 size = 1;
2312 while ((size > 0) && (sum_sizes < entry_size)) {
2314 size = ibuf_contract(sync);
2315 sum_sizes += size;
2319 /*************************************************************************
2320 Gets an upper limit for the combined size of entries buffered in the insert
2321 buffer for a given page. */
2323 ulint
2324 ibuf_get_volume_buffered(
2325 /*=====================*/
2326 /* out: upper limit for the volume of
2327 buffered inserts for the index page, in bytes;
2328 we may also return UNIV_PAGE_SIZE, if the
2329 entries for the index page span on several
2330 pages in the insert buffer */
2331 btr_pcur_t* pcur, /* in: pcur positioned at a place in an
2332 insert buffer tree where we would insert an
2333 entry for the index page whose number is
2334 page_no, latch mode has to be BTR_MODIFY_PREV
2335 or BTR_MODIFY_TREE */
2336 ulint space, /* in: space id */
2337 ulint page_no,/* in: page number of an index page */
2338 mtr_t* mtr) /* in: mtr */
2340 ulint volume;
2341 rec_t* rec;
2342 page_t* page;
2343 ulint prev_page_no;
2344 page_t* prev_page;
2345 ulint next_page_no;
2346 page_t* next_page;
2348 ut_a(trx_sys_multiple_tablespace_format);
2350 ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
2351 || (pcur->latch_mode == BTR_MODIFY_TREE));
2353 /* Count the volume of records earlier in the alphabetical order than
2354 pcur */
2356 volume = 0;
2358 rec = btr_pcur_get_rec(pcur);
2360 page = buf_frame_align(rec);
2362 if (page_rec_is_supremum(rec)) {
2363 rec = page_rec_get_prev(rec);
2366 for (;;) {
2367 if (page_rec_is_infimum(rec)) {
2369 break;
2372 if (page_no != ibuf_rec_get_page_no(rec)
2373 || space != ibuf_rec_get_space(rec)) {
2375 goto count_later;
2378 volume += ibuf_rec_get_volume(rec);
2380 rec = page_rec_get_prev(rec);
2383 /* Look at the previous page */
2385 prev_page_no = btr_page_get_prev(page, mtr);
2387 if (prev_page_no == FIL_NULL) {
2389 goto count_later;
2392 prev_page = buf_page_get(0, prev_page_no, RW_X_LATCH, mtr);
2393 #ifdef UNIV_BTR_DEBUG
2394 ut_a(btr_page_get_next(prev_page, mtr)
2395 == buf_frame_get_page_no(page));
2396 #endif /* UNIV_BTR_DEBUG */
2398 #ifdef UNIV_SYNC_DEBUG
2399 buf_page_dbg_add_level(prev_page, SYNC_TREE_NODE);
2400 #endif /* UNIV_SYNC_DEBUG */
2402 rec = page_get_supremum_rec(prev_page);
2403 rec = page_rec_get_prev(rec);
2405 for (;;) {
2406 if (page_rec_is_infimum(rec)) {
2408 /* We cannot go to yet a previous page, because we
2409 do not have the x-latch on it, and cannot acquire one
2410 because of the latching order: we have to give up */
2412 return(UNIV_PAGE_SIZE);
2415 if (page_no != ibuf_rec_get_page_no(rec)
2416 || space != ibuf_rec_get_space(rec)) {
2418 goto count_later;
2421 volume += ibuf_rec_get_volume(rec);
2423 rec = page_rec_get_prev(rec);
2426 count_later:
2427 rec = btr_pcur_get_rec(pcur);
2429 if (!page_rec_is_supremum(rec)) {
2430 rec = page_rec_get_next(rec);
2433 for (;;) {
2434 if (page_rec_is_supremum(rec)) {
2436 break;
2439 if (page_no != ibuf_rec_get_page_no(rec)
2440 || space != ibuf_rec_get_space(rec)) {
2442 return(volume);
2445 volume += ibuf_rec_get_volume(rec);
2447 rec = page_rec_get_next(rec);
2450 /* Look at the next page */
2452 next_page_no = btr_page_get_next(page, mtr);
2454 if (next_page_no == FIL_NULL) {
2456 return(volume);
2459 next_page = buf_page_get(0, next_page_no, RW_X_LATCH, mtr);
2460 #ifdef UNIV_BTR_DEBUG
2461 ut_a(btr_page_get_prev(next_page, mtr)
2462 == buf_frame_get_page_no(page));
2463 #endif /* UNIV_BTR_DEBUG */
2465 #ifdef UNIV_SYNC_DEBUG
2466 buf_page_dbg_add_level(next_page, SYNC_TREE_NODE);
2467 #endif /* UNIV_SYNC_DEBUG */
2469 rec = page_get_infimum_rec(next_page);
2470 rec = page_rec_get_next(rec);
2472 for (;;) {
2473 if (page_rec_is_supremum(rec)) {
2475 /* We give up */
2477 return(UNIV_PAGE_SIZE);
2480 if (page_no != ibuf_rec_get_page_no(rec)
2481 || space != ibuf_rec_get_space(rec)) {
2483 return(volume);
2486 volume += ibuf_rec_get_volume(rec);
2488 rec = page_rec_get_next(rec);
2492 /*************************************************************************
2493 Reads the biggest tablespace id from the high end of the insert buffer
2494 tree and updates the counter in fil_system. */
2496 void
2497 ibuf_update_max_tablespace_id(void)
2498 /*===============================*/
2500 ulint max_space_id;
2501 rec_t* rec;
2502 byte* field;
2503 ulint len;
2504 ibuf_data_t* ibuf_data;
2505 dict_index_t* ibuf_index;
2506 btr_pcur_t pcur;
2507 mtr_t mtr;
2509 ibuf_data = fil_space_get_ibuf_data(0);
2511 ibuf_index = ibuf_data->index;
2512 ut_a(!dict_table_is_comp(ibuf_index->table));
2514 ibuf_enter();
2516 mtr_start(&mtr);
2518 btr_pcur_open_at_index_side(FALSE, ibuf_index, BTR_SEARCH_LEAF,
2519 &pcur, TRUE, &mtr);
2520 btr_pcur_move_to_prev(&pcur, &mtr);
2522 if (btr_pcur_is_before_first_on_page(&pcur, &mtr)) {
2523 /* The tree is empty */
2525 max_space_id = 0;
2526 } else {
2527 rec = btr_pcur_get_rec(&pcur);
2529 field = rec_get_nth_field_old(rec, 0, &len);
2531 ut_a(len == 4);
2533 max_space_id = mach_read_from_4(field);
2536 mtr_commit(&mtr);
2537 ibuf_exit();
2539 /* printf("Maximum space id in insert buffer %lu\n", max_space_id); */
2541 fil_set_max_space_id_if_bigger(max_space_id);
2544 /*************************************************************************
2545 Makes an index insert to the insert buffer, instead of directly to the disk
2546 page, if this is possible. */
2547 static
2548 ulint
2549 ibuf_insert_low(
2550 /*============*/
2551 /* out: DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */
2552 ulint mode, /* in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */
2553 dtuple_t* entry, /* in: index entry to insert */
2554 dict_index_t* index, /* in: index where to insert; must not be
2555 unique or clustered */
2556 ulint space, /* in: space id where to insert */
2557 ulint page_no,/* in: page number where to insert */
2558 que_thr_t* thr) /* in: query thread */
2560 big_rec_t* dummy_big_rec;
2561 ulint entry_size;
2562 btr_pcur_t pcur;
2563 btr_cur_t* cursor;
2564 dtuple_t* ibuf_entry;
2565 mem_heap_t* heap;
2566 ulint buffered;
2567 rec_t* ins_rec;
2568 ibool old_bit_value;
2569 page_t* bitmap_page;
2570 ibuf_data_t* ibuf_data;
2571 dict_index_t* ibuf_index;
2572 page_t* root;
2573 ulint err;
2574 ibool do_merge;
2575 ulint space_ids[IBUF_MAX_N_PAGES_MERGED];
2576 ib_longlong space_versions[IBUF_MAX_N_PAGES_MERGED];
2577 ulint page_nos[IBUF_MAX_N_PAGES_MERGED];
2578 ulint n_stored;
2579 ulint bits;
2580 mtr_t mtr;
2581 mtr_t bitmap_mtr;
2583 ut_a(!(index->type & DICT_CLUSTERED));
2584 ut_ad(dtuple_check_typed(entry));
2586 ut_a(trx_sys_multiple_tablespace_format);
2588 do_merge = FALSE;
2590 /* Currently the insert buffer of space 0 takes care of inserts to all
2591 tablespaces */
2593 ibuf_data = fil_space_get_ibuf_data(0);
2595 ibuf_index = ibuf_data->index;
2597 mutex_enter(&ibuf_mutex);
2599 if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
2600 /* Insert buffer is now too big, contract it but do not try
2601 to insert */
2603 mutex_exit(&ibuf_mutex);
2605 #ifdef UNIV_IBUF_DEBUG
2606 fputs("Ibuf too big\n", stderr);
2607 #endif
2608 /* Use synchronous contract (== TRUE) */
2609 ibuf_contract(TRUE);
2611 return(DB_STRONG_FAIL);
2614 mutex_exit(&ibuf_mutex);
2616 if (mode == BTR_MODIFY_TREE) {
2617 mutex_enter(&ibuf_pessimistic_insert_mutex);
2619 ibuf_enter();
2621 mutex_enter(&ibuf_mutex);
2623 while (!ibuf_data_enough_free_for_insert(ibuf_data)) {
2625 mutex_exit(&ibuf_mutex);
2627 ibuf_exit();
2629 mutex_exit(&ibuf_pessimistic_insert_mutex);
2631 err = ibuf_add_free_page(0, ibuf_data);
2633 if (err == DB_STRONG_FAIL) {
2635 return(err);
2638 mutex_enter(&ibuf_pessimistic_insert_mutex);
2640 ibuf_enter();
2642 mutex_enter(&ibuf_mutex);
2644 } else {
2645 ibuf_enter();
2648 entry_size = rec_get_converted_size(index, entry);
2650 heap = mem_heap_create(512);
2652 /* Build the entry which contains the space id and the page number as
2653 the first fields and the type information for other fields, and which
2654 will be inserted to the insert buffer. */
2656 ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap);
2658 /* Open a cursor to the insert buffer tree to calculate if we can add
2659 the new entry to it without exceeding the free space limit for the
2660 page. */
2662 mtr_start(&mtr);
2664 btr_pcur_open(ibuf_index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
2666 /* Find out the volume of already buffered inserts for the same index
2667 page */
2668 buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
2670 #ifdef UNIV_IBUF_DEBUG
2671 ut_a((buffered == 0) || ibuf_count_get(space, page_no));
2672 #endif
2673 mtr_start(&bitmap_mtr);
2675 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &bitmap_mtr);
2677 /* We check if the index page is suitable for buffered entries */
2679 if (buf_page_peek(space, page_no)
2680 || lock_rec_expl_exist_on_page(space, page_no)) {
2681 err = DB_STRONG_FAIL;
2683 mtr_commit(&bitmap_mtr);
2685 goto function_exit;
2688 bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no,
2689 IBUF_BITMAP_FREE, &bitmap_mtr);
2691 if (buffered + entry_size + page_dir_calc_reserved_space(1)
2692 > ibuf_index_page_calc_free_from_bits(bits)) {
2693 mtr_commit(&bitmap_mtr);
2695 /* It may not fit */
2696 err = DB_STRONG_FAIL;
2698 do_merge = TRUE;
2700 ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
2701 space_ids, space_versions,
2702 page_nos, &n_stored);
2703 goto function_exit;
2706 /* Set the bitmap bit denoting that the insert buffer contains
2707 buffered entries for this index page, if the bit is not set yet */
2709 old_bit_value = ibuf_bitmap_page_get_bits(bitmap_page, page_no,
2710 IBUF_BITMAP_BUFFERED,
2711 &bitmap_mtr);
2712 if (!old_bit_value) {
2713 ibuf_bitmap_page_set_bits(bitmap_page, page_no,
2714 IBUF_BITMAP_BUFFERED, TRUE,
2715 &bitmap_mtr);
2718 mtr_commit(&bitmap_mtr);
2720 cursor = btr_pcur_get_btr_cur(&pcur);
2722 if (mode == BTR_MODIFY_PREV) {
2723 err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
2724 ibuf_entry, &ins_rec,
2725 &dummy_big_rec, thr,
2726 &mtr);
2727 if (err == DB_SUCCESS) {
2728 /* Update the page max trx id field */
2729 page_update_max_trx_id(buf_frame_align(ins_rec),
2730 thr_get_trx(thr)->id);
2732 } else {
2733 ut_ad(mode == BTR_MODIFY_TREE);
2735 /* We acquire an x-latch to the root page before the insert,
2736 because a pessimistic insert releases the tree x-latch,
2737 which would cause the x-latching of the root after that to
2738 break the latching order. */
2740 root = ibuf_tree_root_get(ibuf_data, 0, &mtr);
2742 err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
2743 | BTR_NO_UNDO_LOG_FLAG,
2744 cursor,
2745 ibuf_entry, &ins_rec,
2746 &dummy_big_rec, thr,
2747 &mtr);
2748 if (err == DB_SUCCESS) {
2749 /* Update the page max trx id field */
2750 page_update_max_trx_id(buf_frame_align(ins_rec),
2751 thr_get_trx(thr)->id);
2754 ibuf_data_sizes_update(ibuf_data, root, &mtr);
2757 function_exit:
2758 #ifdef UNIV_IBUF_DEBUG
2759 if (err == DB_SUCCESS) {
2760 fprintf(stderr,
2761 "Incrementing ibuf count of space %lu page %lu\n"
2762 "from %lu by 1\n", space, page_no,
2763 ibuf_count_get(space, page_no));
2765 ibuf_count_set(space, page_no,
2766 ibuf_count_get(space, page_no) + 1);
2768 #endif
2769 if (mode == BTR_MODIFY_TREE) {
2770 ut_ad(ibuf_validate_low());
2772 mutex_exit(&ibuf_mutex);
2773 mutex_exit(&ibuf_pessimistic_insert_mutex);
2776 mtr_commit(&mtr);
2777 btr_pcur_close(&pcur);
2778 ibuf_exit();
2780 mem_heap_free(heap);
2782 mutex_enter(&ibuf_mutex);
2784 if (err == DB_SUCCESS) {
2785 ibuf_data->empty = FALSE;
2786 ibuf_data->n_inserts++;
2789 mutex_exit(&ibuf_mutex);
2791 if ((mode == BTR_MODIFY_TREE) && (err == DB_SUCCESS)) {
2792 ibuf_contract_after_insert(entry_size);
2795 if (do_merge) {
2796 #ifdef UNIV_IBUF_DEBUG
2797 ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
2798 #endif
2799 buf_read_ibuf_merge_pages(FALSE, space_ids, space_versions,
2800 page_nos, n_stored);
2803 return(err);
2806 /*************************************************************************
2807 Makes an index insert to the insert buffer, instead of directly to the disk
2808 page, if this is possible. Does not do insert if the index is clustered
2809 or unique. */
2811 ibool
2812 ibuf_insert(
2813 /*========*/
2814 /* out: TRUE if success */
2815 dtuple_t* entry, /* in: index entry to insert */
2816 dict_index_t* index, /* in: index where to insert */
2817 ulint space, /* in: space id where to insert */
2818 ulint page_no,/* in: page number where to insert */
2819 que_thr_t* thr) /* in: query thread */
2821 ulint err;
2823 ut_a(trx_sys_multiple_tablespace_format);
2824 ut_ad(dtuple_check_typed(entry));
2826 ut_a(!(index->type & DICT_CLUSTERED));
2828 if (rec_get_converted_size(index, entry)
2829 >= (page_get_free_space_of_empty(dict_table_is_comp(index->table))
2830 / 2)) {
2831 return(FALSE);
2834 err = ibuf_insert_low(BTR_MODIFY_PREV, entry, index, space, page_no,
2835 thr);
2836 if (err == DB_FAIL) {
2837 err = ibuf_insert_low(BTR_MODIFY_TREE, entry, index, space,
2838 page_no, thr);
2841 if (err == DB_SUCCESS) {
2842 #ifdef UNIV_IBUF_DEBUG
2843 /* fprintf(stderr, "Ibuf insert for page no %lu of index %s\n",
2844 page_no, index->name); */
2845 #endif
2846 return(TRUE);
2848 } else {
2849 ut_a(err == DB_STRONG_FAIL);
2851 return(FALSE);
2855 /************************************************************************
2856 During merge, inserts to an index page a secondary index entry extracted
2857 from the insert buffer. */
2858 static
2859 rec_t*
2860 ibuf_insert_to_index_page_low(
2861 /*==========================*/
2862 /* out: newly inserted record */
2863 dtuple_t* entry, /* in: buffered entry to insert */
2864 page_t* page, /* in: index page where the buffered entry
2865 should be placed */
2866 dict_index_t* index, /* in: record descriptor */
2867 mtr_t* mtr, /* in: mtr */
2868 page_cur_t* page_cur)/* in: cursor positioned on the record
2869 after which to insert the buffered entry */
2871 ulint space;
2872 ulint page_no;
2873 page_t* bitmap_page;
2874 ulint old_bits;
2875 rec_t* rec;
2876 DBUG_ENTER("ibuf_insert_to_index_page_low");
2878 rec = page_cur_tuple_insert(page_cur, entry, index, mtr);
2880 if (rec != NULL) {
2881 DBUG_RETURN(rec);
2884 /* If the record did not fit, reorganize */
2886 btr_page_reorganize(page, index, mtr);
2888 page_cur_search(page, index, entry, PAGE_CUR_LE, page_cur);
2890 /* This time the record must fit */
2892 rec = page_cur_tuple_insert(page_cur, entry, index, mtr);
2894 if (rec != NULL) {
2895 DBUG_RETURN(rec);
2898 ut_print_timestamp(stderr);
2900 fprintf(stderr,
2901 " InnoDB: Error: Insert buffer insert fails;"
2902 " page free %lu, dtuple size %lu\n",
2903 (ulong) page_get_max_insert_size(page, 1),
2904 (ulong) rec_get_converted_size(index, entry));
2905 fputs("InnoDB: Cannot insert index record ", stderr);
2906 dtuple_print(stderr, entry);
2907 fputs("\nInnoDB: The table where this index record belongs\n"
2908 "InnoDB: is now probably corrupt. Please run CHECK TABLE on\n"
2909 "InnoDB: that table.\n", stderr);
2911 space = buf_frame_get_space_id(page);
2912 page_no = buf_frame_get_page_no(page);
2914 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, mtr);
2915 old_bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no,
2916 IBUF_BITMAP_FREE, mtr);
2918 fprintf(stderr,
2919 "InnoDB: space %lu, page %lu, bitmap bits %lu\n",
2920 (ulong) space, (ulong) page_no, (ulong) old_bits);
2922 fputs("InnoDB: Submit a detailed bug report"
2923 " to http://bugs.mysql.com\n", stderr);
2925 DBUG_RETURN(NULL);
2928 /************************************************************************
2929 During merge, inserts to an index page a secondary index entry extracted
2930 from the insert buffer. */
2931 static
2932 void
2933 ibuf_insert_to_index_page(
2934 /*======================*/
2935 dtuple_t* entry, /* in: buffered entry to insert */
2936 page_t* page, /* in: index page where the buffered entry
2937 should be placed */
2938 dict_index_t* index, /* in: record descriptor */
2939 mtr_t* mtr) /* in: mtr */
2941 page_cur_t page_cur;
2942 ulint low_match;
2943 rec_t* rec;
2945 DBUG_ENTER("ibuf_insert_to_index_page");
2947 ut_ad(ibuf_inside());
2948 ut_ad(dtuple_check_typed(entry));
2949 ut_ad(!buf_block_align(page)->is_hashed);
2951 if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
2952 != (ibool)!!page_is_comp(page))) {
2953 fputs("InnoDB: Trying to insert a record from"
2954 " the insert buffer to an index page\n"
2955 "InnoDB: but the 'compact' flag does not match!\n",
2956 stderr);
2957 goto dump;
2960 rec = page_rec_get_next(page_get_infimum_rec(page));
2962 if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
2963 != dtuple_get_n_fields(entry))) {
2964 fputs("InnoDB: Trying to insert a record from"
2965 " the insert buffer to an index page\n"
2966 "InnoDB: but the number of fields does not match!\n",
2967 stderr);
2968 dump:
2969 buf_page_print(page);
2971 dtuple_print(stderr, entry);
2973 fputs("InnoDB: The table where where"
2974 " this index record belongs\n"
2975 "InnoDB: is now probably corrupt."
2976 " Please run CHECK TABLE on\n"
2977 "InnoDB: your tables.\n"
2978 "InnoDB: Submit a detailed bug report to"
2979 " http://bugs.mysql.com!\n", stderr);
2981 DBUG_VOID_RETURN;
2984 low_match = page_cur_search(page, index, entry,
2985 PAGE_CUR_LE, &page_cur);
2987 if (UNIV_UNLIKELY(low_match == dtuple_get_n_fields(entry))) {
2988 mem_heap_t* heap;
2989 upd_t* update;
2990 ulint* offsets;
2992 rec = page_cur_get_rec(&page_cur);
2994 /* This is based on
2995 row_ins_sec_index_entry_by_modify(BTR_MODIFY_LEAF). */
2996 ut_ad(rec_get_deleted_flag(rec, page_is_comp(page)));
2998 heap = mem_heap_create(1024);
3000 offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED,
3001 &heap);
3002 update = row_upd_build_sec_rec_difference_binary(
3003 index, entry, rec, NULL, heap);
3005 if (update->n_fields == 0) {
3006 /* The records only differ in the delete-mark.
3007 Clear the delete-mark, like we did before
3008 Bug #56680 was fixed. */
3009 btr_cur_set_deleted_flag_for_ibuf(rec, FALSE, mtr);
3010 updated_in_place:
3011 mem_heap_free(heap);
3012 DBUG_VOID_RETURN;
3015 /* Copy the info bits. Clear the delete-mark. */
3016 update->info_bits = rec_get_info_bits(rec, page_is_comp(page));
3017 update->info_bits &= ~REC_INFO_DELETED_FLAG;
3019 /* We cannot invoke btr_cur_optimistic_update() here,
3020 because we do not have a btr_cur_t or que_thr_t,
3021 as the insert buffer merge occurs at a very low level. */
3022 if (!row_upd_changes_field_size_or_external(index, offsets,
3023 update)) {
3024 /* This is the easy case. Do something similar
3025 to btr_cur_update_in_place(). */
3026 row_upd_rec_in_place(rec, offsets, update);
3028 /* Log the update in place operation. During recovery
3029 MLOG_COMP_REC_UPDATE_IN_PLACE/MLOG_REC_UPDATE_IN_PLACE
3030 expects trx_id, roll_ptr for secondary indexes. So we
3031 just write dummy trx_id(0), roll_ptr(0) */
3032 btr_cur_update_in_place_log(BTR_KEEP_SYS_FLAG, rec,
3033 index, update,
3034 NULL,
3035 ut_dulint_zero, mtr);
3036 DBUG_EXECUTE_IF(
3037 "crash_after_log_ibuf_upd_inplace",
3038 log_buffer_flush_to_disk();
3039 fprintf(stderr,
3040 "InnoDB: Wrote log record for ibuf "
3041 "update in place operation\n");
3042 DBUG_SUICIDE();
3045 goto updated_in_place;
3048 /* A collation may identify values that differ in
3049 storage length.
3050 Some examples (1 or 2 bytes):
3051 utf8_turkish_ci: I = U+0131 LATIN SMALL LETTER DOTLESS I
3052 utf8_general_ci: S = U+00DF LATIN SMALL LETTER SHARP S
3053 utf8_general_ci: A = U+00E4 LATIN SMALL LETTER A WITH DIAERESIS
3055 latin1_german2_ci: SS = U+00DF LATIN SMALL LETTER SHARP S
3057 Examples of a character (3-byte UTF-8 sequence)
3058 identified with 2 or 4 characters (1-byte UTF-8 sequences):
3060 utf8_unicode_ci: 'II' = U+2171 SMALL ROMAN NUMERAL TWO
3061 utf8_unicode_ci: '(10)' = U+247D PARENTHESIZED NUMBER TEN
3064 /* Delete the different-length record, and insert the
3065 buffered one. */
3067 lock_rec_store_on_page_infimum(page, rec);
3068 page_cur_delete_rec(&page_cur, index, offsets, mtr);
3069 page_cur_move_to_prev(&page_cur);
3071 rec = ibuf_insert_to_index_page_low(entry, page, index, mtr,
3072 &page_cur);
3073 ut_ad(!cmp_dtuple_rec(entry, rec,
3074 rec_get_offsets(rec, index, NULL,
3075 ULINT_UNDEFINED,
3076 &heap)));
3077 mem_heap_free(heap);
3078 lock_rec_restore_from_page_infimum(rec, page);
3079 } else {
3080 ibuf_insert_to_index_page_low(entry, page, index, mtr,
3081 &page_cur);
3084 DBUG_VOID_RETURN;
3087 /*************************************************************************
3088 Deletes from ibuf the record on which pcur is positioned. If we have to
3089 resort to a pessimistic delete, this function commits mtr and closes
3090 the cursor. */
3091 static
3092 ibool
3093 ibuf_delete_rec(
3094 /*============*/
3095 /* out: TRUE if mtr was committed and pcur
3096 closed in this operation */
3097 ulint space, /* in: space id */
3098 ulint page_no,/* in: index page number where the record
3099 should belong */
3100 btr_pcur_t* pcur, /* in: pcur positioned on the record to
3101 delete, having latch mode BTR_MODIFY_LEAF */
3102 dtuple_t* search_tuple,
3103 /* in: search tuple for entries of page_no */
3104 mtr_t* mtr) /* in: mtr */
3106 ibool success;
3107 ibuf_data_t* ibuf_data;
3108 page_t* root;
3109 ulint err;
3111 ut_ad(ibuf_inside());
3113 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
3114 if (ibuf_debug == 2) {
3115 /* Inject a fault (crash). We do this before trying
3116 optimistic delete, because a pessimistic delete in the
3117 change buffer would require a larger test case. */
3119 /* Flag the buffered record as processed, to avoid
3120 an assertion failure after crash recovery. */
3121 btr_cur_set_deleted_flag_for_ibuf(
3122 btr_pcur_get_rec(pcur), TRUE, mtr);
3123 mtr_commit(mtr);
3124 log_make_checkpoint_at(ut_dulint_max, TRUE);
3125 DBUG_SUICIDE();
3127 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
3129 success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
3131 if (success) {
3132 #ifdef UNIV_IBUF_DEBUG
3133 fprintf(stderr,
3134 "Decrementing ibuf count of space %lu page %lu\n"
3135 "from %lu by 1\n", space, page_no,
3136 ibuf_count_get(space, page_no));
3137 ibuf_count_set(space, page_no,
3138 ibuf_count_get(space, page_no) - 1);
3139 #endif
3140 return(FALSE);
3143 /* We have to resort to a pessimistic delete from ibuf.
3144 Delete-mark the record so that it will not be applied again,
3145 in case the server crashes before the pessimistic delete is
3146 made persistent. */
3147 btr_cur_set_deleted_flag_for_ibuf(
3148 btr_pcur_get_rec(pcur), TRUE, mtr);
3150 btr_pcur_store_position(pcur, mtr);
3152 btr_pcur_commit_specify_mtr(pcur, mtr);
3154 /* Currently the insert buffer of space 0 takes care of inserts to all
3155 tablespaces */
3157 ibuf_data = fil_space_get_ibuf_data(0);
3159 mutex_enter(&ibuf_mutex);
3161 mtr_start(mtr);
3163 success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
3165 if (!success) {
3166 if (fil_space_get_version(space) == -1) {
3167 /* The tablespace has been dropped. It is possible
3168 that another thread has deleted the insert buffer
3169 entry. Do not complain. */
3170 goto commit_and_exit;
3173 fprintf(stderr,
3174 "InnoDB: ERROR: Submit the output to"
3175 " http://bugs.mysql.com\n"
3176 "InnoDB: ibuf cursor restoration fails!\n"
3177 "InnoDB: ibuf record inserted to page %lu\n",
3178 (ulong) page_no);
3179 fflush(stderr);
3181 rec_print_old(stderr, btr_pcur_get_rec(pcur));
3182 rec_print_old(stderr, pcur->old_rec);
3183 dtuple_print(stderr, search_tuple);
3185 rec_print_old(stderr,
3186 page_rec_get_next(btr_pcur_get_rec(pcur)));
3187 fflush(stderr);
3189 btr_pcur_commit_specify_mtr(pcur, mtr);
3191 fputs("InnoDB: Validating insert buffer tree:\n", stderr);
3192 if (!btr_validate_index(ibuf_data->index, NULL)) {
3193 ut_error;
3196 fprintf(stderr, "InnoDB: ibuf tree ok\n");
3197 fflush(stderr);
3199 goto func_exit;
3202 root = ibuf_tree_root_get(ibuf_data, 0, mtr);
3204 btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur),
3205 FALSE, mtr);
3206 ut_a(err == DB_SUCCESS);
3208 #ifdef UNIV_IBUF_DEBUG
3209 ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
3210 #endif
3211 ibuf_data_sizes_update(ibuf_data, root, mtr);
3213 ut_ad(ibuf_validate_low());
3215 commit_and_exit:
3216 btr_pcur_commit_specify_mtr(pcur, mtr);
3218 func_exit:
3219 btr_pcur_close(pcur);
3221 mutex_exit(&ibuf_mutex);
3223 return(TRUE);
3226 /*************************************************************************
3227 When an index page is read from a disk to the buffer pool, this function
3228 inserts to the page the possible index entries buffered in the insert buffer.
3229 The entries are deleted from the insert buffer. If the page is not read, but
3230 created in the buffer pool, this function deletes its buffered entries from
3231 the insert buffer; there can exist entries for such a page if the page
3232 belonged to an index which subsequently was dropped. */
3234 void
3235 ibuf_merge_or_delete_for_page(
3236 /*==========================*/
3237 page_t* page, /* in: if page has been read from disk, pointer to
3238 the page x-latched, else NULL */
3239 ulint space, /* in: space id of the index page */
3240 ulint page_no,/* in: page number of the index page */
3241 ibool update_ibuf_bitmap)/* in: normally this is set to TRUE, but if
3242 we have deleted or are deleting the tablespace, then we
3243 naturally do not want to update a non-existent bitmap
3244 page */
3246 mem_heap_t* heap;
3247 btr_pcur_t pcur;
3248 dtuple_t* entry;
3249 dtuple_t* search_tuple;
3250 rec_t* ibuf_rec;
3251 buf_block_t* block;
3252 page_t* bitmap_page;
3253 ibuf_data_t* ibuf_data;
3254 ulint n_inserts;
3255 #ifdef UNIV_IBUF_DEBUG
3256 ulint volume;
3257 #endif
3258 ibool tablespace_being_deleted = FALSE;
3259 ibool corruption_noticed = FALSE;
3260 mtr_t mtr;
3262 if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3264 return;
3267 if (ibuf_fixed_addr_page(space, page_no) || fsp_descr_page(page_no)
3268 || trx_sys_hdr_page(space, page_no)) {
3269 return;
3272 if (update_ibuf_bitmap) {
3273 /* If the following returns FALSE, we get the counter
3274 incremented, and must decrement it when we leave this
3275 function. When the counter is > 0, that prevents tablespace
3276 from being dropped. */
3278 tablespace_being_deleted = fil_inc_pending_ibuf_merges(space);
3280 if (tablespace_being_deleted) {
3281 /* Do not try to read the bitmap page from space;
3282 just delete the ibuf records for the page */
3284 page = NULL;
3285 update_ibuf_bitmap = FALSE;
3289 if (update_ibuf_bitmap) {
3290 mtr_start(&mtr);
3291 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
3293 if (!ibuf_bitmap_page_get_bits(bitmap_page, page_no,
3294 IBUF_BITMAP_BUFFERED, &mtr)) {
3295 /* No inserts buffered for this page */
3296 mtr_commit(&mtr);
3298 if (!tablespace_being_deleted) {
3299 fil_decr_pending_ibuf_merges(space);
3302 return;
3304 mtr_commit(&mtr);
3307 /* Currently the insert buffer of space 0 takes care of inserts to all
3308 tablespaces */
3310 ibuf_data = fil_space_get_ibuf_data(0);
3312 ibuf_enter();
3314 heap = mem_heap_create(512);
3316 if (!trx_sys_multiple_tablespace_format) {
3317 ut_a(trx_doublewrite_must_reset_space_ids);
3318 search_tuple = ibuf_search_tuple_build(space, page_no, heap);
3319 } else {
3320 search_tuple = ibuf_new_search_tuple_build(space, page_no,
3321 heap);
3324 if (page) {
3325 /* Move the ownership of the x-latch on the page to this OS
3326 thread, so that we can acquire a second x-latch on it. This
3327 is needed for the insert operations to the index page to pass
3328 the debug checks. */
3330 block = buf_block_align(page);
3331 rw_lock_x_lock_move_ownership(&(block->lock));
3333 if (fil_page_get_type(page) != FIL_PAGE_INDEX) {
3335 corruption_noticed = TRUE;
3337 ut_print_timestamp(stderr);
3339 mtr_start(&mtr);
3341 fputs(" InnoDB: Dump of the ibuf bitmap page:\n",
3342 stderr);
3344 bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
3345 &mtr);
3346 buf_page_print(bitmap_page);
3348 mtr_commit(&mtr);
3350 fputs("\nInnoDB: Dump of the page:\n", stderr);
3352 buf_page_print(page);
3354 fprintf(stderr,
3355 "InnoDB: Error: corruption in the tablespace."
3356 " Bitmap shows insert\n"
3357 "InnoDB: buffer records to page n:o %lu"
3358 " though the page\n"
3359 "InnoDB: type is %lu, which is"
3360 " not an index page!\n"
3361 "InnoDB: We try to resolve the problem"
3362 " by skipping the insert buffer\n"
3363 "InnoDB: merge for this page."
3364 " Please run CHECK TABLE on your tables\n"
3365 "InnoDB: to determine if they are corrupt"
3366 " after this.\n\n"
3367 "InnoDB: Please submit a detailed bug report"
3368 " to http://bugs.mysql.com\n\n",
3369 (ulong) page_no,
3370 (ulong) fil_page_get_type(page));
3374 n_inserts = 0;
3375 #ifdef UNIV_IBUF_DEBUG
3376 volume = 0;
3377 #endif
3378 loop:
3379 mtr_start(&mtr);
3381 if (page) {
3382 ibool success = buf_page_get_known_nowait(RW_X_LATCH, page,
3383 BUF_KEEP_OLD,
3384 __FILE__, __LINE__,
3385 &mtr);
3386 ut_a(success);
3387 #ifdef UNIV_SYNC_DEBUG
3388 buf_page_dbg_add_level(page, SYNC_TREE_NODE);
3389 #endif /* UNIV_SYNC_DEBUG */
3392 /* Position pcur in the insert buffer at the first entry for this
3393 index page */
3394 btr_pcur_open_on_user_rec(ibuf_data->index, search_tuple, PAGE_CUR_GE,
3395 BTR_MODIFY_LEAF, &pcur, &mtr);
3396 if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
3397 ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
3399 goto reset_bit;
3402 for (;;) {
3403 ut_ad(btr_pcur_is_on_user_rec(&pcur, &mtr));
3405 ibuf_rec = btr_pcur_get_rec(&pcur);
3407 /* Check if the entry is for this index page */
3408 if (ibuf_rec_get_page_no(ibuf_rec) != page_no
3409 || ibuf_rec_get_space(ibuf_rec) != space) {
3410 if (page) {
3411 page_header_reset_last_insert(page, &mtr);
3413 goto reset_bit;
3416 if (corruption_noticed) {
3417 fputs("InnoDB: Discarding record\n ", stderr);
3418 rec_print_old(stderr, ibuf_rec);
3419 fputs("\n from the insert buffer!\n\n", stderr);
3420 } else if (page && !rec_get_deleted_flag(ibuf_rec, 0)) {
3421 /* Now we have at pcur a record which should be
3422 inserted to the index page; NOTE that the call below
3423 copies pointers to fields in ibuf_rec, and we must
3424 keep the latch to the ibuf_rec page until the
3425 insertion is finished! */
3426 dict_index_t* dummy_index;
3427 dulint max_trx_id = page_get_max_trx_id(
3428 buf_frame_align(ibuf_rec));
3429 page_update_max_trx_id(page, max_trx_id);
3431 entry = ibuf_build_entry_from_ibuf_rec(
3432 ibuf_rec, heap, &dummy_index);
3433 #ifdef UNIV_IBUF_DEBUG
3434 volume += rec_get_converted_size(dummy_index, entry)
3435 + page_dir_calc_reserved_space(1);
3436 ut_a(volume <= 4 * UNIV_PAGE_SIZE
3437 / IBUF_PAGE_SIZE_PER_FREE_SPACE);
3438 #endif
3439 ibuf_insert_to_index_page(entry, page,
3440 dummy_index, &mtr);
3441 ibuf_dummy_index_free(dummy_index);
3444 n_inserts++;
3446 /* Delete the record from ibuf */
3447 if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3448 &mtr)) {
3449 /* Deletion was pessimistic and mtr was committed:
3450 we start from the beginning again */
3452 goto loop;
3455 if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) {
3456 mtr_commit(&mtr);
3457 btr_pcur_close(&pcur);
3459 goto loop;
3463 reset_bit:
3464 #ifdef UNIV_IBUF_DEBUG
3465 if (ibuf_count_get(space, page_no) > 0) {
3466 /* btr_print_tree(ibuf_data->index->tree, 100);
3467 ibuf_print(); */
3469 #endif
3470 if (update_ibuf_bitmap) {
3471 bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
3472 ibuf_bitmap_page_set_bits(bitmap_page, page_no,
3473 IBUF_BITMAP_BUFFERED, FALSE, &mtr);
3474 if (page) {
3475 ulint old_bits = ibuf_bitmap_page_get_bits(
3476 bitmap_page, page_no, IBUF_BITMAP_FREE, &mtr);
3477 ulint new_bits = ibuf_index_page_calc_free(page);
3478 #if 0 /* defined UNIV_IBUF_DEBUG */
3479 fprintf(stderr, "Old bits %lu new bits %lu"
3480 " max size %lu\n",
3481 old_bits, new_bits,
3482 page_get_max_insert_size_after_reorganize(
3483 page, 1));
3484 #endif
3485 if (old_bits != new_bits) {
3486 ibuf_bitmap_page_set_bits(bitmap_page, page_no,
3487 IBUF_BITMAP_FREE,
3488 new_bits, &mtr);
3492 #if 0 /* defined UNIV_IBUF_DEBUG */
3493 fprintf(stderr,
3494 "Ibuf merge %lu records volume %lu to page no %lu\n",
3495 n_inserts, volume, page_no);
3496 #endif
3497 mtr_commit(&mtr);
3498 btr_pcur_close(&pcur);
3499 mem_heap_free(heap);
3501 /* Protect our statistics keeping from race conditions */
3502 mutex_enter(&ibuf_mutex);
3504 ibuf_data->n_merges++;
3505 ibuf_data->n_merged_recs += n_inserts;
3507 mutex_exit(&ibuf_mutex);
3509 if (update_ibuf_bitmap && !tablespace_being_deleted) {
3511 fil_decr_pending_ibuf_merges(space);
3514 ibuf_exit();
3515 #ifdef UNIV_IBUF_DEBUG
3516 ut_a(ibuf_count_get(space, page_no) == 0);
3517 #endif
3520 /*************************************************************************
3521 Deletes all entries in the insert buffer for a given space id. This is used
3522 in DISCARD TABLESPACE and IMPORT TABLESPACE.
3523 NOTE: this does not update the page free bitmaps in the space. The space will
3524 become CORRUPT when you call this function! */
3526 void
3527 ibuf_delete_for_discarded_space(
3528 /*============================*/
3529 ulint space) /* in: space id */
3531 mem_heap_t* heap;
3532 btr_pcur_t pcur;
3533 dtuple_t* search_tuple;
3534 rec_t* ibuf_rec;
3535 ulint page_no;
3536 ibool closed;
3537 ibuf_data_t* ibuf_data;
3538 ulint n_inserts;
3539 mtr_t mtr;
3541 /* Currently the insert buffer of space 0 takes care of inserts to all
3542 tablespaces */
3544 ibuf_data = fil_space_get_ibuf_data(0);
3546 heap = mem_heap_create(512);
3548 /* Use page number 0 to build the search tuple so that we get the
3549 cursor positioned at the first entry for this space id */
3551 search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
3553 n_inserts = 0;
3554 loop:
3555 ibuf_enter();
3557 mtr_start(&mtr);
3559 /* Position pcur in the insert buffer at the first entry for the
3560 space */
3561 btr_pcur_open_on_user_rec(ibuf_data->index, search_tuple, PAGE_CUR_GE,
3562 BTR_MODIFY_LEAF, &pcur, &mtr);
3563 if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
3564 ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
3566 goto leave_loop;
3569 for (;;) {
3570 ut_ad(btr_pcur_is_on_user_rec(&pcur, &mtr));
3572 ibuf_rec = btr_pcur_get_rec(&pcur);
3574 /* Check if the entry is for this space */
3575 if (ibuf_rec_get_space(ibuf_rec) != space) {
3577 goto leave_loop;
3580 page_no = ibuf_rec_get_page_no(ibuf_rec);
3582 n_inserts++;
3584 /* Delete the record from ibuf */
3585 closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3586 &mtr);
3587 if (closed) {
3588 /* Deletion was pessimistic and mtr was committed:
3589 we start from the beginning again */
3591 ibuf_exit();
3593 goto loop;
3596 if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) {
3597 mtr_commit(&mtr);
3598 btr_pcur_close(&pcur);
3600 ibuf_exit();
3602 goto loop;
3606 leave_loop:
3607 mtr_commit(&mtr);
3608 btr_pcur_close(&pcur);
3610 /* Protect our statistics keeping from race conditions */
3611 mutex_enter(&ibuf_mutex);
3613 ibuf_data->n_merges++;
3614 ibuf_data->n_merged_recs += n_inserts;
3616 mutex_exit(&ibuf_mutex);
3618 fprintf(stderr,
3619 "InnoDB: Discarded %lu ibuf entries for space %lu\n",
3620 (ulong) n_inserts, (ulong) space);
3622 ibuf_exit();
3624 mem_heap_free(heap);
3628 /**********************************************************************
3629 Validates the ibuf data structures when the caller owns ibuf_mutex. */
3631 ibool
3632 ibuf_validate_low(void)
3633 /*===================*/
3634 /* out: TRUE if ok */
3636 ibuf_data_t* data;
3637 ulint sum_sizes;
3639 ut_ad(mutex_own(&ibuf_mutex));
3641 sum_sizes = 0;
3643 data = UT_LIST_GET_FIRST(ibuf->data_list);
3645 while (data) {
3646 sum_sizes += data->size;
3648 data = UT_LIST_GET_NEXT(data_list, data);
3651 ut_a(sum_sizes == ibuf->size);
3653 return(TRUE);
3656 /**********************************************************************
3657 Looks if the insert buffer is empty. */
3659 ibool
3660 ibuf_is_empty(void)
3661 /*===============*/
3662 /* out: TRUE if empty */
3664 ibuf_data_t* data;
3665 ibool is_empty;
3666 page_t* root;
3667 mtr_t mtr;
3669 ibuf_enter();
3671 mutex_enter(&ibuf_mutex);
3673 data = UT_LIST_GET_FIRST(ibuf->data_list);
3675 mtr_start(&mtr);
3677 root = ibuf_tree_root_get(data, 0, &mtr);
3679 if (page_get_n_recs(root) == 0) {
3681 is_empty = TRUE;
3683 if (data->empty == FALSE) {
3684 fprintf(stderr,
3685 "InnoDB: Warning: insert buffer tree is empty"
3686 " but the data struct does not\n"
3687 "InnoDB: know it. This condition is legal"
3688 " if the master thread has not yet\n"
3689 "InnoDB: run to completion.\n");
3691 } else {
3692 ut_a(data->empty == FALSE);
3694 is_empty = FALSE;
3697 mtr_commit(&mtr);
3699 ut_a(data->space == 0);
3701 mutex_exit(&ibuf_mutex);
3703 ibuf_exit();
3705 return(is_empty);
3708 /**********************************************************************
3709 Prints info of ibuf. */
3711 void
3712 ibuf_print(
3713 /*=======*/
3714 FILE* file) /* in: file where to print */
3716 ibuf_data_t* data;
3717 #ifdef UNIV_IBUF_DEBUG
3718 ulint i;
3719 #endif
3721 mutex_enter(&ibuf_mutex);
3723 data = UT_LIST_GET_FIRST(ibuf->data_list);
3725 while (data) {
3726 fprintf(file,
3727 "Ibuf: size %lu, free list len %lu, seg size %lu,\n"
3728 "%lu inserts, %lu merged recs, %lu merges\n",
3729 (ulong) data->size,
3730 (ulong) data->free_list_len,
3731 (ulong) data->seg_size,
3732 (ulong) data->n_inserts,
3733 (ulong) data->n_merged_recs,
3734 (ulong) data->n_merges);
3735 #ifdef UNIV_IBUF_DEBUG
3736 for (i = 0; i < IBUF_COUNT_N_PAGES; i++) {
3737 if (ibuf_count_get(data->space, i) > 0) {
3739 fprintf(stderr,
3740 "Ibuf count for page %lu is %lu\n",
3741 (ulong) i,
3742 (ulong)
3743 ibuf_count_get(data->space, i));
3746 #endif
3747 data = UT_LIST_GET_NEXT(data_list, data);
3750 mutex_exit(&ibuf_mutex);