~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: lbieber
  • Date: 2010-10-06 16:34:16 UTC
  • mfrom: (1816.1.3 build)
  • Revision ID: lbieber@orisndriz08-20101006163416-ea0sl59qgpglk21y
Merge Monty - Change the requirement from either libinnodb to libhaildb. Also, tied it to version 2.2
Merge Andrew - fix bug 650935: remove --compress from all clients
Merge Andrew - fix bug 653471: Add -A to drizzle client
Merge Travis - 621861 = To change C structs to C++ classes in Drizzle

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
4
4
 
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
49
49
#include "btr0cur.h"
50
50
#include "btr0pcur.h"
51
51
#include "btr0btr.h"
52
 
#include "row0upd.h"
53
52
#include "sync0sync.h"
54
53
#include "dict0boot.h"
55
54
#include "fut0lst.h"
56
55
#include "lock0lock.h"
57
56
#include "log0recv.h"
58
57
#include "que0que.h"
59
 
#include "srv0start.h" /* srv_shutdown_state */
60
58
 
61
59
/*      STRUCTURE OF AN INSERT BUFFER RECORD
62
60
 
91
89
looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
92
90
 
93
91
The high-order bit of the character set field in the type info is the
94
 
"nullable" flag for the field.
95
 
 
96
 
In versions >= 5.5:
97
 
 
98
 
The optional marker byte at the start of the fourth field is replaced by
99
 
mandatory 3 fields, totaling 4 bytes:
100
 
 
101
 
 1. 2 bytes: Counter field, used to sort records within a (space id, page
102
 
    no) in the order they were added. This is needed so that for example the
103
 
    sequence of operations "INSERT x, DEL MARK x, INSERT x" is handled
104
 
    correctly.
105
 
 
106
 
 2. 1 byte: Operation type (see ibuf_op_t).
107
 
 
108
 
 3. 1 byte: Flags. Currently only one flag exists, IBUF_REC_COMPACT.
109
 
 
110
 
To ensure older records, which do not have counters to enforce correct
111
 
sorting, are merged before any new records, ibuf_insert checks if we're
112
 
trying to insert to a position that contains old-style records, and if so,
113
 
refuses the insert. Thus, ibuf pages are gradually converted to the new
114
 
format as their corresponding buffer pool pages are read into memory.
115
 
*/
 
92
"nullable" flag for the field. */
116
93
 
117
94
 
118
95
/*      PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
191
168
#define IBUF_TABLE_NAME         "SYS_IBUF_TABLE"
192
169
 
193
170
/** Operations that can currently be buffered. */
194
 
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_ALL;
195
 
 
196
 
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
197
 
/** Flag to control insert buffer debugging. */
198
 
UNIV_INTERN uint        ibuf_debug;
199
 
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
 
171
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_INSERT;
200
172
 
201
173
/** The insert buffer control structure */
202
174
UNIV_INTERN ibuf_t*     ibuf                    = NULL;
204
176
/** Counter for ibuf_should_try() */
205
177
UNIV_INTERN ulint       ibuf_flush_count        = 0;
206
178
 
207
 
#ifdef UNIV_PFS_MUTEX
208
 
UNIV_INTERN mysql_pfs_key_t     ibuf_pessimistic_insert_mutex_key;
209
 
UNIV_INTERN mysql_pfs_key_t     ibuf_mutex_key;
210
 
UNIV_INTERN mysql_pfs_key_t     ibuf_bitmap_mutex_key;
211
 
#endif /* UNIV_PFS_MUTEX */
212
 
 
213
179
#ifdef UNIV_IBUF_COUNT_DEBUG
214
180
/** Number of tablespaces in the ibuf_counts array */
215
181
#define IBUF_COUNT_N_SPACES     4
255
221
                                        list of the ibuf */
256
222
/* @} */
257
223
 
258
 
/* Various constants for checking the type of an ibuf record and extracting
259
 
data from it. For details, see the description of the record format at the
260
 
top of this file. */
261
 
 
262
 
/** @name Format of the fourth column of an insert buffer record
263
 
The fourth column in the MySQL 5.5 format contains an operation
264
 
type, counter, and some flags. */
265
 
/* @{ */
266
 
#define IBUF_REC_INFO_SIZE      4       /*!< Combined size of info fields at
267
 
                                        the beginning of the fourth field */
268
 
#if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
269
 
# error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
270
 
#endif
271
 
 
272
 
/* Offsets for the fields at the beginning of the fourth field */
273
 
#define IBUF_REC_OFFSET_COUNTER 0       /*!< Operation counter */
274
 
#define IBUF_REC_OFFSET_TYPE    2       /*!< Type of operation */
275
 
#define IBUF_REC_OFFSET_FLAGS   3       /*!< Additional flags */
276
 
 
277
 
/* Record flag masks */
278
 
#define IBUF_REC_COMPACT        0x1     /*!< Set in
279
 
                                        IBUF_REC_OFFSET_FLAGS if the
280
 
                                        user index is in COMPACT
281
 
                                        format or later */
282
 
 
283
 
 
284
224
/** The mutex used to block pessimistic inserts to ibuf trees */
285
225
static mutex_t  ibuf_pessimistic_insert_mutex;
286
226
 
402
342
        mtr_t*          mtr)    /*!< in: mtr */
403
343
{
404
344
        buf_block_t*    block;
405
 
        page_t*         root;
406
345
 
407
346
        ut_ad(ibuf_inside());
408
 
        ut_ad(mutex_own(&ibuf_mutex));
409
347
 
410
348
        mtr_x_lock(dict_index_get_lock(ibuf->index), mtr);
411
349
 
414
352
 
415
353
        buf_block_dbg_add_level(block, SYNC_TREE_NODE);
416
354
 
417
 
        root = buf_block_get_frame(block);
418
 
 
419
 
        ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
420
 
        ut_ad(page_get_page_no(root) == FSP_IBUF_TREE_ROOT_PAGE_NO);
421
 
        ut_ad(ibuf->empty == (page_get_n_recs(root) == 0));
422
 
 
423
 
        return(root);
 
355
        return(buf_block_get_frame(block));
424
356
}
425
357
 
426
358
#ifdef UNIV_IBUF_COUNT_DEBUG
458
390
#endif
459
391
 
460
392
/******************************************************************//**
461
 
Closes insert buffer and frees the data structures. */
462
 
UNIV_INTERN
463
 
void
464
 
ibuf_close(void)
465
 
/*============*/
466
 
{
467
 
        mutex_free(&ibuf_pessimistic_insert_mutex);
468
 
        memset(&ibuf_pessimistic_insert_mutex,
469
 
               0x0, sizeof(ibuf_pessimistic_insert_mutex));
470
 
 
471
 
        mutex_free(&ibuf_mutex);
472
 
        memset(&ibuf_mutex, 0x0, sizeof(ibuf_mutex));
473
 
 
474
 
        mutex_free(&ibuf_bitmap_mutex);
475
 
        memset(&ibuf_bitmap_mutex, 0x0, sizeof(ibuf_mutex));
476
 
 
477
 
        mem_free(ibuf);
478
 
        ibuf = NULL;
479
 
}
480
 
 
481
 
/******************************************************************//**
482
393
Updates the size information of the ibuf, assuming the segment size has not
483
394
changed. */
484
395
static
497
408
 
498
409
        /* the '1 +' is the ibuf header page */
499
410
        ibuf->size = ibuf->seg_size - (1 + ibuf->free_list_len);
 
411
 
 
412
        ibuf->empty = page_get_n_recs(root) == 0;
500
413
}
501
414
 
502
415
/******************************************************************//**
516
429
        page_t*         header_page;
517
430
        ulint           error;
518
431
 
519
 
        ibuf = static_cast<ibuf_t *>(mem_alloc(sizeof(ibuf_t)));
 
432
        ibuf = mem_alloc(sizeof(ibuf_t));
520
433
 
521
434
        memset(ibuf, 0, sizeof(*ibuf));
522
435
 
527
440
        ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE
528
441
                / IBUF_POOL_SIZE_PER_MAX_SIZE;
529
442
 
530
 
        mutex_create(ibuf_pessimistic_insert_mutex_key,
531
 
                     &ibuf_pessimistic_insert_mutex,
 
443
        mutex_create(&ibuf_pessimistic_insert_mutex,
532
444
                     SYNC_IBUF_PESS_INSERT_MUTEX);
533
445
 
534
 
        mutex_create(ibuf_mutex_key,
535
 
                     &ibuf_mutex, SYNC_IBUF_MUTEX);
 
446
        mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX);
536
447
 
537
 
        mutex_create(ibuf_bitmap_mutex_key,
538
 
                     &ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
 
448
        mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
539
449
 
540
450
        mtr_start(&mtr);
541
451
 
567
477
        ibuf_size_update(root, &mtr);
568
478
        mutex_exit(&ibuf_mutex);
569
479
 
570
 
        ibuf->empty = (page_get_n_recs(root) == 0);
571
480
        mtr_commit(&mtr);
572
481
 
573
482
        ibuf_exit();
579
488
 
580
489
        dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
581
490
 
582
 
        table->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
 
491
        table->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
583
492
 
584
493
        dict_table_add_to_cache(table, heap);
585
494
        mem_heap_free(heap);
590
499
 
591
500
        dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
592
501
 
593
 
        index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
 
502
        index->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
594
503
 
595
504
        error = dict_index_add_to_cache(table, index,
596
505
                                        FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
643
552
ibuf_parse_bitmap_init(
644
553
/*===================*/
645
554
        byte*           ptr,    /*!< in: buffer */
646
 
        byte*           /*end_ptr __attribute__((unused))*/, /*!< in: buffer end */
 
555
        byte*           end_ptr __attribute__((unused)), /*!< in: buffer end */
647
556
        buf_block_t*    block,  /*!< in: block or NULL */
648
557
        mtr_t*          mtr)    /*!< in: mtr or NULL */
649
558
{
669
578
                                0 for uncompressed pages */
670
579
        ulint           bit,    /*!< in: IBUF_BITMAP_FREE,
671
580
                                IBUF_BITMAP_BUFFERED, ... */
672
 
        mtr_t*          /*mtr __attribute__((unused))*/)
 
581
        mtr_t*          mtr __attribute__((unused)))
673
582
                                /*!< in: mtr containing an
674
583
                                x-latch to the bitmap page */
675
584
{
800
709
is x-latched */
801
710
static
802
711
page_t*
803
 
ibuf_bitmap_get_map_page_func(
804
 
/*==========================*/
805
 
        ulint           space,  /*!< in: space id of the file page */
806
 
        ulint           page_no,/*!< in: page number of the file page */
807
 
        ulint           zip_size,/*!< in: compressed page size in bytes;
808
 
                                0 for uncompressed pages */
809
 
        const char*     file,   /*!< in: file name */
810
 
        ulint           line,   /*!< in: line where called */
811
 
        mtr_t*          mtr)    /*!< in: mtr */
 
712
ibuf_bitmap_get_map_page(
 
713
/*=====================*/
 
714
        ulint   space,  /*!< in: space id of the file page */
 
715
        ulint   page_no,/*!< in: page number of the file page */
 
716
        ulint   zip_size,/*!< in: compressed page size in bytes;
 
717
                        0 for uncompressed pages */
 
718
        mtr_t*  mtr)    /*!< in: mtr */
812
719
{
813
720
        buf_block_t*    block;
814
721
 
815
 
        block = buf_page_get_gen(space, zip_size,
816
 
                                 ibuf_bitmap_page_no_calc(zip_size, page_no),
817
 
                                 RW_X_LATCH, NULL, BUF_GET,
818
 
                                 file, line, mtr);
 
722
        block = buf_page_get(space, zip_size,
 
723
                             ibuf_bitmap_page_no_calc(zip_size, page_no),
 
724
                             RW_X_LATCH, mtr);
819
725
        buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
820
726
 
821
727
        return(buf_block_get_frame(block));
822
728
}
823
729
 
824
 
/********************************************************************//**
825
 
Gets the ibuf bitmap page where the bits describing a given file page are
826
 
stored.
827
 
@return bitmap page where the file page is mapped, that is, the bitmap
828
 
page containing the descriptor bits for the file page; the bitmap page
829
 
is x-latched
830
 
@param space    in: space id of the file page
831
 
@param page_no  in: page number of the file page
832
 
@param zip_size in: compressed page size in bytes; 0 for uncompressed pages
833
 
@param mtr      in: mini-transaction */
834
 
#define ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr)         \
835
 
        ibuf_bitmap_get_map_page_func(space, page_no, zip_size,         \
836
 
                                      __FILE__, __LINE__, mtr)
837
 
 
838
730
/************************************************************************//**
839
731
Sets the free bits of the page in the ibuf bitmap. This is done in a separate
840
732
mini-transaction, hence this operation does not restrict further work to only
1220
1112
        return(0);
1221
1113
}
1222
1114
 
1223
 
/****************************************************************//**
1224
 
Get various information about an ibuf record in >= 4.1.x format. */
1225
 
static
1226
 
void
1227
 
ibuf_rec_get_info(
1228
 
/*==============*/
1229
 
        const rec_t*    rec,            /*!< in: ibuf record */
1230
 
        ibuf_op_t*      op,             /*!< out: operation type, or NULL */
1231
 
        ibool*          comp,           /*!< out: compact flag, or NULL */
1232
 
        ulint*          info_len,       /*!< out: length of info fields at the
1233
 
                                        start of the fourth field, or
1234
 
                                        NULL */
1235
 
        ulint*          counter)        /*!< in: counter value, or NULL */
1236
 
{
1237
 
        const byte*     types;
1238
 
        ulint           fields;
1239
 
        ulint           len;
1240
 
 
1241
 
        /* Local variables to shadow arguments. */
1242
 
        ibuf_op_t       op_local;
1243
 
        ibool           comp_local;
1244
 
        ulint           info_len_local;
1245
 
        ulint           counter_local;
1246
 
 
1247
 
        ut_ad(ibuf_inside());
1248
 
        fields = rec_get_n_fields_old(rec);
1249
 
        ut_a(fields > 4);
1250
 
 
1251
 
        types = rec_get_nth_field_old(rec, 3, &len);
1252
 
 
1253
 
        info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1254
 
 
1255
 
        switch (info_len_local) {
1256
 
        case 0:
1257
 
        case 1:
1258
 
                op_local = IBUF_OP_INSERT;
1259
 
                comp_local = info_len_local;
1260
 
                ut_ad(!counter);
1261
 
                counter_local = ULINT_UNDEFINED;
1262
 
                break;
1263
 
 
1264
 
        case IBUF_REC_INFO_SIZE:
1265
 
                op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE];
1266
 
                comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT;
1267
 
                counter_local = mach_read_from_2(
1268
 
                        types + IBUF_REC_OFFSET_COUNTER);
1269
 
                break;
1270
 
 
1271
 
        default:
1272
 
                ut_error;
1273
 
        }
1274
 
 
1275
 
        ut_a(op_local < IBUF_OP_COUNT);
1276
 
        ut_a((len - info_len_local) ==
1277
 
             (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1278
 
 
1279
 
        if (op) {
1280
 
                *op = op_local;
1281
 
        }
1282
 
 
1283
 
        if (comp) {
1284
 
                *comp = comp_local;
1285
 
        }
1286
 
 
1287
 
        if (info_len) {
1288
 
                *info_len = info_len_local;
1289
 
        }
1290
 
 
1291
 
        if (counter) {
1292
 
                *counter = counter_local;
1293
 
        }
1294
 
}
1295
 
 
1296
 
/****************************************************************//**
1297
 
Returns the operation type field of an ibuf record.
1298
 
@return operation type */
1299
 
static
1300
 
ibuf_op_t
1301
 
ibuf_rec_get_op_type(
1302
 
/*=================*/
1303
 
        const rec_t*    rec)    /*!< in: ibuf record */
1304
 
{
1305
 
        ulint           len;
1306
 
 
1307
 
        ut_ad(ibuf_inside());
1308
 
        ut_ad(rec_get_n_fields_old(rec) > 2);
1309
 
 
1310
 
        (void) rec_get_nth_field_old(rec, 1, &len);
1311
 
 
1312
 
        if (len > 1) {
1313
 
                /* This is a < 4.1.x format record */
1314
 
 
1315
 
                return(IBUF_OP_INSERT);
1316
 
        } else {
1317
 
                ibuf_op_t       op;
1318
 
 
1319
 
                ibuf_rec_get_info(rec, &op, NULL, NULL, NULL);
1320
 
 
1321
 
                return(op);
1322
 
        }
1323
 
}
1324
 
 
1325
 
/****************************************************************//**
1326
 
Read the first two bytes from a record's fourth field (counter field in new
1327
 
records; something else in older records).
1328
 
@return "counter" field, or ULINT_UNDEFINED if for some reason it
1329
 
can't be read */
1330
 
UNIV_INTERN
1331
 
ulint
1332
 
ibuf_rec_get_counter(
1333
 
/*=================*/
1334
 
        const rec_t*    rec)    /*!< in: ibuf record */
1335
 
{
1336
 
        const byte*     ptr;
1337
 
        ulint           len;
1338
 
 
1339
 
        if (rec_get_n_fields_old(rec) < 4) {
1340
 
 
1341
 
                return(ULINT_UNDEFINED);
1342
 
        }
1343
 
 
1344
 
        ptr = rec_get_nth_field_old(rec, 3, &len);
1345
 
 
1346
 
        if (len >= 2) {
1347
 
 
1348
 
                return(mach_read_from_2(ptr));
1349
 
        } else {
1350
 
 
1351
 
                return(ULINT_UNDEFINED);
1352
 
        }
1353
 
}
1354
 
 
1355
 
/****************************************************************//**
1356
 
Add accumulated operation counts to a permanent array. Both arrays must be
1357
 
of size IBUF_OP_COUNT. */
1358
 
static
1359
 
void
1360
 
ibuf_add_ops(
1361
 
/*=========*/
1362
 
        ulint*          arr,    /*!< in/out: array to modify */
1363
 
        const ulint*    ops)    /*!< in: operation counts */
1364
 
 
1365
 
{
1366
 
        ulint   i;
1367
 
 
1368
 
#ifndef HAVE_ATOMIC_BUILTINS
1369
 
        ut_ad(mutex_own(&ibuf_mutex));
1370
 
#endif /* !HAVE_ATOMIC_BUILTINS */
1371
 
 
1372
 
        for (i = 0; i < IBUF_OP_COUNT; i++) {
1373
 
#ifdef HAVE_ATOMIC_BUILTINS
1374
 
                os_atomic_increment_ulint(&arr[i], ops[i]);
1375
 
#else /* HAVE_ATOMIC_BUILTINS */
1376
 
                arr[i] += ops[i];
1377
 
#endif /* HAVE_ATOMIC_BUILTINS */
1378
 
        }
1379
 
}
1380
 
 
1381
 
/****************************************************************//**
1382
 
Print operation counts. The array must be of size IBUF_OP_COUNT. */
1383
 
static
1384
 
void
1385
 
ibuf_print_ops(
1386
 
/*===========*/
1387
 
        const ulint*    ops,    /*!< in: operation counts */
1388
 
        FILE*           file)   /*!< in: file where to print */
1389
 
{
1390
 
        static const char* op_names[] = {
1391
 
                "insert",
1392
 
                "delete mark",
1393
 
                "delete"
1394
 
        };
1395
 
        ulint   i;
1396
 
 
1397
 
        ut_a(UT_ARR_SIZE(op_names) == IBUF_OP_COUNT);
1398
 
 
1399
 
        for (i = 0; i < IBUF_OP_COUNT; i++) {
1400
 
                fprintf(file, "%s %lu%s", op_names[i],
1401
 
                        (ulong) ops[i], (i < (IBUF_OP_COUNT - 1)) ? ", " : "");
1402
 
        }
1403
 
 
1404
 
        putc('\n', file);
1405
 
}
1406
 
 
1407
1115
/********************************************************************//**
1408
1116
Creates a dummy index for inserting a record to a non-clustered index.
 
1117
 
1409
1118
@return dummy index */
1410
1119
static
1411
1120
dict_index_t*
1516
1225
}
1517
1226
 
1518
1227
/*********************************************************************//**
1519
 
Builds the entry used to
1520
 
 
1521
 
1) IBUF_OP_INSERT: insert into a non-clustered index
1522
 
 
1523
 
2) IBUF_OP_DELETE_MARK: find the record whose delete-mark flag we need to
1524
 
   activate
1525
 
 
1526
 
3) IBUF_OP_DELETE: find the record we need to delete
1527
 
 
1528
 
when we have the corresponding record in an ibuf index.
 
1228
Builds the entry to insert into a non-clustered index when we have the
 
1229
corresponding record in an ibuf index.
1529
1230
 
1530
1231
NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1531
1232
hold a latch to the ibuf_rec page as long as the entry is used!
1546
1247
        const byte*     types;
1547
1248
        const byte*     data;
1548
1249
        ulint           len;
1549
 
        ulint           info_len;
1550
1250
        ulint           i;
1551
 
        ulint           comp;
1552
1251
        dict_index_t*   index;
1553
1252
 
1554
1253
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1571
1270
 
1572
1271
        types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1573
1272
 
1574
 
        ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL);
1575
 
 
1576
 
        index = ibuf_dummy_index_create(n_fields, comp);
1577
 
 
1578
 
        len -= info_len;
1579
 
        types += info_len;
 
1273
        ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
 
1274
        index = ibuf_dummy_index_create(
 
1275
                n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
 
1276
 
 
1277
        if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
 
1278
                /* compact record format */
 
1279
                len--;
 
1280
                ut_a(*types == 0);
 
1281
                types++;
 
1282
        }
