~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/ibuf/ibuf0ibuf.c

  • Committer: Monty Taylor
  • Date: 2008-10-23 00:05:28 UTC
  • Revision ID: monty@inaugust.com-20081023000528-grdvrd8c4058nutm
Moved my_handler to myisam, which is where it actually belongs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
 
Place, Suite 330, Boston, MA 02111-1307 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file ibuf/ibuf0ibuf.c
21
 
Insert buffer
22
 
 
23
 
Created 7/19/1997 Heikki Tuuri
24
 
*******************************************************/
25
 
 
26
 
#include "ibuf0ibuf.h"
27
 
 
28
 
/** Number of bits describing a single page */
29
 
#define IBUF_BITS_PER_PAGE      4
30
 
#if IBUF_BITS_PER_PAGE % 2
31
 
# error "IBUF_BITS_PER_PAGE must be an even number!"
32
 
#endif
33
 
/** The start address for an insert buffer bitmap page bitmap */
34
 
#define IBUF_BITMAP             PAGE_DATA
35
 
 
36
 
#ifdef UNIV_NONINL
37
 
#include "ibuf0ibuf.ic"
38
 
#endif
39
 
 
40
 
#ifndef UNIV_HOTBACKUP
41
 
 
42
 
#include "buf0buf.h"
43
 
#include "buf0rea.h"
44
 
#include "fsp0fsp.h"
45
 
#include "trx0sys.h"
46
 
#include "fil0fil.h"
47
 
#include "thr0loc.h"
48
 
#include "rem0rec.h"
49
 
#include "btr0cur.h"
50
 
#include "btr0pcur.h"
51
 
#include "btr0btr.h"
52
 
#include "sync0sync.h"
53
 
#include "dict0boot.h"
54
 
#include "fut0lst.h"
55
 
#include "lock0lock.h"
56
 
#include "log0recv.h"
57
 
#include "que0que.h"
58
 
 
59
 
/*      STRUCTURE OF AN INSERT BUFFER RECORD
60
 
 
61
 
In versions < 4.1.x:
62
 
 
63
 
1. The first field is the page number.
64
 
2. The second field is an array which stores type info for each subsequent
65
 
   field. We store the information which affects the ordering of records, and
66
 
   also the physical storage size of an SQL NULL value. E.g., for CHAR(10) it
67
 
   is 10 bytes.
68
 
3. Next we have the fields of the actual index record.
69
 
 
70
 
In versions >= 4.1.x:
71
 
 
72
 
Note that contary to what we planned in the 1990's, there will only be one
73
 
insert buffer tree, and that is in the system tablespace of InnoDB.
74
 
 
75
 
1. The first field is the space id.
76
 
2. The second field is a one-byte marker (0) which differentiates records from
77
 
   the < 4.1.x storage format.
78
 
3. The third field is the page number.
79
 
4. The fourth field contains the type info, where we have also added 2 bytes to
80
 
   store the charset. In the compressed table format of 5.0.x we must add more
81
 
   information here so that we can build a dummy 'index' struct which 5.0.x
82
 
   can use in the binary search on the index page in the ibuf merge phase.
83
 
5. The rest of the fields contain the fields of the actual index record.
84
 
 
85
 
In versions >= 5.0.3:
86
 
 
87
 
The first byte of the fourth field is an additional marker (0) if the record
88
 
is in the compact format.  The presence of this marker can be detected by
89
 
looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
90
 
 
91
 
The high-order bit of the character set field in the type info is the
92
 
"nullable" flag for the field. */
93
 
 
94
 
 
95
 
/*      PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
96
 
 
97
 
If an OS thread performs any operation that brings in disk pages from
98
 
non-system tablespaces into the buffer pool, or creates such a page there,
99
 
then the operation may have as a side effect an insert buffer index tree
100
 
compression. Thus, the tree latch of the insert buffer tree may be acquired
101
 
in the x-mode, and also the file space latch of the system tablespace may
102
 
be acquired in the x-mode.
103
 
 
104
 
Also, an insert to an index in a non-system tablespace can have the same
105
 
effect. How do we know this cannot lead to a deadlock of OS threads? There
106
 
is a problem with the i\o-handler threads: they break the latching order
107
 
because they own x-latches to pages which are on a lower level than the
108
 
insert buffer tree latch, its page latches, and the tablespace latch an
109
 
insert buffer operation can reserve.
110
 
 
111
 
The solution is the following: Let all the tree and page latches connected
112
 
with the insert buffer be later in the latching order than the fsp latch and
113
 
fsp page latches.
114
 
 
115
 
Insert buffer pages must be such that the insert buffer is never invoked
116
 
when these pages are accessed as this would result in a recursion violating
117
 
the latching order. We let a special i/o-handler thread take care of i/o to
118
 
the insert buffer pages and the ibuf bitmap pages, as well as the fsp bitmap
119
 
pages and the first inode page, which contains the inode of the ibuf tree: let
120
 
us call all these ibuf pages. To prevent deadlocks, we do not let a read-ahead
121
 
access both non-ibuf and ibuf pages.
122
 
 
123
 
Then an i/o-handler for the insert buffer never needs to access recursively the
124
 
insert buffer tree and thus obeys the latching order. On the other hand, other
125
 
i/o-handlers for other tablespaces may require access to the insert buffer,
126
 
but because all kinds of latches they need to access there are later in the
127
 
latching order, no violation of the latching order occurs in this case,
128
 
either.
129
 
 
130
 
A problem is how to grow and contract an insert buffer tree. As it is later
131
 
in the latching order than the fsp management, we have to reserve the fsp
132
 
latch first, before adding or removing pages from the insert buffer tree.
133
 
We let the insert buffer tree have its own file space management: a free
134
 
list of pages linked to the tree root. To prevent recursive using of the
135
 
insert buffer when adding pages to the tree, we must first load these pages
136
 
to memory, obtaining a latch on them, and only after that add them to the
137
 
free list of the insert buffer tree. More difficult is removing of pages
138
 
from the free list. If there is an excess of pages in the free list of the
139
 
ibuf tree, they might be needed if some thread reserves the fsp latch,
140
 
intending to allocate more file space. So we do the following: if a thread
141
 
reserves the fsp latch, we check the writer count field of the latch. If
142
 
this field has value 1, it means that the thread did not own the latch
143
 
before entering the fsp system, and the mtr of the thread contains no
144
 
modifications to the fsp pages. Now we are free to reserve the ibuf latch,
145
 
and check if there is an excess of pages in the free list. We can then, in a
146
 
separate mini-transaction, take them out of the free list and free them to
147
 
the fsp system.
148
 
 
149
 
To avoid deadlocks in the ibuf system, we divide file pages into three levels:
150
 
 
151
 
(1) non-ibuf pages,
152
 
(2) ibuf tree pages and the pages in the ibuf tree free list, and
153
 
(3) ibuf bitmap pages.
154
 
 
155
 
No OS thread is allowed to access higher level pages if it has latches to
156
 
lower level pages; even if the thread owns a B-tree latch it must not access
157
 
the B-tree non-leaf pages if it has latches on lower level pages. Read-ahead
158
 
is only allowed for level 1 and 2 pages. Dedicated i/o-handler threads handle
159
 
exclusively level 1 i/o. A dedicated i/o handler thread handles exclusively
160
 
level 2 i/o. However, if an OS thread does the i/o handling for itself, i.e.,
161
 
it uses synchronous aio, it can access any pages, as long as it obeys the
162
 
access order rules. */
163
 
 
164
 
/** Buffer pool size per the maximum insert buffer size */
165
 
#define IBUF_POOL_SIZE_PER_MAX_SIZE     2
166
 
 
167
 
/** Table name for the insert buffer. */
168
 
#define IBUF_TABLE_NAME         "SYS_IBUF_TABLE"
169
 
 
170
 
/** Operations that can currently be buffered. */
171
 
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_INSERT;
172
 
 
173
 
/** The insert buffer control structure */
174
 
UNIV_INTERN ibuf_t*     ibuf                    = NULL;
175
 
 
176
 
/** Counter for ibuf_should_try() */
177
 
UNIV_INTERN ulint       ibuf_flush_count        = 0;
178
 
 
179
 
#ifdef UNIV_IBUF_COUNT_DEBUG
180
 
/** Number of tablespaces in the ibuf_counts array */
181
 
#define IBUF_COUNT_N_SPACES     4
182
 
/** Number of pages within each tablespace in the ibuf_counts array */
183
 
#define IBUF_COUNT_N_PAGES      130000
184
 
 
185
 
/** Buffered entry counts for file pages, used in debugging */
186
 
static ulint    ibuf_counts[IBUF_COUNT_N_SPACES][IBUF_COUNT_N_PAGES];
187
 
 
188
 
/******************************************************************//**
189
 
Checks that the indexes to ibuf_counts[][] are within limits. */
190
 
UNIV_INLINE
191
 
void
192
 
ibuf_count_check(
193
 
/*=============*/
194
 
        ulint   space_id,       /*!< in: space identifier */
195
 
        ulint   page_no)        /*!< in: page number */
196
 
{
197
 
        if (space_id < IBUF_COUNT_N_SPACES && page_no < IBUF_COUNT_N_PAGES) {
198
 
                return;
199
 
        }
200
 
 
201
 
        fprintf(stderr,
202
 
                "InnoDB: UNIV_IBUF_COUNT_DEBUG limits space_id and page_no\n"
203
 
                "InnoDB: and breaks crash recovery.\n"
204
 
                "InnoDB: space_id=%lu, should be 0<=space_id<%lu\n"
205
 
                "InnoDB: page_no=%lu, should be 0<=page_no<%lu\n",
206
 
                (ulint) space_id, (ulint) IBUF_COUNT_N_SPACES,
207
 
                (ulint) page_no, (ulint) IBUF_COUNT_N_PAGES);
208
 
        ut_error;
209
 
}
210
 
#endif
211
 
 
212
 
/** @name Offsets to the per-page bits in the insert buffer bitmap */
213
 
/* @{ */
214
 
#define IBUF_BITMAP_FREE        0       /*!< Bits indicating the
215
 
                                        amount of free space */
216
 
#define IBUF_BITMAP_BUFFERED    2       /*!< TRUE if there are buffered
217
 
                                        changes for the page */
218
 
#define IBUF_BITMAP_IBUF        3       /*!< TRUE if page is a part of
219
 
                                        the ibuf tree, excluding the
220
 
                                        root page, or is in the free
221
 
                                        list of the ibuf */
222
 
/* @} */
223
 
 
224
 
/** The mutex used to block pessimistic inserts to ibuf trees */
225
 
static mutex_t  ibuf_pessimistic_insert_mutex;
226
 
 
227
 
/** The mutex protecting the insert buffer structs */
228
 
static mutex_t  ibuf_mutex;
229
 
 
230
 
/** The mutex protecting the insert buffer bitmaps */
231
 
static mutex_t  ibuf_bitmap_mutex;
232
 
 
233
 
/** The area in pages from which contract looks for page numbers for merge */
234
 
#define IBUF_MERGE_AREA                 8
235
 
 
236
 
/** Inside the merge area, pages which have at most 1 per this number less
237
 
buffered entries compared to maximum volume that can buffered for a single
238
 
page are merged along with the page whose buffer became full */
239
 
#define IBUF_MERGE_THRESHOLD            4
240
 
 
241
 
/** In ibuf_contract at most this number of pages is read to memory in one
242
 
batch, in order to merge the entries for them in the insert buffer */
243
 
#define IBUF_MAX_N_PAGES_MERGED         IBUF_MERGE_AREA
244
 
 
245
 
/** If the combined size of the ibuf trees exceeds ibuf->max_size by this
246
 
many pages, we start to contract it in connection to inserts there, using
247
 
non-synchronous contract */
248
 
#define IBUF_CONTRACT_ON_INSERT_NON_SYNC        0
249
 
 
250
 
/** If the combined size of the ibuf trees exceeds ibuf->max_size by this
251
 
many pages, we start to contract it in connection to inserts there, using
252
 
synchronous contract */
253
 
#define IBUF_CONTRACT_ON_INSERT_SYNC            5
254
 
 
255
 
/** If the combined size of the ibuf trees exceeds ibuf->max_size by
256
 
this many pages, we start to contract it synchronous contract, but do
257
 
not insert */
258
 
#define IBUF_CONTRACT_DO_NOT_INSERT             10
259
 
 
260
 
/* TODO: how to cope with drop table if there are records in the insert
261
 
buffer for the indexes of the table? Is there actually any problem,
262
 
because ibuf merge is done to a page when it is read in, and it is
263
 
still physically like the index page even if the index would have been
264
 
dropped! So, there seems to be no problem. */
265
 
 
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
 
/*============*/
273
 
{
274
 
        ibool*  ptr;
275
 
 
276
 
        ptr = thr_local_get_in_ibuf_field();
277
 
 
278
 
        ut_ad(*ptr == FALSE);
279
 
 
280
 
        *ptr = TRUE;
281
 
}
282
 
 
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
 
/*===========*/
290
 
{
291
 
        ibool*  ptr;
292
 
 
293
 
        ptr = thr_local_get_in_ibuf_field();
294
 
 
295
 
        ut_ad(*ptr == TRUE);
296
 
 
297
 
        *ptr = FALSE;
298
 
}
299
 
 
300
 
/******************************************************************//**
301
 
Returns TRUE if the current OS thread is performing an insert buffer
302
 
routine.
303
 
 
304
 
For instance, a read-ahead of non-ibuf pages is forbidden by threads
305
 
that are executing an insert buffer routine.
306
 
@return TRUE if inside an insert buffer routine */
307
 
UNIV_INTERN
308
 
ibool
309
 
ibuf_inside(void)
310
 
/*=============*/
311
 
{
312
 
        return(*thr_local_get_in_ibuf_field());
313
 
}
314
 
 
315
 
/******************************************************************//**
316
 
Gets the ibuf header page and x-latches it.
317
 
@return insert buffer header page */
318
 
static
319
 
page_t*
320
 
ibuf_header_page_get(
321
 
/*=================*/
322
 
        mtr_t*  mtr)    /*!< in: mtr */
323
 
{
324
 
        buf_block_t*    block;
325
 
 
326
 
        ut_ad(!ibuf_inside());
327
 
 
328
 
        block = buf_page_get(
329
 
                IBUF_SPACE_ID, 0, FSP_IBUF_HEADER_PAGE_NO, RW_X_LATCH, mtr);
330
 
        buf_block_dbg_add_level(block, SYNC_IBUF_HEADER);
331
 
 
332
 
        return(buf_block_get_frame(block));
333
 
}
334
 
 
335
 
/******************************************************************//**
336
 
Gets the root page and x-latches it.
337
 
@return insert buffer tree root page */
338
 
static
339
 
page_t*
340
 
ibuf_tree_root_get(
341
 
/*===============*/
342
 
        mtr_t*          mtr)    /*!< in: mtr */
343
 
{
344
 
        buf_block_t*    block;
345
 
 
346
 
        ut_ad(ibuf_inside());
347
 
 
348
 
        mtr_x_lock(dict_index_get_lock(ibuf->index), mtr);
349
 
 
350
 
        block = buf_page_get(
351
 
                IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH, mtr);
352
 
 
353
 
        buf_block_dbg_add_level(block, SYNC_TREE_NODE);
354
 
 
355
 
        return(buf_block_get_frame(block));
356
 
}
357
 
 
358
 
#ifdef UNIV_IBUF_COUNT_DEBUG
359
 
/******************************************************************//**
360
 
Gets the ibuf count for a given page.
361
 
@return number of entries in the insert buffer currently buffered for
362
 
this page */
363
 
UNIV_INTERN
364
 
ulint
365
 
ibuf_count_get(
366
 
/*===========*/
367
 
        ulint   space,  /*!< in: space id */
368
 
        ulint   page_no)/*!< in: page number */
369
 
{
370
 
        ibuf_count_check(space, page_no);
371
 
 
372
 
        return(ibuf_counts[space][page_no]);
373
 
}
374
 
 
375
 
/******************************************************************//**
376
 
Sets the ibuf count for a given page. */
377
 
static
378
 
void
379
 
ibuf_count_set(
380
 
/*===========*/
381
 
        ulint   space,  /*!< in: space id */
382
 
        ulint   page_no,/*!< in: page number */
383
 
        ulint   val)    /*!< in: value to set */
384
 
{
385
 
        ibuf_count_check(space, page_no);
386
 
        ut_a(val < UNIV_PAGE_SIZE);
387
 
 
388
 
        ibuf_counts[space][page_no] = val;
389
 
}
390
 
#endif
391
 
 
392
 
/******************************************************************//**
393
 
Updates the size information of the ibuf, assuming the segment size has not
394
 
changed. */
395
 
static
396
 
void
397
 
ibuf_size_update(
398
 
/*=============*/
399
 
        const page_t*   root,   /*!< in: ibuf tree root */
400
 
        mtr_t*          mtr)    /*!< in: mtr */
401
 
{
402
 
        ut_ad(mutex_own(&ibuf_mutex));
403
 
 
404
 
        ibuf->free_list_len = flst_get_len(root + PAGE_HEADER
405
 
                                           + PAGE_BTR_IBUF_FREE_LIST, mtr);
406
 
 
407
 
        ibuf->height = 1 + btr_page_get_level(root, mtr);
408
 
 
409
 
        /* the '1 +' is the ibuf header page */
410
 
        ibuf->size = ibuf->seg_size - (1 + ibuf->free_list_len);
411
 
 
412
 
        ibuf->empty = page_get_n_recs(root) == 0;
413
 
}
414
 
 
415
 
/******************************************************************//**
416
 
Creates the insert buffer data structure at a database startup and initializes
417
 
the data structures for the insert buffer. */
418
 
UNIV_INTERN
419
 
void
420
 
ibuf_init_at_db_start(void)
421
 
/*=======================*/
422
 
{
423
 
        page_t*         root;
424
 
        mtr_t           mtr;
425
 
        dict_table_t*   table;
426
 
        mem_heap_t*     heap;
427
 
        dict_index_t*   index;
428
 
        ulint           n_used;
429
 
        page_t*         header_page;
430
 
        ulint           error;
431
 
 
432
 
        ibuf = mem_alloc(sizeof(ibuf_t));
433
 
 
434
 
        memset(ibuf, 0, sizeof(*ibuf));
435
 
 
436
 
        /* Note that also a pessimistic delete can sometimes make a B-tree
437
 
        grow in size, as the references on the upper levels of the tree can
438
 
        change */
439
 
 
440
 
        ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE
441
 
                / IBUF_POOL_SIZE_PER_MAX_SIZE;
442
 
 
443
 
        mutex_create(&ibuf_pessimistic_insert_mutex,
444
 
                     SYNC_IBUF_PESS_INSERT_MUTEX);
445
 
 
446
 
        mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX);
