~mysql/mysql-server/mysql-6.0

« back to all changes in this revision

Viewing changes to innobase/ibuf/ibuf0ibuf.c

  • Committer: monty at mysql
  • Date: 2001-02-17 12:19:19 UTC
  • mto: (554.1.1)
  • mto: This revision was merged to the branch mainline in revision 556.
  • Revision ID: sp1r-monty@donna.mysql.com-20010217121919-07904
Added Innobase to source distribution

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
Insert buffer
 
3
 
 
4
(c) 1997 Innobase Oy
 
5
 
 
6
Created 7/19/1997 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "ibuf0ibuf.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "ibuf0ibuf.ic"
 
13
#endif
 
14
 
 
15
#include "buf0buf.h"
 
16
#include "buf0rea.h"
 
17
#include "fsp0fsp.h"
 
18
#include "trx0sys.h"
 
19
#include "fil0fil.h"
 
20
#include "thr0loc.h"
 
21
#include "rem0rec.h"
 
22
#include "btr0cur.h"
 
23
#include "btr0pcur.h"
 
24
#include "btr0btr.h"
 
25
#include "sync0sync.h"
 
26
#include "dict0boot.h"
 
27
#include "fut0lst.h"
 
28
#include "lock0lock.h"
 
29
#include "log0recv.h"
 
30
#include "que0que.h"
 
31
 
 
32
/*      PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
 
33
 
 
34
If an OS thread performs any operation that brings in disk pages from
 
35
non-system tablespaces into the buffer pool, or creates such a page there,
 
36
then the operation may have as a side effect an insert buffer index tree
 
37
compression. Thus, the tree latch of the insert buffer tree may be acquired
 
38
in the x-mode, and also the file space latch of the system tablespace may
 
39
be acquired in the x-mode.
 
40
 
 
41
Also, an insert to an index in a non-system tablespace can have the same
 
42
effect. How do we know this cannot lead to a deadlock of OS threads? There
 
43
is a problem with the i\o-handler threads: they break the latching order
 
44
because they own x-latches to pages which are on a lower level than the
 
45
insert buffer tree latch, its page latches, and the tablespace latch an
 
46
insert buffer operation can reserve.
 
47
 
 
48
The solution is the following: We put into each tablespace an insert buffer
 
49
of its own. Let all the tree and page latches connected with the insert buffer
 
50
be later in the latching order than the fsp latch and fsp page latches.
 
51
Insert buffer pages must be such that the insert buffer is never invoked
 
52
when these pages area accessed as this would result in a recursion violating
 
53
the latching order. We let a special i/o-handler thread take care of i/o to
 
54
the insert buffer pages and the ibuf bitmap pages, as well as the fsp bitmap
 
55
pages and the first inode page, which contains the inode of the ibuf tree: let
 
56
us call all these ibuf pages. If the OS does not support asynchronous i/o,
 
57
then there is no special i/o thread, but to prevent deadlocks, we do not let a
 
58
read-ahead access both non-ibuf and ibuf pages.
 
59
 
 
60
Then an i/o-handler for the insert buffer never needs to access the insert
 
61
buffer tree and thus obeys the latching order. On the other hand, other
 
62
i/o-handlers for other tablespaces may require access to the insert buffer,
 
63
but because all kinds of latches they need to access there are later in the
 
64
latching order, no violation of the latching order occurs in this case,
 
65
either.
 
66
 
 
67
A problem is how to grow and contract an insert buffer tree. As it is later
 
68
in the latching order than the fsp management, we have to reserve the fsp
 
69
latch first, before adding or removing pages from the insert buffer tree.
 
70
We let the insert buffer tree have its own file space management: a free
 
71
list of pages linked to the tree root. To prevent recursive using of the
 
72
insert buffer when adding pages to the tree, we must first load these pages
 
73
to memory, obtaining a latch on them, and only after that add them to the
 
74
free list of the insert buffer tree. More difficult is removing of pages
 
75
from the free list. If there is an excess of pages in the free list of the
 
76
ibuf tree, they might be needed if some thread reserves the fsp latch,
 
77
intending to allocate more file space. So we do the following: if a thread
 
78
reserves the fsp latch, we check the writer count field of the latch. If
 
79
this field has value 1, it means that the thread did not own the latch
 
80
before entering the fsp system, and the mtr of the thread contains no
 
81
modifications to the fsp pages. Now we are free to reserve the ibuf latch,
 
82
and check if there is an excess of pages in the free list. We can then, in a
 
83
separate mini-transaction, take them out of the free list and free them to
 
84
the fsp system.
 
85
 
 
86
To avoid deadlocks in the ibuf system, we divide file pages into three levels:
 
87
 
 
88
(1) non-ibuf pages,
 
89
(2) ibuf tree pages and the pages in the ibuf tree free list, and
 
90
(3) ibuf bitmap pages.
 
91
 
 
92
No OS thread is allowed to access higher level pages if it has latches to
 
93
lower level pages; even if the thread owns a B-tree latch it must not access
 
94
the B-tree non-leaf pages if it has latches on lower level pages. Read-ahead
 
95
is only allowed for level 1 and 2 pages. Dedicated i/o-handler threads handle
 
96
exclusively level 1 i/o. A dedicated i/o handler thread handles exclusively
 
97
level 2 i/o. However, if an OS thread does the i/o handling for itself, i.e.,
 
98
it uses synchronous aio or the OS does not support aio, it can access any
 
99
pages, as long as it obeys the access order rules. */
 
100
 
 
101
/* Buffer pool size per the maximum insert buffer size */
 
102
#define IBUF_POOL_SIZE_PER_MAX_SIZE     2
 
103
 
 
104
/* The insert buffer control structure */
 
105
ibuf_t* ibuf    = NULL;
 
106
 
 
107
ulint   ibuf_rnd = 986058871;
 
108
 
 
109
ulint   ibuf_flush_count        = 0;
 
110
 
 
111
/* Dimensions for the ibuf_count array */
 
112
#define IBUF_COUNT_N_SPACES     10
 
113
#define IBUF_COUNT_N_PAGES      10000
 
114
 
 
115
/* Buffered entry counts for file pages, used in debugging */
 
116
ulint*  ibuf_counts[IBUF_COUNT_N_SPACES];
 
117
 
 
118
ibool   ibuf_counts_inited      = FALSE;
 
119
 
 
120
/* The start address for an insert buffer bitmap page bitmap */
 
121
#define IBUF_BITMAP             PAGE_DATA
 
122
 
 
123
/* Offsets in bits for the bits describing a single page in the bitmap */
 
124
#define IBUF_BITMAP_FREE        0
 
125
#define IBUF_BITMAP_BUFFERED    2
 
126
#define IBUF_BITMAP_IBUF        3       /* TRUE if page is a part of the ibuf
 
127
                                        tree, excluding the root page, or is
 
128
                                        in the free list of the ibuf */
 
129
 
 
130
/* Number of bits describing a single page */
 
131
#define IBUF_BITS_PER_PAGE      4
 
132
 
 
133
/* The mutex used to block pessimistic inserts to ibuf trees */
 
134
mutex_t ibuf_pessimistic_insert_mutex;
 
135
 
 
136
/* The mutex protecting the insert buffer structs */
 
137
mutex_t ibuf_mutex;
 
138
 
 
139
/* The mutex protecting the insert buffer bitmaps */
 
140
mutex_t ibuf_bitmap_mutex;
 
141
 
 
142
/* The area in pages from which contract looks for page numbers for merge */
 
143
#define IBUF_MERGE_AREA                 8
 
144
 
 
145
/* Inside the merge area, pages which have at most 1 per this number less
 
146
buffered entries compared to maximum volume that can buffered for a single
 
147
page are merged along with the page whose buffer became full */
 
148
#define IBUF_MERGE_THRESHOLD            4
 
149
 
 
150
/* In ibuf_contract at most this number of pages is read to memory in one
 
151
batch, in order to merge the entries for them in the insert buffer */
 
152
#define IBUF_MAX_N_PAGES_MERGED         IBUF_MERGE_AREA
 
153
 
 
154
/* If the combined size of the ibuf trees exceeds ibuf->max_size by this
 
155
many pages, we start to contract it in connection to inserts there, using
 
156
non-synchronous contract */
 
157
#define IBUF_CONTRACT_ON_INSERT_NON_SYNC        0
 
158
 
 
159
/* Same as above, but use synchronous contract */
 
160
#define IBUF_CONTRACT_ON_INSERT_SYNC            5
 
161
 
 
162
/* Same as above, but no insert is done, only contract is called */
 
163
#define IBUF_CONTRACT_DO_NOT_INSERT             10
 
164
 
 
165
/* TODO: how to cope with drop table if there are records in the insert
 
166
buffer for the indexes of the table? Is there actually any problem,
 
167
because ibuf merge is done to a page when it is read in, and it is
 
168
still physically like the index page even if the index would have been
 
169
dropped! So, there seems to be no problem. */
 
170
 
 
171
/**********************************************************************
 
172
Validates the ibuf data structures when the caller owns ibuf_mutex. */
 
173
static
 
174
ibool
 
175
ibuf_validate_low(void);
 
176
/*===================*/
 
177
                        /* out: TRUE if ok */
 
178
 
 
179
/**********************************************************************
 
180
Sets the flag in the current OS thread local storage denoting that it is
 
181
inside an insert buffer routine. */
 
182
UNIV_INLINE
 
183
void
 
184
ibuf_enter(void)
 
185
/*============*/
 
186
{
 
187
        ibool*  ptr;
 
188
 
 
189
        ptr = thr_local_get_in_ibuf_field();
 
190
 
 
191
        ut_ad(*ptr == FALSE);
 
192
 
 
193
        *ptr = TRUE;
 
194
}
 
195
 
 
196
/**********************************************************************
 
197
Sets the flag in the current OS thread local storage denoting that it is
 
198
exiting an insert buffer routine. */
 
199
UNIV_INLINE
 
200
void
 
201
ibuf_exit(void)
 
202
/*===========*/
 
203
{
 
204
        ibool*  ptr;
 
205
 
 
206
        ptr = thr_local_get_in_ibuf_field();
 
207
 
 
208
        ut_ad(*ptr == TRUE);
 
209
 
 
210
        *ptr = FALSE;
 
211
}
 
212
 
 
213
/**********************************************************************
 
214
Returns TRUE if the current OS thread is performing an insert buffer
 
215
routine. */
 
216
 
 
217
ibool
 
218
ibuf_inside(void)
 
219
/*=============*/
 
220
                /* out: TRUE if inside an insert buffer routine: for instance,
 
221
                a read-ahead of non-ibuf pages is then forbidden */
 
222
{
 
223
        return(*thr_local_get_in_ibuf_field());
 
224
}
 
225
 
 
226
/**********************************************************************
 
227
Gets the ibuf header page and x-latches it. */
 
228
static
 
229
page_t*
 
230
ibuf_header_page_get(
 
231
/*=================*/
 
232
                        /* out: insert buffer header page */
 
233
        ulint   space,  /* in: space id */
 
234
        mtr_t*  mtr)    /* in: mtr */
 
235
{
 
236
        page_t* page;
 
237
 
 
238
        ut_ad(!ibuf_inside());
 
239
 
 
240
        page = buf_page_get(space, FSP_IBUF_HEADER_PAGE_NO, RW_X_LATCH, mtr);
 
241
 
 
242
        buf_page_dbg_add_level(page, SYNC_IBUF_HEADER);
 
243
 
 
244
        return(page);
 
245
}
 
246
 
 
247
/**********************************************************************
 
248
Gets the root page and x-latches it. */
 
249
static
 
250
page_t*
 
251
ibuf_tree_root_get(
 
252
/*===============*/
 
253
                                /* out: insert buffer tree root page */
 
254
        ibuf_data_t*    data,   /* in: ibuf data */
 
255
        ulint           space,  /* in: space id */
 
256
        mtr_t*          mtr)    /* in: mtr */
 
257
{
 
258
        page_t* page;
 
259
 
 
260
        ut_ad(ibuf_inside());
 
261
 
 
262
        mtr_x_lock(dict_tree_get_lock((data->index)->tree), mtr);
 
263
 
 
264
        page = buf_page_get(space, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH,
 
265
                                                                        mtr);
 
266
        buf_page_dbg_add_level(page, SYNC_TREE_NODE);
 
267
 
 
268
        return(page);
 
269
}
 
270
        
 
271
/**********************************************************************
 
272
Gets the ibuf count for a given page. */
 
273
 
 
274
ulint
 
275
ibuf_count_get(
 
276
/*===========*/
 
277
                        /* out: number of entries in the insert buffer
 
278
                        currently buffered for this page */
 
279
        ulint   space,  /* in: space id */
 
280
        ulint   page_no)/* in: page number */
 
281
{
 
282
        ut_ad(space < IBUF_COUNT_N_SPACES);
 
283
        ut_ad(page_no < IBUF_COUNT_N_PAGES);
 
284
 
 
285
        if (!ibuf_counts_inited) {
 
286
 
 
287
                return(0);
 
288
        }
 
289
 
 
290
        return(*(ibuf_counts[space] + page_no));
 
291
}
 
292
 
 
293
/**********************************************************************
 
294
Sets the ibuf count for a given page. */
 
295
static
 
296
void
 
297
ibuf_count_set(
 
298
/*===========*/
 
299
        ulint   space,  /* in: space id */
 
300
        ulint   page_no,/* in: page number */
 
301
        ulint   val)    /* in: value to set */
 