1580
1283
 
1581
1284
        ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1582
1285
 
1606
1309
        return(tuple);
1607
1310
}
1608
1311
 
1609
 
/******************************************************************//**
1610
 
Get the data size.
1611
 
@return size of fields */
1612
 
UNIV_INLINE
1613
 
ulint
1614
 
ibuf_rec_get_size(
1615
 
/*==============*/
1616
 
        const rec_t*    rec,                    /*!< in: ibuf record */
1617
 
        const byte*     types,                  /*!< in: fields */
1618
 
        ulint           n_fields,               /*!< in: number of fields */
1619
 
        ibool           pre_4_1,                /*!< in: TRUE=pre-4.1 format,
1620
 
                                                FALSE=newer */
1621
 
        ulint           comp)                   /*!< in: 0=ROW_FORMAT=REDUNDANT,
1622
 
                                                nonzero=ROW_FORMAT=COMPACT */
1623
 
{
1624
 
        ulint   i;
1625
 
        ulint   field_offset;
1626
 
        ulint   types_offset;
1627
 
        ulint   size = 0;
1628
 
 
1629
 
        if (pre_4_1) {
1630
 
                field_offset = 2;
1631
 
                types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE;
1632
 
        } else {
1633
 
                field_offset = 4;
1634
 
                types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1635
 
        }
1636
 
 
1637
 
        for (i = 0; i < n_fields; i++) {
1638
 
                ulint           len;
1639
 
                dtype_t         dtype;
1640
 
 
1641
 
                rec_get_nth_field_offs_old(rec, i + field_offset, &len);
1642
 
 
1643
 
                if (len != UNIV_SQL_NULL) {
1644
 
                        size += len;
1645
 
                } else if (pre_4_1) {
1646
 
                        dtype_read_for_order_and_null_size(&dtype, types);
1647
 
 
1648
 
                        size += dtype_get_sql_null_size(&dtype, comp);
1649
 
                } else {
1650
 
                        dtype_new_read_for_order_and_null_size(&dtype, types);
1651
 
 
1652
 
                        size += dtype_get_sql_null_size(&dtype, comp);
1653
 
                }
1654
 
 
1655
 
                types += types_offset;
1656
 
        }
1657
 
 
1658
 
        return(size);
1659
 
}
1660
 
 
1661
1312
/********************************************************************//**
1662
1313
Returns the space taken by a stored non-clustered index entry if converted to
1663
1314
an index record.
1669
1320
/*================*/
1670
1321
        const rec_t*    ibuf_rec)/*!< in: ibuf record */