447
 
 
448
 
        mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
449
 
 
450
 
        mtr_start(&mtr);
451
 
 
452
 
        mutex_enter(&ibuf_mutex);
453
 
 
454
 
        mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, NULL), &mtr);
455
 
 
456
 
        header_page = ibuf_header_page_get(&mtr);
457
 
 
458
 
        fseg_n_reserved_pages(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
459
 
                              &n_used, &mtr);
460
 
        ibuf_enter();
461
 
 
462
 
        ut_ad(n_used >= 2);
463
 
 
464
 
        ibuf->seg_size = n_used;
465
 
 
466
 
        {
467
 
                buf_block_t*    block;
468
 
 
469
 
                block = buf_page_get(
470
 
                        IBUF_SPACE_ID, 0, FSP_IBUF_TREE_ROOT_PAGE_NO,
471
 
                        RW_X_LATCH, &mtr);
472
 
                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
473
 
 
474
 
                root = buf_block_get_frame(block);
475
 
        }
476
 
 
477
 
        ibuf_size_update(root, &mtr);
478
 
        mutex_exit(&ibuf_mutex);
479
 
 
480
 
        mtr_commit(&mtr);
481
 
 
482
 
        ibuf_exit();
483
 
 
484
 
        heap = mem_heap_create(450);
485
 
 
486
 
        /* Use old-style record format for the insert buffer. */
487
 
        table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0);
488
 
 
489
 
        dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
490
 
 
491
 
        table->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
492
 
 
493
 
        dict_table_add_to_cache(table, heap);
494
 
        mem_heap_free(heap);
495
 
 
496
 
        index = dict_mem_index_create(
497
 
                IBUF_TABLE_NAME, "CLUST_IND",
498
 
                IBUF_SPACE_ID, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 1);
499
 
 
500
 
        dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
501
 
 
502
 
        index->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
503
 
 
504
 
        error = dict_index_add_to_cache(table, index,
505
 
                                        FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
506
 
        ut_a(error == DB_SUCCESS);
507
 
 
508
 
        ibuf->index = dict_table_get_first_index(table);
509
 
}
510
 
#endif /* !UNIV_HOTBACKUP */
511
 
/*********************************************************************//**
512
 
Initializes an ibuf bitmap page. */
513
 
UNIV_INTERN
514
 
void
515
 
ibuf_bitmap_page_init(
516
 
/*==================*/
517
 
        buf_block_t*    block,  /*!< in: bitmap page */
518
 
        mtr_t*          mtr)    /*!< in: mtr */
519
 
{
520
 
        page_t* page;
521
 
        ulint   byte_offset;
522
 
        ulint   zip_size = buf_block_get_zip_size(block);
523
 
 
524
 
        ut_a(ut_is_2pow(zip_size));
525
 
 
526
 
        page = buf_block_get_frame(block);
527
 
        fil_page_set_type(page, FIL_PAGE_IBUF_BITMAP);
528
 
 
529
 
        /* Write all zeros to the bitmap */
530
 
 
531
 
        if (!zip_size) {
532
 
                byte_offset = UT_BITS_IN_BYTES(UNIV_PAGE_SIZE
533
 
                                               * IBUF_BITS_PER_PAGE);
534
 
        } else {
535
 
                byte_offset = UT_BITS_IN_BYTES(zip_size * IBUF_BITS_PER_PAGE);
536
 
        }
537
 
 
538
 
        memset(page + IBUF_BITMAP, 0, byte_offset);
539
 
 
540
 
        /* The remaining area (up to the page trailer) is uninitialized. */
541
 
 
542
 
#ifndef UNIV_HOTBACKUP
543
 
        mlog_write_initial_log_record(page, MLOG_IBUF_BITMAP_INIT, mtr);
544
 
#endif /* !UNIV_HOTBACKUP */
545
 
}
546
 
 
547
 
/*********************************************************************//**
548
 
Parses a redo log record of an ibuf bitmap page init.
549
 
@return end of log record or NULL */
550
 
UNIV_INTERN
551
 
byte*
552
 
ibuf_parse_bitmap_init(
553
 
/*===================*/
554
 
        byte*           ptr,    /*!< in: buffer */
555
 
        byte*           end_ptr __attribute__((unused)), /*!< in: buffer end */
556
 
        buf_block_t*    block,  /*!< in: block or NULL */
557
 
        mtr_t*          mtr)    /*!< in: mtr or NULL */
558
 
{
559
 
        ut_ad(ptr && end_ptr);
560
 
 
561
 
        if (block) {
562
 
                ibuf_bitmap_page_init(block, mtr);
563
 
        }
564
 
 
565
 
        return(ptr);
566
 
}
567
 
#ifndef UNIV_HOTBACKUP
568
 
/********************************************************************//**
569
 
Gets the desired bits for a given page from a bitmap page.
570
 
@return value of bits */
571
 
UNIV_INLINE
572
 
ulint
573
 
ibuf_bitmap_page_get_bits(
574
 
/*======================*/
575
 
        const page_t*   page,   /*!< in: bitmap page */
576
 
        ulint           page_no,/*!< in: page whose bits to get */
577
 
        ulint           zip_size,/*!< in: compressed page size in bytes;
578
 
                                0 for uncompressed pages */
579
 
        ulint           bit,    /*!< in: IBUF_BITMAP_FREE,
580
 
                                IBUF_BITMAP_BUFFERED, ... */
581
 
        mtr_t*          mtr __attribute__((unused)))
582
 
                                /*!< in: mtr containing an
583
 
                                x-latch to the bitmap page */
584
 
{
585
 
        ulint   byte_offset;
586
 
        ulint   bit_offset;
587
 
        ulint   map_byte;
588
 
        ulint   value;
589
 
 
590
 
        ut_ad(bit < IBUF_BITS_PER_PAGE);
591
 
#if IBUF_BITS_PER_PAGE % 2
592
 
# error "IBUF_BITS_PER_PAGE % 2 != 0"
593
 
#endif
594
 
        ut_ad(ut_is_2pow(zip_size));
595
 
        ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
596
 
 
597
 
        if (!zip_size) {
598
 
                bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE
599
 
                        + bit;
600
 
        } else {
601
 
                bit_offset = (page_no & (zip_size - 1)) * IBUF_BITS_PER_PAGE
602
 
                        + bit;
603
 
        }
604
 
 
605
 
        byte_offset = bit_offset / 8;
606
 
        bit_offset = bit_offset % 8;
607
 
 
608
 
        ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
609
 
 
610
 
        map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
611
 
 
612
 
        value = ut_bit_get_nth(map_byte, bit_offset);
613
 
 
614
 
        if (bit == IBUF_BITMAP_FREE) {
615
 
                ut_ad(bit_offset + 1 < 8);
616
 
 
617
 
                value = value * 2 + ut_bit_get_nth(map_byte, bit_offset + 1);
618
 
        }
619
 
 
620
 
        return(value);
621
 
}
622
 
 
623
 
/********************************************************************//**
624
 
Sets the desired bit for a given page in a bitmap page. */
625
 
static
626
 
void
627
 
ibuf_bitmap_page_set_bits(
628
 
/*======================*/
629
 
        page_t* page,   /*!< in: bitmap page */
630
 
        ulint   page_no,/*!< in: page whose bits to set */
631
 
        ulint   zip_size,/*!< in: compressed page size in bytes;
632
 
                        0 for uncompressed pages */
633
 
        ulint   bit,    /*!< in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */
634
 
        ulint   val,    /*!< in: value to set */
635
 
        mtr_t*  mtr)    /*!< in: mtr containing an x-latch to the bitmap page */
636
 
{
637
 
        ulint   byte_offset;
638
 
        ulint   bit_offset;
639
 
        ulint   map_byte;
640
 
 
641
 
        ut_ad(bit < IBUF_BITS_PER_PAGE);
642
 
#if IBUF_BITS_PER_PAGE % 2
643
 
# error "IBUF_BITS_PER_PAGE % 2 != 0"
644
 
#endif
645
 
        ut_ad(ut_is_2pow(zip_size));
646
 
        ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
647
 
#ifdef UNIV_IBUF_COUNT_DEBUG
648
 
        ut_a((bit != IBUF_BITMAP_BUFFERED) || (val != FALSE)
649
 
             || (0 == ibuf_count_get(page_get_space_id(page),
650
 
                                     page_no)));
651
 
#endif
652
 
        if (!zip_size) {
653
 
                bit_offset = (page_no % UNIV_PAGE_SIZE) * IBUF_BITS_PER_PAGE
654
 
                        + bit;
655
 
        } else {
656
 
                bit_offset = (page_no & (zip_size - 1)) * IBUF_BITS_PER_PAGE
657
 
                        + bit;
658
 
        }
659
 
 
660
 
        byte_offset = bit_offset / 8;
661
 
        bit_offset = bit_offset % 8;
662
 
 
663
 
        ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
664
 
 
665
 
        map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
666
 
 
667
 
        if (bit == IBUF_BITMAP_FREE) {
668
 
                ut_ad(bit_offset + 1 < 8);
669
 
                ut_ad(val <= 3);
670
 
 
671
 
                map_byte = ut_bit_set_nth(map_byte, bit_offset, val / 2);
672
 
                map_byte = ut_bit_set_nth(map_byte, bit_offset + 1, val % 2);
673
 
        } else {
674
 
                ut_ad(val <= 1);
675
 
                map_byte = ut_bit_set_nth(map_byte, bit_offset, val);
676
 
        }
677
 
 
678
 
        mlog_write_ulint(page + IBUF_BITMAP + byte_offset, map_byte,
679
 
                         MLOG_1BYTE, mtr);
680
 
}
681
 
 
682
 
/********************************************************************//**
683
 
Calculates the bitmap page number for a given page number.
684
 
@return the bitmap page number where the file page is mapped */
685
 
UNIV_INLINE
686
 
ulint
687
 
ibuf_bitmap_page_no_calc(
688
 
/*=====================*/
689
 
        ulint   zip_size,       /*!< in: compressed page size in bytes;
690
 
                                0 for uncompressed pages */
691
 
        ulint   page_no)        /*!< in: tablespace page number */
692
 
{
693
 
        ut_ad(ut_is_2pow(zip_size));
694
 
 
695
 
        if (!zip_size) {
696
 
                return(FSP_IBUF_BITMAP_OFFSET
697
 
                       + (page_no & ~(UNIV_PAGE_SIZE - 1)));
698
 
        } else {
699
 
                return(FSP_IBUF_BITMAP_OFFSET
700
 
                       + (page_no & ~(zip_size - 1)));
701
 
        }
702
 
}
703
 
 
704
 
/********************************************************************//**
705
 
Gets the ibuf bitmap page where the bits describing a given file page are
706
 
stored.
707
 
@return bitmap page where the file page is mapped, that is, the bitmap
708
 
page containing the descriptor bits for the file page; the bitmap page
709
 
is x-latched */
710
 
static
711
 
page_t*
712
 
ibuf_bitmap_get_map_page(
713
 
/*=====================*/
714
 
        ulint   space,  /*!< in: space id of the file page */
715
 
        ulint   page_no,/*!< in: page number of the file page */
716
 
        ulint   zip_size,/*!< in: compressed page size in bytes;
717
 
                        0 for uncompressed pages */
718
 
        mtr_t*  mtr)    /*!< in: mtr */
719
 
{
720
 
        buf_block_t*    block;
721
 
 
722
 
        block = buf_page_get(space, zip_size,
723
 
                             ibuf_bitmap_page_no_calc(zip_size, page_no),
724
 
                             RW_X_LATCH, mtr);
725
 
        buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
726
 
 
727
 
        return(buf_block_get_frame(block));
728
 
}
729
 
 
730
 
/************************************************************************//**
731
 
Sets the free bits of the page in the ibuf bitmap. This is done in a separate
732
 
mini-transaction, hence this operation does not restrict further work to only
733
 
ibuf bitmap operations, which would result if the latch to the bitmap page
734
 
were kept. */
735
 
UNIV_INLINE
736
 
void
737
 
ibuf_set_free_bits_low(
738
 
/*===================*/
739
 
        ulint                   zip_size,/*!< in: compressed page size in bytes;
740
 
                                        0 for uncompressed pages */
741
 
        const buf_block_t*      block,  /*!< in: index page; free bits are set if
742
 
                                        the index is non-clustered and page
743
 
                                        level is 0 */
744
 
        ulint                   val,    /*!< in: value to set: < 4 */
745
 
        mtr_t*                  mtr)    /*!< in/out: mtr */
746
 
{
747
 
        page_t* bitmap_page;
748
 
        ulint   space;
749
 
        ulint   page_no;
750
 
 
751
 
        if (!page_is_leaf(buf_block_get_frame(block))) {
752
 
 
753
 
                return;
754
 
        }
755
 
 
756
 
        space = buf_block_get_space(block);
757
 
        page_no = buf_block_get_page_no(block);
758
 
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
759
 
#ifdef UNIV_IBUF_DEBUG
760
 
# if 0
761
 
        fprintf(stderr,
762
 
                "Setting space %lu page %lu free bits to %lu should be %lu\n",
763
 
                space, page_no, val,
764
 
                ibuf_index_page_calc_free(zip_size, block));
765
 
# endif
766
 
 
767
 
        ut_a(val <= ibuf_index_page_calc_free(zip_size, block));
768
 
#endif /* UNIV_IBUF_DEBUG */
769
 
        ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
770
 
                                  IBUF_BITMAP_FREE, val, mtr);
771
 
}
772
 
 
773
 
/************************************************************************//**
774
 
Sets the free bit of the page in the ibuf bitmap. This is done in a separate
775
 
mini-transaction, hence this operation does not restrict further work to only
776
 
ibuf bitmap operations, which would result if the latch to the bitmap page
777
 
were kept. */
778
 
UNIV_INTERN
779
 
void
780
 
ibuf_set_free_bits_func(
781
 
/*====================*/
782
 
        buf_block_t*    block,  /*!< in: index page of a non-clustered index;
783
 
                                free bit is reset if page level is 0 */
784
 
#ifdef UNIV_IBUF_DEBUG
785
 
        ulint           max_val,/*!< in: ULINT_UNDEFINED or a maximum
786
 
                                value which the bits must have before
787
 
                                setting; this is for debugging */
788
 
#endif /* UNIV_IBUF_DEBUG */
789
 
        ulint           val)    /*!< in: value to set: < 4 */
790
 
{
791
 
        mtr_t   mtr;
792
 
        page_t* page;
793
 
        page_t* bitmap_page;
794
 
        ulint   space;
795
 
        ulint   page_no;
796
 
        ulint   zip_size;
797
 
 
798
 
        page = buf_block_get_frame(block);
799
 
 
800
 
        if (!page_is_leaf(page)) {
801
 
 
802
 
                return;
803
 
        }
804
 
 
805
 
        mtr_start(&mtr);
806
 
 
807
 
        space = buf_block_get_space(block);
808
 
        page_no = buf_block_get_page_no(block);
809
 
        zip_size = buf_block_get_zip_size(block);
810
 
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, &mtr);
811
 
 
812
 
#ifdef UNIV_IBUF_DEBUG
813
 
        if (max_val != ULINT_UNDEFINED) {
814
 
                ulint   old_val;
815
 
 
816
 
                old_val = ibuf_bitmap_page_get_bits(
817
 
                        bitmap_page, page_no, zip_size,
818
 
                        IBUF_BITMAP_FREE, &mtr);
819
 
# if 0
820
 
                if (old_val != max_val) {
821
 
                        fprintf(stderr,
822
 
                                "Ibuf: page %lu old val %lu max val %lu\n",
823
 
                                page_get_page_no(page),
824
 
                                old_val, max_val);
825
 
                }
826
 
# endif
827
 
 
828
 
                ut_a(old_val <= max_val);
829
 
        }
830
 
# if 0
831
 
        fprintf(stderr, "Setting page no %lu free bits to %lu should be %lu\n",
832
 
                page_get_page_no(page), val,
833
 
                ibuf_index_page_calc_free(zip_size, block));
834
 
# endif
835
 
 
836
 
        ut_a(val <= ibuf_index_page_calc_free(zip_size, block));
837
 
#endif /* UNIV_IBUF_DEBUG */
838
 
        ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
839
 
                                  IBUF_BITMAP_FREE, val, &mtr);
840
 
        mtr_commit(&mtr);
841
 
}
842
 
 
843
 
/************************************************************************//**
844
 
Resets the free bits of the page in the ibuf bitmap. This is done in a
845
 
separate mini-transaction, hence this operation does not restrict
846
 
further work to only ibuf bitmap operations, which would result if the
847
 
latch to the bitmap page were kept.  NOTE: The free bits in the insert
848
 
buffer bitmap must never exceed the free space on a page.  It is safe
849
 
to decrement or reset the bits in the bitmap in a mini-transaction
850
 
that is committed before the mini-transaction that affects the free
851
 
space. */
852
 
UNIV_INTERN
853
 
void
854
 
ibuf_reset_free_bits(
855
 
/*=================*/
856
 
        buf_block_t*    block)  /*!< in: index page; free bits are set to 0
857
 
                                if the index is a non-clustered
858
 
                                non-unique, and page level is 0 */
859
 
{
860
 
        ibuf_set_free_bits(block, 0, ULINT_UNDEFINED);
861
 
}
862
 
 
863
 
/**********************************************************************//**
864
 
Updates the free bits for an uncompressed page to reflect the present
865
 
state.  Does this in the mtr given, which means that the latching
866
 
order rules virtually prevent any further operations for this OS
867
 
thread until mtr is committed.  NOTE: The free bits in the insert
868
 
buffer bitmap must never exceed the free space on a page.  It is safe
869
 
to set the free bits in the same mini-transaction that updated the
870
 
page. */
871
 
UNIV_INTERN
872
 
void
873
 
ibuf_update_free_bits_low(
874
 
/*======================*/
875
 
        const buf_block_t*      block,          /*!< in: index page */
876
 
        ulint                   max_ins_size,   /*!< in: value of
877
 
                                                maximum insert size
878
 
                                                with reorganize before
879
 
                                                the latest operation
880
 
                                                performed to the page */
881
 
        mtr_t*                  mtr)            /*!< in/out: mtr */
882
 