302
{
 
303
        ut_ad(space < IBUF_COUNT_N_SPACES);
 
304
        ut_ad(page_no < IBUF_COUNT_N_PAGES);
 
305
        ut_ad(val < UNIV_PAGE_SIZE);
 
306
 
 
307
        *(ibuf_counts[space] + page_no) = val;
 
308
}
 
309
 
 
310
/**********************************************************************
 
311
Creates the insert buffer data structure at a database startup and
 
312
initializes the data structures for the insert buffer of each tablespace. */
 
313
 
 
314
void
 
315
ibuf_init_at_db_start(void)
 
316
/*=======================*/
 
317
{
 
318
        ibuf = mem_alloc(sizeof(ibuf_t));
 
319
 
 
320
        /* Note that also a pessimistic delete can sometimes make a B-tree
 
321
        grow in size, as the references on the upper levels of the tree can
 
322
        change */
 
323
        
 
324
        ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE
 
325
                                                / IBUF_POOL_SIZE_PER_MAX_SIZE;
 
326
        ibuf->meter = IBUF_THRESHOLD + 1;
 
327
 
 
328
        UT_LIST_INIT(ibuf->data_list);
 
329
 
 
330
        ibuf->size = 0;                                 
 
331
 
 
332
#ifdef UNIV_IBUF_DEBUG
 
333
        {
 
334
                ulint   i, j;
 
335
 
 
336
                for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
 
337
 
 
338
                        ibuf_counts[i] = mem_alloc(sizeof(ulint)
 
339
                                                * IBUF_COUNT_N_PAGES);
 
340
                        for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {
 
341
                                ibuf_count_set(i, j, 0);
 
342
                        }
 
343
                }
 
344
        }       
 
345
#endif
 
346
        mutex_create(&ibuf_pessimistic_insert_mutex);
 
347
 
 
348
        mutex_set_level(&ibuf_pessimistic_insert_mutex,
 
349
                                                SYNC_IBUF_PESS_INSERT_MUTEX);
 
350
        mutex_create(&ibuf_mutex);
 
351
 
 
352
        mutex_set_level(&ibuf_mutex, SYNC_IBUF_MUTEX);
 
353
 
 
354
        mutex_create(&ibuf_bitmap_mutex);
 
355
 
 
356
        mutex_set_level(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
 
357
 
 
358
        fil_ibuf_init_at_db_start();
 
359
 
 
360
        ibuf_counts_inited = TRUE;
 
361
}
 
362
 
 
363
/**********************************************************************
 
364
Updates the size information in an ibuf data, assuming the segment size has
 
365
not changed. */
 
366
static
 
367
void
 
368
ibuf_data_sizes_update(
 
369
/*===================*/
 
370
        ibuf_data_t*    data,   /* in: ibuf data struct */
 
371
        page_t*         root,   /* in: ibuf tree root */
 
372
        mtr_t*          mtr)    /* in: mtr */
 
373
{
 
374
        ulint   old_size;
 
375
 
 
376
        ut_ad(mutex_own(&ibuf_mutex));
 
377
 
 
378
        old_size = data->size;
 
379
        
 
380
        data->free_list_len = flst_get_len(root + PAGE_HEADER
 
381
                                           + PAGE_BTR_IBUF_FREE_LIST, mtr);
 
382
 
 
383
        data->height = 1 + btr_page_get_level(root, mtr);
 
384
 
 
385
        data->size = data->seg_size - (1 + data->free_list_len);
 
386
                                /* the '1 +' is the ibuf header page */
 
387
        ut_ad(data->size < data->seg_size);
 
388
 
 
389
        if (page_get_n_recs(root) == 0) {
 
390
 
 
391
                data->empty = TRUE;
 
392
        } else {
 
393
                data->empty = FALSE;
 
394
        }
 
395
 
 
396
        ut_ad(ibuf->size + data->size >= old_size);
 
397
 
 
398
        ibuf->size = ibuf->size + data->size - old_size;
 
399
 
 
400
/*      printf("ibuf size %lu, space ibuf size %lu\n", ibuf->size,
 
401
                                                        data->size); */
 
402
}       
 
403
 
 
404
/**********************************************************************
 
405
Creates the insert buffer data struct for a single tablespace. Reads the
 
406
root page of the insert buffer tree in the tablespace. This function can
 
407
be called only after the dictionary system has been initialized, as this
 
408
creates also the insert buffer table and index for this tablespace. */
 
409
 
 
410
ibuf_data_t*
 
411
ibuf_data_init_for_space(
 
412
/*=====================*/
 
413
                        /* out, own: ibuf data struct, linked to the list
 
414
                        in ibuf control structure. */
 
415
        ulint   space)  /* in: space id */
 
416
{
 
417
        ibuf_data_t*    data;
 
418
        page_t*         root;
 
419
        page_t*         header_page;
 
420
        mtr_t           mtr;
 
421
        char            buf[50];
 
422
        dict_table_t*   table;
 
423
        dict_index_t*   index;
 
424
        ulint           n_used;
 
425
        
 
426
#ifdef UNIV_LOG_DEBUG
 
427
        if (space % 2 == 1) {
 
428
 
 
429
                printf("No ibuf op in replicate space\n");
 
430
 
 
431
                return(NULL);
 
432
        }
 
433
#endif
 
434
        data = mem_alloc(sizeof(ibuf_data_t));
 
435
 
 
436
        data->space = space;
 
437
 
 
438
        mtr_start(&mtr);
 
439
 
 
440
        mutex_enter(&ibuf_mutex);
 
441
 
 
442
        mtr_x_lock(fil_space_get_latch(space), &mtr);
 
443
 
 
444
        header_page = ibuf_header_page_get(space, &mtr);
 
445
 
 
446
        fseg_n_reserved_pages(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
 
447
                                                                &n_used, &mtr);
 
448
        ibuf_enter();
 
449
        
 
450
        ut_ad(n_used >= 2);
 
451
 
 
452
        data->seg_size = n_used;
 
453
        
 
454
        root = buf_page_get(space, FSP_IBUF_TREE_ROOT_PAGE_NO, RW_X_LATCH,
 
455
                                                                &mtr);
 
456
        buf_page_dbg_add_level(root, SYNC_TREE_NODE);
 
457
 
 
458
        data->size = 0;
 
459
        data->n_inserts = 0;
 
460
        data->n_merges = 0;
 
461
        data->n_merged_recs = 0;
 
462
        
 
463
        ibuf_data_sizes_update(data, root, &mtr);
 
464
 
 
465
        mutex_exit(&ibuf_mutex);
 
466
 
 
467
        mtr_commit(&mtr);
 
468
 
 
469
        ibuf_exit();
 
470
 
 
471
        sprintf(buf, "SYS_IBUF_TABLE_%lu", space);
 
472
        
 
473
        table = dict_mem_table_create(buf, space, 2);
 
474
 
 
475
        dict_mem_table_add_col(table, "PAGE_NO", DATA_BINARY, 0, 0, 0);
 
476
        dict_mem_table_add_col(table, "TYPES", DATA_BINARY, 0, 0, 0);
 
477
 
 
478
        table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
 
479
 
 
480
        dict_table_add_to_cache(table);
 
481
 
 
482
        index = dict_mem_index_create(buf, "CLUST_IND", space,
 
483
                                DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
 
484
                                2);
 
485
 
 
486
        dict_mem_index_add_field(index, "PAGE_NO", 0);
 
487
        dict_mem_index_add_field(index, "TYPES", 0);
 
488
 
 
489
        index->page_no = FSP_IBUF_TREE_ROOT_PAGE_NO;
 
490
        
 
491
        index->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
 
492
 
 
493
        dict_index_add_to_cache(table, index);
 
494
 
 
495
        data->index = dict_table_get_first_index(table);
 
496
 
 
497
        mutex_enter(&ibuf_mutex);
 
498
 
 
499
        UT_LIST_ADD_LAST(data_list, ibuf->data_list, data);
 
500
 
 
501
        mutex_exit(&ibuf_mutex);
 
502
 
 
503
        return(data);
 
504
}
 
505
 
 
506
/*************************************************************************
 
507
Initializes an ibuf bitmap page. */
 
508
 
 
509
void
 
510
ibuf_bitmap_page_init(
 
511
/*==================*/
 
512
        page_t* page,   /* in: bitmap page */
 
513
        mtr_t*  mtr)    /* in: mtr */
 
514
{
 
515
        ulint   bit_offset;
 
516
        ulint   byte_offset;
 
517
        ulint   i;
 
518
 
 
519
        /* Write all zeros to the bitmap */
 
520
 
 
521
        bit_offset = XDES_DESCRIBED_PER_PAGE * IBUF_BITS_PER_PAGE;
 
522
 
 
523
        byte_offset = bit_offset / 8 + 1;
 
524
 
 
525
        for (i = IBUF_BITMAP; i < IBUF_BITMAP + byte_offset; i++) {
 
526
 
 
527
                *(page + i) = (byte)0;
 
528
        }
 
529
 
 
530
        mlog_write_initial_log_record(page, MLOG_IBUF_BITMAP_INIT, mtr);
 
531
}
 
532
 
 
533
/*************************************************************************
 
534
Parses a redo log record of an ibuf bitmap page init. */
 
535
 
 
536
byte*
 
537
ibuf_parse_bitmap_init(
 
538
/*===================*/
 
539
                        /* out: end of log record or NULL */
 
540
        byte*   ptr,    /* in: buffer */
 
541
        byte*   end_ptr,/* in: buffer end */
 
542
        page_t* page,   /* in: page or NULL */
 
543
        mtr_t*  mtr)    /* in: mtr or NULL */
 
544
{
 
545
        ut_ad(ptr && end_ptr);
 
546
 
 
547
        if (page) {
 
548
                ibuf_bitmap_page_init(page, mtr);
 
549
        }
 
550
 
 
551
        return(ptr);
 
552
}
 
553
 
 
554
/************************************************************************
 
555
Gets the desired bits for a given page from a bitmap page. */
 
556
UNIV_INLINE
 
557
ulint
 
558
ibuf_bitmap_page_get_bits(
 
559
/*======================*/
 
560
                        /* out: value of bits */
 
561
        page_t* page,   /* in: bitmap page */
 
562
        ulint   page_no,/* in: page whose bits to get */
 
563
        ulint   bit,    /* in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */
 
564
        mtr_t*  mtr)    /* in: mtr containing an x-latch to the bitmap page */
 
565
{
 
566
        ulint   byte_offset;
 
567
        ulint   bit_offset;
 
568
        ulint   map_byte;
 
569
        ulint   value;
 
570
 
 
571
        ut_ad(bit < IBUF_BITS_PER_PAGE);
 
572
        ut_ad(IBUF_BITS_PER_PAGE % 2 == 0);
 
573
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
574
                                                MTR_MEMO_PAGE_X_FIX));
 
575
 
 
576
        bit_offset = (page_no % XDES_DESCRIBED_PER_PAGE) * IBUF_BITS_PER_PAGE
 
577
                     + bit;
 
578
 
 
579
        byte_offset = bit_offset / 8;
 
580
        bit_offset = bit_offset % 8;
 
581
 
 
582
        ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
 
583
 
 
584
        map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
 
585
 
 
586
        value = ut_bit_get_nth(map_byte, bit_offset);
 
587
 
 
588
        if (bit == IBUF_BITMAP_FREE) {
 
589
                ut_ad(bit_offset + 1 < 8);
 
590
                
 
591
                value = value * 2 + ut_bit_get_nth(map_byte, bit_offset + 1);
 
592
        }
 
593
 
 
594
        return(value);
 
595
}
 
596
 
 
597
/************************************************************************
 
598
Sets the desired bit for a given page in a bitmap page. */
 
599
static
 
600
void
 
601
ibuf_bitmap_page_set_bits(
 
602
/*======================*/
 
603
        page_t* page,   /* in: bitmap page */
 
604
        ulint   page_no,/* in: page whose bits to set */
 
605
        ulint   bit,    /* in: IBUF_BITMAP_FREE, IBUF_BITMAP_BUFFERED, ... */
 
606
        ulint   val,    /* in: value to set */
 
607
        mtr_t*  mtr)    /* in: mtr containing an x-latch to the bitmap page */
 
608
{
 
609
        ulint   byte_offset;
 
610
        ulint   bit_offset;
 
611
        ulint   map_byte;
 
612
 
 
613
        ut_ad(bit < IBUF_BITS_PER_PAGE);
 
614
        ut_ad(IBUF_BITS_PER_PAGE % 2 == 0);
 
615
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
616
                                                MTR_MEMO_PAGE_X_FIX));
 
617
#ifdef UNIV_IBUF_DEBUG
 
618
        ut_a((bit != IBUF_BITMAP_BUFFERED) || (val != FALSE)
 
619
              || (0 == ibuf_count_get(buf_frame_get_space_id(page), page_no)));
 
620
#endif
 
621
        bit_offset = (page_no % XDES_DESCRIBED_PER_PAGE) * IBUF_BITS_PER_PAGE
 
622
                     + bit;
 
623
 
 
624
        byte_offset = bit_offset / 8;
 
625
        bit_offset = bit_offset % 8;
 
626
 
 
627
        ut_ad(byte_offset + IBUF_BITMAP < UNIV_PAGE_SIZE);
 
628
 
 
629
        map_byte = mach_read_from_1(page + IBUF_BITMAP + byte_offset);
 