1671
1322
{
 
1323
        dtype_t         dtype;
 
1324
        ibool           new_format      = FALSE;
 
1325
        ulint           data_size       = 0;
 
1326
        ulint           n_fields;
 
1327
        const byte*     types;
 
1328
        const byte*     data;
1672
1329
        ulint           len;
1673
 
        const byte*     data;
1674
 
        const byte*     types;
1675
 
        ulint           n_fields;
1676
 
        ulint           data_size;
1677
 
        ibool           pre_4_1;
 
1330
        ulint           i;
1678
1331
        ulint           comp;
1679
1332
 
1680
1333
        ut_ad(ibuf_inside());
1681
1334
        ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
1682
1335
 
1683
1336
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1684
 
        pre_4_1 = (len > 1);
1685
1337
 
1686
 
        if (pre_4_1) {
 
1338
        if (len > 1) {
1687
1339
                /* < 4.1.x format record */
1688
1340
 
1689
1341
                ut_a(trx_doublewrite_must_reset_space_ids);
1697
1349
                comp = 0;
1698
1350
        } else {
1699
1351
                /* >= 4.1.x format record */
1700
 
                ibuf_op_t       op;
1701
 
                ulint           info_len;
1702
1352
 
1703
1353
                ut_a(trx_sys_multiple_tablespace_format);
1704
1354
                ut_a(*data == 0);
1705
1355
 
1706
1356
                types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1707
1357
 
1708
 
                ibuf_rec_get_info(ibuf_rec, &op, &comp, &info_len, NULL);
1709
 
 
1710
 
                if (op == IBUF_OP_DELETE_MARK || op == IBUF_OP_DELETE) {
1711
 
                        /* Delete-marking a record doesn't take any
1712
 
                        additional space, and while deleting a record
1713
 
                        actually frees up space, we have to play it safe and
1714
 
                        pretend it takes no additional space (the record
1715
 
                        might not exist, etc.).  */
1716
 
 
1717
 
                        return(0);
1718
 
                } else if (comp) {
1719
 
                        dtuple_t*       entry;
 
1358
                comp = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
 
1359
 
 
1360
                ut_a(comp <= 1);
 
1361
                if (comp) {
 
1362
                        /* compact record format */
1720
1363
                        ulint           volume;
1721
1364
                        dict_index_t*   dummy_index;
1722
1365
                        mem_heap_t*     heap = mem_heap_create(500);
1723
 
 
1724
 
                        entry = ibuf_build_entry_from_ibuf_rec(
 
1366
                        dtuple_t*       entry = ibuf_build_entry_from_ibuf_rec(
1725
1367
                                ibuf_rec, heap, &dummy_index);
1726
 
 
1727
1368
                        volume = rec_get_converted_size(dummy_index, entry, 0);
1728
 
 
1729
1369
                        ibuf_dummy_index_free(dummy_index);
1730
1370
                        mem_heap_free(heap);
1731
 
 
1732
1371
                        return(volume + page_dir_calc_reserved_space(1));
1733
1372
                }
1734
1373
 
1735
 
                types += info_len;
1736
1374
                n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1737
 
        }
1738
 
 
1739
 
        data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp);
 
1375
 
 
1376
                new_format = TRUE;
 
1377
        }
 
1378
 
 
1379
        for (i = 0; i < n_fields; i++) {
 
1380
                if (new_format) {
 
1381
                        data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
 
1382
 
 
1383
                        dtype_new_read_for_order_and_null_size(
 
1384
                                &dtype, types + i
 
1385
                                * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
 
1386
                } else {
 
1387
                        data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
 
1388
 
 
1389
                        dtype_read_for_order_and_null_size(
 
1390
                                &dtype, types + i
 
1391
                                * DATA_ORDER_NULL_TYPE_BUF_SIZE);
 
1392
                }
 
1393
 
 
1394
                if (len == UNIV_SQL_NULL) {
 
1395
                        data_size += dtype_get_sql_null_size(&dtype, comp);
 
1396
                } else {
 
1397
                        data_size += len;
 
1398
                }
 
1399
        }
1740
1400
 
1741
1401
        return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0)
1742
1402
               + page_dir_calc_reserved_space(1));
1754
1414
dtuple_t*
1755
1415
ibuf_entry_build(
1756
1416
/*=============*/
1757
 
        ibuf_op_t       op,     /*!< in: operation type */
1758
1417
        dict_index_t*   index,  /*!< in: non-clustered index */
1759
1418
        const dtuple_t* entry,  /*!< in: entry for a non-clustered index */
1760
1419
        ulint           space,  /*!< in: space id */
1761
1420
        ulint           page_no,/*!< in: index page number where entry should
1762
1421
                                be inserted */
1763
 
        ulint           counter,/*!< in: counter value;
1764
 
                                ULINT_UNDEFINED=not used */
1765
1422
        mem_heap_t*     heap)   /*!< in: heap into which to build */
1766
1423
{
1767
1424
        dtuple_t*       tuple;
1769
1426
        const dfield_t* entry_field;
1770
1427
        ulint           n_fields;
1771
1428
        byte*           buf;
1772
 
        byte*           ti;
1773
 
        byte*           type_info;
 
1429
        byte*           buf2;
1774
1430
        ulint           i;
1775
1431
 
1776
 
        ut_ad(counter != ULINT_UNDEFINED || op == IBUF_OP_INSERT);
1777
 
        ut_ad(counter == ULINT_UNDEFINED || counter <= 0xFFFF);
1778
 
        ut_ad(op < IBUF_OP_COUNT);
1779
 
 
1780
 
        /* We have to build a tuple with the following fields:
1781
 
 
1782
 
        1-4) These are described at the top of this file.
1783
 
 
1784
 
        5) The rest of the fields are copied from the entry.
1785
 
 
1786
 
        All fields in the tuple are ordered like the type binary in our
1787
 
        insert buffer tree. */
 
1432
        /* Starting from 4.1.x, we have to build a tuple whose
 
1433
        (1) first field is the space id,
 
1434
        (2) the second field a single marker byte (0) to tell that this
 
1435
        is a new format record,
 
1436
        (3) the third contains the page number, and
 
1437
        (4) the fourth contains the relevent type information of each data
 
1438
        field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is
 
1439
        (a) 0 for b-trees in the old format, and
 
1440
        (b) 1 for b-trees in the compact format, the first byte of the field
 
1441
        being the marker (0);
 
1442
        (5) and the rest of the fields are copied from entry. All fields
 
1443
        in the tuple are ordered like the type binary in our insert buffer
 
1444
        tree. */
1788
1445
 
1789
1446
        n_fields = dtuple_get_n_fields(entry);
1790
1447
 
1791
1448
        tuple = dtuple_create(heap, n_fields + 4);
1792
1449
 
1793
 
        /* 1) Space Id */
 
1450
        /* Store the space id in tuple */
1794
1451
 
1795
1452
        field = dtuple_get_nth_field(tuple, 0);
1796
1453
 
1797
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
 
1454
        buf = mem_heap_alloc(heap, 4);
1798
1455
 
1799
1456
        mach_write_to_4(buf, space);
1800
1457
 
1801
1458
        dfield_set_data(field, buf, 4);
1802
1459
 
1803
 
        /* 2) Marker byte */
 
1460
        /* Store the marker byte field in tuple */
1804
1461
 
1805
1462
        field = dtuple_get_nth_field(tuple, 1);
1806
1463
 
1807
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
 
1464
        buf = mem_heap_alloc(heap, 1);
1808
1465
 
1809
1466
        /* We set the marker byte zero */
1810
1467
 
1812
1469
 
1813
1470
        dfield_set_data(field, buf, 1);
1814
1471
 
1815
 
        /* 3) Page number */
 
1472
        /* Store the page number in tuple */
1816
1473
 
1817
1474
        field = dtuple_get_nth_field(tuple, 2);
1818
1475
 
1819
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
 
1476
        buf = mem_heap_alloc(heap, 4);
1820
1477
 
1821
1478
        mach_write_to_4(buf, page_no);
1822
1479
 
1823
1480
        dfield_set_data(field, buf, 4);
1824
1481
 
1825
 
        /* 4) Type info, part #1 */
1826
 
 
1827
 
        if (counter == ULINT_UNDEFINED) {
1828
 
                i = dict_table_is_comp(index->table) ? 1 : 0;
1829
 
        } else {
1830
 
                ut_ad(counter <= 0xFFFF);
1831
 
                i = IBUF_REC_INFO_SIZE;
1832
 
        }
1833
 
 
1834
 
        ti = type_info = static_cast<byte *>(mem_heap_alloc(heap, i + n_fields
1835
 
                                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE));
1836
 
 
1837
 
        switch (i) {
1838
 
        default:
1839
 
                ut_error;
1840
 
                break;
1841
 
        case 1:
1842
 
                /* set the flag for ROW_FORMAT=COMPACT */
1843
 
                *ti++ = 0;
1844
 
                /* fall through */
1845
 
        case 0:
1846
 
                /* the old format does not allow delete buffering */
1847
 
                ut_ad(op == IBUF_OP_INSERT);
1848
 
                break;
1849
 
        case IBUF_REC_INFO_SIZE:
1850
 
                mach_write_to_2(ti + IBUF_REC_OFFSET_COUNTER, counter);
1851
 
 
1852
 
                ti[IBUF_REC_OFFSET_TYPE] = (byte) op;
1853
 
                ti[IBUF_REC_OFFSET_FLAGS] = dict_table_is_comp(index->table)
1854
 
                        ? IBUF_REC_COMPACT : 0;
1855
 
                ti += IBUF_REC_INFO_SIZE;
1856
 
                break;
1857
 
        }
1858
 
 
1859
 
        /* 5+) Fields from the entry */
1860
 
 
 
1482
        /* Store the type info in buf2, and add the fields from entry to
 
1483
        tuple */
 
1484
        buf2 = mem_heap_alloc(heap, n_fields
 
1485
                              * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
 
1486
                              + dict_table_is_comp(index->table));
 
1487
        if (dict_table_is_comp(index->table)) {
 
1488
                *buf2++ = 0; /* write the compact format indicator */
 
1489
        }
1861
1490
        for (i = 0; i < n_fields; i++) {
1862
1491
                ulint                   fixed_len;
1863
1492
                const dict_field_t*     ifield;
1892
1521
#endif /* UNIV_DEBUG */
1893
1522
 
1894
1523
                dtype_new_store_for_order_and_null_size(
1895
 
                        ti, dfield_get_type(entry_field), fixed_len);
1896
 
                ti += DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
 
1524
                        buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
 
1525
                        dfield_get_type(entry_field), fixed_len);
1897
1526
        }
1898
1527
 
1899
 
        /* 4) Type info, part #2 */
 
1528
        /* Store the type info in buf2 to field 3 of tuple */
1900
1529
 
1901
1530
        field = dtuple_get_nth_field(tuple, 3);
1902
1531
 
1903
 
        dfield_set_data(field, type_info, ti - type_info);
 
1532
        if (dict_table_is_comp(index->table)) {
 
1533
                buf2--;
 
1534
        }
1904
1535
 
 
1536
        dfield_set_data(field, buf2, n_fields
 
1537
                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
 
1538
                        + dict_table_is_comp(index->table));
1905
1539
        /* Set all the types in the new tuple binary */
1906
1540
 
1907
1541
        dtuple_set_types_binary(tuple, n_fields + 4);
1935
1569
 
1936
1570
        field = dtuple_get_nth_field(tuple, 0);
1937
1571
 
1938
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
 
1572
        buf = mem_heap_alloc(heap, 4);
1939
1573
 
1940
1574
        mach_write_to_4(buf, page_no);
1941
1575
 
1970
1604
 
1971
1605
        field = dtuple_get_nth_field(tuple, 0);
1972
1606
 
1973
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
 
1607
        buf = mem_heap_alloc(heap, 4);
1974
1608
 
1975
1609
        mach_write_to_4(buf, space);
1976
1610
 
1980
1614
 
1981
1615
        field = dtuple_get_nth_field(tuple, 1);
1982
1616
 
1983
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
 
1617
        buf = mem_heap_alloc(heap, 1);
1984
1618
 
1985
1619
        mach_write_to_1(buf, 0);
1986
1620
 
1990
1624
 
1991
1625
        field = dtuple_get_nth_field(tuple, 2);
1992
1626
 
1993
 
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
 
1627
        buf = mem_heap_alloc(heap, 4);
1994
1628
 
1995
1629
        mach_write_to_4(buf, page_no);
1996
1630
 
2038
1672
/*********************************************************************//**
2039
1673
Allocates a new page from the ibuf file segment and adds it to the free
2040
1674
list.
2041
 
@return TRUE on success, FALSE if no space left */
 
1675
@return DB_SUCCESS, or DB_STRONG_FAIL if no space left */
2042
1676
static
2043
 
ibool
 
1677
ulint
2044
1678
ibuf_add_free_page(void)
2045
1679
/*====================*/
2046
1680
{
2076
1710
                header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
2077
1711
                &mtr);
2078
1712
 
2079
 
        if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
 
1713
        if (page_no == FIL_NULL) {
2080
1714
                mtr_commit(&mtr);
2081
1715
 
2082
 
                return(FALSE);
 
1716
                return(DB_STRONG_FAIL);
2083
1717
        }
2084
1718
 
2085
1719
        {
2117
1751
        bitmap_page = ibuf_bitmap_get_map_page(
2118
1752
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
2119
1753
 
2120
 
        mutex_exit(&ibuf_mutex);
2121
 
 
2122
1754
        ibuf_bitmap_page_set_bits(
2123
1755
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
2124
1756
 
2125
1757
        mtr_commit(&mtr);
2126
1758
 
 
1759
        mutex_exit(&ibuf_mutex);
 
1760
 
2127
1761
        ibuf_exit();
2128
1762
 
2129
 
        return(TRUE);
 
1763
        return(DB_SUCCESS);
2130
1764
}
2131
1765
 
2132
1766
/*********************************************************************//**
2156
1790
        header_page = ibuf_header_page_get(&mtr);
2157
1791
 
2158
1792
        /* Prevent pessimistic inserts to insert buffer trees for a while */
2159
 
        ibuf_enter();
2160
1793
        mutex_enter(&ibuf_pessimistic_insert_mutex);
 
1794
 
 
1795
        ibuf_enter();
 
1796
 
2161
1797
        mutex_enter(&ibuf_mutex);
2162
1798
 
2163
1799
        if (!ibuf_data_too_much_free()) {
2164
1800
 
2165
1801
                mutex_exit(&ibuf_mutex);
 
1802
 
 
1803
                ibuf_exit();
 
1804
 
2166
1805
                mutex_exit(&ibuf_pessimistic_insert_mutex);
2167
1806
 
2168
 
                ibuf_exit();
2169
 
 
2170
1807
                mtr_commit(&mtr);
2171
1808
 
2172
1809
                return;
2176
1813
 
2177
1814
        root = ibuf_tree_root_get(&mtr2);
2178
1815
 
2179
 
        mutex_exit(&ibuf_mutex);
2180
 
 
2181
1816
        page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
2182
1817
                                &mtr2).page;
2183
1818
 
2186
1821
        is a level 2 page. */
2187
1822
 
2188
1823
        mtr_commit(&mtr2);
 
1824
        mutex_exit(&ibuf_mutex);
2189
1825
 
2190
1826
        ibuf_exit();
2191
1827
 
2228
1864
        flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
2229
1865
                    page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
2230
1866
 
2231
 
        mutex_exit(&ibuf_pessimistic_insert_mutex);
2232
 
 
2233
1867
        ibuf->seg_size--;
2234
1868
        ibuf->free_list_len--;
2235
1869
 
 
1870
        mutex_exit(&ibuf_pessimistic_insert_mutex);
 
1871
 
2236
1872
        /* Set the bit indicating that this page is no more an ibuf tree page
2237
1873
        (level 2 page) */
2238
1874
 
2239
1875
        bitmap_page = ibuf_bitmap_get_map_page(
2240
1876
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
2241
1877
 
2242
 
        mutex_exit(&ibuf_mutex);
2243
 
 
2244
1878
        ibuf_bitmap_page_set_bits(
2245
1879
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr);
2246
1880
 
2249
1883
#endif
2250
1884
        mtr_commit(&mtr);
2251
1885
 
 
1886
        mutex_exit(&ibuf_mutex);
 
1887
 
2252
1888
        ibuf_exit();
2253
1889
}
2254
1890
 
2289
1925
 
2290
1926
        for (i = 0; i < 4; i++) {
2291
1927
 
2292
 
                ibool   too_much_free;
2293
 
 
2294
1928
                mutex_enter(&ibuf_mutex);
2295
 
                too_much_free = ibuf_data_too_much_free();
2296
 
                mutex_exit(&ibuf_mutex);
2297
 
 
2298
 
                if (!too_much_free) {
 
1929
 
 
1930
                if (!ibuf_data_too_much_free()) {
 
1931
 
 
1932
                        mutex_exit(&ibuf_mutex);
 
1933
 
2299
1934
                        return;
2300
1935
                }
2301
1936
 
 
1937
                mutex_exit(&ibuf_mutex);
 
1938
 
2302
1939
                ibuf_remove_free_page();
2303
1940
        }
2304
1941
}
2341
1978
 
2342
1979
        *n_stored = 0;
2343
1980
 
2344
 
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4);
 
1981
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
2345
1982
 
2346
1983
        if (page_rec_is_supremum(rec)) {
2347
1984
 
2494
2131
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
2495
2132
        ulint           space_ids[IBUF_MAX_N_PAGES_MERGED];
2496
2133
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
 
2134
        ulint           n_stored;
2497
2135
        ulint           sum_sizes;
2498
2136
        mtr_t           mtr;
2499
2137
 
2500
2138
        *n_pages = 0;
2501
2139
        ut_ad(!ibuf_inside());
2502
2140
 
2503
 
        /* We perform a dirty read of ibuf->empty, without latching
2504
 
        the insert buffer root page. We trust this dirty read except
2505
 
        when a slow shutdown is being executed. During a slow
2506
 
        shutdown, the insert buffer merge must be completed. */
 
2141
        mutex_enter(&ibuf_mutex);
2507
2142
 
2508
 
        if (UNIV_UNLIKELY(ibuf->empty)
2509
 
            && UNIV_LIKELY(!srv_shutdown_state)) {
 
2143
        if (ibuf->empty) {
2510
2144
ibuf_is_empty:
2511
 
 
2512
 
#if 0 /* TODO */
2513
 
                if (srv_shutdown_state) {
2514
 
                        /* If the insert buffer becomes empty during
2515
 
                        shutdown, note it in the system tablespace. */
2516
 
 
2517
 
                        trx_sys_set_ibuf_format(TRX_SYS_IBUF_EMPTY);
2518
 
                }
2519
 
 
2520
 
                /* TO DO: call trx_sys_set_ibuf_format() at startup
2521
 
                and whenever ibuf_use is changed to allow buffered
2522
 
                delete-marking or deleting.  Never downgrade the
2523
 
                stamped format except when the insert buffer becomes
2524
 
                empty. */
2525
 
#endif
 
2145
                mutex_exit(&ibuf_mutex);
2526
2146
 
2527
2147
                return(0);
2528
2148
        }
2536
2156
 
2537
2157
        btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr);
2538
2158
 
2539
 
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
2540
 
 
2541
2159
        if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
2542
 
                /* If a B-tree page is empty, it must be the root page
2543
 
                and the whole B-tree must be empty. InnoDB does not
2544
 
                allow empty B-tree pages other than the root. */
2545
 
                ut_ad(ibuf->empty);
2546
 
                ut_ad(page_get_space_id(btr_pcur_get_page(&pcur))
2547
 
                      == IBUF_SPACE_ID);
2548
 
                ut_ad(page_get_page_no(btr_pcur_get_page(&pcur))
2549
 
                      == FSP_IBUF_TREE_ROOT_PAGE_NO);
 
2160
                /* When the ibuf tree is emptied completely, the last record
 
2161
                is removed using an optimistic delete and ibuf_size_update
 
2162
                is not called, causing ibuf->empty to remain FALSE. If we do
 
2163
                not reset it to TRUE here then database shutdown will hang
 
2164
                in the loop in ibuf_contract_for_n_pages. */
 
2165
 
 
2166
                ibuf->empty = TRUE;
2550
2167
 
2551
2168
                ibuf_exit();
2552
2169
 
2556
2173
                goto ibuf_is_empty;
2557
2174
        }
2558
2175
 
 
2176
        mutex_exit(&ibuf_mutex);
 
2177
 
2559
2178
        sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
2560
2179
                                            space_ids, space_versions,
2561
 
                                            page_nos, n_pages);
 
2180
                                            page_nos, &n_stored);
2562
2181
#if 0 /* defined UNIV_IBUF_DEBUG */
2563
2182
        fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
2564
 
                sync, *n_pages, sum_sizes);
 
2183
                sync, n_stored, sum_sizes);
2565
2184
#endif
2566
2185
        ibuf_exit();
2567
2186
 
2569
2188
        btr_pcur_close(&pcur);
2570
2189
 
2571
2190
        buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos,
2572
 
                                  *n_pages);
 
2191
                                  n_stored);
 
2192
        *n_pages = n_stored;
2573
2193
 
2574
2194
        return(sum_sizes + 1);
2575
2195
}
2639
2259
        ibool   sync;
2640
2260
        ulint   sum_sizes;
2641
2261
        ulint   size;
2642
 
        ulint   max_size;
2643
 
 
2644
 
        /* Perform dirty reads of ibuf->size and ibuf->max_size, to
2645
 
        reduce ibuf_mutex contention. ibuf->max_size remains constant
2646
 
        after ibuf_init_at_db_start(), but ibuf->size should be
2647
 
        protected by ibuf_mutex. Given that ibuf->size fits in a
2648
 
        machine word, this should be OK; at worst we are doing some
2649
 
        excessive ibuf_contract() or occasionally skipping a
2650
 
        ibuf_contract(). */
2651
 
        size = ibuf->size;
2652
 
        max_size = ibuf->max_size;
2653
 
 
2654
 
        if (size < max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
 
2262
 
 
2263
        mutex_enter(&ibuf_mutex);
 
2264
 
 
2265
        if (ibuf->size < ibuf->max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
 
2266
                mutex_exit(&ibuf_mutex);
 
2267
 
2655
2268
                return;
2656
2269
        }
2657
2270
 
2658
 
        sync = (size >= max_size + IBUF_CONTRACT_ON_INSERT_SYNC);
 
2271
        sync = FALSE;
 
2272
 
 
2273
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_ON_INSERT_SYNC) {
 
2274
 
 
2275
                sync = TRUE;
 
2276
        }
 
2277
 
 
2278
        mutex_exit(&ibuf_mutex);
2659
2279
 
2660
2280
        /* Contract at least entry_size many bytes */
2661
2281
        sum_sizes = 0;
2662
2282
        size = 1;
2663
2283
 
2664
 
        do {
 
2284
        while ((size > 0) && (sum_sizes < entry_size)) {
2665
2285
 
2666
2286
                size = ibuf_contract(sync);
2667
2287
                sum_sizes += size;
2668
 
        } while (size > 0 && sum_sizes < entry_size);
2669
 
}
2670
 
 
2671
 
/*********************************************************************//**
2672
 
Determine if an insert buffer record has been encountered already.
2673
 
@return TRUE if a new record, FALSE if possible duplicate */
2674
 
static
2675
 
ibool
2676
 