{
883
 
        ulint   before;
884
 
        ulint   after;
885
 
 
886
 
        ut_a(!buf_block_get_page_zip(block));
887
 
 
888
 
        before = ibuf_index_page_calc_free_bits(0, max_ins_size);
889
 
 
890
 
        after = ibuf_index_page_calc_free(0, block);
891
 
 
892
 
        /* This approach cannot be used on compressed pages, since the
893
 
        computed value of "before" often does not match the current
894
 
        state of the bitmap.  This is because the free space may
895
 
        increase or decrease when a compressed page is reorganized. */
896
 
        if (before != after) {
897
 
                ibuf_set_free_bits_low(0, block, after, mtr);
898
 
        }
899
 
}
900
 
 
901
 
/**********************************************************************//**
902
 
Updates the free bits for a compressed page to reflect the present
903
 
state.  Does this in the mtr given, which means that the latching
904
 
order rules virtually prevent any further operations for this OS
905
 
thread until mtr is committed.  NOTE: The free bits in the insert
906
 
buffer bitmap must never exceed the free space on a page.  It is safe
907
 
to set the free bits in the same mini-transaction that updated the
908
 
page. */
909
 
UNIV_INTERN
910
 
void
911
 
ibuf_update_free_bits_zip(
912
 
/*======================*/
913
 
        buf_block_t*    block,  /*!< in/out: index page */
914
 
        mtr_t*          mtr)    /*!< in/out: mtr */
915
 
{
916
 
        page_t* bitmap_page;
917
 
        ulint   space;
918
 
        ulint   page_no;
919
 
        ulint   zip_size;
920
 
        ulint   after;
921
 
 
922
 
        space = buf_block_get_space(block);
923
 
        page_no = buf_block_get_page_no(block);
924
 
        zip_size = buf_block_get_zip_size(block);
925
 
 
926
 
        ut_a(page_is_leaf(buf_block_get_frame(block)));
927
 
        ut_a(zip_size);
928
 
 
929
 
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
930
 
 
931
 
        after = ibuf_index_page_calc_free_zip(zip_size, block);
932
 
 
933
 
        if (after == 0) {
934
 
                /* We move the page to the front of the buffer pool LRU list:
935
 
                the purpose of this is to prevent those pages to which we
936
 
                cannot make inserts using the insert buffer from slipping
937
 
                out of the buffer pool */
938
 
 
939
 
                buf_page_make_young(&block->page);
940
 
        }
941
 
 
942
 
        ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
943
 
                                  IBUF_BITMAP_FREE, after, mtr);
944
 
}
945
 
 
946
 
/**********************************************************************//**
947
 
Updates the free bits for the two pages to reflect the present state.
948
 
Does this in the mtr given, which means that the latching order rules
949
 
virtually prevent any further operations until mtr is committed.
950
 
NOTE: The free bits in the insert buffer bitmap must never exceed the
951
 
free space on a page.  It is safe to set the free bits in the same
952
 
mini-transaction that updated the pages. */
953
 
UNIV_INTERN
954
 
void
955
 
ibuf_update_free_bits_for_two_pages_low(
956
 
/*====================================*/
957
 
        ulint           zip_size,/*!< in: compressed page size in bytes;
958
 
                                0 for uncompressed pages */
959
 
        buf_block_t*    block1, /*!< in: index page */
960
 
        buf_block_t*    block2, /*!< in: index page */
961
 
        mtr_t*          mtr)    /*!< in: mtr */
962
 
{
963
 
        ulint   state;
964
 
 
965
 
        /* As we have to x-latch two random bitmap pages, we have to acquire
966
 
        the bitmap mutex to prevent a deadlock with a similar operation
967
 
        performed by another OS thread. */
968
 
 
969
 
        mutex_enter(&ibuf_bitmap_mutex);
970
 
 
971
 
        state = ibuf_index_page_calc_free(zip_size, block1);
972
 
 
973
 
        ibuf_set_free_bits_low(zip_size, block1, state, mtr);
974
 
 
975
 
        state = ibuf_index_page_calc_free(zip_size, block2);
976
 
 
977
 
        ibuf_set_free_bits_low(zip_size, block2, state, mtr);
978
 
 
979
 
        mutex_exit(&ibuf_bitmap_mutex);
980
 
}
981
 
 
982
 
/**********************************************************************//**
983
 
Returns TRUE if the page is one of the fixed address ibuf pages.
984
 
@return TRUE if a fixed address ibuf i/o page */
985
 
UNIV_INLINE
986
 
ibool
987
 
ibuf_fixed_addr_page(
988
 
/*=================*/
989
 
        ulint   space,  /*!< in: space id */
990
 
        ulint   zip_size,/*!< in: compressed page size in bytes;
991
 
                        0 for uncompressed pages */
992
 
        ulint   page_no)/*!< in: page number */
993
 
{
994
 
        return((space == IBUF_SPACE_ID && page_no == IBUF_TREE_ROOT_PAGE_NO)
995
 
               || ibuf_bitmap_page(zip_size, page_no));
996
 
}
997
 
 
998
 
/***********************************************************************//**
999
 
Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages.
1000
 
Must not be called when recv_no_ibuf_operations==TRUE.
1001
 
@return TRUE if level 2 or level 3 page */
1002
 
UNIV_INTERN
1003
 
ibool
1004
 
ibuf_page(
1005
 
/*======*/
1006
 
        ulint   space,  /*!< in: space id */
1007
 
        ulint   zip_size,/*!< in: compressed page size in bytes, or 0 */
1008
 
        ulint   page_no,/*!< in: page number */
1009
 
        mtr_t*  mtr)    /*!< in: mtr which will contain an x-latch to the
1010
 
                        bitmap page if the page is not one of the fixed
1011
 
                        address ibuf pages, or NULL, in which case a new
1012
 
                        transaction is created. */
1013
 
{
1014
 
        ibool   ret;
1015
 
        mtr_t   local_mtr;
1016
 
        page_t* bitmap_page;
1017
 
 
1018
 
        ut_ad(!recv_no_ibuf_operations);
1019
 
 
1020
 
        if (ibuf_fixed_addr_page(space, zip_size, page_no)) {
1021
 
 
1022
 
                return(TRUE);
1023
 
        } else if (space != IBUF_SPACE_ID) {
1024
 
 
1025
 
                return(FALSE);
1026
 
        }
1027
 
 
1028
 
        ut_ad(fil_space_get_type(IBUF_SPACE_ID) == FIL_TABLESPACE);
1029
 
 
1030
 
        if (mtr == NULL) {
1031
 
                mtr = &local_mtr;
1032
 
                mtr_start(mtr);
1033
 
        }
1034
 
 
1035
 
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
1036
 
 
1037
 
        ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
1038
 
                                        IBUF_BITMAP_IBUF, mtr);
1039
 
 
1040
 
        if (mtr == &local_mtr) {
1041
 
                mtr_commit(mtr);
1042
 
        }
1043
 
 
1044
 
        return(ret);
1045
 
}
1046
 
 
1047
 
/********************************************************************//**
1048
 
Returns the page number field of an ibuf record.
1049
 
@return page number */
1050
 
static
1051
 
ulint
1052
 
ibuf_rec_get_page_no(
1053
 
/*=================*/
1054
 
        const rec_t*    rec)    /*!< in: ibuf record */
1055
 
{
1056
 
        const byte*     field;
1057
 
        ulint           len;
1058
 
 
1059
 
        ut_ad(ibuf_inside());
1060
 
        ut_ad(rec_get_n_fields_old(rec) > 2);
1061
 
 
1062
 
        field = rec_get_nth_field_old(rec, 1, &len);
1063
 
 
1064
 
        if (len == 1) {
1065
 
                /* This is of the >= 4.1.x record format */
1066
 
                ut_a(trx_sys_multiple_tablespace_format);
1067
 
 
1068
 
                field = rec_get_nth_field_old(rec, 2, &len);
1069
 
        } else {
1070
 
                ut_a(trx_doublewrite_must_reset_space_ids);
1071
 
                ut_a(!trx_sys_multiple_tablespace_format);
1072
 
 
1073
 
                field = rec_get_nth_field_old(rec, 0, &len);
1074
 
        }
1075
 
 
1076
 
        ut_a(len == 4);
1077
 
 
1078
 
        return(mach_read_from_4(field));
1079
 
}
1080
 
 
1081
 
/********************************************************************//**
1082
 
Returns the space id field of an ibuf record. For < 4.1.x format records
1083
 
returns 0.
1084
 
@return space id */
1085
 
static
1086
 
ulint
1087
 
ibuf_rec_get_space(
1088
 
/*===============*/
1089
 
        const rec_t*    rec)    /*!< in: ibuf record */
1090
 
{
1091
 
        const byte*     field;
1092
 
        ulint           len;
1093
 
 
1094
 
        ut_ad(ibuf_inside());
1095
 
        ut_ad(rec_get_n_fields_old(rec) > 2);
1096
 
 
1097
 
        field = rec_get_nth_field_old(rec, 1, &len);
1098
 
 
1099
 
        if (len == 1) {
1100
 
                /* This is of the >= 4.1.x record format */
1101
 
 
1102
 
                ut_a(trx_sys_multiple_tablespace_format);
1103
 
                field = rec_get_nth_field_old(rec, 0, &len);
1104
 
                ut_a(len == 4);
1105
 
 
1106
 
                return(mach_read_from_4(field));
1107
 
        }
1108
 
 
1109
 
        ut_a(trx_doublewrite_must_reset_space_ids);
1110
 
        ut_a(!trx_sys_multiple_tablespace_format);
1111
 
 
1112
 
        return(0);
1113
 
}
1114
 
 
1115
 
/********************************************************************//**
1116
 
Creates a dummy index for inserting a record to a non-clustered index.
1117
 
 
1118
 
@return dummy index */
1119
 
static
1120
 
dict_index_t*
1121
 
ibuf_dummy_index_create(
1122
 
/*====================*/
1123
 
        ulint           n,      /*!< in: number of fields */
1124
 
        ibool           comp)   /*!< in: TRUE=use compact record format */
1125
 
{
1126
 
        dict_table_t*   table;
1127
 
        dict_index_t*   index;
1128
 
 
1129
 
        table = dict_mem_table_create("IBUF_DUMMY",
1130
 
                                      DICT_HDR_SPACE, n,
1131
 
                                      comp ? DICT_TF_COMPACT : 0);
1132
 
 
1133
 
        index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY",
1134
 
                                      DICT_HDR_SPACE, 0, n);
1135
 
 
1136
 
        index->table = table;
1137
 
 
1138
 
        /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
1139
 
        index->cached = TRUE;
1140
 
 
1141
 
        return(index);
1142
 
}
1143
 
/********************************************************************//**
1144
 
Add a column to the dummy index */
1145
 
static
1146
 
void
1147
 
ibuf_dummy_index_add_col(
1148
 
/*=====================*/
1149
 
        dict_index_t*   index,  /*!< in: dummy index */
1150
 
        const dtype_t*  type,   /*!< in: the data type of the column */
1151
 
        ulint           len)    /*!< in: length of the column */
1152
 
{
1153
 
        ulint   i       = index->table->n_def;
1154
 
        dict_mem_table_add_col(index->table, NULL, NULL,
1155
 
                               dtype_get_mtype(type),
1156
 
                               dtype_get_prtype(type),
1157
 
                               dtype_get_len(type));
1158
 
        dict_index_add_col(index, index->table,
1159
 
                           dict_table_get_nth_col(index->table, i), len);
1160
 
}
1161
 
/********************************************************************//**
1162
 
Deallocates a dummy index for inserting a record to a non-clustered index. */
1163
 
static
1164
 
void
1165
 
ibuf_dummy_index_free(
1166
 
/*==================*/
1167
 
        dict_index_t*   index)  /*!< in, own: dummy index */
1168
 
{
1169
 
        dict_table_t*   table = index->table;
1170
 
 
1171
 
        dict_mem_index_free(index);
1172
 
        dict_mem_table_free(table);
1173
 
}
1174
 
 
1175
 
/*********************************************************************//**
1176
 
Builds the entry to insert into a non-clustered index when we have the
1177
 
corresponding record in an ibuf index.
1178
 
 
1179
 
NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1180
 
hold a latch to the ibuf_rec page as long as the entry is used!
1181
 
 
1182
 
@return own: entry to insert to a non-clustered index */
1183
 
UNIV_INLINE
1184
 
dtuple_t*
1185
 
ibuf_build_entry_pre_4_1_x(
1186
 
/*=======================*/
1187
 
        const rec_t*    ibuf_rec,       /*!< in: record in an insert buffer */
1188
 
        mem_heap_t*     heap,           /*!< in: heap where built */
1189
 
        dict_index_t**  pindex)         /*!< out, own: dummy index that
1190
 
                                        describes the entry */
1191
 