630
 
 
631
        if (bit == IBUF_BITMAP_FREE) {
 
632
                ut_ad(bit_offset + 1 < 8);
 
633
                ut_ad(val <= 3);
 
634
                
 
635
                map_byte = ut_bit_set_nth(map_byte, bit_offset, val / 2);
 
636
                map_byte = ut_bit_set_nth(map_byte, bit_offset + 1, val % 2);
 
637
        } else {
 
638
                ut_ad(val <= 1);
 
639
                map_byte = ut_bit_set_nth(map_byte, bit_offset, val);
 
640
        }
 
641
        
 
642
        mlog_write_ulint(page + IBUF_BITMAP + byte_offset, map_byte,
 
643
                                                        MLOG_1BYTE, mtr);
 
644
}
 
645
 
 
646
/************************************************************************
 
647
Calculates the bitmap page number for a given page number. */
 
648
UNIV_INLINE
 
649
ulint
 
650
ibuf_bitmap_page_no_calc(
 
651
/*=====================*/
 
652
                                /* out: the bitmap page number where
 
653
                                the file page is mapped */
 
654
        ulint   page_no)        /* in: tablespace page number */
 
655
{
 
656
        return(FSP_IBUF_BITMAP_OFFSET
 
657
               + XDES_DESCRIBED_PER_PAGE
 
658
                                        * (page_no / XDES_DESCRIBED_PER_PAGE));
 
659
}
 
660
 
 
661
/************************************************************************
 
662
Gets the ibuf bitmap page where the bits describing a given file page are
 
663
stored. */
 
664
static
 
665
page_t*
 
666
ibuf_bitmap_get_map_page(
 
667
/*=====================*/
 
668
                        /* out: bitmap page where the file page is mapped,
 
669
                        that is, the bitmap page containing the descriptor
 
670
                        bits for the file page; the bitmap page is
 
671
                        x-latched */
 
672
        ulint   space,  /* in: space id of the file page */
 
673
        ulint   page_no,/* in: page number of the file page */
 
674
        mtr_t*  mtr)    /* in: mtr */
 
675
{
 
676
        page_t* page;
 
677
        
 
678
        page = buf_page_get(space, ibuf_bitmap_page_no_calc(page_no),
 
679
                                                        RW_X_LATCH, mtr);
 
680
        buf_page_dbg_add_level(page, SYNC_IBUF_BITMAP);
 
681
 
 
682
        return(page);
 
683
}
 
684
 
 
685
/****************************************************************************
 
686
Sets the free bits of the page in the ibuf bitmap. This is done in a separate
 
687
mini-transaction, hence this operation does not restrict further work to only
 
688
ibuf bitmap operations, which would result if the latch to the bitmap pag
 
689
were kept. */
 
690
UNIV_INLINE
 
691
void
 
692
ibuf_set_free_bits_low(
 
693
/*===================*/
 
694
        ulint   type,   /* in: index type */
 
695
        page_t* page,   /* in: index page; free bit is reset if the index is
 
696
                        a non-clustered non-unique, and page level is 0 */
 
697
        ulint   val,    /* in: value to set: < 4 */
 
698
        mtr_t*  mtr)    /* in: mtr */
 
699
{
 
700
        page_t* bitmap_page;
 
701
 
 
702
        if (type & (DICT_CLUSTERED | DICT_UNIQUE)) {
 
703
 
 
704
                return;
 
705
        }
 
706
 
 
707
        if (btr_page_get_level_low(page) != 0) {
 
708
 
 
709
                return;
 
710
        }
 
711
 
 
712
        bitmap_page = ibuf_bitmap_get_map_page(buf_frame_get_space_id(page),
 
713
                                        buf_frame_get_page_no(page), mtr);
 
714
#ifdef UNIV_IBUF_DEBUG
 
715
        /* printf("Setting page no %lu free bits to %lu should be %lu\n",
 
716
                                        buf_frame_get_page_no(page), val,
 
717
                                ibuf_index_page_calc_free(page)); */
 
718
        
 
719
        ut_a(val <= ibuf_index_page_calc_free(page));
 
720
#endif
 
721
        ibuf_bitmap_page_set_bits(bitmap_page, buf_frame_get_page_no(page),
 
722
                                                IBUF_BITMAP_FREE, val, mtr);
 
723
 
 
724
}
 
725
 
 
726
/****************************************************************************
 
727
Sets the free bit of the page in the ibuf bitmap. This is done in a separate
 
728
mini-transaction, hence this operation does not restrict further work to only
 
729
ibuf bitmap operations, which would result if the latch to the bitmap page
 
730
were kept. */
 
731
 
 
732
void
 
733
ibuf_set_free_bits(
 
734
/*===============*/
 
735
        ulint   type,   /* in: index type */
 
736
        page_t* page,   /* in: index page; free bit is reset if the index is
 
737
                        a non-clustered non-unique, and page level is 0 */
 
738
        ulint   val,    /* in: value to set: < 4 */
 
739
        ulint   max_val)/* in: ULINT_UNDEFINED or a maximum value which
 
740
                        the bits must have before setting; this is for
 
741
                        debugging */
 
742
{
 
743
        mtr_t   mtr;
 
744
        page_t* bitmap_page;
 
745
 
 
746
        if (type & (DICT_CLUSTERED | DICT_UNIQUE)) {
 
747
 
 
748
                return;
 
749
        }
 
750
 
 
751
        if (btr_page_get_level_low(page) != 0) {
 
752
 
 
753
                return;
 
754
        }
 
755
 
 
756
        mtr_start(&mtr);
 
757
        
 
758
        bitmap_page = ibuf_bitmap_get_map_page(buf_frame_get_space_id(page),
 
759
                                        buf_frame_get_page_no(page), &mtr);
 
760
 
 
761
        if (max_val != ULINT_UNDEFINED) {
 
762
#ifdef UNIV_IBUF_DEBUG
 
763
                ulint   old_val;
 
764
 
 
765
                old_val = ibuf_bitmap_page_get_bits(bitmap_page,
 
766
                                        buf_frame_get_page_no(page),
 
767
                                                IBUF_BITMAP_FREE, &mtr);
 
768
                if (old_val != max_val) {
 
769
                        /* printf(
 
770
                        "Ibuf: page %lu old val %lu max val %lu\n",
 
771
                        buf_frame_get_page_no(page), old_val, max_val); */
 
772
                }
 
773
 
 
774
                ut_a(old_val <= max_val);
 
775
#endif
 
776
        }
 
777
#ifdef UNIV_IBUF_DEBUG
 
778
/*      printf("Setting page no %lu free bits to %lu should be %lu\n",
 
779
                                        buf_frame_get_page_no(page), val,
 
780
                                ibuf_index_page_calc_free(page)); */
 
781
 
 
782
        ut_a(val <= ibuf_index_page_calc_free(page));
 
783
#endif                          
 
784
        ibuf_bitmap_page_set_bits(bitmap_page, buf_frame_get_page_no(page),
 
785
                                                IBUF_BITMAP_FREE, val, &mtr);
 
786
        mtr_commit(&mtr);
 
787
}
 
788
 
 
789
/****************************************************************************
 
790
Resets the free bits of the page in the ibuf bitmap. This is done in a
 
791
separate mini-transaction, hence this operation does not restrict further
 
792
work to only ibuf bitmap operations, which would result if the latch to the
 
793
bitmap page were kept. */
 
794
 
 
795
void
 
796
ibuf_reset_free_bits_with_type(
 
797
/*===========================*/
 
798
        ulint   type,   /* in: index type */
 
799
        page_t* page)   /* in: index page; free bits are set to 0 if the index
 
800
                        is non-clustered and non-unique and the page level is
 
801
                        0 */
 
802
{
 
803
        ibuf_set_free_bits(type, page, 0, ULINT_UNDEFINED);
 
804
}
 
805
 
 
806
/****************************************************************************
 
807
Resets the free bits of the page in the ibuf bitmap. This is done in a
 
808
separate mini-transaction, hence this operation does not restrict further
 
809
work to solely ibuf bitmap operations, which would result if the latch to
 
810
the bitmap page were kept. */
 
811
 
 
812
void
 
813
ibuf_reset_free_bits(
 
814
/*=================*/
 
815
        dict_index_t*   index,  /* in: index */
 
816
        page_t*         page)   /* in: index page; free bits are set to 0 if
 
817
                                the index is non-clustered and non-unique and
 
818
                                the page level is 0 */
 
819
{
 
820
        ibuf_set_free_bits(index->type, page, 0, ULINT_UNDEFINED);
 
821
}
 
822
 
 
823
/**************************************************************************
 
824
Updates the free bits for a page to reflect the present state. Does this
 
825
in the mtr given, which means that the latching order rules virtually prevent
 
826
any further operations for this OS thread until mtr is committed. */
 
827
 
 
828
void
 
829
ibuf_update_free_bits_low(
 
830
/*======================*/
 
831
        dict_index_t*   index,          /* in: index */
 
832
        page_t*         page,           /* in: index page */
 
833
        ulint           max_ins_size,   /* in: value of maximum insert size
 
834
                                        with reorganize before the latest
 
835
                                        operation performed to the page */
 
836
        mtr_t*          mtr)            /* in: mtr */
 
837
{
 
838
        ulint   before;
 
839
        ulint   after;
 
840
 
 
841
        before = ibuf_index_page_calc_free_bits(max_ins_size);
 
842
 
 
843
        after = ibuf_index_page_calc_free(page);
 
844
 
 
845
        if (before != after) {
 
846
                ibuf_set_free_bits_low(index->type, page, after, mtr);
 
847
        }
 
848
}
 
849
 
 
850
/**************************************************************************
 
851
Updates the free bits for the two pages to reflect the present state. Does
 
852
this in the mtr given, which means that the latching order rules virtually
 
853
prevent any further operations until mtr is committed. */
 
854
 
 
855
void
 
856
ibuf_update_free_bits_for_two_pages_low(
 
857
/*====================================*/
 
858
        dict_index_t*   index,  /* in: index */
 
859
        page_t*         page1,  /* in: index page */
 
860
        page_t*         page2,  /* in: index page */
 
861
        mtr_t*          mtr)    /* in: mtr */
 
862
{
 
863
        ulint   state;
 
864
 
 
865
        /* As we have to x-latch two random bitmap pages, we have to acquire
 
866
        the bitmap mutex to prevent a deadlock with a similar operation
 
867
        performed by another OS thread. */
 
868
 
 
869
        mutex_enter(&ibuf_bitmap_mutex);
 
870
        
 
871
        state = ibuf_index_page_calc_free(page1);
 
872
 
 
873
        ibuf_set_free_bits_low(index->type, page1, state, mtr);
 
874
 
 
875
        state = ibuf_index_page_calc_free(page2);
 
876
 
 
877
        ibuf_set_free_bits_low(index->type, page2, state, mtr);
 
878
 
 
879
        mutex_exit(&ibuf_bitmap_mutex);
 
880
}
 
881
 
 
882
/**************************************************************************
 
883
Returns TRUE if the page is one of the fixed address ibuf pages. */
 
884
UNIV_INLINE
 
885
ibool
 
886
ibuf_fixed_addr_page(
 
887
/*=================*/
 
888
                        /* out: TRUE if a fixed address ibuf i/o page */        
 
889
        ulint   page_no)/* in: page number */
 
890
{
 
891
        if ((ibuf_bitmap_page(page_no))
 
892
                                || (page_no == IBUF_TREE_ROOT_PAGE_NO)) {
 
893
                return(TRUE);
 
894
        }
 
895
 
 
896
        return(FALSE);
 
897
}
 
898
 
 
899
/***************************************************************************
 
900
Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */
 
901
 
 
902
ibool
 
903
ibuf_page(
 
904
/*======*/
 
905
                        /* out: TRUE if level 2 or level 3 page */
 
906
        ulint   space,  /* in: space id */
 
907
        ulint   page_no)/* in: page number */
 
908
{
 
909
        page_t* bitmap_page;
 
910
        mtr_t   mtr;
 
911
        ibool   ret;
 
912
 
 
913
        if (recv_no_ibuf_operations) {
 
914
                /* Recovery is running: no ibuf operations should be
 
915
                performed */
 
916
 
 
917
                return(FALSE);
 
918
        }
 
919
 
 
920
        if (ibuf_fixed_addr_page(page_no)) {
 
921
 
 
922
                return(TRUE);
 
923
        }
 
924
 
 
925
        ut_ad(fil_space_get_type(space) == FIL_TABLESPACE);
 
926
 
 
927
        mtr_start(&mtr);
 
928
 
 
929
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
 
930
 
 
931
        ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
 
932
                                                                        &mtr);
 
933
        mtr_commit(&mtr);
 
934
 
 
935
        return(ret);
 
936
}
 
937
 
 
938
/***************************************************************************
 
939
Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */
 
940
 
 
941
ibool
 
942
ibuf_page_low(
 
943
/*==========*/
 
944
                        /* out: TRUE if level 2 or level 3 page */
 
945
        ulint   space,  /* in: space id */
 
946
        ulint   page_no,/* in: page number */
 
947
        mtr_t*  mtr)    /* in: mtr which will contain an x-latch to the
 
948
                        bitmap page if the page is not one of the fixed
 
949
                        address ibuf pages */
 
950
{
 
951
        page_t* bitmap_page;
 
952
        ibool   ret;
 
953
 
 
954
#ifdef UNIV_LOG_DEBUG
 
955
        if (space % 2 != 0) {
 
956
 
 
957
                printf("No ibuf in a replicate space\n");
 
958
 
 
959
                return(FALSE);
 
960
        }
 
961
#endif  
 
962
        if (ibuf_fixed_addr_page(page_no)) {
 
963
 
 
964
                return(TRUE);
 
965
        }
 
966
 
 
967
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, mtr);
 