ibuf_get_volume_buffered_hash(
2677
 
/*==========================*/
2678
 
        const rec_t*    rec,    /*!< in: ibuf record in post-4.1 format */
2679
 
        const byte*     types,  /*!< in: fields */
2680
 
        const byte*     data,   /*!< in: start of user record data */
2681
 
        ulint           comp,   /*!< in: 0=ROW_FORMAT=REDUNDANT,
2682
 
                                nonzero=ROW_FORMAT=COMPACT */
2683
 
        ulint*          hash,   /*!< in/out: hash array */
2684
 
        ulint           size)   /*!< in: number of elements in hash array */
2685
 
{
2686
 
        ulint           len;
2687
 
        ulint           fold;
2688
 
        ulint           bitmask;
2689
 
 
2690
 
        len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4,
2691
 
                                FALSE, comp);
2692
 
        fold = ut_fold_binary(data, len);
2693
 
 
2694
 
        hash += (fold / (8 * sizeof *hash)) % size; // 8 = bits in byte
2695
 
        bitmask = 1 << (fold % (8 * sizeof *hash));
2696
 
 
2697
 
        if (*hash & bitmask) {
2698
 
 
2699
 
                return(FALSE);
2700
 
        }
2701
 
 
2702
 
        /* We have not seen this record yet.  Insert it. */
2703
 
        *hash |= bitmask;
2704
 
 
2705
 
        return(TRUE);
2706
 
}
2707
 
 
2708
 
/*********************************************************************//**
2709
 
Update the estimate of the number of records on a page, and
2710
 
get the space taken by merging the buffered record to the index page.
2711
 
@return size of index record in bytes + an upper limit of the space
2712
 
taken in the page directory */
2713
 
static
2714
 
ulint
2715
 
ibuf_get_volume_buffered_count(
2716
 
/*===========================*/
2717
 
        const rec_t*    rec,    /*!< in: insert buffer record */
2718
 
        ulint*          hash,   /*!< in/out: hash array */
2719
 
        ulint           size,   /*!< in: number of elements in hash array */
2720
 
        lint*           n_recs) /*!< in/out: estimated number of records
2721
 
                                on the page that rec points to */
2722
 
{
2723
 
        ulint           len;
2724
 
        ibuf_op_t       ibuf_op;
2725
 
        const byte*     types;
2726
 
        ulint           n_fields        = rec_get_n_fields_old(rec);
2727
 
 
2728
 
        ut_ad(ibuf_inside());
2729
 
        ut_ad(n_fields > 4);
2730
 
        n_fields -= 4;
2731
 
 
2732
 
        rec_get_nth_field_offs_old(rec, 1, &len);
2733
 
        /* This function is only invoked when buffering new
2734
 
        operations.  All pre-4.1 records should have been merged
2735
 
        when the database was started up. */
2736
 
        ut_a(len == 1);
2737
 
        ut_ad(trx_sys_multiple_tablespace_format);
2738
 
 
2739
 
        types = rec_get_nth_field_old(rec, 3, &len);
2740
 
 
2741
 
        switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
2742
 
                            IBUF_REC_INFO_SIZE)) {
2743
 
        default:
2744
 
                ut_error;
2745
 
        case 0:
2746
 
                /* This ROW_TYPE=REDUNDANT record does not include an
2747
 
                operation counter.  Exclude it from the *n_recs,
2748
 
                because deletes cannot be buffered if there are
2749
 
                old-style inserts buffered for the page. */
2750
 
 
2751
 
                len = ibuf_rec_get_size(rec, types, n_fields, FALSE, 0);
2752
 
 
2753
 
                return(len
2754
 
                       + rec_get_converted_extra_size(len, n_fields, 0)
2755
 
                       + page_dir_calc_reserved_space(1));
2756
 
        case 1:
2757
 
                /* This ROW_TYPE=COMPACT record does not include an
2758
 
                operation counter.  Exclude it from the *n_recs,
2759
 
                because deletes cannot be buffered if there are
2760
 
                old-style inserts buffered for the page. */
2761
 
                goto get_volume_comp;
2762
 
 
2763
 
        case IBUF_REC_INFO_SIZE:
2764
 
                ibuf_op = (ibuf_op_t) types[IBUF_REC_OFFSET_TYPE];
2765
 
                break;
2766
 
        }
2767
 
 
2768
 
        switch (ibuf_op) {
2769
 
        case IBUF_OP_INSERT:
2770
 
                /* Inserts can be done by updating a delete-marked record.
2771
 
                Because delete-mark and insert operations can be pointing to
2772
 
                the same records, we must not count duplicates. */
2773
 
        case IBUF_OP_DELETE_MARK:
2774
 
                /* There must be a record to delete-mark.
2775
 
                See if this record has been already buffered. */
2776
 
                if (n_recs && ibuf_get_volume_buffered_hash(
2777
 
                            rec, types + IBUF_REC_INFO_SIZE,
2778
 
                            types + len,
2779
 
                            types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT,
2780
 
                            hash, size)) {
2781
 
                        (*n_recs)++;
2782
 
                }
2783
 
 
2784
 
                if (ibuf_op == IBUF_OP_DELETE_MARK) {
2785
 
                        /* Setting the delete-mark flag does not
2786
 
                        affect the available space on the page. */
2787
 
                        return(0);
2788
 
                }
2789
 
                break;
2790
 
        case IBUF_OP_DELETE:
2791
 
                /* A record will be removed from the page. */
2792
 
                if (n_recs) {
2793
 
                        (*n_recs)--;
2794
 
                }
2795
 
                /* While deleting a record actually frees up space,
2796
 
                we have to play it safe and pretend that it takes no
2797
 
                additional space (the record might not exist, etc.). */
2798
 
                return(0);
2799
 
        default:
2800
 
                ut_error;
2801
 
        }
2802
 
 
2803
 
        ut_ad(ibuf_op == IBUF_OP_INSERT);
2804
 
 
2805
 
get_volume_comp:
2806
 
        {
2807
 
                dtuple_t*       entry;
2808
 
                ulint           volume;
2809
 
                dict_index_t*   dummy_index;
2810
 
                mem_heap_t*     heap = mem_heap_create(500);
2811
 
 
2812
 
                entry = ibuf_build_entry_from_ibuf_rec(
2813
 
                        rec, heap, &dummy_index);
2814
 
 
2815
 
                volume = rec_get_converted_size(dummy_index, entry, 0);
2816
 
 
2817
 
                ibuf_dummy_index_free(dummy_index);
2818
 
                mem_heap_free(heap);
2819
 
 
2820
 
                return(volume + page_dir_calc_reserved_space(1));
2821
2288
        }
2822
2289
}
2823
2290
 
2838
2305
                                or BTR_MODIFY_TREE */
2839
2306
        ulint           space,  /*!< in: space id */
2840
2307
        ulint           page_no,/*!< in: page number of an index page */
2841
 
        lint*           n_recs, /*!< in/out: minimum number of records on the
2842
 
                                page after the buffered changes have been
2843
 
                                applied, or NULL to disable the counting */
2844
2308
        mtr_t*          mtr)    /*!< in: mtr */
2845
2309
{
2846
2310
        ulint   volume;
2850
2314
        page_t* prev_page;
2851
2315
        ulint   next_page_no;
2852
2316
        page_t* next_page;
2853
 
        ulint   hash_bitmap[128 / sizeof(ulint)]; /* bitmap of buffered recs */
2854
2317
 
2855
2318
        ut_a(trx_sys_multiple_tablespace_format);
2856
2319
 
2857
2320
        ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
2858
2321
              || (pcur->latch_mode == BTR_MODIFY_TREE));
2859
2322
 
2860
 
        /* Count the volume of inserts earlier in the alphabetical order than
 
2323
        /* Count the volume of records earlier in the alphabetical order than
2861
2324
        pcur */
2862
2325
 
2863
2326
        volume = 0;
2864
2327
 
2865
 
        if (n_recs) {
2866
 
                memset(hash_bitmap, 0, sizeof hash_bitmap);
2867
 
        }
2868
 
 
2869
2328
        rec = btr_pcur_get_rec(pcur);
2870
2329
        page = page_align(rec);
2871
 
        ut_ad(page_validate(page, ibuf->index));
2872
2330
 
2873
2331
        if (page_rec_is_supremum(rec)) {
2874
2332
                rec = page_rec_get_prev(rec);
2886
2344
                        goto count_later;
2887
2345
                }
2888
2346
 
2889
 
                volume += ibuf_get_volume_buffered_count(
2890
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2347
                volume += ibuf_rec_get_volume(rec);
2891
2348
 
2892
2349
                rec = page_rec_get_prev(rec);
2893
 
                ut_ad(page_align(rec) == page);
2894
2350
        }
2895
2351
 
2896
2352
        /* Look at the previous page */
2912
2368
 
2913
2369
 
2914
2370
                prev_page = buf_block_get_frame(block);
2915
 
                ut_ad(page_validate(prev_page, ibuf->index));
2916
2371
        }
2917
2372
 
2918
2373
#ifdef UNIV_BTR_DEBUG
2939
2394
                        goto count_later;
2940
2395
                }
2941
2396
 
2942
 
                volume += ibuf_get_volume_buffered_count(
2943
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2397
                volume += ibuf_rec_get_volume(rec);
2944
2398
 
2945
2399
                rec = page_rec_get_prev(rec);
2946
 
                ut_ad(page_align(rec) == prev_page);
2947
2400
        }
2948
2401
 
2949
2402
count_later:
2965
2418
                        return(volume);
2966
2419
                }
2967
2420
 
2968
 
                volume += ibuf_get_volume_buffered_count(
2969
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2421
                volume += ibuf_rec_get_volume(rec);
2970
2422
 
2971
2423
                rec = page_rec_get_next(rec);
2972
2424
        }
2990
2442
 
2991
2443
 
2992
2444
                next_page = buf_block_get_frame(block);
2993
 
                ut_ad(page_validate(next_page, ibuf->index));
2994
2445
        }
2995
2446
 
2996
2447
#ifdef UNIV_BTR_DEBUG
3014
2465
                        return(volume);
3015
2466
                }
3016
2467
 
3017
 
                volume += ibuf_get_volume_buffered_count(
3018
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2468
                volume += ibuf_rec_get_volume(rec);
3019
2469
 
3020
2470
                rec = page_rec_get_next(rec);
3021
 
                ut_ad(page_align(rec) == next_page);
3022
2471
        }
3023
2472
}
3024
2473
 
3046
2495
        btr_pcur_open_at_index_side(
3047
2496
                FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3048
2497
 
3049
 
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
3050
 
 
3051
2498
        btr_pcur_move_to_prev(&pcur, &mtr);
3052
2499
 
3053
2500
        if (btr_pcur_is_before_first_on_page(&pcur)) {
3072
2519
        fil_set_max_space_id_if_bigger(max_space_id);
3073
2520
}
3074
2521
 
3075
 
/****************************************************************//**
3076
 
Helper function for ibuf_set_entry_counter. Checks if rec is for (space,
3077
 
page_no), and if so, reads counter value from it and returns that + 1.
3078
 
Otherwise, returns 0.
3079
 
@return new counter value, or 0 */
3080
 
static
3081
 
ulint
3082
 
ibuf_get_entry_counter_low(
3083
 
/*=======================*/
3084
 
        const rec_t*    rec,            /*!< in: insert buffer record */
3085
 
        ulint           space,          /*!< in: space id */
3086
 
        ulint           page_no)        /*!< in: page number */
3087
 
{
3088
 
        ulint           counter;
3089
 
        const byte*     field;
3090
 
        ulint           len;
3091
 
 
3092
 
        ut_ad(ibuf_inside());
3093
 
        ut_ad(rec_get_n_fields_old(rec) > 2);
3094
 
 
3095
 
        field = rec_get_nth_field_old(rec, 1, &len);
3096
 
 
3097
 
        if (UNIV_UNLIKELY(len != 1)) {
3098
 
                /* pre-4.1 format */
3099
 
                ut_a(trx_doublewrite_must_reset_space_ids);
3100
 
                ut_a(!trx_sys_multiple_tablespace_format);
3101
 
 
3102
 
                return(ULINT_UNDEFINED);
3103
 
        }
3104
 
 
3105
 
        ut_a(trx_sys_multiple_tablespace_format);
3106
 
 
3107
 
        /* Check the tablespace identifier. */
3108
 
        field = rec_get_nth_field_old(rec, 0, &len);
3109
 
        ut_a(len == 4);
3110
 
 
3111
 
        if (mach_read_from_4(field) != space) {
3112
 
 
3113
 
                return(0);
3114
 
        }
3115
 
 
3116
 
        /* Check the page offset. */
3117
 
        field = rec_get_nth_field_old(rec, 2, &len);
3118
 
        ut_a(len == 4);
3119
 
 
3120
 
        if (mach_read_from_4(field) != page_no) {
3121
 
 
3122
 
                return(0);
3123
 
        }
3124
 
 
3125
 
        /* Check if the record contains a counter field. */
3126
 
        field = rec_get_nth_field_old(rec, 3, &len);
3127
 
 
3128
 
        switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
3129
 
        default:
3130
 
                ut_error;
3131
 
        case 0: /* ROW_FORMAT=REDUNDANT */
3132
 
        case 1: /* ROW_FORMAT=COMPACT */
3133
 
                return(ULINT_UNDEFINED);
3134
 
 
3135
 
        case IBUF_REC_INFO_SIZE:
3136
 
                counter = mach_read_from_2(field + IBUF_REC_OFFSET_COUNTER);
3137
 
                ut_a(counter < 0xFFFF);
3138
 
                return(counter + 1);
3139
 
        }
3140
 
}
3141
 
 
3142
 
/****************************************************************//**
3143
 
Set the counter field in entry to the correct value based on the current
3144
 
last record in ibuf for (space, page_no).
3145
 
@return FALSE if we should abort this insertion to ibuf */
3146
 
static
3147
 
ibool
3148
 
ibuf_set_entry_counter(
3149
 
/*===================*/
3150
 
        dtuple_t*       entry,          /*!< in/out: entry to patch */
3151
 
        ulint           space,          /*!< in: space id of entry */
3152
 
        ulint           page_no,        /*!< in: page number of entry */
3153
 
        btr_pcur_t*     pcur,           /*!< in: pcur positioned on the record
3154
 
                                        found by btr_pcur_open(.., entry,
3155
 
                                        PAGE_CUR_LE, ..., pcur, ...) */
3156
 
        ibool           is_optimistic,  /*!< in: is this an optimistic insert */
3157
 
        mtr_t*          mtr)            /*!< in: mtr */
3158
 
{
3159
 
        dfield_t*       field;
3160
 
        byte*           data;
3161
 
        ulint           counter = 0;
3162
 
 
3163
 
        /* pcur points to either a user rec or to a page's infimum record. */
3164
 
        ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index));
3165
 
 
3166
 
        if (btr_pcur_is_on_user_rec(pcur)) {
3167
 
 
3168
 
                counter = ibuf_get_entry_counter_low(
3169
 
                        btr_pcur_get_rec(pcur), space, page_no);
3170
 
 
3171
 
                if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
3172
 
                        /* The record lacks a counter field.
3173
 
                        Such old records must be merged before
3174
 
                        new records can be buffered. */
3175
 
 
3176
 
                        return(FALSE);
3177
 
                }