{
1192
 
        ulint           i;
1193
 
        ulint           len;
1194
 
        const byte*     types;
1195
 
        dtuple_t*       tuple;
1196
 
        ulint           n_fields;
1197
 
 
1198
 
        ut_a(trx_doublewrite_must_reset_space_ids);
1199
 
        ut_a(!trx_sys_multiple_tablespace_format);
1200
 
 
1201
 
        n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
1202
 
        tuple = dtuple_create(heap, n_fields);
1203
 
        types = rec_get_nth_field_old(ibuf_rec, 1, &len);
1204
 
 
1205
 
        ut_a(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1206
 
 
1207
 
        for (i = 0; i < n_fields; i++) {
1208
 
                const byte*     data;
1209
 
                dfield_t*       field;
1210
 
 
1211
 
                field = dtuple_get_nth_field(tuple, i);
1212
 
 
1213
 
                data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1214
 
 
1215
 
                dfield_set_data(field, data, len);
1216
 
 
1217
 
                dtype_read_for_order_and_null_size(
1218
 
                        dfield_get_type(field),
1219
 
                        types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1220
 
        }
1221
 
 
1222
 
        *pindex = ibuf_dummy_index_create(n_fields, FALSE);
1223
 
 
1224
 
        return(tuple);
1225
 
}
1226
 
 
1227
 
/*********************************************************************//**
1228
 
Builds the entry to insert into a non-clustered index when we have the
1229
 
corresponding record in an ibuf index.
1230
 
 
1231
 
NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1232
 
hold a latch to the ibuf_rec page as long as the entry is used!
1233
 
 
1234
 
@return own: entry to insert to a non-clustered index */
1235
 
static
1236
 
dtuple_t*
1237
 
ibuf_build_entry_from_ibuf_rec(
1238
 
/*===========================*/
1239
 
        const rec_t*    ibuf_rec,       /*!< in: record in an insert buffer */
1240
 
        mem_heap_t*     heap,           /*!< in: heap where built */
1241
 
        dict_index_t**  pindex)         /*!< out, own: dummy index that
1242
 
                                        describes the entry */
1243
 
{
1244
 
        dtuple_t*       tuple;
1245
 
        dfield_t*       field;
1246
 
        ulint           n_fields;
1247
 
        const byte*     types;
1248
 
        const byte*     data;
1249
 
        ulint           len;
1250
 
        ulint           i;
1251
 
        dict_index_t*   index;
1252
 
 
1253
 
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1254
 
 
1255
 
        if (len > 1) {
1256
 
                /* This a < 4.1.x format record */
1257
 
 
1258
 
                return(ibuf_build_entry_pre_4_1_x(ibuf_rec, heap, pindex));
1259
 
        }
1260
 
 
1261
 
        /* This a >= 4.1.x format record */
1262
 
 
1263
 
        ut_a(trx_sys_multiple_tablespace_format);
1264
 
        ut_a(*data == 0);
1265
 
        ut_a(rec_get_n_fields_old(ibuf_rec) > 4);
1266
 
 
1267
 
        n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1268
 
 
1269
 
        tuple = dtuple_create(heap, n_fields);
1270
 
 
1271
 
        types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1272
 
 
1273
 
        ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
1274
 
        index = ibuf_dummy_index_create(
1275
 
                n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1276
 
 
1277
 
        if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
1278
 
                /* compact record format */
1279
 
                len--;
1280
 
                ut_a(*types == 0);
1281
 
                types++;
1282
 
        }
1283
 
 
1284
 
        ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1285
 
 
1286
 
        for (i = 0; i < n_fields; i++) {
1287
 
                field = dtuple_get_nth_field(tuple, i);
1288
 
 
1289
 
                data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1290
 
 
1291
 
                dfield_set_data(field, data, len);
1292
 
 
1293
 
                dtype_new_read_for_order_and_null_size(
1294
 
                        dfield_get_type(field),
1295
 
                        types + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1296
 
 
1297
 
                ibuf_dummy_index_add_col(index, dfield_get_type(field), len);
1298
 
        }
1299
 
 
1300
 
        /* Prevent an ut_ad() failure in page_zip_write_rec() by
1301
 
        adding system columns to the dummy table pointed to by the
1302
 
        dummy secondary index.  The insert buffer is only used for
1303
 
        secondary indexes, whose records never contain any system
1304
 
        columns, such as DB_TRX_ID. */
1305
 
        ut_d(dict_table_add_system_columns(index->table, index->table->heap));
1306
 
 
1307
 
        *pindex = index;
1308
 
 
1309
 
        return(tuple);
1310
 
}
1311
 
 
1312
 
/********************************************************************//**
1313
 
Returns the space taken by a stored non-clustered index entry if converted to
1314
 
an index record.
1315
 
@return size of index record in bytes + an upper limit of the space
1316
 
taken in the page directory */
1317
 
static
1318
 
ulint
1319
 
ibuf_rec_get_volume(
1320
 
/*================*/
1321
 
        const rec_t*    ibuf_rec)/*!< in: ibuf record */
1322
 
{
1323
 
        dtype_t         dtype;
1324
 
        ibool           new_format      = FALSE;
1325
 
        ulint           data_size       = 0;
1326
 
        ulint           n_fields;
1327
 
        const byte*     types;
1328
 
        const byte*     data;
1329
 
        ulint           len;
1330
 
        ulint           i;
1331
 
        ulint           comp;
1332
 
 
1333
 
        ut_ad(ibuf_inside());
1334
 
        ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
1335
 
 
1336
 
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1337
 
 
1338
 
        if (len > 1) {
1339
 
                /* < 4.1.x format record */
1340
 
 
1341
 
                ut_a(trx_doublewrite_must_reset_space_ids);
1342
 
                ut_a(!trx_sys_multiple_tablespace_format);
1343
 
 
1344
 
                n_fields = rec_get_n_fields_old(ibuf_rec) - 2;
1345
 
 
1346
 
                types = rec_get_nth_field_old(ibuf_rec, 1, &len);
1347
 
 
1348
 
                ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1349
 
                comp = 0;
1350
 
        } else {
1351
 
                /* >= 4.1.x format record */
1352
 
 
1353
 
                ut_a(trx_sys_multiple_tablespace_format);
1354
 
                ut_a(*data == 0);
1355
 
 
1356
 
                types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1357
 
 
1358
 
                comp = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1359
 
 
1360
 
                ut_a(comp <= 1);
1361
 
                if (comp) {
1362
 
                        /* compact record format */
1363
 
                        ulint           volume;
1364
 
                        dict_index_t*   dummy_index;
1365
 
                        mem_heap_t*     heap = mem_heap_create(500);
1366
 
                        dtuple_t*       entry = ibuf_build_entry_from_ibuf_rec(
1367
 
                                ibuf_rec, heap, &dummy_index);
1368
 
                        volume = rec_get_converted_size(dummy_index, entry, 0);
1369
 
                        ibuf_dummy_index_free(dummy_index);
1370
 
                        mem_heap_free(heap);
1371
 
                        return(volume + page_dir_calc_reserved_space(1));
1372
 
                }
1373
 
 
1374
 
                n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1375
 
 
1376
 
                new_format = TRUE;
1377
 
        }
1378
 
 
1379
 
        for (i = 0; i < n_fields; i++) {
1380
 
                if (new_format) {
1381
 
                        data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1382
 
 
1383
 
                        dtype_new_read_for_order_and_null_size(
1384
 
                                &dtype, types + i
1385
 
                                * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1386
 
                } else {
1387
 
                        data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1388
 
 
1389
 
                        dtype_read_for_order_and_null_size(
1390
 
                                &dtype, types + i
1391
 
                                * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1392
 
                }
1393
 
 
1394
 
                if (len == UNIV_SQL_NULL) {
1395
 
                        data_size += dtype_get_sql_null_size(&dtype, comp);
1396
 
                } else {
1397
 
                        data_size += len;
1398
 
                }
1399
 
        }
1400
 
 
1401
 
        return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0)
1402
 
               + page_dir_calc_reserved_space(1));
1403
 
}
1404
 
 
1405
 
/*********************************************************************//**
1406
 
Builds the tuple to insert to an ibuf tree when we have an entry for a
1407
 
non-clustered index.
1408
 
 
1409
 
NOTE that the original entry must be kept because we copy pointers to
1410
 
its fields.
1411
 
 
1412
 
@return own: entry to insert into an ibuf index tree */
1413
 
static
1414
 
dtuple_t*
1415
 
ibuf_entry_build(
1416
 
/*=============*/
1417
 
        dict_index_t*   index,  /*!< in: non-clustered index */
1418
 
        const dtuple_t* entry,  /*!< in: entry for a non-clustered index */
1419
 
        ulint           space,  /*!< in: space id */
1420
 
        ulint           page_no,/*!< in: index page number where entry should
1421
 
                                be inserted */
1422
 
        mem_heap_t*     heap)   /*!< in: heap into which to build */
1423
 
{
1424
 
        dtuple_t*       tuple;
1425
 
        dfield_t*       field;
1426
 
        const dfield_t* entry_field;
1427
 
        ulint           n_fields;
1428
 
        byte*           buf;
1429
 
        byte*           buf2;
1430
 
        ulint           i;
1431
 
 
1432
 
        /* Starting from 4.1.x, we have to build a tuple whose
1433
 
        (1) first field is the space id,
1434
 
        (2) the second field a single marker byte (0) to tell that this
1435
 
        is a new format record,
1436
 
        (3) the third contains the page number, and
1437
 
        (4) the fourth contains the relevent type information of each data
1438
 
        field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is
1439
 
        (a) 0 for b-trees in the old format, and
1440
 
        (b) 1 for b-trees in the compact format, the first byte of the field
1441
 
        being the marker (0);
1442
 
        (5) and the rest of the fields are copied from entry. All fields
1443
 
        in the tuple are ordered like the type binary in our insert buffer
1444
 
        tree. */
1445
 
 
1446
 
        n_fields = dtuple_get_n_fields(entry);
1447
 
 
1448
 
        tuple = dtuple_create(heap, n_fields + 4);
1449
 
 
1450
 
        /* Store the space id in tuple */
1451
 
 
1452
 
        field = dtuple_get_nth_field(tuple, 0);
1453
 
 
1454
 
        buf = mem_heap_alloc(heap, 4);
1455
 
 
1456
 
        mach_write_to_4(buf, space);
1457
 
 
1458
 
        dfield_set_data(field, buf, 4);
1459
 
 
1460
 
        /* Store the marker byte field in tuple */
1461
 
 
1462
 
        field = dtuple_get_nth_field(tuple, 1);
1463
 
 
1464
 
        buf = mem_heap_alloc(heap, 1);
1465
 
 
1466
 
        /* We set the marker byte zero */
1467
 
 
1468
 
        mach_write_to_1(buf, 0);
1469
 
 
1470
 
        dfield_set_data(field, buf, 1);
1471
 
 
1472
 
        /* Store the page number in tuple */
1473
 
 
1474
 
        field = dtuple_get_nth_field(tuple, 2);
1475
 
 
1476
 
        buf = mem_heap_alloc(heap, 4);
1477
 
 
1478
 
        mach_write_to_4(buf, page_no);
1479
 
 
1480
 
        dfield_set_data(field, buf, 4);
1481
 
 
1482
 
        /* Store the type info in buf2, and add the fields from entry to
1483
 
        tuple */
1484
 
        buf2 = mem_heap_alloc(heap, n_fields
1485
 
                              * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1486
 
                              + dict_table_is_comp(index->table));
1487
 
        if (dict_table_is_comp(index->table)) {
1488
 
                *buf2++ = 0; /* write the compact format indicator */
1489
 
        }
1490
 
        for (i = 0; i < n_fields; i++) {
1491
 
                ulint                   fixed_len;
1492
 
                const dict_field_t*     ifield;
1493
 
 
1494
 
                /* We add 4 below because we have the 4 extra fields at the
1495
 
                start of an ibuf record */
1496
 
 
1497
 
                field = dtuple_get_nth_field(tuple, i + 4);
1498
 
                entry_field = dtuple_get_nth_field(entry, i);
1499
 
                dfield_copy(field, entry_field);
1500
 
 
1501
 
                ifield = dict_index_get_nth_field(index, i);
1502
 
                /* Prefix index columns of fixed-length columns are of
1503
 
                fixed length.  However, in the function call below,
1504
 
                dfield_get_type(entry_field) contains the fixed length
1505
 
                of the column in the clustered index.  Replace it with
1506
 
                the fixed length of the secondary index column. */
1507
 
                fixed_len = ifield->fixed_len;
1508
 
 
1509
 
#ifdef UNIV_DEBUG
1510
 
                if (fixed_len) {
1511
 
                        /* dict_index_add_col() should guarantee these */
1512
 
                        ut_ad(fixed_len <= (ulint)
1513
 
                              dfield_get_type(entry_field)->len);
1514
 
                        if (ifield->prefix_len) {
1515
 
                                ut_ad(ifield->prefix_len == fixed_len);
1516
 
                        } else {
1517
 
                                ut_ad(fixed_len == (ulint)
1518
 
                                      dfield_get_type(entry_field)->len);
1519
 
                        }
1520
 
                }
1521
 
#endif /* UNIV_DEBUG */
1522
 
 
1523
 
                dtype_new_store_for_order_and_null_size(
1524
 
                        buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
1525
 
                        dfield_get_type(entry_field), fixed_len);
1526
 
        }
1527
 
 
1528
 
        /* Store the type info in buf2 to field 3 of tuple */
1529
 
 
1530
 
        field = dtuple_get_nth_field(tuple, 3);
1531
 
 
1532
 
        if (dict_table_is_comp(index->table)) {
1533
 
                buf2--;
1534
 
        }
1535
 
 
1536
 
        dfield_set_data(field, buf2, n_fields
1537
 
                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1538
 
                        + dict_table_is_comp(index->table));
1539
 
        /* Set all the types in the new tuple binary */
1540
 
 
1541
 
        dtuple_set_types_binary(tuple, n_fields + 4);
1542
 
 
1543
 
        return(tuple);
1544
 
}
1545
 
 
1546
 
/*********************************************************************//**
1547
 
Builds a search tuple used to search buffered inserts for an index page.
1548
 
This is for < 4.1.x format records
1549
 
@return own: search tuple */
1550
 
static
1551
 
dtuple_t*
1552
 
ibuf_search_tuple_build(
1553
 
/*====================*/
1554
 
        ulint           space,  /*!< in: space id */
1555
 
        ulint           page_no,/*!< in: index page number */
1556
 
        mem_heap_t*     heap)   /*!< in: heap into which to build */
1557
 
{
1558
 
        dtuple_t*       tuple;
1559
 
        dfield_t*       field;
1560
 
        byte*           buf;
1561
 
 
1562
 
        ut_a(space == 0);
1563
 
        ut_a(trx_doublewrite_must_reset_space_ids);
1564
 
        ut_a(!trx_sys_multiple_tablespace_format);
1565
 
 
1566
 
        tuple = dtuple_create(heap, 1);
1567
 
 
1568
 
        /* Store the page number in tuple */
1569
 
 
1570
 
        field = dtuple_get_nth_field(tuple, 0);
1571
 
 
1572
 
        buf = mem_heap_alloc(heap, 4);
1573
 
 
1574
 
        mach_write_to_4(buf, page_no);
1575
 
 
1576
 
        dfield_set_data(field, buf, 4);
1577
 
 
1578
 
        dtuple_set_types_binary(tuple, 1);
1579
 
 
1580
 
        return(tuple);
1581
 
}
1582
 
 
1583
 
/*********************************************************************//**
1584
 
Builds a search tuple used to search buffered inserts for an index page.
1585
 
This is for >= 4.1.x format records.
1586
 
@return own: search tuple */
1587
 
static
1588
 
dtuple_t*
1589
 
ibuf_new_search_tuple_build(
1590
 
/*========================*/
1591
 
        ulint           space,  /*!< in: space id */
1592
 
        ulint           page_no,/*!< in: index page number */
1593
 
        mem_heap_t*     heap)   /*!< in: heap into which to build */
1594
 
{
1595
 
        dtuple_t*       tuple;
1596
 
        dfield_t*       field;
1597
 
        byte*           buf;
1598
 
 
1599
 
        ut_a(trx_sys_multiple_tablespace_format);
1600
 
 
1601
 
        tuple = dtuple_create(heap, 3);
1602
 
 
1603
 
        /* Store the space id in tuple */
1604
 
 
1605
 
        field = dtuple_get_nth_field(tuple, 0);
1606
 
 
1607
 
        buf = mem_heap_alloc(heap, 4);
1608
 
 
1609
 
        mach_write_to_4(buf, space);
1610
 
 
1611
 
        dfield_set_data(field, buf, 4);
1612
 
 
1613
 
        /* Store the new format record marker byte */
1614
 
 
1615
 
        field = dtuple_get_nth_field(tuple, 1);
1616
 
 
1617
 
        buf = mem_heap_alloc(heap, 1);
1618
 
 
1619
 
        mach_write_to_1(buf, 0);
1620
 
 
1621
 
        dfield_set_data(field, buf, 1);
1622
 
 
1623
 
        /* Store the page number in tuple */
1624
 
 
1625
 
        field = dtuple_get_nth_field(tuple, 2);
1626
 
 
1627
 
        buf = mem_heap_alloc(heap, 4);
1628
 
 
1629
 
        mach_write_to_4(buf, page_no);
1630
 
 
1631
 
        dfield_set_data(field, buf, 4);
1632
 
 
1633
 
        dtuple_set_types_binary(tuple, 3);
1634
 
 
1635
 
        return(tuple);
1636
 
}
1637
 
 
1638
 
/*********************************************************************//**
1639
 
Checks if there are enough pages in the free list of the ibuf tree that we
1640
 
dare to start a pessimistic insert to the insert buffer.
1641
 
@return TRUE if enough free pages in list */
1642
 
UNIV_INLINE
1643
 
ibool
1644
 
ibuf_data_enough_free_for_insert(void)
1645
 
/*==================================*/
1646
 
{
1647
 
        ut_ad(mutex_own(&ibuf_mutex));
1648
 
 
1649
 
        /* We want a big margin of free pages, because a B-tree can sometimes
1650
 
        grow in size also if records are deleted from it, as the node pointers
1651
 
        can change, and we must make sure that we are able to delete the
1652
 
        inserts buffered for pages that we read to the buffer pool, without
1653
 
        any risk of running out of free space in the insert buffer. */
1654
 
 
1655
 
        return(ibuf->free_list_len >= (ibuf->size / 2) + 3 * ibuf->height);
1656
 
}
1657
 
 
1658
 
/*********************************************************************//**
1659
 
Checks if there are enough pages in the free list of the ibuf tree that we
1660
 
should remove them and free to the file space management.
1661
 
@return TRUE if enough free pages in list */
1662
 
UNIV_INLINE
1663
 
ibool
1664
 
ibuf_data_too_much_free(void)
1665
 
/*=========================*/
1666
 
{
1667
 
        ut_ad(mutex_own(&ibuf_mutex));
1668
 
 
1669
 
        return(ibuf->free_list_len >= 3 + (ibuf->size / 2) + 3 * ibuf->height);
1670
 
}
1671
 
 
1672
 
/*********************************************************************//**
1673
 
Allocates a new page from the ibuf file segment and adds it to the free
1674
 
list.
1675
 
@return DB_SUCCESS, or DB_STRONG_FAIL if no space left */
1676
 
static
1677
 
ulint
1678
 
ibuf_add_free_page(void)
1679
 
/*====================*/
1680
 
{
1681
 
        mtr_t   mtr;
1682
 
        page_t* header_page;
1683
 
        ulint   flags;
1684
 
        ulint   zip_size;
1685
 
        ulint   page_no;
1686
 
        page_t* page;
1687
 
        page_t* root;
1688
 
        page_t* bitmap_page;
1689
 
 
1690
 
        mtr_start(&mtr);
1691
 
 
1692
 
        /* Acquire the fsp latch before the ibuf header, obeying the latching
1693
 
        order */
1694
 
        mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, &flags), &mtr);
1695
 
        zip_size = dict_table_flags_to_zip_size(flags);
1696
 
 
1697
 
        header_page = ibuf_header_page_get(&mtr);
1698
 
 
1699
 
        /* Allocate a new page: NOTE that if the page has been a part of a
1700
 
        non-clustered index which has subsequently been dropped, then the
1701
 
        page may have buffered inserts in the insert buffer, and these
1702
 
        should be deleted from there. These get deleted when the page
1703
 
        allocation creates the page in buffer. Thus the call below may end
1704
 
        up calling the insert buffer routines and, as we yet have no latches
1705
 
        to insert buffer tree pages, these routines can run without a risk
1706
 
        of a deadlock. This is the reason why we created a special ibuf
1707
 
        header page apart from the ibuf tree. */
1708
 
 
1709
 
        page_no = fseg_alloc_free_page(
1710
 
                header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
1711
 
                &mtr);
1712
 
 
1713
 
        if (page_no == FIL_NULL) {
1714
 
                mtr_commit(&mtr);
1715
 
 
1716
 
                return(DB_STRONG_FAIL);
1717
 
        }
1718
 
 
1719
 
        {
1720
 
                buf_block_t*    block;
1721
 
 
1722
 
                block = buf_page_get(
1723
 
                        IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
1724
 
 
1725
 
                buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
1726
 
 
1727
 
 
1728
 
                page = buf_block_get_frame(block);
1729
 
        }
1730
 
 
1731
 
        ibuf_enter();
1732
 
 
1733
 
        mutex_enter(&ibuf_mutex);
1734
 
 
1735
 
        root = ibuf_tree_root_get(&mtr);
1736
 
 
1737
 
        /* Add the page to the free list and update the ibuf size data */
1738
 
 
1739
 
        flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1740
 
                      page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
1741
 
 
1742
 
        mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_IBUF_FREE_LIST,
1743
 
                         MLOG_2BYTES, &mtr);
1744
 
 
1745
 
        ibuf->seg_size++;
1746
 
        ibuf->free_list_len++;
1747
 
 
1748
 
        /* Set the bit indicating that this page is now an ibuf tree page
1749
 
        (level 2 page) */
1750
 
 
1751
 
        bitmap_page = ibuf_bitmap_get_map_page(
1752
 
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
1753
 
 
1754
 
        ibuf_bitmap_page_set_bits(
1755
 
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
1756
 
 
1757
 
        mtr_commit(&mtr);
1758
 
 
1759
 
        mutex_exit(&ibuf_mutex);
1760
 
 
1761
 
        ibuf_exit();
1762
 
 
1763
 
        return(DB_SUCCESS);
1764
 
}
1765
 
 
1766
 
/*********************************************************************//**
1767
 
Removes a page from the free list and frees it to the fsp system. */
1768
 
static
1769
 
void
1770
 
ibuf_remove_free_page(void)
1771
 
/*=======================*/
1772
 
{
1773
 
        mtr_t   mtr;
1774
 
        mtr_t   mtr2;
1775
 
        page_t* header_page;
1776
 
        ulint   flags;
1777
 
        ulint   zip_size;
1778
 
        ulint   page_no;
1779
 
        page_t* page;
1780
 
        page_t* root;
1781
 
        page_t* bitmap_page;
1782
 
 
1783
 
        mtr_start(&mtr);
1784
 
 
1785
 
        /* Acquire the fsp latch before the ibuf header, obeying the latching
1786
 
        order */
1787
 
        mtr_x_lock(fil_space_get_latch(IBUF_SPACE_ID, &flags), &mtr);
1788
 
        zip_size = dict_table_flags_to_zip_size(flags);
1789
 
 
1790
 
        header_page = ibuf_header_page_get(&mtr);
1791
 
 
1792
 
        /* Prevent pessimistic inserts to insert buffer trees for a while */
1793
 
        mutex_enter(&ibuf_pessimistic_insert_mutex);
1794
 
 
1795
 
        ibuf_enter();
1796
 
 
1797
 
        mutex_enter(&ibuf_mutex);
1798
 
 
1799
 
        if (!ibuf_data_too_much_free()) {
1800
 
 
1801
 
                mutex_exit(&ibuf_mutex);
1802
 
 
1803
 
                ibuf_exit();
1804
 
 
1805
 
                mutex_exit(&ibuf_pessimistic_insert_mutex);
1806
 
 
1807
 
                mtr_commit(&mtr);
1808
 
 
1809
 
                return;
1810
 
        }
1811
 
 
1812
 
        mtr_start(&mtr2);
1813
 
 
1814
 
        root = ibuf_tree_root_get(&mtr2);
1815
 
 
1816
 
        page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1817
 
                                &mtr2).page;
1818
 
 
1819
 
        /* NOTE that we must release the latch on the ibuf tree root
1820
 
        because in fseg_free_page we access level 1 pages, and the root
1821
 
        is a level 2 page. */
1822
 
 
1823
 
        mtr_commit(&mtr2);
1824
 
        mutex_exit(&ibuf_mutex);
1825
 
 
1826
 
        ibuf_exit();
1827
 
 
1828
 
        /* Since pessimistic inserts were prevented, we know that the
1829
 
        page is still in the free list. NOTE that also deletes may take
1830
 
        pages from the free list, but they take them from the start, and
1831
 
        the free list was so long that they cannot have taken the last
1832
 
        page from it. */
1833
 
 
1834
 
        fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
1835
 
                       IBUF_SPACE_ID, page_no, &mtr);
1836
 
 
1837
 
#ifdef UNIV_DEBUG_FILE_ACCESSES
1838
 
        buf_page_reset_file_page_was_freed(IBUF_SPACE_ID, page_no);
1839
 
#endif
1840
 
 
1841
 
        ibuf_enter();
1842
 
 
1843
 
        mutex_enter(&ibuf_mutex);
1844
 
 
1845
 
        root = ibuf_tree_root_get(&mtr);
1846
 
 
1847
 
        ut_ad(page_no == flst_get_last(root + PAGE_HEADER
1848
 
                                       + PAGE_BTR_IBUF_FREE_LIST, &mtr).page);
1849
 
 
1850
 
        {
1851
 
                buf_block_t*    block;
1852
 
 
1853
 
                block = buf_page_get(
1854
 
                        IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
1855
 
 
1856
 
                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
1857
 
 
1858
 
 
1859
 
                page = buf_block_get_frame(block);
1860
 
        }
1861
 
 
1862
 
        /* Remove the page from the free list and update the ibuf size data */
1863
 
 
1864
 
        flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1865
 
                    page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
1866
 
 
1867
 
        ibuf->seg_size--;
1868
 
        ibuf->free_list_len--;
1869
 
 
1870
 
        mutex_exit(&ibuf_pessimistic_insert_mutex);
1871
 
 
1872
 
        /* Set the bit indicating that this page is no more an ibuf tree page
1873
 
        (level 2 page) */
1874
 
 
1875
 
        bitmap_page = ibuf_bitmap_get_map_page(
1876
 
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
1877
 
 
1878
 
        ibuf_bitmap_page_set_bits(
1879
 
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr);
1880
 
 
1881
 
#ifdef UNIV_DEBUG_FILE_ACCESSES
1882
 
        buf_page_set_file_page_was_freed(IBUF_SPACE_ID, page_no);
1883
 
#endif
1884
 
        mtr_commit(&mtr);
1885
 
 
1886
 
        mutex_exit(&ibuf_mutex);
1887
 
 
1888
 
        ibuf_exit();
1889
 
}
1890
 
 
1891
 
/***********************************************************************//**
1892
 
Frees excess pages from the ibuf free list. This function is called when an OS
1893
 
thread calls fsp services to allocate a new file segment, or a new page to a
1894
 
file segment, and the thread did not own the fsp latch before this call. */
1895
 
UNIV_INTERN
1896
 
void
1897
 
ibuf_free_excess_pages(void)
1898
 
/*========================*/
1899
 
{
1900
 
        ulint           i;
1901
 
 
1902
 
#ifdef UNIV_SYNC_DEBUG
1903
 
        ut_ad(rw_lock_own(fil_space_get_latch(IBUF_SPACE_ID, NULL),
1904
 
                          RW_LOCK_EX));
1905
 
#endif /* UNIV_SYNC_DEBUG */
1906
 
 
1907
 
        ut_ad(rw_lock_get_x_lock_count(
1908
 
                fil_space_get_latch(IBUF_SPACE_ID, NULL)) == 1);
1909
 
 
1910
 
        ut_ad(!ibuf_inside());
1911
 
 
1912
 
        /* NOTE: We require that the thread did not own the latch before,
1913
 
        because then we know that we can obey the correct latching order
1914
 
        for ibuf latches */
1915
 
 
1916
 
        if (!ibuf) {
1917
 
                /* Not yet initialized; not sure if this is possible, but
1918
 
                does no harm to check for it. */
1919
 
 
1920
 
                return;
1921
 
        }
1922
 
 
1923
 
        /* Free at most a few pages at a time, so that we do not delay the
1924
 
        requested service too much */
1925
 
 
1926
 
        for (i = 0; i < 4; i++) {
1927
 
 
1928
 
                mutex_enter(&ibuf_mutex);
1929
 
 
1930
 
                if (!ibuf_data_too_much_free()) {
1931
 
 
1932
 
                        mutex_exit(&ibuf_mutex);
1933
 
 
1934
 
                        return;
1935
 
                }
1936
 
 
1937
 
                mutex_exit(&ibuf_mutex);
1938
 
 
1939
 
                ibuf_remove_free_page();
1940
 
        }
1941
 
}
1942
 
 
1943
 
/*********************************************************************//**
1944
 
Reads page numbers from a leaf in an ibuf tree.
1945
 
@return a lower limit for the combined volume of records which will be
1946
 
merged */
1947
 
static
1948
 
ulint
1949
 
ibuf_get_merge_page_nos(
1950
 
/*====================*/
1951
 
        ibool           contract,/*!< in: TRUE if this function is called to
1952
 
                                contract the tree, FALSE if this is called
1953
 
                                when a single page becomes full and we look
1954
 
                                if it pays to read also nearby pages */
1955
 
        rec_t*          rec,    /*!< in: record from which we read up and down
1956
 
                                in the chain of records */
1957
 
        ulint*          space_ids,/*!< in/out: space id's of the pages */
1958
 
        ib_int64_t*     space_versions,/*!< in/out: tablespace version
1959
 
                                timestamps; used to prevent reading in old
1960
 
                                pages after DISCARD + IMPORT tablespace */
1961
 
        ulint*          page_nos,/*!< in/out: buffer for at least
1962
 
                                IBUF_MAX_N_PAGES_MERGED many page numbers;
1963
 
                                the page numbers are in an ascending order */
1964
 
        ulint*          n_stored)/*!< out: number of page numbers stored to
1965
 
                                page_nos in this function */
1966
 
{
1967
 
        ulint   prev_page_no;
1968
 
        ulint   prev_space_id;
1969
 
        ulint   first_page_no;
1970
 
        ulint   first_space_id;
1971
 
        ulint   rec_page_no;
1972
 
        ulint   rec_space_id;
1973
 
        ulint   sum_volumes;
1974
 
        ulint   volume_for_page;
1975
 
        ulint   rec_volume;
1976
 
        ulint   limit;
1977
 
        ulint   n_pages;
1978
 
 
1979
 
        *n_stored = 0;
1980
 
 
1981
 
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
1982
 
 
1983
 
        if (page_rec_is_supremum(rec)) {
1984
 
 
1985
 
                rec = page_rec_get_prev(rec);
1986
 
        }
1987
 
 
1988
 
        if (page_rec_is_infimum(rec)) {
1989
 
 
1990
 
                rec = page_rec_get_next(rec);
1991
 
        }
1992
 
 
1993
 
        if (page_rec_is_supremum(rec)) {
1994
 
 
1995
 
                return(0);
1996
 
        }
1997
 
 
1998
 
        first_page_no = ibuf_rec_get_page_no(rec);
1999
 
        first_space_id = ibuf_rec_get_space(rec);
2000
 
        n_pages = 0;
2001
 
        prev_page_no = 0;
2002
 
        prev_space_id = 0;
2003
 
 
2004
 
        /* Go backwards from the first rec until we reach the border of the
2005
 
        'merge area', or the page start or the limit of storeable pages is
2006
 
        reached */
2007
 
 
2008
 
        while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) {
2009
 
 
2010
 
                rec_page_no = ibuf_rec_get_page_no(rec);
2011
 
                rec_space_id = ibuf_rec_get_space(rec);
2012
 
 
2013
 
                if (rec_space_id != first_space_id
2014
 
                    || (rec_page_no / IBUF_MERGE_AREA)
2015
 
                    != (first_page_no / IBUF_MERGE_AREA)) {
2016
 
 
2017
 
                        break;
2018
 
                }
2019
 
 
2020
 
                if (rec_page_no != prev_page_no
2021
 
                    || rec_space_id != prev_space_id) {
2022
 
                        n_pages++;
2023
 
                }
2024
 
 
2025
 
                prev_page_no = rec_page_no;
2026
 
                prev_space_id = rec_space_id;
2027
 
 
2028
 
                rec = page_rec_get_prev(rec);
2029
 
        }
2030
 
 
2031
 
        rec = page_rec_get_next(rec);
2032
 
 
2033
 
        /* At the loop start there is no prev page; we mark this with a pair
2034
 
        of space id, page no (0, 0) for which there can never be entries in
2035
 
        the insert buffer */
2036
 
 
2037
 
        prev_page_no = 0;
2038
 
        prev_space_id = 0;
2039
 
        sum_volumes = 0;
2040
 
        volume_for_page = 0;
2041
 
 
2042
 
        while (*n_stored < limit) {
2043
 
                if (page_rec_is_supremum(rec)) {
2044
 
                        /* When no more records available, mark this with
2045
 
                        another 'impossible' pair of space id, page no */
2046
 
                        rec_page_no = 1;
2047
 
                        rec_space_id = 0;
2048
 
                } else {
2049
 
                        rec_page_no = ibuf_rec_get_page_no(rec);
2050
 
                        rec_space_id = ibuf_rec_get_space(rec);
2051
 
                        ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
2052
 
                }
2053
 
 
2054
 
#ifdef UNIV_IBUF_DEBUG
2055
 
                ut_a(*n_stored < IBUF_MAX_N_PAGES_MERGED);
2056
 
#endif
2057
 
                if ((rec_space_id != prev_space_id
2058
 
                     || rec_page_no != prev_page_no)
2059
 
                    && (prev_space_id != 0 || prev_page_no != 0)) {
2060
 
 
2061
 
                        if ((prev_page_no == first_page_no
2062
 
                             && prev_space_id == first_space_id)
2063
 
                            || contract
2064
 
                            || (volume_for_page
2065
 
                                > ((IBUF_MERGE_THRESHOLD - 1)
2066
 
                                   * 4 * UNIV_PAGE_SIZE
2067
 
                                   / IBUF_PAGE_SIZE_PER_FREE_SPACE)
2068
 
                                / IBUF_MERGE_THRESHOLD)) {
2069
 
 
2070
 
                                space_ids[*n_stored] = prev_space_id;
2071
 
                                space_versions[*n_stored]
2072
 
                                        = fil_space_get_version(prev_space_id);
2073
 
                                page_nos[*n_stored] = prev_page_no;
2074
 
 
2075
 
                                (*n_stored)++;
2076
 
 
2077
 
                                sum_volumes += volume_for_page;
2078
 
                        }
2079
 
 
2080
 
                        if (rec_space_id != first_space_id
2081
 
                            || rec_page_no / IBUF_MERGE_AREA
2082
 
                            != first_page_no / IBUF_MERGE_AREA) {
2083
 
 
2084
 
                                break;
2085
 
                        }
2086
 
 
2087
 
                        volume_for_page = 0;
2088
 
                }
2089
 
 
2090
 
                if (rec_page_no == 1 && rec_space_id == 0) {
2091
 
                        /* Supremum record */
2092
 
 
2093
 
                        break;
2094
 
                }
2095
 
 
2096
 
                rec_volume = ibuf_rec_get_volume(rec);
2097
 
 
2098
 
                volume_for_page += rec_volume;
2099
 
 
2100
 
                prev_page_no = rec_page_no;
2101
 
                prev_space_id = rec_space_id;
2102
 
 
2103
 
                rec = page_rec_get_next(rec);
2104
 
        }
2105
 
 
2106
 
#ifdef UNIV_IBUF_DEBUG
2107
 
        ut_a(*n_stored <= IBUF_MAX_N_PAGES_MERGED);
2108
 
#endif
2109
 
#if 0
2110
 
        fprintf(stderr, "Ibuf merge batch %lu pages %lu volume\n",
2111
 
                *n_stored, sum_volumes);
2112
 
#endif
2113
 
        return(sum_volumes);
2114
 
}
2115
 
 
2116
 
/*********************************************************************//**
2117
 
Contracts insert buffer trees by reading pages to the buffer pool.
2118
 
@return a lower limit for the combined size in bytes of entries which
2119
 
will be merged from ibuf trees to the pages read, 0 if ibuf is
2120
 
empty */
2121
 
static
2122
 
ulint
2123
 
ibuf_contract_ext(
2124
 
/*==============*/
2125
 
        ulint*  n_pages,/*!< out: number of pages to which merged */
2126
 
        ibool   sync)   /*!< in: TRUE if the caller wants to wait for the
2127
 
                        issued read with the highest tablespace address
2128
 
                        to complete */
2129
 
{
2130
 
        btr_pcur_t      pcur;
2131
 
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
2132
 
        ulint           space_ids[IBUF_MAX_N_PAGES_MERGED];
2133
 
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
2134
 
        ulint           n_stored;
2135
 
        ulint           sum_sizes;
2136
 
        mtr_t           mtr;
2137
 
 
2138
 
        *n_pages = 0;
2139
 
        ut_ad(!ibuf_inside());
2140
 
 
2141
 
        mutex_enter(&ibuf_mutex);
2142
 
 
2143
 
        if (ibuf->empty) {
2144
 
ibuf_is_empty:
2145
 
                mutex_exit(&ibuf_mutex);
2146
 
 
2147
 
                return(0);
2148
 
        }
2149
 
 
2150
 
        mtr_start(&mtr);
2151
 
 
2152
 
        ibuf_enter();
2153
 
 
2154
 
        /* Open a cursor to a randomly chosen leaf of the tree, at a random
2155
 
        position within the leaf */
2156
 
 
2157
 
        btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr);
2158
 
 
2159
 
        if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
2160
 
                /* When the ibuf tree is emptied completely, the last record
2161
 
                is removed using an optimistic delete and ibuf_size_update
2162
 
                is not called, causing ibuf->empty to remain FALSE. If we do
2163
 
                not reset it to TRUE here then database shutdown will hang
2164
 
                in the loop in ibuf_contract_for_n_pages. */
2165
 
 
2166
 
                ibuf->empty = TRUE;
2167
 
 
2168
 
                ibuf_exit();
2169
 
 
2170
 
                mtr_commit(&mtr);
2171
 
                btr_pcur_close(&pcur);
2172
 
 
2173
 
                goto ibuf_is_empty;
2174
 
        }
2175
 
 
2176
 
        mutex_exit(&ibuf_mutex);
2177
 
 
2178
 
        sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
2179
 
                                            space_ids, space_versions,
2180
 
                                            page_nos, &n_stored);