968
 
 
969
        ret = ibuf_bitmap_page_get_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
 
970
                                                                        mtr);
 
971
        return(ret);
 
972
}
 
973
 
 
974
/************************************************************************
 
975
Returns the page number field of an ibuf record. */
 
976
static
 
977
ulint
 
978
ibuf_rec_get_page_no(
 
979
/*=================*/
 
980
                        /* out: page number */
 
981
        rec_t*  rec)    /* in: ibuf record */
 
982
{
 
983
        byte*   field;
 
984
        ulint   len;
 
985
 
 
986
        ut_ad(ibuf_inside());
 
987
        ut_ad(rec_get_n_fields(rec) > 2);
 
988
 
 
989
        field = rec_get_nth_field(rec, 0, &len);
 
990
 
 
991
        ut_ad(len == 4);
 
992
 
 
993
        return(mach_read_from_4(field));
 
994
}
 
995
 
 
996
/************************************************************************
 
997
Returns the space taken by a stored non-clustered index entry if converted to
 
998
an index record. */
 
999
static
 
1000
ulint
 
1001
ibuf_rec_get_volume(
 
1002
/*================*/
 
1003
                        /* out: size of index record in bytes + an upper
 
1004
                        limit of the space taken in the page directory */
 
1005
        rec_t*  rec)    /* in: ibuf record */
 
1006
{
 
1007
        ulint   n_fields;
 
1008
        byte*   field;
 
1009
        ulint   len;
 
1010
        ulint   data_size;
 
1011
 
 
1012
        ut_ad(ibuf_inside());
 
1013
        ut_ad(rec_get_n_fields(rec) > 2);
 
1014
 
 
1015
        n_fields = rec_get_n_fields(rec) - 2;
 
1016
 
 
1017
        field = rec_get_nth_field(rec, 2, &len);
 
1018
 
 
1019
        data_size = rec_get_data_size(rec) - (field - rec);
 
1020
 
 
1021
        return(data_size + rec_get_converted_extra_size(data_size, n_fields)
 
1022
                                        + page_dir_calc_reserved_space(1));
 
1023
}
 
1024
 
 
1025
/*************************************************************************
 
1026
Builds the tuple to insert to an ibuf tree when we have an entry for a
 
1027
non-clustered index. */
 
1028
static
 
1029
dtuple_t*
 
1030
ibuf_entry_build(
 
1031
/*=============*/
 
1032
                                /* out, own: entry to insert into an ibuf
 
1033
                                index tree; NOTE that the original entry
 
1034
                                must be kept because we copy pointers to its
 
1035
                                fields */
 
1036
        dtuple_t*       entry,  /* in: entry for a non-clustered index */
 
1037
        ulint           page_no,/* in: index page number where entry should
 
1038
                                be inserted */
 
1039
        mem_heap_t*     heap)   /* in: heap into which to build */
 
1040
{
 
1041
        dtuple_t*       tuple;
 
1042
        dfield_t*       field;
 
1043
        dfield_t*       entry_field;
 
1044
        ulint           n_fields;
 
1045
        byte*           buf;
 
1046
        byte*           buf2;
 
1047
        ulint           i;
 
1048
        
 
1049
        /* We have to build a tuple whose first field is the page number,
 
1050
        the second field contains the original type information for entry,
 
1051
        and the rest of the fields are copied from entry. All fields
 
1052
        in the tuple are of the type binary. */
 
1053
 
 
1054
        n_fields = dtuple_get_n_fields(entry);
 
1055
 
 
1056
        tuple = dtuple_create(heap, n_fields + 2);
 
1057
 
 
1058
        /* Store the page number in tuple */
 
1059
 
 
1060
        field = dtuple_get_nth_field(tuple, 0);
 
1061
 
 
1062
        buf = mem_heap_alloc(heap, 4);
 
1063
 
 
1064
        mach_write_to_4(buf, page_no);
 
1065
 
 
1066
        dfield_set_data(field, buf, 4);
 
1067
 
 
1068
        /* Store the type info in tuple */
 
1069
 
 
1070
        buf2 = mem_heap_alloc(heap, n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
 
1071
 
 
1072
        for (i = 0; i < n_fields; i++) {
 
1073
 
 
1074
                field = dtuple_get_nth_field(tuple, i + 2);
 
1075
 
 
1076
                entry_field = dtuple_get_nth_field(entry, i);
 
1077
 
 
1078
                dfield_copy(field, entry_field);
 
1079
 
 
1080
                dtype_store_for_order_and_null_size(
 
1081
                                buf2 + i * DATA_ORDER_NULL_TYPE_BUF_SIZE,
 
1082
                                dfield_get_type(entry_field));
 
1083
        }
 
1084
 
 
1085
        field = dtuple_get_nth_field(tuple, 1);
 
1086
 
 
1087
        dfield_set_data(field, buf2, n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
 
1088
 
 
1089
        /* Set the types in the new tuple binary */
 
1090
 
 
1091
        dtuple_set_types_binary(tuple, n_fields + 2);
 
1092
 
 
1093
        return(tuple);
 
1094
}       
 
1095
 
 
1096
/*************************************************************************
 
1097
Builds the entry to insert into a non-clustered index when we have the
 
1098
corresponding record in an ibuf index. */
 
1099
static
 
1100
dtuple_t*
 
1101
ibuf_build_entry_from_ibuf_rec(
 
1102
/*===========================*/
 
1103
                                        /* out, own: entry to insert to
 
1104
                                        a non-clustered index; NOTE that
 
1105
                                        as we copy pointers to fields in
 
1106
                                        ibuf_rec, the caller must hold a
 
1107
                                        latch to the ibuf_rec page as long
 
1108
                                        as the entry is used! */
 
1109
        rec_t*          ibuf_rec,       /* in: record in an insert buffer */
 
1110
        mem_heap_t*     heap)           /* in: heap where built */
 
1111
{
 
1112
        dtuple_t*       tuple;
 
1113
        dfield_t*       field;
 
1114
        ulint           n_fields;
 
1115
        byte*           types;
 
1116
        byte*           data;
 
1117
        ulint           len;
 
1118
        ulint           i;
 
1119
        
 
1120
        n_fields = rec_get_n_fields(ibuf_rec) - 2;
 
1121
 
 
1122
        tuple = dtuple_create(heap, n_fields);
 
1123
 
 
1124
        types = rec_get_nth_field(ibuf_rec, 1, &len);
 
1125
 
 
1126
        ut_ad(len == n_fields * DATA_ORDER_NULL_TYPE_BUF_SIZE);
 
1127
 
 
1128
        for (i = 0; i < n_fields; i++) {
 
1129
                field = dtuple_get_nth_field(tuple, i);
 
1130
 
 
1131
                data = rec_get_nth_field(ibuf_rec, i + 2, &len);
 
1132
 
 
1133
                dfield_set_data(field, data, len);
 
1134
 
 
1135
                dtype_read_for_order_and_null_size(dfield_get_type(field),
 
1136
                                   types + i * DATA_ORDER_NULL_TYPE_BUF_SIZE);
 
1137
        }
 
1138
 
 
1139
        return(tuple);
 
1140
}
 
1141
 
 
1142
/*************************************************************************
 
1143
Builds a search tuple used to search buffered inserts for an index page. */
 
1144
static
 
1145
dtuple_t*
 
1146
ibuf_search_tuple_build(
 
1147
/*====================*/
 
1148
                                /* out, own: search tuple */
 
1149
        ulint           page_no,/* in: index page number */
 
1150
        mem_heap_t*     heap)   /* in: heap into which to build */
 
1151
{
 
1152
        dtuple_t*       tuple;
 
1153
        dfield_t*       field;
 
1154
        byte*           buf;
 
1155
        
 
1156
        tuple = dtuple_create(heap, 1);
 
1157
 
 
1158
        /* Store the page number in tuple */
 
1159
 
 
1160
        field = dtuple_get_nth_field(tuple, 0);
 
1161
 
 
1162
        buf = mem_heap_alloc(heap, 4);
 
1163
 
 
1164
        mach_write_to_4(buf, page_no);
 
1165
 
 
1166
        dfield_set_data(field, buf, 4);
 
1167
 
 
1168
        dtuple_set_types_binary(tuple, 1);
 
1169
 
 
1170
        return(tuple);
 
1171
}
 
1172
 
 
1173
/*************************************************************************
 
1174
Checks if there are enough pages in the free list of the ibuf tree that we
 
1175
dare to start a pessimistic insert to the insert buffer. */
 
1176
UNIV_INLINE
 
1177
ibool
 
1178
ibuf_data_enough_free_for_insert(
 
1179
/*=============================*/
 
1180
                                /* out: TRUE if enough free pages in list */
 
1181
        ibuf_data_t*    data)   /* in: ibuf data for the space */
 
1182
{
 
1183
        ut_ad(mutex_own(&ibuf_mutex));
 
1184
 
 
1185
        /* We want a big margin of free pages, because a B-tree can sometimes
 
1186
        grow in size also if records are deleted from it, as the node pointers
 
1187
        can change, and we must make sure that we are able to delete the
 
1188
        inserts buffered for pages that we read to the buffer pool, without
 
1189
        any risk of running out of free space in the insert buffer. */
 
1190
 
 
1191
        if (data->free_list_len >= data->size / 2 + 3 * data->height) {
 
1192
 
 
1193
                return(TRUE);
 
1194
        }
 
1195
 
 
1196
        return(FALSE);
 
1197
}
 
1198
 
 
1199
/*************************************************************************
 
1200
Checks if there are enough pages in the free list of the ibuf tree that we
 
1201
should remove them and free to the file space management. */
 
1202
UNIV_INLINE
 
1203
ibool
 
1204
ibuf_data_too_much_free(
 
1205
/*====================*/
 
1206
                                /* out: TRUE if enough free pages in list */
 
1207
        ibuf_data_t*    data)   /* in: ibuf data for the space */
 
1208
{
 
1209
        ut_ad(mutex_own(&ibuf_mutex));
 
1210
 
 
1211
        if (data->free_list_len >= 3 + data->size / 2 + 3 * data->height) {
 
1212
 
 
1213
                return(TRUE);
 
1214
        }
 
1215
 
 
1216
        return(FALSE);
 
1217
}
 
1218
 
 
1219
/*************************************************************************
 
1220
Allocates a new page from the ibuf file segment and adds it to the free
 
1221
list. */
 
1222
static
 
1223
ulint
 
1224
ibuf_add_free_page(
 
1225
/*===============*/
 
1226
                                        /* out: DB_SUCCESS, or DB_STRONG_FAIL
 
1227
                                        if no space left */
 
1228
        ulint           space,          /* in: space id */
 
1229
        ibuf_data_t*    ibuf_data)      /* in: ibuf data for the space */
 
1230
{
 
1231
        mtr_t   mtr;
 
1232
        page_t* header_page;
 
1233
        ulint   page_no;
 
1234
        page_t* page;
 
1235
        page_t* root;
 
1236
        page_t* bitmap_page;
 
1237
 
 
1238
        mtr_start(&mtr);
 
1239
 
 
1240
        /* Acquire the fsp latch before the ibuf header, obeying the latching
 
1241
        order */
 
1242
        mtr_x_lock(fil_space_get_latch(space), &mtr);
 
1243
        
 
1244
        header_page = ibuf_header_page_get(space, &mtr);
 
1245
 
 
1246
        /* Allocate a new page: NOTE that if the page has been a part of a
 
1247
        non-clustered index which has subsequently been dropped, then the
 
1248
        page may have buffered inserts in the insert buffer, and these
 
1249
        should be deleted from there. These get deleted when the page
 
1250
        allocation creates the page in buffer. Thus the call below may end
 
1251
        up calling the insert buffer routines and, as we yet have no latches
 
1252
        to insert buffer tree pages, these routines can run without a risk
 
1253
        of a deadlock. This is the reason why we created a special ibuf
 
1254
        header page apart from the ibuf tree. */
 
1255
 
 
1256
        page_no = fseg_alloc_free_page(header_page + IBUF_HEADER
 
1257
                                        + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
 
1258
                                                                        &mtr);
 
1259
        if (page_no == FIL_NULL) {
 
1260
                mtr_commit(&mtr);
 
1261
 
 
1262
                return(DB_STRONG_FAIL);
 
1263
        }
 
1264
 
 
1265
        page = buf_page_get(space, page_no, RW_X_LATCH, &mtr);
 
1266
 
 
1267
        buf_page_dbg_add_level(page, SYNC_TREE_NODE_NEW);
 
1268
 
 
1269
        ibuf_enter();
 
1270
 
 
1271
        mutex_enter(&ibuf_mutex);
 
1272
 
 
1273
        root = ibuf_tree_root_get(ibuf_data, space, &mtr);
 
1274
 
 
1275
        /* Add the page to the free list and update the ibuf size data */
 
1276
 
 
1277
        flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 
1278
                      page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
 
1279
 
 
1280
        ibuf_data->seg_size++;
 
1281
        ibuf_data->free_list_len++;
 
1282
 
 
1283
        /* Set the bit indicating that this page is now an ibuf tree page
 
1284
        (level 2 page) */
 
1285
 
 
1286
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
 
1287
 
 
1288
        ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
 
1289
                                                                TRUE, &mtr);
 
1290
        mtr_commit(&mtr);
 
1291
 
 
1292
        mutex_exit(&ibuf_mutex);
 
1293
 
 
1294
        ibuf_exit();
 
1295
}
 
1296
 
 
1297
/*************************************************************************
 
1298
Removes a page from the free list and frees it to the fsp system. */
 
1299
static
 
1300
void
 
1301
ibuf_remove_free_page(
 
1302
/*==================*/
 
1303
        ulint           space,          /* in: space id */
 
1304
        ibuf_data_t*    ibuf_data)      /* in: ibuf data for the space */
 
1305
{
 
1306
        mtr_t   mtr;
 
1307
        mtr_t   mtr2;
 
1308
        page_t* header_page;
 
1309
        ulint   page_no;
 
1310
        page_t* page;
 
1311
        page_t* root;
 
1312
        page_t* bitmap_page;
 
1313
 
 
1314
        mtr_start(&mtr);
 
1315
 
 
1316
        /* Acquire the fsp latch before the ibuf header, obeying the latching
 
1317
        order */
 
1318
        mtr_x_lock(fil_space_get_latch(space), &mtr);
 
1319
        
 
1320
        header_page = ibuf_header_page_get(space, &mtr);
 
1321
 
 
1322
        /* Prevent pessimistic inserts to insert buffer trees for a while */
 
1323
        mutex_enter(&ibuf_pessimistic_insert_mutex);
 
1324
 
 
1325
        ibuf_enter();
 
1326
 
 
1327
        mutex_enter(&ibuf_mutex);
 
1328
 
 
1329
        if (!ibuf_data_too_much_free(ibuf_data)) {
 
1330
 
 
1331
                mutex_exit(&ibuf_mutex);
 
1332
 
 
1333
                ibuf_exit();
 
1334
                
 
1335
                mutex_exit(&ibuf_pessimistic_insert_mutex);
 
1336
 
 
1337
                mtr_commit(&mtr);
 
1338
 
 
1339
                return;
 
1340
        }
 
1341
        
 
1342
        mtr_start(&mtr2);
 
1343
        
 
1344
        root = ibuf_tree_root_get(ibuf_data, space, &mtr2);
 
1345
 
 
1346
        page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 
1347
                                                                        &mtr2)
 
1348
                  .page;
 
1349
 
 
1350
        /* NOTE that we must release the latch on the ibuf tree root
 
1351
        because in fseg_free_page we access level 1 pages, and the root
 
1352
        is a level 2 page. */
 
1353
                  
 
1354
        mtr_commit(&mtr2);
 
1355
        mutex_exit(&ibuf_mutex);
 
1356
 
 
1357
        ibuf_exit();
 
1358
        
 
1359
        /* Since pessimistic inserts were prevented, we know that the
 
1360
        page is still in the free list. NOTE that also deletes may take
 
1361
        pages from the free list, but they take them from the start, and
 
1362
        the free list was so long that they cannot have taken the last
 
1363
        page from it. */
 
1364
        
 
1365
        fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
 
1366
                                                        space, page_no, &mtr);
 