3178
 
        } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) {
3179
 
                /* Ibuf tree is either completely empty, or the insert
3180
 
                position is at the very first record of a non-empty tree. In
3181
 
                either case we have no previous records for (space,
3182
 
                page_no). */
3183
 
 
3184
 
                counter = 0;
3185
 
        } else if (btr_pcur_is_before_first_on_page(pcur)) {
3186
 
                btr_cur_t*      cursor = btr_pcur_get_btr_cur(pcur);
3187
 
 
3188
 
                if (cursor->low_match < 3) {
3189
 
                        /* If low_match < 3, we know that the father node
3190
 
                        pointer did not contain the searched for (space,
3191
 
                        page_no), which means that the search ended on the
3192
 
                        right page regardless of the counter value, and
3193
 
                        since we're at the infimum record, there are no
3194
 
                        existing records. */
3195
 
 
3196
 
                        counter = 0;
3197
 
                } else {
3198
 
                        rec_t*          rec;
3199
 
                        const page_t*   page;
3200
 
                        buf_block_t*    block;
3201
 
                        page_t*         prev_page;
3202
 
                        ulint           prev_page_no;
3203
 
 
3204
 
                        ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED);
3205
 
 
3206
 
                        page = btr_pcur_get_page(pcur);
3207
 
                        prev_page_no = btr_page_get_prev(page, mtr);
3208
 
 
3209
 
                        ut_a(prev_page_no != FIL_NULL);
3210
 
 
3211
 
                        block = buf_page_get(
3212
 
                                IBUF_SPACE_ID, 0, prev_page_no,
3213
 
                                RW_X_LATCH, mtr);
3214
 
 
3215
 
                        buf_block_dbg_add_level(block, SYNC_TREE_NODE);
3216
 
 
3217
 
                        prev_page = buf_block_get_frame(block);
3218
 
 
3219
 
                        rec = page_rec_get_prev(
3220
 
                                page_get_supremum_rec(prev_page));
3221
 
 
3222
 
                        ut_ad(page_rec_is_user_rec(rec));
3223
 
 
3224
 
                        counter = ibuf_get_entry_counter_low(
3225
 
                                rec, space, page_no);
3226
 
 
3227
 
                        if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
3228
 
                                /* The record lacks a counter field.
3229
 
                                Such old records must be merged before
3230
 
                                new records can be buffered. */
3231
 
 
3232
 
                                return(FALSE);
3233
 
                        }
3234
 
 
3235
 
                        if (counter < cursor->ibuf_cnt) {
3236
 
                                /* Search ended on the wrong page. */
3237
 
 
3238
 
                                if (is_optimistic) {
3239
 
                                        /* In an optimistic insert, we can
3240
 
                                        shift the insert position to the left
3241
 
                                        page, since it only needs an X-latch
3242
 
                                        on the page itself, which the
3243
 
                                        original search acquired for us. */
3244
 
 
3245
 
                                        btr_cur_position(
3246
 
                                                ibuf->index, rec, block,
3247
 
                                                btr_pcur_get_btr_cur(pcur));
3248
 
                                } else {
3249
 
                                        /* We can't shift the insert
3250
 
                                        position to the left page in a
3251
 
                                        pessimistic insert since it would
3252
 
                                        require an X-latch on the left
3253
 
                                        page's left page, so we have to
3254
 
                                        abort. */
3255
 
 
3256
 
                                        return(FALSE);
3257
 
                                }
3258
 
                        } else {
3259
 
                                /* The counter field in the father node is
3260
 
                                the same as we would insert; we don't know
3261
 
                                whether the insert should go to this page or
3262
 
                                the left page (the later fields can differ),
3263
 
                                so refuse the insert. */
3264
 
 
3265
 
                                return(FALSE);
3266
 
                        }
3267
 
                }
3268
 
        } else {
3269
 
                /* The cursor is not positioned at or before a user record. */
3270
 
                return(FALSE);
3271
 
        }
3272
 
 
3273
 
        /* Patch counter value in already built entry. */
3274
 
        field = dtuple_get_nth_field(entry, 3);
3275
 
        data = static_cast<byte *>(dfield_get_data(field));
3276
 
 
3277
 
        mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter);
3278
 
 
3279
 
        return(TRUE);
3280
 
}
3281
 
 
3282
2522
/*********************************************************************//**
3283
 
Buffer an operation in the insert/delete buffer, instead of doing it
3284
 
directly to the disk page, if this is possible.
3285
 
@return DB_SUCCESS, DB_STRONG_FAIL or other error */
 
2523
Makes an index insert to the insert buffer, instead of directly to the disk
 
2524
page, if this is possible.
 
2525
@return DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */
3286
2526
static
3287
2527
ulint
3288
2528
ibuf_insert_low(
3289
2529
/*============*/
3290
2530
        ulint           mode,   /*!< in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */
3291
 
        ibuf_op_t       op,     /*!< in: operation type */
3292
 
        ibool           no_counter,
3293
 
                                /*!< in: TRUE=use 5.0.3 format;
3294
 
                                FALSE=allow delete buffering */
3295
2531
        const dtuple_t* entry,  /*!< in: index entry to insert */
3296
2532
        ulint           entry_size,
3297
2533
                                /*!< in: rec_get_converted_size(index, entry) */
3308
2544
        dtuple_t*       ibuf_entry;
3309
2545
        mem_heap_t*     heap;
3310
2546
        ulint           buffered;
3311
 
        lint            min_n_recs;
3312
2547
        rec_t*          ins_rec;
3313
2548
        ibool           old_bit_value;
3314
2549
        page_t*         bitmap_page;
3315
 
        buf_block_t*    block;
3316
2550
        page_t*         root;
3317
2551
        ulint           err;
3318
2552
        ibool           do_merge;
3320
2554
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
3321
2555
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
3322
2556
        ulint           n_stored;
 
2557
        ulint           bits;
3323
2558
        mtr_t           mtr;
3324
2559
        mtr_t           bitmap_mtr;
3325
2560
 
3326
2561
        ut_a(!dict_index_is_clust(index));
3327
2562
        ut_ad(dtuple_check_typed(entry));
3328
2563
        ut_ad(ut_is_2pow(zip_size));
3329
 
        ut_ad(!no_counter || op == IBUF_OP_INSERT);
3330
 
        ut_a(op < IBUF_OP_COUNT);
3331
2564
 
3332
2565
        ut_a(trx_sys_multiple_tablespace_format);
3333
2566
 
3334
2567
        do_merge = FALSE;
3335
2568
 
3336
 
        /* Perform dirty reads of ibuf->size and ibuf->max_size, to
3337
 
        reduce ibuf_mutex contention. ibuf->max_size remains constant
3338
 
        after ibuf_init_at_db_start(), but ibuf->size should be
3339
 
        protected by ibuf_mutex. Given that ibuf->size fits in a
3340
 
        machine word, this should be OK; at worst we are doing some
3341
 
        excessive ibuf_contract() or occasionally skipping a
3342
 
        ibuf_contract(). */
 
2569
        mutex_enter(&ibuf_mutex);
 
2570
 
3343
2571
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
3344
2572
                /* Insert buffer is now too big, contract it but do not try
3345
2573
                to insert */
3346
2574
 
 
2575
                mutex_exit(&ibuf_mutex);
3347
2576
 
3348
2577
#ifdef UNIV_IBUF_DEBUG
3349
2578
                fputs("Ibuf too big\n", stderr);
3354
2583
                return(DB_STRONG_FAIL);
3355
2584
        }
3356
2585
 
 
2586
        mutex_exit(&ibuf_mutex);
 
2587
 
 
2588
        if (mode == BTR_MODIFY_TREE) {
 
2589
                mutex_enter(&ibuf_pessimistic_insert_mutex);
 
2590
 
 
2591
                ibuf_enter();
 
2592
 
 
2593
                mutex_enter(&ibuf_mutex);
 
2594
 
 
2595
                while (!ibuf_data_enough_free_for_insert()) {
 
2596
 
 
2597
                        mutex_exit(&ibuf_mutex);
 
2598
 
 
2599
                        ibuf_exit();
 
2600
 
 
2601
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2602
 
 
2603
                        err = ibuf_add_free_page();
 
2604
 
 
2605
                        if (err == DB_STRONG_FAIL) {
 
2606
 
 
2607
                                return(err);
 
2608
                        }
 
2609
 
 
2610
                        mutex_enter(&ibuf_pessimistic_insert_mutex);
 
2611
 
 
2612
                        ibuf_enter();
 
2613
 
 
2614
                        mutex_enter(&ibuf_mutex);
 
2615
                }
 
2616
        } else {
 
2617
                ibuf_enter();
 
2618
        }
 
2619
 
3357
2620
        heap = mem_heap_create(512);
3358
2621
 
3359
 
        /* Build the entry which contains the space id and the page number
3360
 
        as the first fields and the type information for other fields, and
3361
 
        which will be inserted to the insert buffer. Using a counter value
3362
 
        of 0xFFFF we find the last record for (space, page_no), from which
3363
 
        we can then read the counter value N and use N + 1 in the record we
3364
 
        insert. (We patch the ibuf_entry's counter field to the correct
3365
 
        value just before actually inserting the entry.) */
 
2622
        /* Build the entry which contains the space id and the page number as
 
2623
        the first fields and the type information for other fields, and which
 
2624
        will be inserted to the insert buffer. */
3366
2625
 
3367
 
        ibuf_entry = ibuf_entry_build(
3368
 
                op, index, entry, space, page_no,
3369
 
                no_counter ? ULINT_UNDEFINED : 0xFFFF, heap);
 
2626
        ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap);
3370
2627
 
3371
2628
        /* Open a cursor to the insert buffer tree to calculate if we can add
3372
2629
        the new entry to it without exceeding the free space limit for the
3373
2630
        page. */
3374
2631
 
3375
 
        if (mode == BTR_MODIFY_TREE) {
3376
 
                for (;;) {
3377
 
                        ibuf_enter();
3378
 
                        mutex_enter(&ibuf_pessimistic_insert_mutex);
3379
 
                        mutex_enter(&ibuf_mutex);
3380
 
 
3381
 
                        if (UNIV_LIKELY(ibuf_data_enough_free_for_insert())) {
3382
 
 
3383
 
                                break;
3384
 
                        }
3385
 
 
3386
 
                        mutex_exit(&ibuf_mutex);
3387
 
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
3388
 
                        ibuf_exit();
3389
 
 
3390
 
                        if (UNIV_UNLIKELY(!ibuf_add_free_page())) {
3391
 
 
3392
 
                                mem_heap_free(heap);
3393
 
                                return(DB_STRONG_FAIL);
3394
 
                        }
3395
 
                }
3396
 
        } else {
3397
 
                ibuf_enter();
3398
 
        }
3399
 
 
3400
2632
        mtr_start(&mtr);
3401
2633
 
3402
2634
        btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
3403
 
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
3404
2635
 
3405
2636
        /* Find out the volume of already buffered inserts for the same index
3406
2637
        page */
3407
 
        min_n_recs = 0;
3408
 
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no,
3409
 
                                            op == IBUF_OP_DELETE
3410
 
                                            ? &min_n_recs
3411
 
                                            : NULL, &mtr);
3412
 
 
3413
 
        if (op == IBUF_OP_DELETE
3414
 
            && (min_n_recs < 2
3415
 
                || buf_pool_watch_occurred(space, page_no))) {
3416
 
                /* The page could become empty after the record is
3417
 
                deleted, or the page has been read in to the buffer
3418
 
                pool.  Refuse to buffer the operation. */
3419
 
 
3420
 
                /* The buffer pool watch is needed for IBUF_OP_DELETE
3421
 
                because of latching order considerations.  We can
3422
 
                check buf_pool_watch_occurred() only after latching
3423
 
                the insert buffer B-tree pages that contain buffered
3424
 
                changes for the page.  We never buffer IBUF_OP_DELETE,
3425
 
                unless some IBUF_OP_INSERT or IBUF_OP_DELETE_MARK have
3426
 
                been previously buffered for the page.  Because there
3427
 
                are buffered operations for the page, the insert
3428
 
                buffer B-tree page latches held by mtr will guarantee
3429
 
                that no changes for the user page will be merged
3430
 
                before mtr_commit(&mtr).  We must not mtr_commit(&mtr)
3431
 
                until after the IBUF_OP_DELETE has been buffered. */
3432
 
 
3433
 
fail_exit:
3434
 
                if (mode == BTR_MODIFY_TREE) {
3435
 
                        mutex_exit(&ibuf_mutex);
3436
 
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
3437
 
                }
3438
 
 
3439
 
                err = DB_STRONG_FAIL;
3440
 
                goto func_exit;
3441
 
        }
3442
 
 
3443
 
        /* After this point, the page could still be loaded to the
3444
 
        buffer pool, but we do not have to care about it, since we are
3445
 
        holding a latch on the insert buffer leaf page that contains
3446
 
        buffered changes for (space, page_no).  If the page enters the
3447
 
        buffer pool, buf_page_io_complete() for (space, page_no) will
3448
 
        have to acquire a latch on the same insert buffer leaf page,
3449
 
        which it cannot do until we have buffered the IBUF_OP_DELETE
3450
 
        and done mtr_commit(&mtr) to release the latch. */
 
2638
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
3451
2639
 
3452
2640
#ifdef UNIV_IBUF_COUNT_DEBUG
3453
2641
        ut_a((buffered == 0) || ibuf_count_get(space, page_no));
3461
2649
 
3462
2650
        if (buf_page_peek(space, page_no)
3463
2651
            || lock_rec_expl_exist_on_page(space, page_no)) {
3464
 
 
3465
 
                goto bitmap_fail;
3466
 
        }
3467
 
 
3468
 
        if (op == IBUF_OP_INSERT) {
3469
 
                ulint   bits = ibuf_bitmap_page_get_bits(
3470
 
                        bitmap_page, page_no, zip_size, IBUF_BITMAP_FREE,
3471
 
                        &bitmap_mtr);
3472
 
 
3473
 
                if (buffered + entry_size + page_dir_calc_reserved_space(1)
3474
 
                    > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
3475
 
                        /* Release the bitmap page latch early. */
3476
 
                        mtr_commit(&bitmap_mtr);
3477
 
 
3478
 
                        /* It may not fit */
3479
 
                        do_merge = TRUE;
3480
 
 
3481
 
                        ibuf_get_merge_page_nos(
3482
 
                                FALSE, btr_pcur_get_rec(&pcur),
3483
 
                                space_ids, space_versions,
3484
 
                                page_nos, &n_stored);
3485
 
 
3486
 
                        goto fail_exit;
3487
 
                }
3488
 
        }
3489
 
 
3490
 
        /* Patch correct counter value to the entry to insert. This can
3491
 
        change the insert position, which can result in the need to abort in
3492
 
        some cases. */
3493
 
        if (!no_counter
3494
 
            && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur,
3495
 
                                       mode == BTR_MODIFY_PREV, &mtr)) {
3496
 
bitmap_fail:
3497
 
                mtr_commit(&bitmap_mtr);
3498
 
 
3499
 
                goto fail_exit;
 
2652
                err = DB_STRONG_FAIL;
 
2653
 
 
2654
                mtr_commit(&bitmap_mtr);
 
2655
 
 
2656
                goto function_exit;
 
2657
        }
 
2658
 
 
2659
        bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
 
2660
                                         IBUF_BITMAP_FREE, &bitmap_mtr);
 
2661
 
 
2662
        if (buffered + entry_size + page_dir_calc_reserved_space(1)
 
2663
            > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
 
2664
                mtr_commit(&bitmap_mtr);
 
2665
 
 
2666
                /* It may not fit */
 
2667
                err = DB_STRONG_FAIL;
 
2668
 
 
2669
                do_merge = TRUE;
 
2670
 
 
2671
                ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
 
2672
                                        space_ids, space_versions,
 
2673
                                        page_nos, &n_stored);
 
2674
                goto function_exit;
3500
2675
        }
3501
2676
 
3502
2677
        /* Set the bitmap bit denoting that the insert buffer contains
3520
2695
                err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
3521
2696
                                                ibuf_entry, &ins_rec,
3522
2697
                                                &dummy_big_rec, 0, thr, &mtr);
3523
 
                block = btr_cur_get_block(cursor);
3524
 
                ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
3525
 
 
3526
 
                /* If this is the root page, update ibuf->empty. */
3527
 
                if (UNIV_UNLIKELY(buf_block_get_page_no(block)
3528
 
                                  == FSP_IBUF_TREE_ROOT_PAGE_NO)) {
3529
 
                        const page_t*   page_root = buf_block_get_frame(block);
3530
 
 
3531
 
                        ut_ad(page_get_space_id(page_root) == IBUF_SPACE_ID);
3532
 
                        ut_ad(page_get_page_no(page_root)
3533
 
                              == FSP_IBUF_TREE_ROOT_PAGE_NO);
3534
 
 
3535
 
                        ibuf->empty = (page_get_n_recs(page_root) == 0);
 
2698
                if (err == DB_SUCCESS) {
 
2699
                        /* Update the page max trx id field */
 
2700
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
 
2701
                                               thr_get_trx(thr)->id, &mtr);
3536
2702
                }