2181
 
#if 0 /* defined UNIV_IBUF_DEBUG */
2182
 
        fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
2183
 
                sync, n_stored, sum_sizes);
2184
 
#endif
2185
 
        ibuf_exit();
2186
 
 
2187
 
        mtr_commit(&mtr);
2188
 
        btr_pcur_close(&pcur);
2189
 
 
2190
 
        buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos,
2191
 
                                  n_stored);
2192
 
        *n_pages = n_stored;
2193
 
 
2194
 
        return(sum_sizes + 1);
2195
 
}
2196
 
 
2197
 
/*********************************************************************//**
2198
 
Contracts insert buffer trees by reading pages to the buffer pool.
2199
 
@return a lower limit for the combined size in bytes of entries which
2200
 
will be merged from ibuf trees to the pages read, 0 if ibuf is
2201
 
empty */
2202
 
UNIV_INTERN
2203
 
ulint
2204
 
ibuf_contract(
2205
 
/*==========*/
2206
 
        ibool   sync)   /*!< in: TRUE if the caller wants to wait for the
2207
 
                        issued read with the highest tablespace address
2208
 
                        to complete */
2209
 
{
2210
 
        ulint   n_pages;
2211
 
 
2212
 
        return(ibuf_contract_ext(&n_pages, sync));
2213
 
}
2214
 
 
2215
 
/*********************************************************************//**
2216
 
Contracts insert buffer trees by reading pages to the buffer pool.
2217
 
@return a lower limit for the combined size in bytes of entries which
2218
 
will be merged from ibuf trees to the pages read, 0 if ibuf is
2219
 
empty */
2220
 
UNIV_INTERN
2221
 
ulint
2222
 
ibuf_contract_for_n_pages(
2223
 
/*======================*/
2224
 
        ibool   sync,   /*!< in: TRUE if the caller wants to wait for the
2225
 
                        issued read with the highest tablespace address
2226
 
                        to complete */
2227
 
        ulint   n_pages)/*!< in: try to read at least this many pages to
2228
 
                        the buffer pool and merge the ibuf contents to
2229
 
                        them */
2230
 
{
2231
 
        ulint   sum_bytes       = 0;
2232
 
        ulint   sum_pages       = 0;
2233
 
        ulint   n_bytes;
2234
 
        ulint   n_pag2;
2235
 
 
2236
 
        while (sum_pages < n_pages) {
2237
 
                n_bytes = ibuf_contract_ext(&n_pag2, sync);
2238
 
 
2239
 
                if (n_bytes == 0) {
2240
 
                        return(sum_bytes);
2241
 
                }
2242
 
 
2243
 
                sum_bytes += n_bytes;
2244
 
                sum_pages += n_pag2;
2245
 
        }
2246
 
 
2247
 
        return(sum_bytes);
2248
 
}
2249
 
 
2250
 
/*********************************************************************//**
2251
 
Contract insert buffer trees after insert if they are too big. */
2252
 
UNIV_INLINE
2253
 
void
2254
 
ibuf_contract_after_insert(
2255
 
/*=======================*/
2256
 
        ulint   entry_size)     /*!< in: size of a record which was inserted
2257
 
                                into an ibuf tree */
2258
 