1367
        ibuf_enter();
 
1368
                                                        
 
1369
        mutex_enter(&ibuf_mutex);
 
1370
 
 
1371
        root = ibuf_tree_root_get(ibuf_data, space, &mtr);
 
1372
 
 
1373
        ut_ad(page_no == flst_get_last(root + PAGE_HEADER
 
1374
                                        + PAGE_BTR_IBUF_FREE_LIST, &mtr)
 
1375
                         .page);
 
1376
 
 
1377
        page = buf_page_get(space, page_no, RW_X_LATCH, &mtr);
 
1378
 
 
1379
        buf_page_dbg_add_level(page, SYNC_TREE_NODE);
 
1380
 
 
1381
        /* Remove the page from the free list and update the ibuf size data */
 
1382
        
 
1383
        flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 
1384
                    page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
 
1385
 
 
1386
        ibuf_data->seg_size--;
 
1387
        ibuf_data->free_list_len--;
 
1388
                      
 
1389
        mutex_exit(&ibuf_pessimistic_insert_mutex);
 
1390
 
 
1391
        /* Set the bit indicating that this page is no more an ibuf tree page
 
1392
        (level 2 page) */
 
1393
 
 
1394
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
 
1395
 
 
1396
        ibuf_bitmap_page_set_bits(bitmap_page, page_no, IBUF_BITMAP_IBUF,
 
1397
                                                                FALSE, &mtr);
 
1398
        mtr_commit(&mtr);
 
1399
 
 
1400
        mutex_exit(&ibuf_mutex);
 
1401
 
 
1402
        ibuf_exit();
 
1403
}
 
1404
 
 
1405
/***************************************************************************
 
1406
Frees excess pages from the ibuf free list. This function is called when an OS
 
1407
thread calls fsp services to allocate a new file segment, or a new page to a
 
1408
file segment, and the thread did not own the fsp latch before this call. */ 
 
1409
 
 
1410
void
 
1411
ibuf_free_excess_pages(
 
1412
/*===================*/
 
1413
        ulint   space)  /* in: space id */
 
1414
{
 
1415
        ibuf_data_t*    ibuf_data;
 
1416
        ulint           i;
 
1417
        
 
1418
        ut_ad(rw_lock_own(fil_space_get_latch(space), RW_LOCK_EX));
 
1419
        ut_ad(rw_lock_get_x_lock_count(fil_space_get_latch(space)) == 1);
 
1420
        ut_ad(!ibuf_inside());
 
1421
        
 
1422
        /* NOTE: We require that the thread did not own the latch before,
 
1423
        because then we know that we can obey the correct latching order
 
1424
        for ibuf latches */
 
1425
 
 
1426
        ibuf_data = fil_space_get_ibuf_data(space);
 
1427
 
 
1428
        if (ibuf_data == NULL) {
 
1429
                /* Not yet initialized */
 
1430
 
 
1431
#ifdef UNIV_DEBUG
 
1432
                /*printf("Ibuf for space %lu not yet initialized\n", space); */
 
1433
#endif
 
1434
 
 
1435
                return;
 
1436
        }
 
1437
 
 
1438
        /* Free at most a few pages at a time, so that we do not delay the
 
1439
        requested service too much */
 
1440
 
 
1441
        for (i = 0; i < 4; i++) {
 
1442
 
 
1443
                mutex_enter(&ibuf_mutex);
 
1444
 
 
1445
                if (!ibuf_data_too_much_free(ibuf_data)) {
 
1446
 
 
1447
                        mutex_exit(&ibuf_mutex);
 
1448
 
 
1449
                        return;
 
1450
                }
 
1451
 
 
1452
                mutex_exit(&ibuf_mutex);
 
1453
 
 
1454
                ibuf_remove_free_page(space, ibuf_data);
 
1455
        }
 
1456
}
 
1457
 
 
1458
/*************************************************************************
 
1459
Reads page numbers from a leaf in an ibuf tree. */
 
1460
static
 
1461
ulint
 
1462
ibuf_get_merge_page_nos(
 
1463
/*====================*/
 
1464
                                /* out: a lower limit for the combined volume
 
1465
                                of records which will be merged */
 
1466
        ibool           contract,/* in: TRUE if this function is called to
 
1467
                                contract the tree, FALSE if this is called
 
1468
                                when a single page becomes full and we look
 
1469
                                if it pays to read also nearby pages */
 
1470
        rec_t*          first_rec,/* in: record from which we read down and
 
1471
                                up in the chain of records */
 
1472
        ulint*          page_nos,/* in/out: buffer for at least
 
1473
                                IBUF_MAX_N_PAGES_MERGED many page numbers;
 
1474
                                the page numbers are in an ascending order */
 
1475
        ulint*          n_stored)/* out: number of page numbers stored to
 
1476
                                page_nos in this function */
 
1477
{
 
1478
        ulint   prev_page_no;
 
1479
        ulint   first_page_no;
 
1480
        ulint   rec_page_no;
 
1481
        rec_t*  rec;
 
1482
        ulint   sum_volumes;
 
1483
        ulint   volume_for_page;
 
1484
        ulint   rec_volume;
 
1485
        ulint   limit;
 
1486
        page_t* page;
 
1487
        ulint   n_pages;
 
1488
 
 
1489
        *n_stored = 0;
 
1490
 
 
1491
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
 
1492
 
 
1493
        page = buf_frame_align(first_rec);
 
1494
        
 
1495
        if (first_rec == page_get_supremum_rec(page)) {
 
1496
 
 
1497
                first_rec = page_rec_get_prev(first_rec);
 
1498
        }
 
1499
 
 
1500
        if (first_rec == page_get_infimum_rec(page)) {
 
1501
 
 
1502
                first_rec = page_rec_get_next(first_rec);
 
1503
        }
 
1504
 
 
1505
        if (first_rec == page_get_supremum_rec(page)) {
 
1506
 
 
1507
                return(0);
 
1508
        }
 
1509
 
 
1510
        rec = first_rec;
 
1511
        first_page_no = ibuf_rec_get_page_no(first_rec);
 
1512
        n_pages = 0;
 
1513
        prev_page_no = 0;
 
1514
        
 
1515
        while ((rec != page_get_infimum_rec(page)) && (n_pages < limit)) {
 
1516
 
 
1517
                rec_page_no = ibuf_rec_get_page_no(rec);
 
1518
 
 
1519
                ut_ad(rec_page_no != 0);
 
1520
 
 
1521
                if (rec_page_no / IBUF_MERGE_AREA
 
1522
                    != first_page_no / IBUF_MERGE_AREA) {
 
1523
 
 
1524
                        break;
 
1525
                }
 
1526
                
 
1527
                if (rec_page_no != prev_page_no) {
 
1528
                        n_pages++;
 
1529
                }
 
1530
 
 
1531
                prev_page_no = rec_page_no;
 
1532
 
 
1533
                rec = page_rec_get_prev(rec);
 
1534
        }
 
1535
 
 
1536
        rec = page_rec_get_next(rec);
 
1537
 
 
1538
        prev_page_no = 0;
 
1539
        sum_volumes = 0;
 
1540
        volume_for_page = 0;
 
1541
        
 
1542
        while (*n_stored < limit) {
 
1543
                if (rec == page_get_supremum_rec(page)) {
 
1544
                        rec_page_no = 1;
 
1545
                } else {
 
1546
                        rec_page_no = ibuf_rec_get_page_no(rec);
 
1547
                        ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
 
1548
                }
 
1549
 
 
1550
#ifdef UNIV_IBUF_DEBUG
 
1551
                ut_a(*n_stored < IBUF_MAX_N_PAGES_MERGED);
 
1552
#endif
 
1553
                if (rec_page_no != prev_page_no) {
 
1554
                        if ((prev_page_no == first_page_no)
 
1555
                            || contract
 
1556
                            || (volume_for_page >
 
1557
                             ((IBUF_MERGE_THRESHOLD - 1)
 
1558
                              * 4 * UNIV_PAGE_SIZE
 
1559
                                    / IBUF_PAGE_SIZE_PER_FREE_SPACE)
 
1560
                             / IBUF_MERGE_THRESHOLD)) {
 
1561
 
 
1562
                                page_nos[*n_stored] = prev_page_no;
 
1563
 
 
1564
                                (*n_stored)++;
 
1565
 
 
1566
                                sum_volumes += volume_for_page;
 
1567
                        }
 
1568
 
 
1569
                        if (rec_page_no / IBUF_MERGE_AREA
 
1570
                                != first_page_no / IBUF_MERGE_AREA) {
 
1571
 
 
1572
                                break;
 
1573
                        }
 
1574
 
 
1575
                        volume_for_page = 0;
 
1576
                }
 
1577
 
 
1578
                if (rec_page_no == 1) {
 
1579
                        /* Supremum record */
 
1580
 
 
1581
                        break;
 
1582
                }
 
1583
 
 
1584
                rec_volume = ibuf_rec_get_volume(rec);
 
1585
 
 
1586
                volume_for_page += rec_volume;
 
1587
                
 
1588
                prev_page_no = rec_page_no;
 
1589
 
 
1590
                rec = page_rec_get_next(rec);
 
1591
        }
 
1592
 
 
1593
#ifdef UNIV_IBUF_DEBUG
 
1594
        ut_a(*n_stored <= IBUF_MAX_N_PAGES_MERGED);
 
1595
#endif
 
1596
/*      printf("Ibuf merge batch %lu pages %lu volume\n", *n_stored,
 
1597
                                                        sum_volumes); */
 
1598
        return(sum_volumes);
 
1599
}
 
1600
 
 
1601
/*************************************************************************
 
1602
Contracts insert buffer trees by reading pages to the buffer pool. */
 
1603
 
 
1604
ulint
 
1605
ibuf_contract(
 
1606
/*==========*/
 
1607
                        /* out: a lower limit for the combined size in bytes
 
1608
                        of entries which will be merged from ibuf trees to the
 
1609
                        pages read, 0 if ibuf is empty */
 
1610
        ibool   sync)   /* in: TRUE if the caller wants to wait for the
 
1611
                        issued read with the highest tablespace address
 
1612
                        to complete */
 