3537
2703
        } else {
3538
2704
                ut_ad(mode == BTR_MODIFY_TREE);
3549
2715
                                                 cursor,
3550
2716
                                                 ibuf_entry, &ins_rec,
3551
2717
                                                 &dummy_big_rec, 0, thr, &mtr);
3552
 
                mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2718
                if (err == DB_SUCCESS) {
 
2719
                        /* Update the page max trx id field */
 
2720
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
 
2721
                                               thr_get_trx(thr)->id, &mtr);
 
2722
                }
 
2723
 
3553
2724
                ibuf_size_update(root, &mtr);
3554
 
                mutex_exit(&ibuf_mutex);
3555
 
                ibuf->empty = (page_get_n_recs(root) == 0);
3556
 
 
3557
 
                block = btr_cur_get_block(cursor);
3558
 
                ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
3559
 
        }
3560
 
 
3561
 
        if (err == DB_SUCCESS && op != IBUF_OP_DELETE) {
3562
 
                /* Update the page max trx id field */
3563
 
                page_update_max_trx_id(block, NULL,
3564
 
                                       thr_get_trx(thr)->id, &mtr);
3565
 
        }
3566
 
 
3567
 
func_exit:
 
2725
        }
 
2726
 
 
2727
function_exit:
3568
2728
#ifdef UNIV_IBUF_COUNT_DEBUG
3569
2729
        if (err == DB_SUCCESS) {
3570
2730
                fprintf(stderr,
3576
2736
                               ibuf_count_get(space, page_no) + 1);
3577
2737
        }
3578
2738
#endif
 
2739
        if (mode == BTR_MODIFY_TREE) {
 
2740
 
 
2741
                mutex_exit(&ibuf_mutex);
 
2742
                mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2743
        }
3579
2744
 
3580
2745
        mtr_commit(&mtr);
3581
2746
        btr_pcur_close(&pcur);
3583
2748
 
3584
2749
        mem_heap_free(heap);
3585
2750
 