{
2259
 
        ibool   sync;
2260
 
        ulint   sum_sizes;
2261
 
        ulint   size;
2262
 
 
2263
 
        mutex_enter(&ibuf_mutex);
2264
 
 
2265
 
        if (ibuf->size < ibuf->max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
2266
 
                mutex_exit(&ibuf_mutex);
2267
 
 
2268
 
                return;
2269
 
        }
2270
 
 
2271
 
        sync = FALSE;
2272
 
 
2273
 
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_ON_INSERT_SYNC) {
2274
 
 
2275
 
                sync = TRUE;
2276
 
        }
2277
 
 
2278
 
        mutex_exit(&ibuf_mutex);
2279
 
 
2280
 
        /* Contract at least entry_size many bytes */
2281
 
        sum_sizes = 0;
2282
 
        size = 1;
2283
 
 
2284
 
        while ((size > 0) && (sum_sizes < entry_size)) {
2285
 
 
2286
 
                size = ibuf_contract(sync);
2287
 
                sum_sizes += size;
2288
 
        }
2289
 
}
2290
 
 
2291
 
/*********************************************************************//**
2292
 
Gets an upper limit for the combined size of entries buffered in the insert
2293
 
buffer for a given page.
2294
 
@return upper limit for the volume of buffered inserts for the index
2295
 
page, in bytes; UNIV_PAGE_SIZE, if the entries for the index page span
2296
 
several pages in the insert buffer */
2297
 
static
2298
 
ulint
2299
 
ibuf_get_volume_buffered(
2300
 
/*=====================*/
2301
 
        btr_pcur_t*     pcur,   /*!< in: pcur positioned at a place in an
2302
 
                                insert buffer tree where we would insert an
2303
 
                                entry for the index page whose number is
2304
 
                                page_no, latch mode has to be BTR_MODIFY_PREV
2305
 
                                or BTR_MODIFY_TREE */
2306
 
        ulint           space,  /*!< in: space id */
2307
 
        ulint           page_no,/*!< in: page number of an index page */
2308
 
        mtr_t*          mtr)    /*!< in: mtr */
2309
 
{
2310
 
        ulint   volume;
2311
 
        rec_t*  rec;
2312
 
        page_t* page;
2313
 
        ulint   prev_page_no;
2314
 
        page_t* prev_page;
2315
 
        ulint   next_page_no;
2316
 
        page_t* next_page;
2317
 
 
2318
 
        ut_a(trx_sys_multiple_tablespace_format);
2319
 
 
2320
 
        ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
2321
 
              || (pcur->latch_mode == BTR_MODIFY_TREE));
2322
 
 
2323
 
        /* Count the volume of records earlier in the alphabetical order than
2324
 
        pcur */
2325
 
 
2326
 
        volume = 0;
2327
 
 
2328
 
        rec = btr_pcur_get_rec(pcur);
2329
 
        page = page_align(rec);
2330
 
 
2331
 
        if (page_rec_is_supremum(rec)) {
2332
 
                rec = page_rec_get_prev(rec);
2333
 
        }
2334
 
 
2335
 
        for (;;) {
2336
 
                if (page_rec_is_infimum(rec)) {
2337
 
 
2338
 
                        break;
2339
 
                }
2340
 
 
2341
 
                if (page_no != ibuf_rec_get_page_no(rec)
2342
 
                    || space != ibuf_rec_get_space(rec)) {
2343
 
 
2344
 
                        goto count_later;
2345
 
                }
2346
 
 
2347
 
                volume += ibuf_rec_get_volume(rec);
2348
 
 
2349
 
                rec = page_rec_get_prev(rec);
2350
 
        }
2351
 
 
2352
 
        /* Look at the previous page */
2353
 
 
2354
 
        prev_page_no = btr_page_get_prev(page, mtr);
2355
 
 
2356
 
        if (prev_page_no == FIL_NULL) {
2357
 
 
2358
 
                goto count_later;
2359
 
        }
2360
 
 
2361
 
        {
2362
 
                buf_block_t*    block;
2363
 
 
2364
 
                block = buf_page_get(
2365
 
                        IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr);
2366
 
 
2367
 
                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
2368
 
 
2369
 
 
2370
 
                prev_page = buf_block_get_frame(block);
2371
 
        }
2372
 
 
2373
 
#ifdef UNIV_BTR_DEBUG
2374
 
        ut_a(btr_page_get_next(prev_page, mtr)
2375
 
             == page_get_page_no(page));
2376
 
#endif /* UNIV_BTR_DEBUG */
2377
 
 
2378
 
        rec = page_get_supremum_rec(prev_page);
2379
 
        rec = page_rec_get_prev(rec);
2380
 
 
2381
 
        for (;;) {
2382
 
                if (page_rec_is_infimum(rec)) {
2383
 
 
2384
 
                        /* We cannot go to yet a previous page, because we
2385
 
                        do not have the x-latch on it, and cannot acquire one
2386
 
                        because of the latching order: we have to give up */
2387
 
 
2388
 
                        return(UNIV_PAGE_SIZE);
2389
 
                }
2390
 
 
2391
 
                if (page_no != ibuf_rec_get_page_no(rec)
2392
 
                    || space != ibuf_rec_get_space(rec)) {
2393
 
 
2394
 
                        goto count_later;
2395
 
                }
2396
 
 
2397
 
                volume += ibuf_rec_get_volume(rec);
2398
 
 
2399
 
                rec = page_rec_get_prev(rec);
2400
 
        }
2401
 
 
2402
 
count_later:
2403
 
        rec = btr_pcur_get_rec(pcur);
2404
 
 
2405
 
        if (!page_rec_is_supremum(rec)) {
2406
 
                rec = page_rec_get_next(rec);
2407
 
        }
2408
 
 
2409
 
        for (;;) {
2410
 
                if (page_rec_is_supremum(rec)) {
2411
 
 
2412
 
                        break;
2413
 
                }
2414
 
 
2415
 
                if (page_no != ibuf_rec_get_page_no(rec)
2416
 
                    || space != ibuf_rec_get_space(rec)) {
2417
 
 
2418
 
                        return(volume);
2419
 
                }
2420
 
 
2421
 
                volume += ibuf_rec_get_volume(rec);
2422
 
 
2423
 
                rec = page_rec_get_next(rec);
2424
 
        }
2425
 
 
2426
 
        /* Look at the next page */
2427
 
 
2428
 
        next_page_no = btr_page_get_next(page, mtr);
2429
 
 
2430
 
        if (next_page_no == FIL_NULL) {
2431
 
 
2432
 
                return(volume);
2433
 
        }
2434
 
 
2435
 
        {
2436
 
                buf_block_t*    block;
2437
 
 
2438
 
                block = buf_page_get(
2439
 
                        IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr);
2440
 
 
2441
 
                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
2442
 
 
2443
 
 
2444
 
                next_page = buf_block_get_frame(block);
2445
 
        }
2446
 
 
2447
 
#ifdef UNIV_BTR_DEBUG
2448
 
        ut_a(btr_page_get_prev(next_page, mtr) == page_get_page_no(page));
2449
 
#endif /* UNIV_BTR_DEBUG */
2450
 
 
2451
 
        rec = page_get_infimum_rec(next_page);
2452
 
        rec = page_rec_get_next(rec);
2453
 
 
2454
 
        for (;;) {
2455
 
                if (page_rec_is_supremum(rec)) {
2456
 
 
2457
 
                        /* We give up */
2458
 
 
2459
 
                        return(UNIV_PAGE_SIZE);
2460
 
                }
2461
 
 
2462
 
                if (page_no != ibuf_rec_get_page_no(rec)
2463
 
                    || space != ibuf_rec_get_space(rec)) {
2464
 
 
2465
 
                        return(volume);
2466
 
                }
2467
 
 
2468
 
                volume += ibuf_rec_get_volume(rec);
2469
 
 
2470
 
                rec = page_rec_get_next(rec);
2471
 
        }
2472
 
}
2473
 
 
2474
 
/*********************************************************************//**
2475
 
Reads the biggest tablespace id from the high end of the insert buffer
2476
 
tree and updates the counter in fil_system. */
2477
 
UNIV_INTERN
2478
 
void
2479
 
ibuf_update_max_tablespace_id(void)
2480
 
/*===============================*/
2481
 
{
2482
 
        ulint           max_space_id;
2483
 
        const rec_t*    rec;
2484
 
        const byte*     field;
2485
 
        ulint           len;
2486
 
        btr_pcur_t      pcur;
2487
 
        mtr_t           mtr;
2488
 
 
2489
 
        ut_a(!dict_table_is_comp(ibuf->index->table));
2490
 
 
2491
 
        ibuf_enter();
2492
 
 
2493
 
        mtr_start(&mtr);
2494
 
 
2495
 
        btr_pcur_open_at_index_side(
2496
 
                FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
2497
 
 
2498
 
        btr_pcur_move_to_prev(&pcur, &mtr);
2499
 
 
2500
 
        if (btr_pcur_is_before_first_on_page(&pcur)) {
2501
 
                /* The tree is empty */
2502
 
 
2503
 
                max_space_id = 0;
2504
 
        } else {
2505
 
                rec = btr_pcur_get_rec(&pcur);
2506
 
 
2507
 
                field = rec_get_nth_field_old(rec, 0, &len);
2508
 
 
2509
 
                ut_a(len == 4);
2510
 
 
2511
 
                max_space_id = mach_read_from_4(field);
2512
 
        }
2513
 
 
2514
 
        mtr_commit(&mtr);
2515
 
        ibuf_exit();
2516
 
 
2517
 
        /* printf("Maximum space id in insert buffer %lu\n", max_space_id); */
2518
 
 
2519
 
        fil_set_max_space_id_if_bigger(max_space_id);
2520
 
}
2521
 
 
2522
 
/*********************************************************************//**
2523
 
Makes an index insert to the insert buffer, instead of directly to the disk
2524
 
page, if this is possible.
2525
 
@return DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */
2526
 
static
2527
 
ulint
2528
 
ibuf_insert_low(
2529
 
/*============*/
2530
 
        ulint           mode,   /*!< in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */
2531
 
        const dtuple_t* entry,  /*!< in: index entry to insert */
2532
 
        ulint           entry_size,
2533
 
                                /*!< in: rec_get_converted_size(index, entry) */
2534
 
        dict_index_t*   index,  /*!< in: index where to insert; must not be
2535
 
                                unique or clustered */
2536
 
        ulint           space,  /*!< in: space id where to insert */
2537
 
        ulint           zip_size,/*!< in: compressed page size in bytes, or 0 */
2538
 
        ulint           page_no,/*!< in: page number where to insert */
2539
 
        que_thr_t*      thr)    /*!< in: query thread */
2540
 
{
2541
 
        big_rec_t*      dummy_big_rec;
2542
 
        btr_pcur_t      pcur;
2543
 
        btr_cur_t*      cursor;
2544
 
        dtuple_t*       ibuf_entry;
2545
 
        mem_heap_t*     heap;
2546
 
        ulint           buffered;
2547
 
        rec_t*          ins_rec;
2548
 
        ibool           old_bit_value;
2549
 
        page_t*         bitmap_page;
2550
 
        page_t*         root;
2551
 
        ulint           err;
2552
 
        ibool           do_merge;
2553
 
        ulint           space_ids[IBUF_MAX_N_PAGES_MERGED];
2554
 
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
2555
 
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
2556
 
        ulint           n_stored;
2557
 
        ulint           bits;
2558
 
        mtr_t           mtr;
2559
 
        mtr_t           bitmap_mtr;
2560
 
 
2561
 
        ut_a(!dict_index_is_clust(index));
2562
 
        ut_ad(dtuple_check_typed(entry));
2563
 
        ut_ad(ut_is_2pow(zip_size));
2564
 
 
2565
 
        ut_a(trx_sys_multiple_tablespace_format);
2566
 
 
2567
 
        do_merge = FALSE;
2568
 
 
2569
 
        mutex_enter(&ibuf_mutex);
2570
 
 
2571
 
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
2572
 
                /* Insert buffer is now too big, contract it but do not try
2573
 
                to insert */
2574
 
 
2575
 
                mutex_exit(&ibuf_mutex);
2576
 
 
2577
 
#ifdef UNIV_IBUF_DEBUG
2578
 
                fputs("Ibuf too big\n", stderr);
2579
 
#endif
2580
 
                /* Use synchronous contract (== TRUE) */
2581
 
                ibuf_contract(TRUE);
2582
 
 
2583
 
                return(DB_STRONG_FAIL);
2584
 
        }
2585
 
 
2586
 
        mutex_exit(&ibuf_mutex);
2587
 
 
2588
 
        if (mode == BTR_MODIFY_TREE) {
2589
 
                mutex_enter(&ibuf_pessimistic_insert_mutex);
2590
 
 
2591
 
                ibuf_enter();
2592
 
 
2593
 
                mutex_enter(&ibuf_mutex);
2594
 
 
2595
 
                while (!ibuf_data_enough_free_for_insert()) {
2596
 
 
2597
 
                        mutex_exit(&ibuf_mutex);
2598
 
 
2599
 
                        ibuf_exit();
2600
 
 
2601
 
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
2602
 
 
2603
 
                        err = ibuf_add_free_page();
2604
 
 
2605
 
                        if (err == DB_STRONG_FAIL) {
2606
 
 
2607
 
                                return(err);
2608
 
                        }
2609
 
 
2610
 
                        mutex_enter(&ibuf_pessimistic_insert_mutex);
2611
 
 
2612
 
                        ibuf_enter();
2613
 
 
2614
 
                        mutex_enter(&ibuf_mutex);
2615
 
                }
2616
 
        } else {
2617
 
                ibuf_enter();
2618
 
        }
2619
 
 
2620
 
        heap = mem_heap_create(512);
2621
 
 
2622
 
        /* Build the entry which contains the space id and the page number as
2623
 
        the first fields and the type information for other fields, and which
2624
 
        will be inserted to the insert buffer. */
2625
 
 
2626
 
        ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap);
2627
 
 
2628
 
        /* Open a cursor to the insert buffer tree to calculate if we can add
2629
 
        the new entry to it without exceeding the free space limit for the
2630
 
        page. */
2631
 
 
2632
 
        mtr_start(&mtr);
2633
 
 
2634
 
        btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
2635
 
 
2636
 
        /* Find out the volume of already buffered inserts for the same index
2637
 
        page */
2638
 
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
2639
 
 
2640
 
#ifdef UNIV_IBUF_COUNT_DEBUG
2641
 
        ut_a((buffered == 0) || ibuf_count_get(space, page_no));
2642
 
#endif
2643
 
        mtr_start(&bitmap_mtr);
2644
 
 
2645
 
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
2646
 
                                               zip_size, &bitmap_mtr);
2647
 
 
2648
 
        /* We check if the index page is suitable for buffered entries */
2649
 
 
2650
 
        if (buf_page_peek(space, page_no)
2651
 
            || lock_rec_expl_exist_on_page(space, page_no)) {
2652
 
                err = DB_STRONG_FAIL;
2653
 
 
2654
 
                mtr_commit(&bitmap_mtr);
2655
 
 
2656
 
                goto function_exit;
2657
 
        }
2658
 
 
2659
 
        bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
2660
 
                                         IBUF_BITMAP_FREE, &bitmap_mtr);
2661
 
 
2662
 
        if (buffered + entry_size + page_dir_calc_reserved_space(1)
2663
 
            > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
2664
 
                mtr_commit(&bitmap_mtr);
2665
 
 
2666
 
                /* It may not fit */
2667
 
                err = DB_STRONG_FAIL;
2668
 
 
2669
 
                do_merge = TRUE;
2670
 
 
2671
 
                ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
2672
 
                                        space_ids, space_versions,
2673
 
                                        page_nos, &n_stored);
2674
 
                goto function_exit;
2675
 
        }
2676
 
 
2677
 
        /* Set the bitmap bit denoting that the insert buffer contains
2678
 
        buffered entries for this index page, if the bit is not set yet */
2679
 
 
2680
 
        old_bit_value = ibuf_bitmap_page_get_bits(
2681
 
                bitmap_page, page_no, zip_size,
2682
 
                IBUF_BITMAP_BUFFERED, &bitmap_mtr);
2683
 
 
2684
 
        if (!old_bit_value) {
2685
 
                ibuf_bitmap_page_set_bits(bitmap_page, page_no, zip_size,
2686
 
                                          IBUF_BITMAP_BUFFERED, TRUE,
2687
 
                                          &bitmap_mtr);
2688
 
        }
2689
 
 
2690
 
        mtr_commit(&bitmap_mtr);
2691
 
 
2692
 
        cursor = btr_pcur_get_btr_cur(&pcur);
2693
 
 
2694
 
        if (mode == BTR_MODIFY_PREV) {
2695
 
                err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
2696
 
                                                ibuf_entry, &ins_rec,
2697
 
                                                &dummy_big_rec, 0, thr, &mtr);
2698
 
                if (err == DB_SUCCESS) {
2699
 
                        /* Update the page max trx id field */
2700
 
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
2701
 
                                               thr_get_trx(thr)->id, &mtr);
2702
 
                }
2703
 
        } else {
2704
 
                ut_ad(mode == BTR_MODIFY_TREE);
2705
 
 
2706
 
                /* We acquire an x-latch to the root page before the insert,
2707
 
                because a pessimistic insert releases the tree x-latch,
2708
 
                which would cause the x-latching of the root after that to
2709
 
                break the latching order. */
2710
 
 
2711
 
                root = ibuf_tree_root_get(&mtr);
2712
 
 
2713
 
                err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
2714
 
                                                 | BTR_NO_UNDO_LOG_FLAG,
2715
 
                                                 cursor,
2716
 
                                                 ibuf_entry, &ins_rec,
2717
 
                                                 &dummy_big_rec, 0, thr, &mtr);
2718
 
                if (err == DB_SUCCESS) {
2719
 
                        /* Update the page max trx id field */
2720
 
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
2721
 
                                               thr_get_trx(thr)->id, &mtr);
2722
 
                }
2723
 
 
2724
 
                ibuf_size_update(root, &mtr);
2725
 
        }
2726
 
 
2727
 
function_exit:
2728
 
#ifdef UNIV_IBUF_COUNT_DEBUG
2729
 
        if (err == DB_SUCCESS) {
2730
 
                fprintf(stderr,
2731
 
                        "Incrementing ibuf count of space %lu page %lu\n"
2732
 
                        "from %lu by 1\n", space, page_no,
2733
 
                        ibuf_count_get(space, page_no));
2734
 
 
2735
 
                ibuf_count_set(space, page_no,
2736
 
                               ibuf_count_get(space, page_no) + 1);
2737
 
        }
2738
 