1613
{
 
1614
        ulint           rnd_pos;
 
1615
        ibuf_data_t*    data;
 
1616
        btr_pcur_t      pcur;
 
1617
        ulint           space;
 
1618
        ibool           all_trees_empty;
 
1619
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
 
1620
        ulint           n_stored;
 
1621
        ulint           sum_sizes;
 
1622
        mtr_t           mtr;
 
1623
loop:
 
1624
        ut_ad(!ibuf_inside());
 
1625
 
 
1626
        mutex_enter(&ibuf_mutex);
 
1627
 
 
1628
        ut_ad(ibuf_validate_low());     
 
1629
 
 
1630
        /* Choose an ibuf tree at random */
 
1631
        ibuf_rnd += 865558671;
 
1632
 
 
1633
        rnd_pos = ibuf_rnd % ibuf->size;
 
1634
 
 
1635
        all_trees_empty = TRUE;
 
1636
 
 
1637
        data = UT_LIST_GET_FIRST(ibuf->data_list);
 
1638
 
 
1639
        for (;;) {
 
1640
                if (!data->empty) {
 
1641
                        all_trees_empty = FALSE;
 
1642
                
 
1643
                        if (rnd_pos < data->size) {
 
1644
 
 
1645
                                break;
 
1646
                        }
 
1647
                
 
1648
                        rnd_pos -= data->size;
 
1649
                }
 
1650
                        
 
1651
                data = UT_LIST_GET_NEXT(data_list, data);
 
1652
 
 
1653
                if (data == NULL) {
 
1654
                        if (all_trees_empty) {
 
1655
                                mutex_exit(&ibuf_mutex);
 
1656
 
 
1657
                                return(0);
 
1658
                        }
 
1659
                        
 
1660
                        data = UT_LIST_GET_FIRST(ibuf->data_list);
 
1661
                }
 
1662
        }
 
1663
 
 
1664
        ut_ad(data);
 
1665
 
 
1666
        space = (data->index)->space;
 
1667
 
 
1668
        mtr_start(&mtr);
 
1669
 
 
1670
        ibuf_enter();
 
1671
        
 
1672
        /* Open a cursor to a randomly chosen leaf of the tree, at a random
 
1673
        position within the leaf */
 
1674
 
 
1675
        btr_pcur_open_at_rnd_pos(data->index, BTR_SEARCH_LEAF, &pcur, &mtr);
 
1676
 
 
1677
        if (data->size == 1
 
1678
                        && 0 == page_get_n_recs(btr_pcur_get_page(&pcur))) {
 
1679
 
 
1680
                /* This tree is empty */
 
1681
            
 
1682
                data->empty = TRUE;
 
1683
 
 
1684
                ibuf_exit();
 
1685
 
 
1686
                mtr_commit(&mtr);
 
1687
                btr_pcur_close(&pcur);
 
1688
 
 
1689
                mutex_exit(&ibuf_mutex);
 
1690
 
 
1691
                goto loop;
 
1692
        }
 
1693
        
 
1694
        mutex_exit(&ibuf_mutex);
 
1695
 
 
1696
        sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
 
1697
                                                        page_nos, &n_stored);
 
1698
 
 
1699
#ifdef UNIV_IBUF_DEBUG
 
1700
        /* printf("Ibuf contract sync %lu pages %lu volume %lu\n", sync,
 
1701
                                                n_stored, sum_sizes); */
 
1702
#endif
 
1703
        ibuf_exit();
 
1704
 
 
1705
        mtr_commit(&mtr);
 
1706
        btr_pcur_close(&pcur);
 
1707
 
 
1708
        buf_read_ibuf_merge_pages(sync, space, page_nos, n_stored);
 
1709
 
 
1710
        return(sum_sizes + 1);
 
1711
}
 
1712
 
 
1713
/*************************************************************************
 
1714
Contract insert buffer trees after insert if they are too big. */
 
1715
UNIV_INLINE
 
1716
void
 
1717
ibuf_contract_after_insert(
 
1718
/*=======================*/
 
1719
        ulint   entry_size)     /* in: size of a record which was inserted
 
1720
                                into an ibuf tree */
 
1721
{
 
1722
        ibool   sync;
 
1723
        ulint   sum_sizes;
 
1724
        ulint   size;
 
1725
 
 
1726
        mutex_enter(&ibuf_mutex);
 
1727
 
 
1728
        if (ibuf->size < ibuf->max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
 
1729
                mutex_exit(&ibuf_mutex);
 
1730
 
 
1731
                return;
 
1732
        }
 
1733
 
 
1734
        sync = FALSE;
 
1735
        
 
1736
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_ON_INSERT_SYNC) {
 
1737
 
 
1738
                sync = TRUE;
 
1739
        }
 
1740
 
 
1741
        mutex_exit(&ibuf_mutex);
 
1742
 
 
1743
        /* Contract at least entry_size many bytes */
 
1744
        sum_sizes = 0;
 
1745
        size = 1;
 
1746
 
 
1747
        while ((size > 0) && (sum_sizes < entry_size)) {
 
1748
 
 
1749
                size = ibuf_contract(sync);
 
1750
                sum_sizes += size;
 
1751
        }
 
1752
}
 
1753
 
 
1754
/*************************************************************************
 
1755
Gets an upper limit for the combined size of entries buffered in the insert
 
1756
buffer for a given page. */
 
1757
 
 
1758
ulint
 
1759
ibuf_get_volume_buffered(
 
1760
/*=====================*/
 
1761
                                /* out: upper limit for the volume of
 
1762
                                buffered inserts for the index page, in bytes;
 
1763
                                we may also return UNIV_PAGE_SIZE, if the
 
1764
                                entries for the index page span on several
 
1765
                                pages in the insert buffer */
 
1766
        btr_pcur_t*     pcur,   /* in: pcur positioned at a place in an
 
1767
                                insert buffer tree where we would insert an
 
1768
                                entry for the index page whose number is
 
1769
                                page_no, latch mode has to be BTR_MODIFY_PREV
 
1770
                                or BTR_MODIFY_TREE */
 
1771
        ulint           space,  /* in: space id */
 
1772
        ulint           page_no,/* in: page number of an index page */
 
1773
        mtr_t*          mtr)    /* in: mtr */
 
1774
{
 
1775
        ulint   volume;
 
1776
        rec_t*  rec;
 
1777
        page_t* page;
 
1778
        ulint   prev_page_no;
 
1779
        page_t* prev_page;
 
1780
        ulint   next_page_no;
 
1781
        page_t* next_page;
 
1782
        
 
1783
        ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
 
1784
                                || (pcur->latch_mode == BTR_MODIFY_TREE));
 
1785
 
 
1786
        /* Count the volume of records earlier in the alphabetical order than
 
1787
        pcur */
 
1788
 
 
1789
        volume = 0;
 
1790
        
 
1791
        rec = btr_pcur_get_rec(pcur);
 
1792
 
 
1793
        page = buf_frame_align(rec);
 
1794
 
 
1795
        if (rec == page_get_supremum_rec(page)) {
 
1796
                rec = page_rec_get_prev(rec);
 
1797
        }
 
1798
 
 
1799
        for (;;) {
 
1800
                if (rec == page_get_infimum_rec(page)) {
 
1801
 
 
1802
                        break;
 
1803
                }
 
1804
                
 
1805
                if (page_no != ibuf_rec_get_page_no(rec)) {
 
1806
 
 
1807
                        goto count_later;
 
1808
                }
 
1809
 
 
1810
                volume += ibuf_rec_get_volume(rec);
 
1811
 
 
1812
                rec = page_rec_get_prev(rec);
 
1813
        }
 
1814
 
 
1815
        /* Look at the previous page */
 
1816
        
 
1817
        prev_page_no = btr_page_get_prev(page, mtr);
 
1818
 
 
1819
        if (prev_page_no == FIL_NULL) {
 
1820
 
 
1821
                goto count_later;
 
1822
        }
 
1823
 
 
1824
        prev_page = buf_page_get(space, prev_page_no, RW_X_LATCH, mtr);
 
1825
 
 
1826
        buf_page_dbg_add_level(prev_page, SYNC_TREE_NODE);
 
1827
 
 
1828
        rec = page_get_supremum_rec(prev_page);
 
1829
        rec = page_rec_get_prev(rec);
 
1830
        
 
1831
        for (;;) {
 
1832
                if (rec == page_get_infimum_rec(prev_page)) {
 
1833
 
 
1834
                        /* We cannot go to yet a previous page, because we
 
1835
                        do not have the x-latch on it, and cannot acquire one
 
1836
                        because of the latching order: we have to give up */
 
1837
                
 
1838
                        return(UNIV_PAGE_SIZE);
 
1839
                }
 
1840
                
 
1841
                if (page_no != ibuf_rec_get_page_no(rec)) {
 
1842
 
 
1843
                        goto count_later;
 
1844
                }
 
1845
 
 
1846
                volume += ibuf_rec_get_volume(rec);
 
1847
 
 
1848
                rec = page_rec_get_prev(rec);
 
1849
        }
 
1850
                
 
1851
count_later:
 
1852
        rec = btr_pcur_get_rec(pcur);
 
1853
 
 
1854
        if (rec != page_get_supremum_rec(page)) {
 
1855
                rec = page_rec_get_next(rec);
 
1856
        }
 
1857
 
 
1858
        for (;;) {
 
1859
                if (rec == page_get_supremum_rec(page)) {
 
1860
 
 
1861
                        break;
 
1862
                }
 
1863
                
 
1864
                if (page_no != ibuf_rec_get_page_no(rec)) {
 
1865
 
 
1866
                        return(volume);
 
1867
                }
 
1868
 
 
1869
                volume += ibuf_rec_get_volume(rec);
 
1870
 
 
1871
                rec = page_rec_get_next(rec);
 
1872
        }
 
1873
 
 
1874
        /* Look at the next page */
 
1875
        
 
1876
        next_page_no = btr_page_get_next(page, mtr);
 
1877
 
 
1878
        if (next_page_no == FIL_NULL) {
 
1879
 
 
1880
                return(volume);
 
1881
        }
 
1882
 
 
1883
        next_page = buf_page_get(space, next_page_no, RW_X_LATCH, mtr);
 
1884
 
 
1885
        buf_page_dbg_add_level(next_page, SYNC_TREE_NODE);
 
1886
 
 
1887
        rec = page_get_infimum_rec(next_page);
 
1888
        rec = page_rec_get_next(rec);
 
1889
 
 
1890
        for (;;) {
 
1891
                if (rec == page_get_supremum_rec(next_page)) {
 
1892
 
 
1893
                        /* We give up */
 
1894
                
 
1895
                        return(UNIV_PAGE_SIZE);
 
1896
                }
 
1897
                
 
1898
                if (page_no != ibuf_rec_get_page_no(rec)) {
 
1899
 
 
1900
                        return(volume);
 
1901
                }
 
1902
 
 
1903
                volume += ibuf_rec_get_volume(rec);
 
1904
 
 
1905
                rec = page_rec_get_next(rec);
 
1906
        }
 
1907
}
 
1908
 
 
1909
/*************************************************************************
 
1910
Makes an index insert to the insert buffer, instead of directly to the disk
 
1911
page, if this is possible. */
 
1912
static
 
1913
ulint
 
1914
ibuf_insert_low(
 
1915
/*============*/
 
1916
                                /* out: DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */
 
1917
        ulint           mode,   /* in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */
 
1918
        dtuple_t*       entry,  /* in: index entry to insert */
 
1919
        dict_index_t*   index,  /* in: index where to insert; must not be
 
1920
                                unique or clustered */
 
1921
        ulint           space,  /* in: space id where to insert */
 
1922
        ulint           page_no,/* in: page number where to insert */
 
1923
        que_thr_t*      thr)    /* in: query thread */
 
1924
{
 
1925
        ulint           entry_size;
 
1926
        btr_pcur_t      pcur;
 
1927
        btr_cur_t*      cursor;
 
1928
        mtr_t           mtr;
 
1929
        mtr_t           bitmap_mtr;
 
1930
        dtuple_t*       ibuf_entry;
 
1931
        mem_heap_t*     heap;
 
1932
        ulint           buffered;
 
1933
        rec_t*          ins_rec;
 
1934
        ibool           old_bit_value;
 
1935
        page_t*         bitmap_page;
 
1936
        ibuf_data_t*    ibuf_data;
 
1937
        dict_index_t*   ibuf_index;
 
1938
        page_t*         root;
 
1939
        ulint           err;
 
1940
        ibool           do_merge;
 
1941
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
 
1942
        ulint           n_stored;
 
1943
        ulint           bits;
 
1944
        
 
1945
        ut_ad(!(index->type & (DICT_UNIQUE | DICT_CLUSTERED)));
 
1946
        ut_ad(dtuple_check_typed(entry));
 
1947
 
 
1948
        do_merge = FALSE;
 
1949
        
 
1950
        ibuf_data = fil_space_get_ibuf_data(space);
 
1951
 
 
1952
        ibuf_index = ibuf_data->index;
 
1953
 
 
1954
        mutex_enter(&ibuf_mutex);
 
1955
 
 
1956
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
 
1957
                /* Insert buffer is now too big, contract it but do not try
 
1958
                to insert */
 
1959
 
 
1960
                mutex_exit(&ibuf_mutex);
 
1961
 
 
1962
#ifdef UNIV_IBUF_DEBUG
 
1963
                printf("Ibuf too big\n");
 
1964
#endif          
 
1965
                /* Use synchronous contract (== TRUE) */
 
1966
                ibuf_contract(TRUE);
 
1967
 
 
1968
                return(DB_STRONG_FAIL);
 
1969
        }
 
1970
 
 
1971
        mutex_exit(&ibuf_mutex);
 