3586
 
        if (err == DB_SUCCESS && mode == BTR_MODIFY_TREE) {
3587
 
                ibuf_contract_after_insert(entry_size);
 
2751
        if (err == DB_SUCCESS) {
 
2752
                mutex_enter(&ibuf_mutex);
 
2753
 
 
2754
                ibuf->empty = FALSE;
 
2755
                ibuf->n_inserts++;
 
2756
 
 
2757
                mutex_exit(&ibuf_mutex);
 
2758
 
 
2759
                if (mode == BTR_MODIFY_TREE) {
 
2760
                        ibuf_contract_after_insert(entry_size);
 
2761
                }
3588
2762
        }
3589
2763
 
3590
2764
        if (do_merge) {
3599
2773
}
3600
2774
 
3601
2775
/*********************************************************************//**
3602
 
Buffer an operation in the insert/delete buffer, instead of doing it
3603
 
directly to the disk page, if this is possible. Does not do it if the index
3604
 
is clustered or unique.
 
2776
Makes an index insert to the insert buffer, instead of directly to the disk
 
2777
page, if this is possible. Does not do insert if the index is clustered
 
2778
or unique.
3605
2779
@return TRUE if success */
3606
2780
UNIV_INTERN
3607
2781
ibool
3608
2782
ibuf_insert(
3609
2783
/*========*/
3610
 
        ibuf_op_t       op,     /*!< in: operation type */
3611
2784
        const dtuple_t* entry,  /*!< in: index entry to insert */
3612
2785
        dict_index_t*   index,  /*!< in: index where to insert */
3613
2786
        ulint           space,  /*!< in: space id where to insert */
3615
2788
        ulint           page_no,/*!< in: page number where to insert */
3616
2789
        que_thr_t*      thr)    /*!< in: query thread */
3617
2790
{
3618
 
        ulint           err;
3619
 
        ulint           entry_size;
3620
 
        ibool           no_counter;
3621
 
        /* Read the settable global variable ibuf_use only once in
3622
 
        this function, so that we will have a consistent view of it. */
3623
 
        ibuf_use_t      use             = ibuf_use;
 
2791
        ulint   err;
 
2792
        ulint   entry_size;
3624
2793
 
3625
2794
        ut_a(trx_sys_multiple_tablespace_format);
3626
2795
        ut_ad(dtuple_check_typed(entry));
3628
2797
 
3629
2798
        ut_a(!dict_index_is_clust(index));
3630
2799
 
3631
 
        no_counter = use <= IBUF_USE_INSERT;
3632
 
 
3633
 
        switch (op) {
3634
 
        case IBUF_OP_INSERT:
3635
 
                switch (use) {
3636
 
                case IBUF_USE_NONE:
3637
 
                case IBUF_USE_DELETE:
3638
 
                case IBUF_USE_DELETE_MARK:
3639
 
                        return(FALSE);
3640
 
                case IBUF_USE_INSERT:
3641
 
                case IBUF_USE_INSERT_DELETE_MARK:
3642
 
                case IBUF_USE_ALL:
3643
 
                        goto check_watch;
3644
 
                case IBUF_USE_COUNT:
3645
 
                        break;
3646
 
                }
3647
 
                break;
3648
 
        case IBUF_OP_DELETE_MARK:
3649
 
                switch (use) {
3650
 
                case IBUF_USE_NONE:
3651
 
                case IBUF_USE_INSERT:
3652
 
                        return(FALSE);
3653
 
                case IBUF_USE_DELETE_MARK:
3654
 
                case IBUF_USE_DELETE:
3655
 
                case IBUF_USE_INSERT_DELETE_MARK:
3656
 
                case IBUF_USE_ALL:
3657
 
                        ut_ad(!no_counter);
3658
 
                        goto check_watch;
3659
 
                case IBUF_USE_COUNT:
3660
 
                        break;
3661
 
                }
3662
 
                break;
3663
 
        case IBUF_OP_DELETE:
3664
 
                switch (use) {
3665
 
                case IBUF_USE_NONE:
3666
 
                case IBUF_USE_INSERT:
3667
 
                case IBUF_USE_INSERT_DELETE_MARK:
3668
 
                        return(FALSE);
3669
 
                case IBUF_USE_DELETE_MARK:
3670
 
                case IBUF_USE_DELETE:
3671
 
                case IBUF_USE_ALL:
3672
 
                        ut_ad(!no_counter);
3673
 
                        goto skip_watch;
3674
 
                case IBUF_USE_COUNT:
3675
 
                        break;
3676
 
                }
3677
 
                break;
3678
 
        case IBUF_OP_COUNT:
3679
 
                break;
3680
 
        }
3681
 
 
3682
 
        /* unknown op or use */
3683
 
        ut_error;
3684
 
 
3685
 
check_watch:
3686
 
        /* If a thread attempts to buffer an insert on a page while a
3687
 
        purge is in progress on the same page, the purge must not be
3688
 
        buffered, because it could remove a record that was
3689
 
        re-inserted later.  For simplicity, we block the buffering of
3690
 
        all operations on a page that has a purge pending.
3691
 
 
3692
 
        We do not check this in the IBUF_OP_DELETE case, because that
3693
 
        would always trigger the buffer pool watch during purge and
3694
 
        thus prevent the buffering of delete operations.  We assume
3695
 
        that the issuer of IBUF_OP_DELETE has called
3696
 
        buf_pool_watch_set(space, page_no). */
3697
 
 
3698
 
        {
3699
 
                buf_page_t*     bpage;
3700
 
                ulint           fold = buf_page_address_fold(space, page_no);
3701
 
                buf_pool_t*     buf_pool = buf_pool_get(space, page_no);
3702
 
 
3703
 
                buf_pool_mutex_enter(buf_pool);
3704
 
                bpage = buf_page_hash_get_low(buf_pool, space, page_no, fold);
3705
 
                buf_pool_mutex_exit(buf_pool);
3706
 
 
3707
 
                if (UNIV_LIKELY_NULL(bpage)) {
3708
 
                        /* A buffer pool watch has been set or the
3709
 
                        page has been read into the buffer pool.
3710
 
                        Do not buffer the request.  If a purge operation
3711
 
                        is being buffered, have this request executed
3712
 
                        directly on the page in the buffer pool after the
3713
 
                        buffered entries for this page have been merged. */
3714
 
                        return(FALSE);
3715
 
                }
3716
 
        }
3717
 
 
3718
 
skip_watch:
 
2800
        switch (UNIV_EXPECT(ibuf_use, IBUF_USE_INSERT)) {
 
2801
        case IBUF_USE_NONE:
 
2802
                return(FALSE);
 
2803
        case IBUF_USE_INSERT:
 
2804
                goto do_insert;
 
2805
        case IBUF_USE_COUNT:
 
2806
                break;
 
2807
        }
 
2808
 
 
2809
        ut_error; /* unknown value of ibuf_use */
 
2810
 
 
2811
do_insert:
3719
2812
        entry_size = rec_get_converted_size(index, entry, 0);
3720
2813
 
3721
2814
        if (entry_size
3722
 
            >= page_get_free_space_of_empty(dict_table_is_comp(index->table))
3723
 
            / 2) {
3724
 
 
 
2815
            >= (page_get_free_space_of_empty(dict_table_is_comp(index->table))
 
2816
                / 2)) {
3725
2817
                return(FALSE);
3726
2818
        }
3727
2819
 
3728
 
        err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter,
3729
 
                              entry, entry_size,
 
2820
        err = ibuf_insert_low(BTR_MODIFY_PREV, entry, entry_size,
3730
2821
                              index, space, zip_size, page_no, thr);
3731
2822
        if (err == DB_FAIL) {
3732
 
                err = ibuf_insert_low(BTR_MODIFY_TREE, op, no_counter,
3733
 
                                      entry, entry_size,
 
2823
                err = ibuf_insert_low(BTR_MODIFY_TREE, entry, entry_size,
3734
2824
                                      index, space, zip_size, page_no, thr);
3735
2825
        }
3736
2826
 
3753
2843
from the insert buffer. */
3754
2844
static
3755
2845
void
3756
 
ibuf_insert_to_index_page_low(
3757
 
/*==========================*/
3758
 
        const dtuple_t* entry,  /*!< in: buffered entry to insert */
3759
 
        buf_block_t*    block,  /*!< in/out: index page where the buffered
3760
 
                                entry should be placed */
3761
 
        dict_index_t*   index,  /*!< in: record descriptor */
3762
 
        mtr_t*          mtr,    /*!< in/out: mtr */
3763
 
        page_cur_t*     page_cur)/*!< in/out: cursor positioned on the record
3764
 
                                after which to insert the buffered entry */
3765
 
{
3766
 
        const page_t*   page;
3767
 
        ulint           space;
3768
 
        ulint           page_no;
3769
 
        ulint           zip_size;
3770
 
        const page_t*   bitmap_page;
3771
 
        ulint           old_bits;
3772
 
 
3773
 
        if (UNIV_LIKELY
3774
 
            (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
3775
 
                return;
3776
 
        }
3777
 
 
3778
 
        /* If the record did not fit, reorganize */
3779
 
 
3780
 
        btr_page_reorganize(block, index, mtr);
3781
 
        page_cur_search(block, index, entry, PAGE_CUR_LE, page_cur);
3782
 
 
3783
 
        /* This time the record must fit */
3784
 
 
3785
 
        if (UNIV_LIKELY
3786
 
            (page_cur_tuple_insert(page_cur, entry, index, 0, mtr) != NULL)) {
3787
 
                return;
3788
 
        }
3789
 
 
3790
 
        page = buf_block_get_frame(block);
3791
 
 
3792
 
        ut_print_timestamp(stderr);
3793
 
 
3794
 
        fprintf(stderr,
3795
 
                "  InnoDB: Error: Insert buffer insert fails;"
3796
 
                " page free %lu, dtuple size %lu\n",
3797
 
                (ulong) page_get_max_insert_size(page, 1),
3798
 
                (ulong) rec_get_converted_size(index, entry, 0));
3799
 
        fputs("InnoDB: Cannot insert index record ", stderr);
3800
 
        dtuple_print(stderr, entry);
3801
 
        fputs("\nInnoDB: The table where this index record belongs\n"
3802
 
              "InnoDB: is now probably corrupt. Please run CHECK TABLE on\n"
3803
 
              "InnoDB: that table.\n", stderr);
3804
 
 
3805
 
        space = page_get_space_id(page);
3806
 
        zip_size = buf_block_get_zip_size(block);
3807
 
        page_no = page_get_page_no(page);
3808
 
 
3809
 
        bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr);
3810
 
        old_bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
3811
 
                                             IBUF_BITMAP_FREE, mtr);
3812
 
 
3813
 
        fprintf(stderr,
3814
 
                "InnoDB: space %lu, page %lu, zip_size %lu, bitmap bits %lu\n",
3815
 
                (ulong) space, (ulong) page_no,
3816
 
                (ulong) zip_size, (ulong) old_bits);
3817
 
 
3818
 
        fputs("InnoDB: Submit a detailed bug report"
3819
 
              " to http://bugs.mysql.com\n", stderr);
3820
 
}
3821
 
 
3822
 
/************************************************************************
3823
 
During merge, inserts to an index page a secondary index entry extracted
3824
 
from the insert buffer. */
3825
 
static
3826
 
void
3827
2846
ibuf_insert_to_index_page(
3828
2847
/*======================*/
3829
 
        const dtuple_t* entry,  /*!< in: buffered entry to insert */
 
2848
        dtuple_t*       entry,  /*!< in: buffered entry to insert */
3830
2849
        buf_block_t*    block,  /*!< in/out: index page where the buffered entry
3831
2850
                                should be placed */
3832
2851
        dict_index_t*   index,  /*!< in: record descriptor */
3836
2855
        ulint           low_match;
3837
2856
        page_t*         page            = buf_block_get_frame(block);
3838
2857
        rec_t*          rec;
 
2858
        page_t*         bitmap_page;
 
2859
        ulint           old_bits;
3839
2860
 
3840
2861
        ut_ad(ibuf_inside());
3841
2862
        ut_ad(dtuple_check_typed(entry));
3842
 
        ut_ad(!buf_block_align(page)->is_hashed);
3843
2863
 
3844
2864
        if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
3845
2865
                          != (ibool)!!page_is_comp(page))) {
3852
2872
 
3853
2873
        rec = page_rec_get_next(page_get_infimum_rec(page));
3854
2874
 
3855
 
        if (page_rec_is_supremum(rec)) {
3856
 
                fputs("InnoDB: Trying to insert a record from"
3857
 
                      " the insert buffer to an index page\n"
3858
 
                      "InnoDB: but the index page is empty!\n",
3859
 
                      stderr);
3860
 
                goto dump;
3861
 
        }
3862
 
 
3863
2875
        if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
3864
2876
                          != dtuple_get_n_fields(entry))) {
3865
2877
                fputs("InnoDB: Trying to insert a record from"
3885
2897
        low_match = page_cur_search(block, index, entry,
3886
2898
                                    PAGE_CUR_LE, &page_cur);
3887
2899
 
3888
 
        if (UNIV_UNLIKELY(low_match == dtuple_get_n_fields(entry))) {
3889
 
                mem_heap_t*     heap;
3890
 
                upd_t*          update;
3891
 
                ulint*          offsets;
 
2900
        if (low_match == dtuple_get_n_fields(entry)) {
3892
2901
                page_zip_des_t* page_zip;
3893
2902
 
3894
2903
                rec = page_cur_get_rec(&page_cur);
3895
 
 
3896
 
                /* This is based on
3897
 
                row_ins_sec_index_entry_by_modify(BTR_MODIFY_LEAF). */
3898
 
                ut_ad(rec_get_deleted_flag(rec, page_is_comp(page)));
3899
 
 
3900
 
                heap = mem_heap_create(1024);
3901
 
 
3902
 
                offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED,
3903
 
                                          &heap);
3904
 
                update = row_upd_build_sec_rec_difference_binary(
3905
 
                        index, entry, rec, NULL, heap);
3906
 
 
3907
2904
                page_zip = buf_block_get_page_zip(block);
3908
2905
 
3909
 
                if (update->n_fields == 0) {
3910
 
                        /* The records only differ in the delete-mark.
3911
 
                        Clear the delete-mark, like we did before
3912
 
                        Bug #56680 was fixed. */
3913
 
                        btr_cur_set_deleted_flag_for_ibuf(
3914
 
                                rec, page_zip, FALSE, mtr);
3915
 
updated_in_place:
3916
 
                        mem_heap_free(heap);
 
2906
                btr_cur_del_unmark_for_ibuf(rec, page_zip, mtr);
 
2907
        } else {
 
2908
                rec = page_cur_tuple_insert(&page_cur, entry, index, 0, mtr);
 
2909
 
 
2910
                if (UNIV_LIKELY(rec != NULL)) {
3917
2911
                        return;
3918
2912
                }
3919
2913
 
3920
 
                /* Copy the info bits. Clear the delete-mark. */
3921
 
                update->info_bits = rec_get_info_bits(rec, page_is_comp(page));
3922
 
                update->info_bits &= ~REC_INFO_DELETED_FLAG;
3923
 
 
3924
 
                /* We cannot invoke btr_cur_optimistic_update() here,
3925
 
                because we do not have a btr_cur_t or que_thr_t,
3926
 
                as the insert buffer merge occurs at a very low level. */
3927
 
                if (!row_upd_changes_field_size_or_external(index, offsets,
3928
 
                                                            update)
3929
 
                    && (!page_zip || btr_cur_update_alloc_zip(
3930
 
                                page_zip, block, index,
3931
 
                                rec_offs_size(offsets), FALSE, mtr))) {
3932
 
                        /* This is the easy case. Do something similar
3933
 
                        to btr_cur_update_in_place(). */
3934
 
                        row_upd_rec_in_place(rec, index, offsets,
3935
 
                                             update, page_zip);
3936
 
                        goto updated_in_place;
3937
 
                }
3938
 
 
3939
 
                /* A collation may identify values that differ in
3940
 
                storage length.
3941
 
                Some examples (1 or 2 bytes):
3942
 
                utf8_turkish_ci: I = U+0131 LATIN SMALL LETTER DOTLESS I
3943
 
                utf8_general_ci: S = U+00DF LATIN SMALL LETTER SHARP S
3944
 
                utf8_general_ci: A = U+00E4 LATIN SMALL LETTER A WITH DIAERESIS
3945
 
 
3946
 
                latin1_german2_ci: SS = U+00DF LATIN SMALL LETTER SHARP S
3947
 
 
3948
 
                Examples of a character (3-byte UTF-8 sequence)
3949
 
                identified with 2 or 4 characters (1-byte UTF-8 sequences):
3950
 
 
3951
 
                utf8_unicode_ci: 'II' = U+2171 SMALL ROMAN NUMERAL TWO
3952
 
                utf8_unicode_ci: '(10)' = U+247D PARENTHESIZED NUMBER TEN
3953
 
                */
3954
 
 
3955
 
                /* Delete the different-length record, and insert the
3956
 
                buffered one. */
3957
 
 
3958
 
                lock_rec_store_on_page_infimum(block, rec);
3959
 
                page_cur_delete_rec(&page_cur, index, offsets, mtr);
3960
 
                page_cur_move_to_prev(&page_cur);
3961
 
                mem_heap_free(heap);
3962
 
 
3963
 
                ibuf_insert_to_index_page_low(entry, block, index, mtr,
3964
 
                                              &page_cur);
3965
 
                lock_rec_restore_from_page_infimum(block, rec, block);
3966
 
        } else {
3967
 
                ibuf_insert_to_index_page_low(entry, block, index, mtr,
3968
 
                                              &page_cur);
3969
 
        }
3970
 
}
3971
 
 
3972
 
/****************************************************************//**
3973
 
During merge, sets the delete mark on a record for a secondary index
3974
 
entry. */
3975
 
static
3976
 
void
3977
 
ibuf_set_del_mark(
3978
 
/*==============*/
3979
 
        const dtuple_t*         entry,  /*!< in: entry */
3980
 
        buf_block_t*            block,  /*!< in/out: block */
3981
 
        const dict_index_t*     index,  /*!< in: record descriptor */
3982
 
        mtr_t*                  mtr)    /*!< in: mtr */
3983
 
{
3984
 
        page_cur_t      page_cur;
3985
 
        ulint           low_match;
3986
 
 
3987
 
        ut_ad(ibuf_inside());
3988
 
        ut_ad(dtuple_check_typed(entry));
3989
 
 
3990
 
        low_match = page_cur_search(
3991
 
                block, index, entry, PAGE_CUR_LE, &page_cur);
3992
 
 
3993
 
        if (low_match == dtuple_get_n_fields(entry)) {
3994
 
                rec_t*          rec;
3995
 
                page_zip_des_t* page_zip;
3996
 
 
3997
 
                rec = page_cur_get_rec(&page_cur);
3998
 
                page_zip = page_cur_get_page_zip(&page_cur);
3999
 
 
4000
 
                /* Delete mark the old index record. According to a
4001
 
                comment in row_upd_sec_index_entry(), it can already
4002
 
                have been delete marked if a lock wait occurred in
4003
 
                row_ins_index_entry() in a previous invocation of
4004
 
                row_upd_sec_index_entry(). */
4005
 
 
4006
 
                if (UNIV_LIKELY
4007
 
                    (!rec_get_deleted_flag(
4008
 
                            rec, dict_table_is_comp(index->table)))) {
4009
 
                        btr_cur_set_deleted_flag_for_ibuf(rec, page_zip,
4010
 
                                                          TRUE, mtr);
4011
 
                }
4012
 
        } else {
4013
 
                ut_print_timestamp(stderr);
4014
 
                fputs("  InnoDB: unable to find a record to delete-mark\n",
4015
 
                      stderr);
4016
 
                fputs("InnoDB: tuple ", stderr);
4017
 
                dtuple_print(stderr, entry);
4018
 
                fputs("\n"
4019
 
                      "InnoDB: record ", stderr);
4020
 
                rec_print(stderr, page_cur_get_rec(&page_cur), index);
4021
 
                putc('\n', stderr);
4022
 
                fputs("\n"
4023
 
                      "InnoDB: Submit a detailed bug report"
4024
 
                      " to http://bugs.mysql.com\n", stderr);
4025
 
                ut_ad(0);
4026
 
        }
4027
 
}
4028
 
 
4029
 
/****************************************************************//**
4030
 
During merge, delete a record for a secondary index entry. */
4031
 
static
4032
 
void
4033
 
ibuf_delete(
4034
 
/*========*/
4035
 
        const dtuple_t* entry,  /*!< in: entry */
4036
 
        buf_block_t*    block,  /*!< in/out: block */
4037
 
        dict_index_t*   index,  /*!< in: record descriptor */
4038
 
        mtr_t*          mtr)    /*!< in/out: mtr; must be committed
4039
 
                                before latching any further pages */
4040
 
{
4041
 
        page_cur_t      page_cur;
4042
 
        ulint           low_match;
4043
 
 
4044
 
        ut_ad(ibuf_inside());
4045
 
        ut_ad(dtuple_check_typed(entry));
4046
 
 
4047
 
        low_match = page_cur_search(
4048
 
                block, index, entry, PAGE_CUR_LE, &page_cur);
4049
 
 
4050
 
        if (low_match == dtuple_get_n_fields(entry)) {
4051
 
                page_zip_des_t* page_zip= buf_block_get_page_zip(block);
4052
 
                page_t*         page    = buf_block_get_frame(block);
4053
 
                rec_t*          rec     = page_cur_get_rec(&page_cur);
4054
 
 
4055
 
                /* TODO: the below should probably be a separate function,
4056
 
                it's a bastardized version of btr_cur_optimistic_delete. */
4057
 
 
4058
 
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
4059
 
                ulint*          offsets = offsets_;
4060
 
                mem_heap_t*     heap = NULL;
4061
 
                ulint           max_ins_size;
4062
 
 
4063
 
                rec_offs_init(offsets_);
4064
 
 
4065
 
                offsets = rec_get_offsets(
4066
 
                        rec, index, offsets, ULINT_UNDEFINED, &heap);
4067
 
 
4068
 
                /* Refuse to delete the last record. */
4069
 
                ut_a(page_get_n_recs(page) > 1);
4070
 
 
4071
 
                /* The record should have been marked for deletion. */
4072
 
                ut_ad(REC_INFO_DELETED_FLAG
4073
 
                      & rec_get_info_bits(rec, page_is_comp(page)));
4074
 
 
4075
 
                lock_update_delete(block, rec);
4076
 
 
4077
 
                if (!page_zip) {
4078
 
                        max_ins_size
4079
 
                                = page_get_max_insert_size_after_reorganize(
4080
 
                                        page, 1);
4081
 
                }
4082
 
#ifdef UNIV_ZIP_DEBUG
4083
 
                ut_a(!page_zip || page_zip_validate(page_zip, page));
4084
 
#endif /* UNIV_ZIP_DEBUG */
4085
 
                page_cur_delete_rec(&page_cur, index, offsets, mtr);
4086
 
#ifdef UNIV_ZIP_DEBUG
4087
 
                ut_a(!page_zip || page_zip_validate(page_zip, page));
4088
 
#endif /* UNIV_ZIP_DEBUG */
4089
 
 
4090
 
                if (page_zip) {
4091
 
                        ibuf_update_free_bits_zip(block, mtr);
4092
 
                } else {
4093
 
                        ibuf_update_free_bits_low(block, max_ins_size, mtr);
4094
 
                }
4095
 
 
4096
 
                if (UNIV_LIKELY_NULL(heap)) {
4097
 
                        mem_heap_free(heap);
4098
 
                }
4099
 
        } else {
4100
 
                /* The record must have been purged already. */
4101
 
        }
4102
 
}
4103
 
 
4104
 
/*********************************************************************//**
4105
 
Restores insert buffer tree cursor position
4106
 
@return TRUE if the position was restored; FALSE if not */
4107
 
static __attribute__((nonnull))
4108
 
ibool
4109
 
ibuf_restore_pos(
4110
 
/*=============*/
4111
 
        ulint           space,  /*!< in: space id */
4112
 
        ulint           page_no,/*!< in: index page number where the record
4113
 
                                should belong */
4114
 
        const dtuple_t* search_tuple,
4115
 
                                /*!< in: search tuple for entries of page_no */
4116
 
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
4117
 
        btr_pcur_t*     pcur,   /*!< in/out: persistent cursor whose
4118
 
                                position is to be restored */
4119
 
        mtr_t*          mtr)    /*!< in/out: mini-transaction */
4120
 
{
4121
 
        ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE);
4122
 
 
4123
 
        if (btr_pcur_restore_position(mode, pcur, mtr)) {
4124
 
 
4125
 
                return(TRUE);
4126
 
        }
4127
 
 
4128
 
        if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
4129
 
                /* The tablespace has been dropped.  It is possible
4130
 
                that another thread has deleted the insert buffer
4131
 
                entry.  Do not complain. */
4132
 
                btr_pcur_commit_specify_mtr(pcur, mtr);
4133
 
        } else {
4134
 
                fprintf(stderr,
4135
 
                        "InnoDB: ERROR: Submit the output to"
4136
 
                        " http://bugs.mysql.com\n"
4137
 
                        "InnoDB: ibuf cursor restoration fails!\n"
4138
 
                        "InnoDB: ibuf record inserted to page %lu:%lu\n",
4139
 
                        (ulong) space, (ulong) page_no);
4140
 
                fflush(stderr);
4141
 
 
4142
 
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
4143
 
                rec_print_old(stderr, pcur->old_rec);
4144
 
                dtuple_print(stderr, search_tuple);
4145
 
 
4146
 
                rec_print_old(stderr,
4147
 
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
4148
 
                fflush(stderr);
4149
 
 
4150
 
                btr_pcur_commit_specify_mtr(pcur, mtr);
4151
 
 
4152
 
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
4153
 
                if (!btr_validate_index(ibuf->index, NULL)) {
4154
 
                        ut_error;
4155
 
                }
4156
 
 
4157
 
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
4158
 
                fflush(stderr);
4159
 
        }
4160
 
 
4161
 
        return(FALSE);
 
2914
                /* If the record did not fit, reorganize */
 
2915
 
 
2916
                btr_page_reorganize(block, index, mtr);
 
2917
                page_cur_search(block, index, entry, PAGE_CUR_LE, &page_cur);
 
2918
 
 
2919
                /* This time the record must fit */
 
2920
                if (UNIV_UNLIKELY
 
2921
                    (!page_cur_tuple_insert(&page_cur, entry, index,
 
2922
                                            0, mtr))) {
 
2923
                        ulint   space;
 
2924
                        ulint   page_no;
 
2925
                        ulint   zip_size;
 
2926
 
 
2927
                        ut_print_timestamp(stderr);
 
2928
 
 
2929
                        fprintf(stderr,
 
2930
                                "  InnoDB: Error: Insert buffer insert"
 
2931
                                " fails; page free %lu,"
 
2932
                                " dtuple size %lu\n",
 
2933
                                (ulong) page_get_max_insert_size(
 
2934
                                        page, 1),
 
2935
                                (ulong) rec_get_converted_size(
 
2936
                                        index, entry, 0));
 
2937
                        fputs("InnoDB: Cannot insert index record ",
 
2938
                              stderr);
 
2939
                        dtuple_print(stderr, entry);
 
2940
                        fputs("\nInnoDB: The table where"
 
2941
                              " this index record belongs\n"
 
2942
                              "InnoDB: is now probably corrupt."
 
2943
                              " Please run CHECK TABLE on\n"
 
2944
                              "InnoDB: that table.\n", stderr);
 
2945
 
 
2946
                        space = page_get_space_id(page);
 
2947
                        zip_size = buf_block_get_zip_size(block);
 
2948
                        page_no = page_get_page_no(page);
 
2949
 
 
2950
                        bitmap_page = ibuf_bitmap_get_map_page(
 
2951
                                space, page_no, zip_size, mtr);
 
2952
                        old_bits = ibuf_bitmap_page_get_bits(
 
2953
                                bitmap_page, page_no, zip_size,
 
2954
                                IBUF_BITMAP_FREE, mtr);
 
2955
 
 
2956
                        fprintf(stderr,
 
2957
                                "InnoDB: space %lu, page %lu,"
 
2958
                                " zip_size %lu, bitmap bits %lu\n",
 
2959
                                (ulong) space, (ulong) page_no,
 
2960
                                (ulong) zip_size, (ulong) old_bits);
 
2961
 
 
2962
                        fputs("InnoDB: Submit a detailed bug report"
 
2963
                              " to http://bugs.mysql.com\n", stderr);
 
2964
                }
 
2965
        }
4162
2966
}
4163
2967
 
4164
2968
/*********************************************************************//**
4191
2995
        success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
4192
2996
 
4193
2997
        if (success) {
4194
 
                if (UNIV_UNLIKELY(!page_get_n_recs(btr_pcur_get_page(pcur)))) {
4195
 
                        /* If a B-tree page is empty, it must be the root page
4196
 
                        and the whole B-tree must be empty. InnoDB does not
4197
 
                        allow empty B-tree pages other than the root. */
4198
 
                        root = btr_pcur_get_page(pcur);
4199
 
 
4200
 
                        ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
4201
 
                        ut_ad(page_get_page_no(root)
4202
 
                              == FSP_IBUF_TREE_ROOT_PAGE_NO);
4203
 
 
4204
 
                        /* ibuf->empty is protected by the root page latch.
4205
 
                        Before the deletion, it had to be FALSE. */
4206
 
                        ut_ad(!ibuf->empty);
4207
 
                        ibuf->empty = TRUE;
4208
 
                }