#endif
2739
 
        if (mode == BTR_MODIFY_TREE) {
2740
 
 
2741
 
                mutex_exit(&ibuf_mutex);
2742
 
                mutex_exit(&ibuf_pessimistic_insert_mutex);
2743
 
        }
2744
 
 
2745
 
        mtr_commit(&mtr);
2746
 
        btr_pcur_close(&pcur);
2747
 
        ibuf_exit();
2748
 
 
2749
 
        mem_heap_free(heap);
2750
 
 
2751
 
        if (err == DB_SUCCESS) {
2752
 
                mutex_enter(&ibuf_mutex);
2753
 
 
2754
 
                ibuf->empty = FALSE;
2755
 
                ibuf->n_inserts++;
2756
 
 
2757
 
                mutex_exit(&ibuf_mutex);
2758
 
 
2759
 
                if (mode == BTR_MODIFY_TREE) {
2760
 
                        ibuf_contract_after_insert(entry_size);
2761
 
                }
2762
 
        }
2763
 
 
2764
 
        if (do_merge) {
2765
 
#ifdef UNIV_IBUF_DEBUG
2766
 
                ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
2767
 
#endif
2768
 
                buf_read_ibuf_merge_pages(FALSE, space_ids, space_versions,
2769
 
                                          page_nos, n_stored);
2770
 
        }
2771
 
 
2772
 
        return(err);
2773
 
}
2774
 
 
2775
 
/*********************************************************************//**
2776
 
Makes an index insert to the insert buffer, instead of directly to the disk
2777
 
page, if this is possible. Does not do insert if the index is clustered
2778
 
or unique.
2779
 
@return TRUE if success */
2780
 
UNIV_INTERN
2781
 
ibool
2782
 
ibuf_insert(
2783
 
/*========*/
2784
 
        const dtuple_t* entry,  /*!< in: index entry to insert */
2785
 
        dict_index_t*   index,  /*!< in: index where to insert */
2786
 
        ulint           space,  /*!< in: space id where to insert */
2787
 
        ulint           zip_size,/*!< in: compressed page size in bytes, or 0 */
2788
 
        ulint           page_no,/*!< in: page number where to insert */
2789
 
        que_thr_t*      thr)    /*!< in: query thread */
2790
 
{
2791
 
        ulint   err;
2792
 
        ulint   entry_size;
2793
 
 
2794
 
        ut_a(trx_sys_multiple_tablespace_format);
2795
 
        ut_ad(dtuple_check_typed(entry));
2796
 
        ut_ad(ut_is_2pow(zip_size));
2797
 
 
2798
 
        ut_a(!dict_index_is_clust(index));
2799
 
 
2800
 
        switch (UNIV_EXPECT(ibuf_use, IBUF_USE_INSERT)) {
2801
 
        case IBUF_USE_NONE:
2802
 
                return(FALSE);
2803
 
        case IBUF_USE_INSERT:
2804
 
                goto do_insert;
2805
 
        case IBUF_USE_COUNT:
2806
 
                break;
2807
 
        }
2808
 
 
2809
 
        ut_error; /* unknown value of ibuf_use */
2810
 
 
2811
 
do_insert:
2812
 
        entry_size = rec_get_converted_size(index, entry, 0);
2813
 
 
2814
 
        if (entry_size
2815
 
            >= (page_get_free_space_of_empty(dict_table_is_comp(index->table))
2816
 
                / 2)) {
2817
 
                return(FALSE);
2818
 
        }
2819
 
 
2820
 
        err = ibuf_insert_low(BTR_MODIFY_PREV, entry, entry_size,
2821
 
                              index, space, zip_size, page_no, thr);
2822
 
        if (err == DB_FAIL) {
2823
 
                err = ibuf_insert_low(BTR_MODIFY_TREE, entry, entry_size,
2824
 
                                      index, space, zip_size, page_no, thr);
2825
 
        }
2826
 
 
2827
 
        if (err == DB_SUCCESS) {
2828
 
#ifdef UNIV_IBUF_DEBUG
2829
 
                /* fprintf(stderr, "Ibuf insert for page no %lu of index %s\n",
2830
 
                page_no, index->name); */
2831
 
#endif
2832
 
                return(TRUE);
2833
 
 
2834
 
        } else {
2835
 
                ut_a(err == DB_STRONG_FAIL);
2836
 
 
2837
 
                return(FALSE);
2838
 
        }
2839
 
}
2840
 
 
2841
 
/********************************************************************//**
2842
 
During merge, inserts to an index page a secondary index entry extracted
2843
 
from the insert buffer. */
2844
 
static
2845
 
void
2846
 
ibuf_insert_to_index_page(
2847
 
/*======================*/
2848
 
        dtuple_t*       entry,  /*!< in: buffered entry to insert */
2849
 
        buf_block_t*    block,  /*!< in/out: index page where the buffered entry
2850
 
                                should be placed */
2851
 
        dict_index_t*   index,  /*!< in: record descriptor */
2852
 
        mtr_t*          mtr)    /*!< in: mtr */
2853
 
{
2854
 
        page_cur_t      page_cur;
2855
 
        ulint           low_match;
2856
 
        page_t*         page            = buf_block_get_frame(block);
2857
 
        rec_t*          rec;
2858
 
        page_t*         bitmap_page;
2859
 
        ulint           old_bits;
2860
 
 
2861
 
        ut_ad(ibuf_inside());
2862
 
        ut_ad(dtuple_check_typed(entry));
2863
 
 
2864
 
        if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
2865
 
                          != (ibool)!!page_is_comp(page))) {
2866
 
                fputs("InnoDB: Trying to insert a record from"
2867
 
                      " the insert buffer to an index page\n"
2868
 
                      "InnoDB: but the 'compact' flag does not match!\n",
2869
 
                      stderr);
2870
 
                goto dump;
2871
 
        }
2872
 
 
2873
 
        rec = page_rec_get_next(page_get_infimum_rec(page));
2874
 
 
2875
 
        if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
2876
 
                          != dtuple_get_n_fields(entry))) {
2877
 
                fputs("InnoDB: Trying to insert a record from"
2878
 
                      " the insert buffer to an index page\n"
2879
 
                      "InnoDB: but the number of fields does not match!\n",
2880
 
                      stderr);
2881
 
dump:
2882
 
                buf_page_print(page, 0);
2883
 
 
2884
 
                dtuple_print(stderr, entry);
2885
 
 
2886
 
                fputs("InnoDB: The table where where"
2887
 
                      " this index record belongs\n"
2888
 
                      "InnoDB: is now probably corrupt."
2889
 
                      " Please run CHECK TABLE on\n"
2890
 
                      "InnoDB: your tables.\n"
2891
 
                      "InnoDB: Submit a detailed bug report to"
2892
 
                      " http://bugs.mysql.com!\n", stderr);
2893
 
 
2894
 
                return;
2895
 
        }
2896
 
 
2897
 
        low_match = page_cur_search(block, index, entry,
2898
 
                                    PAGE_CUR_LE, &page_cur);
2899
 
 
2900
 
        if (low_match == dtuple_get_n_fields(entry)) {
2901
 
                page_zip_des_t* page_zip;
2902
 
 
2903
 
                rec = page_cur_get_rec(&page_cur);
2904
 
                page_zip = buf_block_get_page_zip(block);
2905
 
 
2906
 
                btr_cur_del_unmark_for_ibuf(rec, page_zip, mtr);
2907
 
        } else {
2908
 
                rec = page_cur_tuple_insert(&page_cur, entry, index, 0, mtr);
2909
 
 
2910
 
                if (UNIV_LIKELY(rec != NULL)) {
2911
 
                        return;
2912
 
                }
2913
 
 
2914
 
                /* If the record did not fit, reorganize */
2915
 
 
2916
 
                btr_page_reorganize(block, index, mtr);
2917
 
                page_cur_search(block, index, entry, PAGE_CUR_LE, &page_cur);
2918
 
 
2919
 
                /* This time the record must fit */
2920
 
                if (UNIV_UNLIKELY
2921
 
                    (!page_cur_tuple_insert(&page_cur, entry, index,
2922
 
                                            0, mtr))) {
2923
 
                        ulint   space;
2924
 
                        ulint   page_no;
2925
 
                        ulint   zip_size;
2926
 
 
2927
 
                        ut_print_timestamp(stderr);
2928
 
 
2929
 
                        fprintf(stderr,
2930
 
                                "  InnoDB: Error: Insert buffer insert"
2931
 
                                " fails; page free %lu,"
2932
 
                                " dtuple size %lu\n",
2933
 
                                (ulong) page_get_max_insert_size(
2934
 
                                        page, 1),
2935
 
                                (ulong) rec_get_converted_size(
2936
 
                                        index, entry, 0));
2937
 
                        fputs("InnoDB: Cannot insert index record ",
2938
 
                              stderr);
2939
 
                        dtuple_print(stderr, entry);
2940
 
                        fputs("\nInnoDB: The table where"
2941
 
                              " this index record belongs\n"
2942
 
                              "InnoDB: is now probably corrupt."
2943
 
                              " Please run CHECK TABLE on\n"
2944
 
                              "InnoDB: that table.\n", stderr);
2945
 
 
2946
 
                        space = page_get_space_id(page);
2947
 
                        zip_size = buf_block_get_zip_size(block);
2948
 
                        page_no = page_get_page_no(page);
2949
 
 
2950
 
                        bitmap_page = ibuf_bitmap_get_map_page(
2951
 
                                space, page_no, zip_size, mtr);
2952
 
                        old_bits = ibuf_bitmap_page_get_bits(
2953
 
                                bitmap_page, page_no, zip_size,
2954
 
                                IBUF_BITMAP_FREE, mtr);
2955
 
 
2956
 
                        fprintf(stderr,
2957
 
                                "InnoDB: space %lu, page %lu,"
2958
 
                                " zip_size %lu, bitmap bits %lu\n",
2959
 
                                (ulong) space, (ulong) page_no,
2960
 
                                (ulong) zip_size, (ulong) old_bits);
2961
 
 
2962
 
                        fputs("InnoDB: Submit a detailed bug report"
2963
 
                              " to http://bugs.mysql.com\n", stderr);
2964
 
                }
2965
 
        }
2966
 
}
2967
 
 
2968
 
/*********************************************************************//**
2969
 
Deletes from ibuf the record on which pcur is positioned. If we have to
2970
 
resort to a pessimistic delete, this function commits mtr and closes
2971
 
the cursor.
2972
 
@return TRUE if mtr was committed and pcur closed in this operation */
2973
 
static
2974
 
ibool
2975
 
ibuf_delete_rec(
2976
 
/*============*/
2977
 
        ulint           space,  /*!< in: space id */
2978
 
        ulint           page_no,/*!< in: index page number where the record
2979
 
                                should belong */
2980
 
        btr_pcur_t*     pcur,   /*!< in: pcur positioned on the record to
2981
 
                                delete, having latch mode BTR_MODIFY_LEAF */
2982
 
        const dtuple_t* search_tuple,
2983
 
                                /*!< in: search tuple for entries of page_no */
2984
 
        mtr_t*          mtr)    /*!< in: mtr */
2985
 
{
2986
 
        ibool           success;
2987
 
        page_t*         root;
2988
 
        ulint           err;
2989
 
 
2990
 
        ut_ad(ibuf_inside());
2991
 
        ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur)));
2992
 
        ut_ad(ibuf_rec_get_page_no(btr_pcur_get_rec(pcur)) == page_no);
2993
 
        ut_ad(ibuf_rec_get_space(btr_pcur_get_rec(pcur)) == space);
2994
 
 
2995
 
        success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
2996
 
 
2997
 
        if (success) {
2998
 
#ifdef UNIV_IBUF_COUNT_DEBUG
2999
 
                fprintf(stderr,
3000
 
                        "Decrementing ibuf count of space %lu page %lu\n"
3001
 
                        "from %lu by 1\n", space, page_no,
3002
 
                        ibuf_count_get(space, page_no));
3003
 
                ibuf_count_set(space, page_no,
3004
 
                               ibuf_count_get(space, page_no) - 1);
3005
 
#endif
3006
 
                return(FALSE);
3007
 
        }
3008
 
 
3009
 
        ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur)));
3010
 
        ut_ad(ibuf_rec_get_page_no(btr_pcur_get_rec(pcur)) == page_no);
3011
 
        ut_ad(ibuf_rec_get_space(btr_pcur_get_rec(pcur)) == space);
3012
 
 
3013
 
        /* We have to resort to a pessimistic delete from ibuf */
3014
 
        btr_pcur_store_position(pcur, mtr);
3015
 
 
3016
 
        btr_pcur_commit_specify_mtr(pcur, mtr);
3017
 
 
3018
 
        mutex_enter(&ibuf_mutex);
3019
 
 
3020
 
        mtr_start(mtr);
3021
 
 
3022
 
        success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
3023
 
 
3024
 
        if (!success) {
3025
 
                if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
3026
 
                        /* The tablespace has been dropped.  It is possible
3027
 
                        that another thread has deleted the insert buffer
3028
 
                        entry.  Do not complain. */
3029
 
                        goto commit_and_exit;
3030
 
                }
3031
 
 
3032
 
                fprintf(stderr,
3033
 
                        "InnoDB: ERROR: Submit the output to"
3034
 
                        " http://bugs.mysql.com\n"
3035
 
                        "InnoDB: ibuf cursor restoration fails!\n"
3036
 
                        "InnoDB: ibuf record inserted to page %lu\n",
3037
 
                        (ulong) page_no);
3038
 
                fflush(stderr);
3039
 
 
3040
 
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
3041
 
                rec_print_old(stderr, pcur->old_rec);
3042
 
                dtuple_print(stderr, search_tuple);
3043
 
 
3044
 
                rec_print_old(stderr,
3045
 
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
3046
 
                fflush(stderr);
3047
 
 
3048
 
                btr_pcur_commit_specify_mtr(pcur, mtr);
3049
 
 
3050
 
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
3051
 
                if (!btr_validate_index(ibuf->index, NULL)) {
3052
 
                        ut_error;
3053
 
                }
3054
 
 
3055
 
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
3056
 
                fflush(stderr);
3057
 
 
3058
 
                goto func_exit;
3059
 
        }
3060
 
 
3061
 
        root = ibuf_tree_root_get(mtr);
3062
 
 
3063
 
        btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur),
3064
 
                                   RB_NONE, mtr);
3065
 
        ut_a(err == DB_SUCCESS);
3066
 
 
3067
 
#ifdef UNIV_IBUF_COUNT_DEBUG
3068
 
        ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
3069
 
#endif
3070
 
        ibuf_size_update(root, mtr);
3071
 
 
3072
 
commit_and_exit:
3073
 
        btr_pcur_commit_specify_mtr(pcur, mtr);
3074
 
 
3075
 
func_exit:
3076
 
        btr_pcur_close(pcur);
3077
 
 
3078
 
        mutex_exit(&ibuf_mutex);
3079
 
 
3080
 
        return(TRUE);
3081
 
}
3082
 
 
3083
 
/*********************************************************************//**
3084
 
When an index page is read from a disk to the buffer pool, this function
3085
 
inserts to the page the possible index entries buffered in the insert buffer.
3086
 
The entries are deleted from the insert buffer. If the page is not read, but
3087
 
created in the buffer pool, this function deletes its buffered entries from
3088
 
the insert buffer; there can exist entries for such a page if the page
3089
 
belonged to an index which subsequently was dropped. */
3090
 
UNIV_INTERN
3091
 
void
3092
 
ibuf_merge_or_delete_for_page(
3093
 
/*==========================*/
3094
 
        buf_block_t*    block,  /*!< in: if page has been read from
3095
 
                                disk, pointer to the page x-latched,
3096
 
                                else NULL */
3097
 
        ulint           space,  /*!< in: space id of the index page */
3098
 
        ulint           page_no,/*!< in: page number of the index page */
3099
 
        ulint           zip_size,/*!< in: compressed page size in bytes,
3100
 
                                or 0 */
3101
 
        ibool           update_ibuf_bitmap)/*!< in: normally this is set
3102
 
                                to TRUE, but if we have deleted or are
3103
 
                                deleting the tablespace, then we
3104
 
                                naturally do not want to update a
3105
 
                                non-existent bitmap page */
3106
 
{
3107
 
        mem_heap_t*     heap;
3108
 
        btr_pcur_t      pcur;
3109
 
        dtuple_t*       search_tuple;
3110
 
        ulint           n_inserts;
3111
 
#ifdef UNIV_IBUF_DEBUG
3112
 
        ulint           volume;
3113
 
#endif
3114
 
        page_zip_des_t* page_zip                = NULL;
3115
 
        ibool           tablespace_being_deleted = FALSE;
3116
 
        ibool           corruption_noticed      = FALSE;
3117
 
        mtr_t           mtr;
3118
 
 
3119
 
        ut_ad(!block || buf_block_get_space(block) == space);
3120
 
        ut_ad(!block || buf_block_get_page_no(block) == page_no);
3121
 
        ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
3122
 
 
3123
 
        if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE
3124
 
            || trx_sys_hdr_page(space, page_no)) {
3125
 
                return;
3126
 
        }
3127
 
 
3128
 
        /* We cannot refer to zip_size in the following, because
3129
 
        zip_size is passed as ULINT_UNDEFINED (it is unknown) when
3130
 
        buf_read_ibuf_merge_pages() is merging (discarding) changes
3131
 
        for a dropped tablespace.  When block != NULL or
3132
 
        update_ibuf_bitmap is specified, the zip_size must be known.
3133
 
        That is why we will repeat the check below, with zip_size in
3134
 
        place of 0.  Passing zip_size as 0 assumes that the
3135
 
        uncompressed page size always is a power-of-2 multiple of the
3136
 
        compressed page size. */
3137
 
 
3138
 
        if (ibuf_fixed_addr_page(space, 0, page_no)
3139
 
            || fsp_descr_page(0, page_no)) {
3140
 
                return;
3141
 
        }
3142
 
 
3143
 
        if (UNIV_LIKELY(update_ibuf_bitmap)) {
3144
 
                ut_a(ut_is_2pow(zip_size));
3145
 
 
3146
 
                if (ibuf_fixed_addr_page(space, zip_size, page_no)
3147
 
                    || fsp_descr_page(zip_size, page_no)) {
3148
 
                        return;
3149
 
                }
3150
 
 
3151
 
                /* If the following returns FALSE, we get the counter
3152
 
                incremented, and must decrement it when we leave this
3153
 
                function. When the counter is > 0, that prevents tablespace
3154
 
                from being dropped. */
3155
 
 
3156
 
                tablespace_being_deleted = fil_inc_pending_ibuf_merges(space);
3157
 
 
3158
 
                if (UNIV_UNLIKELY(tablespace_being_deleted)) {
3159
 
                        /* Do not try to read the bitmap page from space;
3160
 
                        just delete the ibuf records for the page */
3161
 
 
3162
 
                        block = NULL;
3163
 
                        update_ibuf_bitmap = FALSE;
3164
 
                } else {
3165
 
                        page_t* bitmap_page;
3166
 
 
3167
 
                        mtr_start(&mtr);
3168
 
 
3169
 
                        bitmap_page = ibuf_bitmap_get_map_page(
3170
 
                                space, page_no, zip_size, &mtr);
3171
 
 
3172
 
                        if (!ibuf_bitmap_page_get_bits(bitmap_page, page_no,
3173
 
                                                       zip_size,
3174
 
                                                       IBUF_BITMAP_BUFFERED,
3175
 
                                                       &mtr)) {
3176
 
                                /* No inserts buffered for this page */
3177
 
                                mtr_commit(&mtr);
3178
 
 
3179
 
                                if (!tablespace_being_deleted) {
3180
 
                                        fil_decr_pending_ibuf_merges(space);
3181
 
                                }
3182
 
 
3183
 
                                return;
3184
 
                        }
3185
 
                        mtr_commit(&mtr);
3186
 
                }
3187
 
        } else if (block
3188
 
                   && (ibuf_fixed_addr_page(space, zip_size, page_no)
3189
 
                      || fsp_descr_page(zip_size, page_no))) {
3190
 
 
3191
 
                return;
3192
 
        }
3193
 
 
3194
 
        ibuf_enter();
3195
 
 
3196
 
        heap = mem_heap_create(512);
3197
 
 
3198
 
        if (!trx_sys_multiple_tablespace_format) {
3199
 
                ut_a(trx_doublewrite_must_reset_space_ids);
3200
 
                search_tuple = ibuf_search_tuple_build(space, page_no, heap);
3201
 
        } else {
3202
 
                search_tuple = ibuf_new_search_tuple_build(space, page_no,
3203
 
                                                           heap);
3204
 
        }
3205
 
 
3206
 
        if (block) {
3207
 
                /* Move the ownership of the x-latch on the page to this OS
3208
 
                thread, so that we can acquire a second x-latch on it. This
3209
 
                is needed for the insert operations to the index page to pass
3210
 
                the debug checks. */
3211
 
 
3212
 
                rw_lock_x_lock_move_ownership(&(block->lock));
3213
 
                page_zip = buf_block_get_page_zip(block);
3214
 
 
3215
 
                if (UNIV_UNLIKELY(fil_page_get_type(block->frame)
3216
 
                                  != FIL_PAGE_INDEX)
3217
 
                    || UNIV_UNLIKELY(!page_is_leaf(block->frame))) {
3218
 
 
3219
 
                        page_t* bitmap_page;
3220
 
 
3221
 
                        corruption_noticed = TRUE;
3222
 
 
3223
 
                        ut_print_timestamp(stderr);
3224
 
 
3225
 
                        mtr_start(&mtr);
3226
 
 
3227
 
                        fputs("  InnoDB: Dump of the ibuf bitmap page:\n",
3228
 
                              stderr);
3229
 
 
3230
 
                        bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
3231
 
                                                               zip_size, &mtr);
3232
 
                        buf_page_print(bitmap_page, 0);
3233
 
 
3234
 
                        mtr_commit(&mtr);
3235
 
 
3236
 
                        fputs("\nInnoDB: Dump of the page:\n", stderr);
3237
 
 
3238
 
                        buf_page_print(block->frame, 0);
3239
 
 
3240
 
                        fprintf(stderr,
3241
 
                                "InnoDB: Error: corruption in the tablespace."
3242
 
                                " Bitmap shows insert\n"
3243
 
                                "InnoDB: buffer records to page n:o %lu"
3244
 
                                " though the page\n"
3245
 
                                "InnoDB: type is %lu, which is"
3246
 
                                " not an index leaf page!\n"
3247
 
                                "InnoDB: We try to resolve the problem"
3248
 
                                " by skipping the insert buffer\n"
3249
 
                                "InnoDB: merge for this page."
3250
 
                                " Please run CHECK TABLE on your tables\n"
3251
 
                                "InnoDB: to determine if they are corrupt"
3252
 
                                " after this.\n\n"
3253
 
                                "InnoDB: Please submit a detailed bug report"
3254
 
                                " to http://bugs.mysql.com\n\n",
3255
 
                                (ulong) page_no,
3256
 
                                (ulong)
3257
 
                                fil_page_get_type(block->frame));
3258
 
                }
3259
 
        }
3260
 
 
3261
 
        n_inserts = 0;
3262
 
#ifdef UNIV_IBUF_DEBUG
3263
 
        volume = 0;
3264
 
#endif
3265
 
loop:
3266
 
        mtr_start(&mtr);
3267
 
 
3268
 
        if (block) {
3269
 
                ibool success;
3270
 
 
3271
 
                success = buf_page_get_known_nowait(
3272
 
                        RW_X_LATCH, block,
3273
 
                        BUF_KEEP_OLD, __FILE__, __LINE__, &mtr);
3274
 
 
3275
 
                ut_a(success);
3276
 
 
3277
 
                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
3278
 
        }
3279
 
 
3280
 
        /* Position pcur in the insert buffer at the first entry for this
3281
 
        index page */
3282
 
        btr_pcur_open_on_user_rec(
3283
 
                ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
3284
 
                &pcur, &mtr);
3285
 
 
3286
 
        if (!btr_pcur_is_on_user_rec(&pcur)) {
3287
 
                ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
3288
 
 
3289
 
                goto reset_bit;
3290
 
        }
3291
 
 
3292
 
        for (;;) {
3293
 
                rec_t*  rec;
3294
 
 
3295
 
                ut_ad(btr_pcur_is_on_user_rec(&pcur));
3296
 
 
3297
 
                rec = btr_pcur_get_rec(&pcur);
3298
 
 
3299
 
                /* Check if the entry is for this index page */
3300
 
                if (ibuf_rec_get_page_no(rec) != page_no
3301
 
                    || ibuf_rec_get_space(rec) != space) {
3302
 
 
3303
 
                        if (block) {
3304
 
                                page_header_reset_last_insert(
3305
 
                                        block->frame, page_zip, &mtr);
3306
 
                        }
3307
 
 
3308
 
                        goto reset_bit;
3309
 
                }
3310
 
 
3311
 
                if (UNIV_UNLIKELY(corruption_noticed)) {
3312
 
                        fputs("InnoDB: Discarding record\n ", stderr);
3313
 
                        rec_print_old(stderr, rec);
3314
 
                        fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
3315
 
                } else if (block) {
3316
 
                        /* Now we have at pcur a record which should be
3317
 
                        inserted to the index page; NOTE that the call below
3318
 
                        copies pointers to fields in rec, and we must
3319
 
                        keep the latch to the rec page until the
3320
 
                        insertion is finished! */
3321
 
                        dtuple_t*       entry;
3322
 
                        trx_id_t        max_trx_id;
3323
 
                        dict_index_t*   dummy_index;
3324
 
 
3325
 
                        max_trx_id = page_get_max_trx_id(page_align(rec));
3326
 
                        page_update_max_trx_id(block, page_zip, max_trx_id,
3327
 
                                               &mtr);
3328
 
 
3329
 
                        entry = ibuf_build_entry_from_ibuf_rec(
3330
 
                                rec, heap, &dummy_index);
3331
 
#ifdef UNIV_IBUF_DEBUG
3332
 
                        volume += rec_get_converted_size(dummy_index, entry, 0)
3333
 
                                + page_dir_calc_reserved_space(1);
3334
 
                        ut_a(volume <= 4 * UNIV_PAGE_SIZE
3335
 
                             / IBUF_PAGE_SIZE_PER_FREE_SPACE);
3336
 
#endif
3337
 
                        ibuf_insert_to_index_page(entry, block,
3338
 
                                                  dummy_index, &mtr);
3339
 
                        ibuf_dummy_index_free(dummy_index);
3340
 
                }
3341
 
 
3342
 
                n_inserts++;
3343
 
 
3344
 
                /* Delete the record from ibuf */
3345
 
                if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3346
 
                                    &mtr)) {
3347
 
                        /* Deletion was pessimistic and mtr was committed:
3348
 
                        we start from the beginning again */
3349
 
 
3350
 
                        goto loop;
3351
 
                } else if (btr_pcur_is_after_last_on_page(&pcur)) {
3352
 
                        mtr_commit(&mtr);
3353
 
                        btr_pcur_close(&pcur);
3354
 
 
3355
 
                        goto loop;
3356
 
                }
3357
 
        }
3358
 
 
3359
 
reset_bit:
3360
 
#ifdef UNIV_IBUF_COUNT_DEBUG
3361
 
        if (ibuf_count_get(space, page_no) > 0) {
3362
 
                /* btr_print_tree(ibuf_data->index->tree, 100);
3363
 
                ibuf_print(); */
3364
 
        }
3365
 
#endif
3366
 
        if (UNIV_LIKELY(update_ibuf_bitmap)) {
3367
 
                page_t* bitmap_page;
3368
 
 
3369
 
                bitmap_page = ibuf_bitmap_get_map_page(
3370
 
                        space, page_no, zip_size, &mtr);
3371
 
 
3372
 
                ibuf_bitmap_page_set_bits(
3373
 
                        bitmap_page, page_no, zip_size,
3374
 
                        IBUF_BITMAP_BUFFERED, FALSE, &mtr);
3375
 
 
3376
 
                if (block) {
3377
 
                        ulint old_bits = ibuf_bitmap_page_get_bits(
3378
 
                                bitmap_page, page_no, zip_size,
3379
 
                                IBUF_BITMAP_FREE, &mtr);
3380
 
 
3381
 
                        ulint new_bits = ibuf_index_page_calc_free(
3382
 
                                zip_size, block);
3383
 
 
3384
 
                        if (old_bits != new_bits) {
3385
 
                                ibuf_bitmap_page_set_bits(
3386
 
                                        bitmap_page, page_no, zip_size,
3387
 
                                        IBUF_BITMAP_FREE, new_bits, &mtr);
3388
 
                        }
3389
 
                }
3390
 
        }
3391
 
 
3392
 
        mtr_commit(&mtr);
3393
 
        btr_pcur_close(&pcur);
3394
 
        mem_heap_free(heap);
3395
 
 
3396
 
        /* Protect our statistics keeping from race conditions */
3397
 
        mutex_enter(&ibuf_mutex);
3398
 
 
3399
 
        ibuf->n_merges++;
3400
 
        ibuf->n_merged_recs += n_inserts;
3401
 
 
3402
 
        mutex_exit(&ibuf_mutex);
3403
 
 
3404
 
        if (update_ibuf_bitmap && !tablespace_being_deleted) {
3405
 
 
3406
 
                fil_decr_pending_ibuf_merges(space);
3407
 
        }
3408
 
 
3409
 
        ibuf_exit();
3410
 
 
3411
 
#ifdef UNIV_IBUF_COUNT_DEBUG
3412
 
        ut_a(ibuf_count_get(space, page_no) == 0);
3413
 
#endif
3414
 
}
3415
 
 
3416
 
/*********************************************************************//**
3417
 
Deletes all entries in the insert buffer for a given space id. This is used
3418
 
in DISCARD TABLESPACE and IMPORT TABLESPACE.
3419
 
NOTE: this does not update the page free bitmaps in the space. The space will
3420
 
become CORRUPT when you call this function! */
3421
 
UNIV_INTERN
3422
 
void
3423
 
ibuf_delete_for_discarded_space(
3424
 
/*============================*/
3425
 
        ulint   space)  /*!< in: space id */
3426
 
{
3427
 
        mem_heap_t*     heap;
3428
 
        btr_pcur_t      pcur;
3429
 
        dtuple_t*       search_tuple;
3430
 
        rec_t*          ibuf_rec;
3431
 
        ulint           page_no;
3432
 
        ibool           closed;
3433
 
        ulint           n_inserts;
3434
 
        mtr_t           mtr;
3435
 
 
3436
 
        heap = mem_heap_create(512);
3437
 
 
3438
 
        /* Use page number 0 to build the search tuple so that we get the
3439
 
        cursor positioned at the first entry for this space id */
3440
 
 
3441
 
        search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
3442
 
 
3443
 
        n_inserts = 0;
3444
 
loop:
3445
 
        ibuf_enter();
3446
 
 
3447
 
        mtr_start(&mtr);
3448
 
 
3449
 
        /* Position pcur in the insert buffer at the first entry for the
3450
 
        space */
3451
 
        btr_pcur_open_on_user_rec(
3452
 
                ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
3453
 
                &pcur, &mtr);
3454
 
 
3455
 
        if (!btr_pcur_is_on_user_rec(&pcur)) {
3456
 
                ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
3457
 
 
3458
 
                goto leave_loop;
3459
 
        }
3460
 
 
3461
 
        for (;;) {
3462
 
                ut_ad(btr_pcur_is_on_user_rec(&pcur));
3463
 
 
3464
 
                ibuf_rec = btr_pcur_get_rec(&pcur);
3465
 
 
3466
 
                /* Check if the entry is for this space */
3467
 
                if (ibuf_rec_get_space(ibuf_rec) != space) {
3468
 
 
3469
 
                        goto leave_loop;
3470
 
                }
3471
 
 
3472
 
                page_no = ibuf_rec_get_page_no(ibuf_rec);
3473
 
 
3474
 
                n_inserts++;
3475
 
 
3476
 
                /* Delete the record from ibuf */
3477
 
                closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3478
 
                                         &mtr);
3479
 
                if (closed) {
3480
 
                        /* Deletion was pessimistic and mtr was committed:
3481
 
                        we start from the beginning again */
3482
 
 
3483
 
                        ibuf_exit();
3484
 
 
3485
 
                        goto loop;
3486
 
                }
3487
 
 
3488
 
                if (btr_pcur_is_after_last_on_page(&pcur)) {
3489
 
                        mtr_commit(&mtr);
3490
 
                        btr_pcur_close(&pcur);
3491
 
 
3492
 
                        ibuf_exit();
3493
 
 
3494
 
                        goto loop;
3495
 
                }
3496
 
        }
3497
 
 
3498
 
leave_loop:
3499
 
        mtr_commit(&mtr);
3500
 
        btr_pcur_close(&pcur);
3501
 
 
3502
 
        /* Protect our statistics keeping from race conditions */
3503
 
        mutex_enter(&ibuf_mutex);
3504
 
 
3505
 
        ibuf->n_merges++;
3506
 
        ibuf->n_merged_recs += n_inserts;
3507
 
 
3508
 
        mutex_exit(&ibuf_mutex);
3509
 
 
3510
 
        ibuf_exit();
3511
 
 
3512
 
        mem_heap_free(heap);
3513
 
}
3514
 
 
3515
 
/******************************************************************//**
3516
 
Looks if the insert buffer is empty.
3517
 
@return TRUE if empty */
3518
 
UNIV_INTERN
3519
 
ibool
3520
 
ibuf_is_empty(void)
3521
 
/*===============*/
3522
 
{
3523
 
        ibool           is_empty;
3524
 
        const page_t*   root;
3525
 
        mtr_t           mtr;
3526
 
 
3527
 
        ibuf_enter();
3528
 
 
3529
 
        mutex_enter(&ibuf_mutex);
3530
 
 
3531
 
        mtr_start(&mtr);
3532
 
 
3533
 
        root = ibuf_tree_root_get(&mtr);
3534
 
 
3535
 
        if (page_get_n_recs(root) == 0) {
3536
 
 
3537
 
                is_empty = TRUE;
3538
 
 
3539
 
                if (ibuf->empty == FALSE) {
3540
 
                        fprintf(stderr,
3541
 
                                "InnoDB: Warning: insert buffer tree is empty"
3542
 
                                " but the data struct does not\n"
3543
 
                                "InnoDB: know it. This condition is legal"
3544
 
                                " if the master thread has not yet\n"
3545
 
                                "InnoDB: run to completion.\n");
3546
 
                }
3547
 
        } else {
3548
 
                ut_a(ibuf->empty == FALSE);
3549
 
 
3550
 
                is_empty = FALSE;
3551
 
        }
3552
 
 
3553
 
        mtr_commit(&mtr);
3554
 
 
3555
 
        mutex_exit(&ibuf_mutex);
3556
 
 
3557
 
        ibuf_exit();
3558
 
 
3559
 
        return(is_empty);
3560
 
}
3561
 
 
3562
 
/******************************************************************//**
3563
 
Prints info of ibuf. */
3564
 
UNIV_INTERN
3565
 
void
3566
 
ibuf_print(
3567
 
/*=======*/
3568
 
        FILE*   file)   /*!< in: file where to print */
3569
 
{
3570
 
#ifdef UNIV_IBUF_COUNT_DEBUG
3571
 
        ulint           i;
3572
 
        ulint           j;
3573
 
#endif
3574
 
 
3575
 
        mutex_enter(&ibuf_mutex);
3576
 
 
3577
 
        fprintf(file,
3578
 
                "Ibuf: size %lu, free list len %lu, seg size %lu,\n"
3579
 
                "%lu inserts, %lu merged recs, %lu merges\n",
3580
 
                (ulong) ibuf->size,
3581
 
                (ulong) ibuf->free_list_len,
3582
 
                (ulong) ibuf->seg_size,
3583
 
                (ulong) ibuf->n_inserts,
3584
 
                (ulong) ibuf->n_merged_recs,
3585
 
                (ulong) ibuf->n_merges);
3586
 
#ifdef UNIV_IBUF_COUNT_DEBUG
3587
 
        for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
3588
 
                for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {
3589
 
                        ulint   count = ibuf_count_get(i, j);
3590
 
 
3591
 
                        if (count > 0) {
3592
 
                                fprintf(stderr,
3593
 
                                        "Ibuf count for space/page %lu/%lu"
3594
 
                                        " is %lu\n",
3595
 
                                        (ulong) i, (ulong) j, (ulong) count);
3596
 
                        }
3597
 
                }
3598
 
        }
3599
 
#endif /* UNIV_IBUF_COUNT_DEBUG */
3600
 
 
3601
 
        mutex_exit(&ibuf_mutex);
3602
 
}
3603
 
#endif /* !UNIV_HOTBACKUP */