1972
 
 
1973
        if (mode == BTR_MODIFY_TREE) {
 
1974
                mutex_enter(&ibuf_pessimistic_insert_mutex);
 
1975
 
 
1976
                ibuf_enter();
 
1977
        
 
1978
                mutex_enter(&ibuf_mutex);
 
1979
 
 
1980
                while (!ibuf_data_enough_free_for_insert(ibuf_data)) {
 
1981
 
 
1982
                        mutex_exit(&ibuf_mutex);
 
1983
 
 
1984
                        ibuf_exit();
 
1985
                        
 
1986
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
 
1987
 
 
1988
                        err = ibuf_add_free_page(space, ibuf_data);
 
1989
 
 
1990
                        if (err == DB_STRONG_FAIL) {
 
1991
 
 
1992
                                return(err);
 
1993
                        }
 
1994
 
 
1995
                        mutex_enter(&ibuf_pessimistic_insert_mutex);
 
1996
 
 
1997
                        ibuf_enter();
 
1998
                        
 
1999
                        mutex_enter(&ibuf_mutex);
 
2000
                }
 
2001
        } else {
 
2002
                ibuf_enter();
 
2003
        }
 
2004
 
 
2005
        entry_size = rec_get_converted_size(entry);
 
2006
 
 
2007
        heap = mem_heap_create(512);
 
2008
 
 
2009
        /* Build the entry which contains the space id and the page number as
 
2010
        the first fields and the type information for other fields, and which
 
2011
        will be inserted to the insert buffer. */
 
2012
 
 
2013
        ibuf_entry = ibuf_entry_build(entry, page_no, heap);
 
2014
 
 
2015
        /* Open a cursor to the insert buffer tree to calculate if we can add
 
2016
        the new entry to it without exceeding the free space limit for the
 
2017
        page. */
 
2018
 
 
2019
        mtr_start(&mtr);
 
2020
 
 
2021
        btr_pcur_open(ibuf_index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
 
2022
 
 
2023
        /* Find out the volume of already buffered inserts for the same index
 
2024
        page */
 
2025
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
 
2026
 
 
2027
#ifdef UNIV_IBUF_DEBUG
 
2028
        ut_a((buffered == 0) || ibuf_count_get(space, page_no));
 
2029
#endif
 
2030
        mtr_start(&bitmap_mtr);
 
2031
 
 
2032
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &bitmap_mtr);
 
2033
 
 
2034
        /* We check if the index page is suitable for buffered entries */
 
2035
 
 
2036
        if (buf_page_peek(space, page_no)
 
2037
                        || lock_rec_expl_exist_on_page(space, page_no)) {
 
2038
 
 
2039
                err = DB_STRONG_FAIL;
 
2040
 
 
2041
                mtr_commit(&bitmap_mtr);
 
2042
 
 
2043
                goto function_exit;
 
2044
        }
 
2045
 
 
2046
        bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no,
 
2047
                                                IBUF_BITMAP_FREE, &bitmap_mtr);
 
2048
 
 
2049
        if (buffered + entry_size + page_dir_calc_reserved_space(1)
 
2050
                                > ibuf_index_page_calc_free_from_bits(bits)) {
 
2051
 
 
2052
                mtr_commit(&bitmap_mtr);
 
2053
 
 
2054
                /* It may not fit */
 
2055
                err = DB_STRONG_FAIL;
 
2056
 
 
2057
                do_merge = TRUE; 
 
2058
 
 
2059
                ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
 
2060
                                                        page_nos, &n_stored);
 
2061
                goto function_exit;
 
2062
        }
 
2063
 
 
2064
        /* Set the bitmap bit denoting that the insert buffer contains
 
2065
        buffered entries for this index page, if the bit is not set yet */
 
2066
 
 
2067
        old_bit_value = ibuf_bitmap_page_get_bits(bitmap_page, page_no,
 
2068
                                        IBUF_BITMAP_BUFFERED, &bitmap_mtr);
 
2069
        if (!old_bit_value) {
 
2070
                ibuf_bitmap_page_set_bits(bitmap_page, page_no,
 
2071
                                IBUF_BITMAP_BUFFERED, TRUE, &bitmap_mtr);
 
2072
        }
 
2073
 
 
2074
        mtr_commit(&bitmap_mtr);
 
2075
                                                
 
2076
        cursor = btr_pcur_get_btr_cur(&pcur);
 
2077
        
 
2078
        if (mode == BTR_MODIFY_PREV) {
 
2079
                err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
 
2080
                                                ibuf_entry, &ins_rec, thr,
 
2081
                                                &mtr);
 
2082
                if (err == DB_SUCCESS) {
 
2083
                        /* Update the page max trx id field */
 
2084
                        page_update_max_trx_id(buf_frame_align(ins_rec),
 
2085
                                                        thr_get_trx(thr)->id);
 
2086
                }
 
2087
        } else {
 
2088
                ut_ad(mode == BTR_MODIFY_TREE);
 
2089
 
 
2090
                /* We acquire an x-latch to the root page before the insert,
 
2091
                because a pessimistic insert releases the tree x-latch,
 
2092
                which would cause the x-latching of the root after that to
 
2093
                break the latching order. */
 
2094
                
 
2095
                root = ibuf_tree_root_get(ibuf_data, space, &mtr);
 
2096
 
 
2097
                err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
 
2098
                                                | BTR_NO_UNDO_LOG_FLAG,
 
2099
                                                cursor,
 
2100
                                                ibuf_entry, &ins_rec, thr,
 
2101
                                                &mtr);
 
2102
                if (err == DB_SUCCESS) {
 
2103
                        /* Update the page max trx id field */
 
2104
                        page_update_max_trx_id(buf_frame_align(ins_rec),
 
2105
                                                        thr_get_trx(thr)->id);
 
2106
                }
 
2107
 
 
2108
                ibuf_data_sizes_update(ibuf_data, root, &mtr);
 
2109
        }
 
2110
 
 
2111
function_exit:
 
2112
#ifdef UNIV_IBUF_DEBUG
 
2113
        if (err == DB_SUCCESS) {
 
2114
                ibuf_count_set(space, page_no,
 
2115
                                        ibuf_count_get(space, page_no) + 1);
 
2116
        }
 
2117
#endif
 
2118
        if (mode == BTR_MODIFY_TREE) {
 
2119
                ut_ad(ibuf_validate_low());
 
2120
 
 
2121
                mutex_exit(&ibuf_mutex);
 
2122
                mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2123
        }
 
2124
        
 
2125
        mtr_commit(&mtr);
 
2126
        btr_pcur_close(&pcur);
 
2127
        ibuf_exit();
 
2128
 
 
2129
        mem_heap_free(heap);
 
2130
 
 
2131
        mutex_enter(&ibuf_mutex);
 
2132
 
 
2133
        if (err == DB_SUCCESS) {
 
2134
                ibuf_data->empty = FALSE;
 
2135
                ibuf_data->n_inserts++;
 
2136
        }
 
2137
        
 
2138
        mutex_exit(&ibuf_mutex);
 
2139
 
 
2140
        if ((mode == BTR_MODIFY_TREE) && (err == DB_SUCCESS)) {
 
2141
                ibuf_contract_after_insert(entry_size);
 
2142
        }
 
2143
        
 
2144
        if (do_merge) {
 
2145
#ifdef UNIV_IBUF_DEBUG
 
2146
                ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
 
2147
#endif
 
2148
                buf_read_ibuf_merge_pages(FALSE, space, page_nos, n_stored);
 
2149
        }
 
2150
        
 
2151
        return(err);
 
2152
}
 
2153
 
 
2154
/*************************************************************************
 
2155
Makes an index insert to the insert buffer, instead of directly to the disk
 
2156
page, if this is possible. Does not do insert if the index is clustered
 
2157
or unique. */
 
2158
 
 
2159
ibool
 
2160
ibuf_insert(
 
2161
/*========*/
 
2162
                                /* out: TRUE if success */
 
2163
        dtuple_t*       entry,  /* in: index entry to insert */
 
2164
        dict_index_t*   index,  /* in: index where to insert */
 
2165
        ulint           space,  /* in: space id where to insert */
 
2166
        ulint           page_no,/* in: page number where to insert */
 
2167
        que_thr_t*      thr)    /* in: query thread */
 
2168
{
 
2169
        ulint   err;
 
2170
 
 
2171
        ut_ad(dtuple_check_typed(entry));
 
2172
 
 
2173
        if (index->type & DICT_CLUSTERED || index->type & DICT_UNIQUE) {
 
2174
 
 
2175
                return(FALSE);
 
2176
        }
 
2177
        
 
2178
        if (rec_get_converted_size(entry)
 
2179
                                >= page_get_free_space_of_empty() / 2) {
 
2180
                return(FALSE);
 
2181
        }
 
2182
        
 
2183
        err = ibuf_insert_low(BTR_MODIFY_PREV, entry, index, space, page_no,
 
2184
                                                                        thr);
 
2185
        if (err == DB_FAIL) {
 
2186
                err = ibuf_insert_low(BTR_MODIFY_TREE, entry, index, space,
 
2187
                                                        page_no, thr);
 
2188
        }
 
2189
        
 
2190
        if (err == DB_SUCCESS) {
 
2191
#ifdef UNIV_IBUF_DEBUG
 
2192
                /* printf("Ibuf insert for page no %lu of index %s\n", page_no,
 
2193
                                                        index->name); */
 
2194
#endif
 
2195
                return(TRUE);
 
2196
 
 
2197
        } else {
 
2198
                ut_a(err == DB_STRONG_FAIL);
 
2199
 
 
2200
                return(FALSE);
 
2201
        }
 
2202
}
 
2203
        
 
2204
/************************************************************************
 
2205
During merge, inserts to an index page a secondary index entry extracted
 
2206
from the insert buffer. */
 
2207
static
 
2208
void
 
2209
ibuf_insert_to_index_page(
 
2210
/*======================*/
 
2211
        dtuple_t*       entry,  /* in: buffered entry to insert */
 
2212
        page_t*         page,   /* in: index page where the buffered entry
 
2213
                                should be placed */
 
2214
        mtr_t*          mtr)    /* in: mtr */
 
2215
{
 
2216
        page_cur_t      page_cur;
 
2217
        ulint           low_match;
 
2218
        rec_t*          rec;
 
2219
        page_t*         bitmap_page;
 
2220
        ulint           old_bits;
 
2221
 
 
2222
        ut_ad(ibuf_inside());
 
2223
        ut_ad(dtuple_check_typed(entry));
 
2224
 
 
2225
        low_match = page_cur_search(page, entry, PAGE_CUR_LE, &page_cur);
 
2226
        
 
2227
        if (low_match == dtuple_get_n_fields(entry)) {
 
2228
                rec = page_cur_get_rec(&page_cur);
 
2229
 
 
2230
                ut_ad(rec_get_deleted_flag(rec));
 
2231
                
 
2232
                btr_cur_del_unmark_for_ibuf(rec, mtr);
 
2233
        } else {
 
2234
                rec = page_cur_tuple_insert(&page_cur, entry, mtr);
 
2235
                
 
2236
                if (rec == NULL) {
 
2237
                        /* If the record did not fit, reorganize */
 
2238
 
 
2239
                        btr_page_reorganize(page, mtr);
 
2240
 
 
2241
                        page_cur_search(page, entry, PAGE_CUR_LE, &page_cur);
 
2242
 
 
2243
                        /* This time the record must fit */
 
2244
                        if (!page_cur_tuple_insert(&page_cur, entry, mtr)) {
 
2245
                                printf(
 
2246
                        "Ibuf insert fails; page free %lu, dtuple size %lu\n",
 
2247
                                page_get_max_insert_size(page, 1),
 
2248
                                rec_get_converted_size(entry));
 
2249
 
 
2250
                                bitmap_page = ibuf_bitmap_get_map_page(
 
2251
                                                buf_frame_get_space_id(page),
 
2252
                                                buf_frame_get_page_no(page),
 
2253
                                                mtr);
 
2254
 
 
2255
                                old_bits = ibuf_bitmap_page_get_bits(
 
2256
                                                bitmap_page,
 
2257
                                                buf_frame_get_page_no(page),
 
2258
                                                IBUF_BITMAP_FREE, mtr);
 
2259
 
 
2260
                                printf("Bitmap bits %lu\n", old_bits);
 
2261
                                                
 
2262
                                ut_error;
 
2263
                        }       
 
2264
                }
 
2265
        }
 
2266
}
 
2267
        
 
2268
/*************************************************************************
 
2269
Deletes from ibuf the record on which pcur is positioned. If we have to
 
2270
resort to a pessimistic delete, this function commits mtr and closes
 
2271
the cursor. */
 
2272
static
 
2273
ibool
 
2274
ibuf_delete_rec(
 
2275
/*============*/
 
2276
                                /* out: TRUE if mtr was committed and pcur
 
2277
                                closed in this operation */
 
2278
        ulint           space,  /* in: space id */
 
2279
        ulint           page_no,/* in: index page number where the record
 
2280
                                should belong */
 
2281
        btr_pcur_t*     pcur,   /* in: pcur positioned on the record to
 
2282
                                delete, having latch mode BTR_MODIFY_LEAF */
 
2283
        mtr_t*          mtr)    /* in: mtr */
 
2284
{
 
2285
        ibool           success;
 
2286
        ibuf_data_t*    ibuf_data;
 
2287
        page_t*         root;
 
2288
        ulint           err;
 
2289
 
 
2290
        ut_ad(ibuf_inside());
 
2291
 
 
2292
        success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);   
 
2293
 
 
2294
        if (success) {
 
2295
#ifdef UNIV_IBUF_DEBUG
 
2296
                ibuf_count_set(space, page_no,
 
2297
                                        ibuf_count_get(space, page_no) - 1);
 
2298
#endif
 
2299
                return(FALSE);
 
2300
        }
 
2301
        
 
2302
        /* We have to resort to a pessimistic delete from ibuf */               
 
2303
        btr_pcur_store_position(pcur, mtr);
 
2304
 
 
2305
        btr_pcur_commit_specify_mtr(pcur, mtr);
 
2306
 
 
2307
        ibuf_data = fil_space_get_ibuf_data(space);
 
2308
 
 
2309
        mutex_enter(&ibuf_mutex);
 
2310
 
 
2311
        mtr_start(mtr);
 
2312
        
 
2313
        ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
 
2314
 
 
2315
        root = ibuf_tree_root_get(ibuf_data, space, mtr);
 
2316
 
 
2317
        btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur),
 
2318
                                                                        mtr);
 
2319
        ut_a(err == DB_SUCCESS);
 
2320
 
 
2321
#ifdef UNIV_IBUF_DEBUG
 
2322
        ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
 
2323
#endif
 
2324
        ibuf_data_sizes_update(ibuf_data, root, mtr);
 
2325
 
 
2326
        ut_ad(ibuf_validate_low());
 
2327
 
 
2328
        btr_pcur_commit_specify_mtr(pcur, mtr);
 
2329
 
 
2330
        btr_pcur_close(pcur);
 
2331
 
 
2332
        mutex_exit(&ibuf_mutex);
 
2333
 
 
2334
        return(TRUE);
 
2335
}
 
2336
 
 
2337
/*************************************************************************
 
2338
When an index page is read from a disk to the buffer pool, this function
 
2339
inserts to the page the possible index entries buffered in the insert buffer.
 
2340
The entries are deleted from the insert buffer. If the page is not read, but
 
2341
created in the buffer pool, this function deletes its buffered entries from
 
2342
the insert buffer; there can exist entries for such a page if the page
 
2343
belonged to an index which subsequently was dropped. */
 
2344
 
 
2345
void
 
2346
ibuf_merge_or_delete_for_page(
 
2347
/*==========================*/
 
2348
        page_t* page,   /* in: if page has been read from disk, pointer to
 
2349
                        the page x-latched, else NULL */
 
2350
        ulint   space,  /* in: space id of the index page */
 
2351
        ulint   page_no)/* in: page number of the index page */
 
2352
{
 
2353
        mem_heap_t*     heap;
 
2354
        btr_pcur_t      pcur;
 
2355
        dtuple_t*       entry;
 
2356
        dtuple_t*       search_tuple;
 
2357
        rec_t*          ibuf_rec;
 
2358
        ibool           closed;
 
2359
        buf_block_t*    block;
 
2360
        page_t*         bitmap_page;
 
2361
        ibuf_data_t*    ibuf_data;
 
2362
        ibool           success;
 
2363
        ulint           n_inserts;
 
2364
        ulint           volume;
 
2365
        ulint           old_bits;
 
2366
        ulint           new_bits;
 
2367
        dulint          max_trx_id;
 
2368
        mtr_t           mtr;
 
2369
 
 
2370
        /* TODO: get MySQL type info to use in ibuf_insert_to_index_page */
 
2371
 
 
2372
#ifdef UNIV_LOG_DEBUG
 
2373
        if (space % 2 != 0) {
 
2374
 
 
2375
                printf("No ibuf operation in a replicate space\n");
 
2376
 
 
2377
                return;
 
2378
        }
 
2379
#endif  
 
2380
        if (ibuf_fixed_addr_page(page_no) || fsp_descr_page(page_no)
 
2381
                                        || trx_sys_hdr_page(space, page_no)) {
 
2382
                return;
 
2383
        }
 
2384
 
 
2385
        mtr_start(&mtr);
 
2386
 
 
2387
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
 
2388
 
 
2389
        if (!ibuf_bitmap_page_get_bits(bitmap_page, page_no,
 
2390
                                                IBUF_BITMAP_BUFFERED, &mtr)) {
 
2391
                /* No inserts buffered for this page */
 
2392
 
 
2393
                mtr_commit(&mtr);
 
2394
 
 
2395
                return;
 
2396
        }
 
2397
 
 
2398
        mtr_commit(&mtr);
 
2399
 
 
2400
        ibuf_data = fil_space_get_ibuf_data(space);
 
2401
 
 
2402
        ibuf_enter();
 
2403
 
 
2404
        heap = mem_heap_create(512);
 
2405
 
 
2406
        search_tuple = ibuf_search_tuple_build(page_no, heap);
 
2407
                
 
2408
        if (page) {
 
2409
                /* Move the ownership of the x-latch on the page to this OS
 
2410
                thread, so that we can acquire a second x-latch on it. This
 
2411
                is needed for the insert operations to the index page to pass
 
2412
                the debug checks. */
 
2413
 
 
2414
                block = buf_block_align(page);
 
2415
                rw_lock_x_lock_move_ownership(&(block->lock));
 
2416
        }
 
2417
 
 
2418
        n_inserts = 0;
 
2419
        volume = 0;
 
2420
loop:
 
2421
        mtr_start(&mtr);
 
2422
 
 
2423
        if (page) {
 
2424
                success = buf_page_get_known_nowait(RW_X_LATCH, page,
 
2425
                                        BUF_KEEP_OLD,
 
2426
#ifdef UNIV_SYNC_DEBUG
 
2427
                                        __FILE__, __LINE__,
 
2428
#endif
 
2429
                                        &mtr);
 
2430
 
 
2431
                ut_a(success);
 
2432
 
 
2433
                buf_page_dbg_add_level(page, SYNC_TREE_NODE);
 
2434
        }
 
2435
        
 
2436
        /* Position pcur in the insert buffer at the first entry for this
 
2437
        index page */
 
2438
        btr_pcur_open_on_user_rec(ibuf_data->index, search_tuple, PAGE_CUR_GE,
 
2439
                                                BTR_MODIFY_LEAF, &pcur, &mtr);
 
2440
 
 
2441
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
 
2442
                ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
 
2443
 
 
2444
                goto reset_bit;
 
2445
        }
 
2446
 
 
2447
        for (;;) {
 
2448
                ut_ad(btr_pcur_is_on_user_rec(&pcur, &mtr));
 
2449
 
 
2450
                ibuf_rec = btr_pcur_get_rec(&pcur);
 
2451
        
 
2452
                /* Check if the entry is for this index page */
 
2453
                if (ibuf_rec_get_page_no(ibuf_rec) != page_no) {
 
2454
 
 
2455
                        if (page) {
 
2456
                                page_header_reset_last_insert(page, &mtr);
 
2457
                        }
 
2458
 
 
2459
                        goto reset_bit;
 
2460
                }
 
2461
        
 
2462
                if (page) {
 
2463
                        /* Now we have at pcur a record which should be
 
2464
                        inserted to the index page; NOTE that the call below
 
2465
                        copies pointers to fields in ibuf_rec, and we must
 
2466
                        keep the latch to the ibuf_rec page until the
 
2467
                        insertion is finished! */
 
2468
 
 
2469
                        max_trx_id = page_get_max_trx_id(
 
2470
                                                buf_frame_align(ibuf_rec));
 
2471
        
 
2472
                        page_update_max_trx_id(page, max_trx_id);
 
2473
                        
 
2474
                        entry = ibuf_build_entry_from_ibuf_rec(ibuf_rec, heap);
 
2475
#ifdef UNIV_IBUF_DEBUG
 
2476
                        volume += rec_get_converted_size(entry)
 
2477
                                        + page_dir_calc_reserved_space(1);
 
2478
            
 
2479
                        ut_a(volume <= 4 * UNIV_PAGE_SIZE
 
2480
                                        / IBUF_PAGE_SIZE_PER_FREE_SPACE);
 
2481
#endif
 
2482
                        ibuf_insert_to_index_page(entry, page, &mtr);
 
2483
 
 
2484
                        n_inserts++;
 
2485
                }
 
2486
                
 
2487
                /* Delete the record from ibuf */
 
2488
                closed = ibuf_delete_rec(space, page_no, &pcur, &mtr);
 
2489
 
 
2490
                if (closed) {
 
2491
                        /* Deletion was pessimistic and mtr was committed:
 
2492
                        we start from the beginning again */
 
2493
 
 
2494
                        goto loop;
 
2495
                }
 
2496
 
 
2497
                if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) {
 
2498
                        mtr_commit(&mtr);
 
2499
 
 
2500
                        goto loop;
 
2501
                }
 
2502
        }
 
2503
 
 
2504
reset_bit:
 
2505
 
 
2506
#ifdef UNIV_IBUF_DEBUG
 
2507
        if (ibuf_count_get(space, page_no) > 0) {
 
2508
 
 
2509
                /* btr_print_tree(ibuf_data->index->tree, 100);
 
2510
                ibuf_print(); */
 
2511
        }
 
2512
#endif
 
2513
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, &mtr);
 
2514
 
 
2515
        ibuf_bitmap_page_set_bits(bitmap_page, page_no,
 
2516
                                        IBUF_BITMAP_BUFFERED, FALSE, &mtr);
 
2517
        if (page) {
 
2518
                old_bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no,
 
2519
                                                IBUF_BITMAP_FREE, &mtr);
 
2520
                new_bits = ibuf_index_page_calc_free(page);
 
2521
 
 
2522
#ifdef UNIV_IBUF_DEBUG
 
2523
                /* printf("Old bits %lu new bits %lu max size %lu\n", old_bits,
 
2524
                        new_bits,
 
2525
                        page_get_max_insert_size_after_reorganize(page, 1)); */
 
2526
#endif
 
2527
                if (old_bits != new_bits) {
 
2528
                        
 
2529
                        ibuf_bitmap_page_set_bits(bitmap_page, page_no,
 
2530
                                                        IBUF_BITMAP_FREE,
 
2531
                                                        new_bits, &mtr);
 
2532
                }
 
2533
        }
 
2534
 
 
2535
        ibuf_data->n_merges++;  
 
2536
        ibuf_data->n_merged_recs += n_inserts;
 
2537
 
 
2538
#ifdef UNIV_IBUF_DEBUG
 
2539
        /* printf("Ibuf merge %lu records volume %lu to page no %lu\n",
 
2540
                                        n_inserts, volume, page_no); */
 
2541
#endif
 
2542
        mtr_commit(&mtr);
 
2543
        btr_pcur_close(&pcur);
 
2544
        
 
2545
        mem_heap_free(heap);
 
2546
 
 
2547
        ibuf_exit();
 
2548
#ifdef UNIV_IBUF_DEBUG
 
2549
        ut_a(ibuf_count_get(space, page_no) == 0);
 
2550
#endif
 
2551
}
 
2552
 
 
2553
/**********************************************************************
 
2554
Validates the ibuf data structures when the caller owns ibuf_mutex. */
 
2555
static
 
2556
ibool
 
2557
ibuf_validate_low(void)
 
2558
/*===================*/
 
2559
                        /* out: TRUE if ok */
 
2560
{
 
2561
        ibuf_data_t*    data;
 
2562
        ulint           sum_sizes;
 
2563
 
 
2564
        ut_ad(mutex_own(&ibuf_mutex));
 
2565
 
 
2566
        sum_sizes = 0;
 
2567
        
 
2568
        data = UT_LIST_GET_FIRST(ibuf->data_list);
 
2569
 
 
2570
        while (data) {
 
2571
                sum_sizes += data->size;
 
2572
        
 
2573
                data = UT_LIST_GET_NEXT(data_list, data);
 
2574
        }
 
2575
 
 
2576
        ut_a(sum_sizes == ibuf->size);
 
2577
 
 
2578
        return(TRUE);
 
2579
}
 
2580
 
 
2581
/**********************************************************************
 
2582
Prints info of ibuf. */
 
2583
 
 
2584
void
 
2585
ibuf_print(void)
 
2586
/*============*/
 
2587
{
 
2588
        ibuf_data_t*    data;
 
2589
#ifdef UNIV_IBUF_DEBUG
 
2590
        ulint           i;
 
2591
#endif
 
2592
        mutex_enter(&ibuf_mutex);
 
2593
 
 
2594
        printf("Ibuf size %lu max size %lu\n", ibuf->size, ibuf->max_size);
 
2595
 
 
2596
        data = UT_LIST_GET_FIRST(ibuf->data_list);
 
2597
 
 
2598
        while (data) {
 
2599
                printf(
 
2600
        "Ibuf for space %lu: size %lu, free list len %lu, seg size %lu,\n",
 
2601
                data->space, data->size, data->free_list_len, data->seg_size);
 
2602
                printf("%lu inserts, %lu merged recs, %lu merges\n",
 
2603
                        data->n_inserts, data->n_merged_recs, data->n_merges);
 
2604
#ifdef UNIV_IBUF_DEBUG
 
2605
                for (i = 0; i < IBUF_COUNT_N_PAGES; i++) {
 
2606
                        if (ibuf_count_get(data->space, i) > 0) {
 
2607
 
 
2608
                                printf("Ibuf count for page %lu is %lu\n",
 
2609
                                        i, ibuf_count_get(data->space, i));
 
2610
                        }
 
2611
                }
 
2612
#endif
 
2613
                data = UT_LIST_GET_NEXT(data_list, data);
 
2614
        }
 
2615
 
 
2616
        mutex_exit(&ibuf_mutex);
 
2617
}