4209
 
 
4210
2998
#ifdef UNIV_IBUF_COUNT_DEBUG
4211
2999
                fprintf(stderr,
4212
3000
                        "Decrementing ibuf count of space %lu page %lu\n"
4231
3019
 
4232
3020
        mtr_start(mtr);
4233
3021
 
4234
 
        if (!ibuf_restore_pos(space, page_no, search_tuple,
4235
 
                              BTR_MODIFY_TREE, pcur, mtr)) {
4236
 
 
4237
 
                mutex_exit(&ibuf_mutex);
 
3022
        success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
 
3023
 
 
3024
        if (!success) {
 
3025
                if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
 
3026
                        /* The tablespace has been dropped.  It is possible
 
3027
                        that another thread has deleted the insert buffer
 
3028
                        entry.  Do not complain. */
 
3029
                        goto commit_and_exit;
 
3030
                }
 
3031
 
 
3032
                fprintf(stderr,
 
3033
                        "InnoDB: ERROR: Submit the output to"
 
3034
                        " http://bugs.mysql.com\n"
 
3035
                        "InnoDB: ibuf cursor restoration fails!\n"
 
3036
                        "InnoDB: ibuf record inserted to page %lu\n",
 
3037
                        (ulong) page_no);
 
3038
                fflush(stderr);
 
3039
 
 
3040
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
 
3041
                rec_print_old(stderr, pcur->old_rec);
 
3042
                dtuple_print(stderr, search_tuple);
 
3043
 
 
3044
                rec_print_old(stderr,
 
3045
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
 
3046
                fflush(stderr);
 
3047
 
 
3048
                btr_pcur_commit_specify_mtr(pcur, mtr);
 
3049
 
 
3050
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
 
3051
                if (!btr_validate_index(ibuf->index, NULL)) {
 
3052
                        ut_error;
 
3053
                }
 
3054
 
 
3055
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
 
3056
                fflush(stderr);
 
3057
 
4238
3058
                goto func_exit;
4239
3059
        }
4240
3060
 
4248
3068
        ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
4249
3069
#endif
4250
3070
        ibuf_size_update(root, mtr);
4251
 
        mutex_exit(&ibuf_mutex);
4252
3071
 
4253
 
        ibuf->empty = (page_get_n_recs(root) == 0);
 
3072
commit_and_exit:
4254
3073
        btr_pcur_commit_specify_mtr(pcur, mtr);
4255
3074
 
4256
3075
func_exit:
4257
3076
        btr_pcur_close(pcur);
4258
3077
 
 
3078
        mutex_exit(&ibuf_mutex);
 
3079
 
4259
3080
        return(TRUE);
4260
3081
}
4261
3082
 
4262
3083
/*********************************************************************//**
4263
3084
When an index page is read from a disk to the buffer pool, this function
4264
 
applies any buffered operations to the page and deletes the entries from the
4265
 
insert buffer. If the page is not read, but created in the buffer pool, this
4266
 
function deletes its buffered entries from the insert buffer; there can
4267
 
exist entries for such a page if the page belonged to an index which
4268
 
subsequently was dropped. */
 
3085
inserts to the page the possible index entries buffered in the insert buffer.
 
3086
The entries are deleted from the insert buffer. If the page is not read, but
 
3087
created in the buffer pool, this function deletes its buffered entries from
 
3088
the insert buffer; there can exist entries for such a page if the page
 
3089
belonged to an index which subsequently was dropped. */
4269
3090
UNIV_INTERN
4270
3091
void
4271
3092
ibuf_merge_or_delete_for_page(
4286
3107
        mem_heap_t*     heap;
4287
3108
        btr_pcur_t      pcur;
4288
3109
        dtuple_t*       search_tuple;
 
3110
        ulint           n_inserts;
4289
3111
#ifdef UNIV_IBUF_DEBUG
4290
 
        ulint           volume                  = 0;
 
3112
        ulint           volume;
4291
3113
#endif
4292
3114
        page_zip_des_t* page_zip                = NULL;
4293
3115
        ibool           tablespace_being_deleted = FALSE;
4294
3116
        ibool           corruption_noticed      = FALSE;
4295
3117
        mtr_t           mtr;
4296
3118
 
4297
 
        /* Counts for merged & discarded operations. */
4298
 
        ulint           mops[IBUF_OP_COUNT];
4299
 
        ulint           dops[IBUF_OP_COUNT];
4300
 
 
4301
3119
        ut_ad(!block || buf_block_get_space(block) == space);
4302
3120
        ut_ad(!block || buf_block_get_page_no(block) == page_no);
4303
3121
        ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
4440
3258
                }
4441
3259
        }
4442
3260
 
4443
 
        memset(mops, 0, sizeof(mops));
4444
 
        memset(dops, 0, sizeof(dops));
4445
 
 
 
3261
        n_inserts = 0;
 
3262
#ifdef UNIV_IBUF_DEBUG
 
3263
        volume = 0;
 
3264
#endif
4446
3265
loop:
4447
3266
        mtr_start(&mtr);
4448
3267
 
4495
3314
                        fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
4496
3315
                } else if (block) {
4497
3316
                        /* Now we have at pcur a record which should be
4498
 
                        applied on the index page; NOTE that the call below
 
3317
                        inserted to the index page; NOTE that the call below
4499
3318
                        copies pointers to fields in rec, and we must
4500
3319
                        keep the latch to the rec page until the
4501
3320
                        insertion is finished! */
4502
3321
                        dtuple_t*       entry;
4503
3322
                        trx_id_t        max_trx_id;
4504
3323
                        dict_index_t*   dummy_index;
4505
 
                        ibuf_op_t       op = ibuf_rec_get_op_type(rec);
4506
3324
 
4507
3325
                        max_trx_id = page_get_max_trx_id(page_align(rec));
4508
3326
                        page_update_max_trx_id(block, page_zip, max_trx_id,
4509
3327
                                               &mtr);
4510
3328
 
4511
 
                        ut_ad(page_validate(page_align(rec), ibuf->index));
4512
 
 
4513
3329
                        entry = ibuf_build_entry_from_ibuf_rec(
4514
3330
                                rec, heap, &dummy_index);
4515
 
 
4516
 
                        ut_ad(page_validate(block->frame, dummy_index));
4517
 
 
4518
 
                        switch (op) {
4519
 
                                ibool   success;
4520
 
                        case IBUF_OP_INSERT:
4521
3331
#ifdef UNIV_IBUF_DEBUG
4522
 
                                volume += rec_get_converted_size(
4523
 
                                        dummy_index, entry, 0);
4524
 
 
4525
 
                                volume += page_dir_calc_reserved_space(1);
4526
 
 
4527
 
                                ut_a(volume <= 4 * UNIV_PAGE_SIZE
4528
 
                                        / IBUF_PAGE_SIZE_PER_FREE_SPACE);
 
3332
                        volume += rec_get_converted_size(dummy_index, entry, 0)
 
3333
                                + page_dir_calc_reserved_space(1);
 
3334
                        ut_a(volume <= 4 * UNIV_PAGE_SIZE
 
3335
                             / IBUF_PAGE_SIZE_PER_FREE_SPACE);
4529
3336
#endif
4530
 
                                ibuf_insert_to_index_page(
4531
 
                                        entry, block, dummy_index, &mtr);
4532
 
                                break;
4533
 
 
4534
 
                        case IBUF_OP_DELETE_MARK:
4535
 
                                ibuf_set_del_mark(
4536
 
                                        entry, block, dummy_index, &mtr);
4537
 
                                break;
4538
 
 
4539
 
                        case IBUF_OP_DELETE:
4540
 
                                ibuf_delete(entry, block, dummy_index, &mtr);
4541
 
                                /* Because ibuf_delete() will latch an
4542
 
                                insert buffer bitmap page, commit mtr
4543
 
                                before latching any further pages.
4544
 
                                Store and restore the cursor position. */
4545
 
                                ut_ad(rec == btr_pcur_get_rec(&pcur));
4546
 
                                ut_ad(page_rec_is_user_rec(rec));
4547
 
                                ut_ad(ibuf_rec_get_page_no(rec) == page_no);
4548
 
                                ut_ad(ibuf_rec_get_space(rec) == space);
4549
 
 
4550
 
                                btr_pcur_store_position(&pcur, &mtr);
4551
 
                                btr_pcur_commit_specify_mtr(&pcur, &mtr);
4552
 
 
4553
 
                                mtr_start(&mtr);
4554
 
 
4555
 
                                success = buf_page_get_known_nowait(
4556
 
                                        RW_X_LATCH, block,
4557
 
                                        BUF_KEEP_OLD,
4558
 
                                        __FILE__, __LINE__, &mtr);
4559
 
                                ut_a(success);
4560
 
 
4561
 
                                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
4562
 
 
4563
 
                                if (!ibuf_restore_pos(space, page_no,
4564
 
                                                      search_tuple,
4565
 
                                                      BTR_MODIFY_LEAF,
4566
 
                                                      &pcur, &mtr)) {
4567
 
 
4568
 
                                        mtr_commit(&mtr);
4569
 
                                        mops[op]++;
4570
 
                                        ibuf_dummy_index_free(dummy_index);
4571
 
                                        goto loop;
4572
 
                                }
4573
 
 
4574
 
                                break;
4575
 
                        default:
4576
 
                                ut_error;
4577
 
                        }
4578
 
 
4579
 
                        mops[op]++;
4580
 
 
 
3337
                        ibuf_insert_to_index_page(entry, block,
 
3338
                                                  dummy_index, &mtr);
4581
3339
                        ibuf_dummy_index_free(dummy_index);
4582
 
                } else {
4583
 
                        dops[ibuf_rec_get_op_type(rec)]++;
4584
3340
                }
4585
3341
 
 
3342
                n_inserts++;
 
3343
 
4586
3344
                /* Delete the record from ibuf */
4587
3345
                if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
4588
3346
                                    &mtr)) {
4599
3357
        }
4600
3358
 
4601
3359
reset_bit:
 
3360
#ifdef UNIV_IBUF_COUNT_DEBUG
 
3361
        if (ibuf_count_get(space, page_no) > 0) {
 
3362
                /* btr_print_tree(ibuf_data->index->tree, 100);
 
3363
                ibuf_print(); */
 
3364
        }
 
3365
#endif
4602
3366
        if (UNIV_LIKELY(update_ibuf_bitmap)) {
4603
3367
                page_t* bitmap_page;
4604
3368
 
4629
3393
        btr_pcur_close(&pcur);
4630
3394
        mem_heap_free(heap);
4631
3395
 
4632
 
#ifdef HAVE_ATOMIC_BUILTINS
4633
 
        os_atomic_increment_ulint(&ibuf->n_merges, 1);
4634
 
        ibuf_add_ops(ibuf->n_merged_ops, mops);
4635
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
4636
 
#else /* HAVE_ATOMIC_BUILTINS */
4637
3396
        /* Protect our statistics keeping from race conditions */
4638
3397
        mutex_enter(&ibuf_mutex);
4639
3398
 
4640
3399
        ibuf->n_merges++;
4641
 
        ibuf_add_ops(ibuf->n_merged_ops, mops);
4642
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
 
3400
        ibuf->n_merged_recs += n_inserts;
4643
3401
 
4644
3402
        mutex_exit(&ibuf_mutex);
4645
 
#endif /* HAVE_ATOMIC_BUILTINS */
4646
3403
 
4647
3404
        if (update_ibuf_bitmap && !tablespace_being_deleted) {
4648
3405
 
4673
3430
        rec_t*          ibuf_rec;
4674
3431
        ulint           page_no;
4675
3432
        ibool           closed;
 
3433
        ulint           n_inserts;
4676
3434
        mtr_t           mtr;
4677
3435
 
4678
 
        /* Counts for discarded operations. */
4679
 
        ulint           dops[IBUF_OP_COUNT];
4680
 
 
4681
3436
        heap = mem_heap_create(512);
4682
3437
 
4683
3438
        /* Use page number 0 to build the search tuple so that we get the
4685
3440
 
4686
3441
        search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
4687
3442
 
4688
 
        memset(dops, 0, sizeof(dops));
 
3443
        n_inserts = 0;
4689
3444
loop:
4690
3445
        ibuf_enter();
4691
3446
 
4716
3471
 
4717
3472
                page_no = ibuf_rec_get_page_no(ibuf_rec);
4718
3473
 
4719
 
                dops[ibuf_rec_get_op_type(ibuf_rec)]++;
 
3474
                n_inserts++;
4720
3475
 
4721
3476
                /* Delete the record from ibuf */
4722
3477
                closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
4744
3499
        mtr_commit(&mtr);
4745
3500
        btr_pcur_close(&pcur);
4746
3501
 
4747
 
#ifdef HAVE_ATOMIC_BUILTINS
4748
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
4749
 
#else /* HAVE_ATOMIC_BUILTINS */
4750
3502
        /* Protect our statistics keeping from race conditions */
4751
3503
        mutex_enter(&ibuf_mutex);
4752
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
 
3504
 
 
3505
        ibuf->n_merges++;
 
3506
        ibuf->n_merged_recs += n_inserts;
 
3507
 
4753
3508
        mutex_exit(&ibuf_mutex);
4754
 
#endif /* HAVE_ATOMIC_BUILTINS */
4755
3509
 
4756
3510
        ibuf_exit();
4757
3511
 
4771
3525
        mtr_t           mtr;
4772
3526
 
4773
3527
        ibuf_enter();
 
3528
 
 
3529
        mutex_enter(&ibuf_mutex);
 
3530
 
4774
3531
        mtr_start(&mtr);
4775
3532
 
4776
 
        mutex_enter(&ibuf_mutex);
4777
3533
        root = ibuf_tree_root_get(&mtr);
 
3534
 
 
3535
        if (page_get_n_recs(root) == 0) {
 
3536
 
 
3537
                is_empty = TRUE;
 
3538
 
 
3539
                if (ibuf->empty == FALSE) {
 
3540
                        fprintf(stderr,
 
3541
                                "InnoDB: Warning: insert buffer tree is empty"
 
3542
                                " but the data struct does not\n"
 
3543
                                "InnoDB: know it. This condition is legal"
 
3544
                                " if the master thread has not yet\n"
 
3545
                                "InnoDB: run to completion.\n");
 
3546
                }
 
3547
        } else {
 
3548
                ut_a(ibuf->empty == FALSE);
 
3549
 
 
3550
                is_empty = FALSE;
 
3551
        }
 
3552
 
 
3553
        mtr_commit(&mtr);
 
3554
 
4778
3555
        mutex_exit(&ibuf_mutex);
4779
3556
 
4780
 
        is_empty = (page_get_n_recs(root) == 0);
4781
 
        mtr_commit(&mtr);
4782
3557
        ibuf_exit();
4783
3558
 
4784
 
        ut_a(is_empty == ibuf->empty);
4785
 
 
4786
3559
        return(is_empty);
4787
3560
}
4788
3561
 
4802
3575
        mutex_enter(&ibuf_mutex);
4803
3576
 
4804
3577
        fprintf(file,
4805
 
                "Ibuf: size %lu, free list len %lu,"
4806
 
                " seg size %lu, %lu merges\n",
 
3578
                "Ibuf: size %lu, free list len %lu, seg size %lu,\n"
 
3579
                "%lu inserts, %lu merged recs, %lu merges\n",
4807
3580
                (ulong) ibuf->size,
4808
3581
                (ulong) ibuf->free_list_len,
4809
3582
                (ulong) ibuf->seg_size,
 
3583
                (ulong) ibuf->n_inserts,
 
3584
                (ulong) ibuf->n_merged_recs,
4810
3585
                (ulong) ibuf->n_merges);
4811
 
 
4812
 
        fputs("merged operations:\n ", file);
4813
 
        ibuf_print_ops(ibuf->n_merged_ops, file);
4814
 
 
4815
 
        fputs("discarded operations:\n ", file);
4816
 
        ibuf_print_ops(ibuf->n_discarded_ops, file);
4817
 
 
4818
3586
#ifdef UNIV_IBUF_COUNT_DEBUG
4819
3587
        for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
4820
3588
                for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {