~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-10-22 17:44:34 UTC
  • mto: This revision was merged to the branch mainline in revision 1873.
  • Revision ID: brian@tangent.org-20101022174434-q8fjovcpclzqer7n
TableShare is no longer in the house (i.e. we no longer directly have a copy
of it in cursor).

One more bit of the knot now gone.

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
55
55
#include "lock0lock.h"
56
56
#include "log0recv.h"
57
57
#include "que0que.h"
58
 
#include "srv0start.h" /* srv_shutdown_state */
59
58
 
60
59
/*      STRUCTURE OF AN INSERT BUFFER RECORD
61
60
 
90
89
looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
91
90
 
92
91
The high-order bit of the character set field in the type info is the
93
 
"nullable" flag for the field.
94
 
 
95
 
In versions >= 5.5:
96
 
 
97
 
The optional marker byte at the start of the fourth field is replaced by
98
 
mandatory 3 fields, totaling 4 bytes:
99
 
 
100
 
 1. 2 bytes: Counter field, used to sort records within a (space id, page
101
 
    no) in the order they were added. This is needed so that for example the
102
 
    sequence of operations "INSERT x, DEL MARK x, INSERT x" is handled
103
 
    correctly.
104
 
 
105
 
 2. 1 byte: Operation type (see ibuf_op_t).
106
 
 
107
 
 3. 1 byte: Flags. Currently only one flag exists, IBUF_REC_COMPACT.
108
 
 
109
 
To ensure older records, which do not have counters to enforce correct
110
 
sorting, are merged before any new records, ibuf_insert checks if we're
111
 
trying to insert to a position that contains old-style records, and if so,
112
 
refuses the insert. Thus, ibuf pages are gradually converted to the new
113
 
format as their corresponding buffer pool pages are read into memory.
114
 
*/
 
92
"nullable" flag for the field. */
115
93
 
116
94
 
117
95
/*      PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
190
168
#define IBUF_TABLE_NAME         "SYS_IBUF_TABLE"
191
169
 
192
170
/** Operations that can currently be buffered. */
193
 
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_ALL;
 
171
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_INSERT;
194
172
 
195
173
/** The insert buffer control structure */
196
174
UNIV_INTERN ibuf_t*     ibuf                    = NULL;
198
176
/** Counter for ibuf_should_try() */
199
177
UNIV_INTERN ulint       ibuf_flush_count        = 0;
200
178
 
201
 
#ifdef UNIV_PFS_MUTEX
202
 
UNIV_INTERN mysql_pfs_key_t     ibuf_pessimistic_insert_mutex_key;
203
 
UNIV_INTERN mysql_pfs_key_t     ibuf_mutex_key;
204
 
UNIV_INTERN mysql_pfs_key_t     ibuf_bitmap_mutex_key;
205
 
#endif /* UNIV_PFS_MUTEX */
206
 
 
207
179
#ifdef UNIV_IBUF_COUNT_DEBUG
208
180
/** Number of tablespaces in the ibuf_counts array */
209
181
#define IBUF_COUNT_N_SPACES     4
249
221
                                        list of the ibuf */
250
222
/* @} */
251
223
 
252
 
/* Various constants for checking the type of an ibuf record and extracting
253
 
data from it. For details, see the description of the record format at the
254
 
top of this file. */
255
 
 
256
 
/** @name Format of the fourth column of an insert buffer record
257
 
The fourth column in the MySQL 5.5 format contains an operation
258
 
type, counter, and some flags. */
259
 
/* @{ */
260
 
#define IBUF_REC_INFO_SIZE      4       /*!< Combined size of info fields at
261
 
                                        the beginning of the fourth field */
262
 
#if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
263
 
# error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
264
 
#endif
265
 
 
266
 
/* Offsets for the fields at the beginning of the fourth field */
267
 
#define IBUF_REC_OFFSET_COUNTER 0       /*!< Operation counter */
268
 
#define IBUF_REC_OFFSET_TYPE    2       /*!< Type of operation */
269
 
#define IBUF_REC_OFFSET_FLAGS   3       /*!< Additional flags */
270
 
 
271
 
/* Record flag masks */
272
 
#define IBUF_REC_COMPACT        0x1     /*!< Set in
273
 
                                        IBUF_REC_OFFSET_FLAGS if the
274
 
                                        user index is in COMPACT
275
 
                                        format or later */
276
 
 
277
 
 
278
224
/** The mutex used to block pessimistic inserts to ibuf trees */
279
225
static mutex_t  ibuf_pessimistic_insert_mutex;
280
226
 
396
342
        mtr_t*          mtr)    /*!< in: mtr */
397
343
{
398
344
        buf_block_t*    block;
399
 
        page_t*         root;
400
345
 
401
346
        ut_ad(ibuf_inside());
402
 
        ut_ad(mutex_own(&ibuf_mutex));
403
347
 
404
348
        mtr_x_lock(dict_index_get_lock(ibuf->index), mtr);
405
349
 
408
352
 
409
353
        buf_block_dbg_add_level(block, SYNC_TREE_NODE);
410
354
 
411
 
        root = buf_block_get_frame(block);
412
 
 
413
 
        ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
414
 
        ut_ad(page_get_page_no(root) == FSP_IBUF_TREE_ROOT_PAGE_NO);
415
 
        ut_ad(ibuf->empty == (page_get_n_recs(root) == 0));
416
 
 
417
 
        return(root);
 
355
        return(buf_block_get_frame(block));
418
356
}
419
357
 
420
358
#ifdef UNIV_IBUF_COUNT_DEBUG
491
429
 
492
430
        /* the '1 +' is the ibuf header page */
493
431
        ibuf->size = ibuf->seg_size - (1 + ibuf->free_list_len);
 
432
 
 
433
        ibuf->empty = page_get_n_recs(root) == 0;
494
434
}
495
435
 
496
436
/******************************************************************//**
521
461
        ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE
522
462
                / IBUF_POOL_SIZE_PER_MAX_SIZE;
523
463
 
524
 
        mutex_create(ibuf_pessimistic_insert_mutex_key,
525
 
                     &ibuf_pessimistic_insert_mutex,
 
464
        mutex_create(&ibuf_pessimistic_insert_mutex,
526
465
                     SYNC_IBUF_PESS_INSERT_MUTEX);
527
466
 
528
 
        mutex_create(ibuf_mutex_key,
529
 
                     &ibuf_mutex, SYNC_IBUF_MUTEX);
 
467
        mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX);
530
468
 
531
 
        mutex_create(ibuf_bitmap_mutex_key,
532
 
                     &ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
 
469
        mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
533
470
 
534
471
        mtr_start(&mtr);
535
472
 
561
498
        ibuf_size_update(root, &mtr);
562
499
        mutex_exit(&ibuf_mutex);
563
500
 
564
 
        ibuf->empty = (page_get_n_recs(root) == 0);
565
501
        mtr_commit(&mtr);
566
502
 
567
503
        ibuf_exit();
573
509
 
574
510
        dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
575
511
 
576
 
        table->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
 
512
        table->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
577
513
 
578
514
        dict_table_add_to_cache(table, heap);
579
515
        mem_heap_free(heap);
584
520
 
585
521
        dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
586
522
 
587
 
        index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
 
523
        index->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
588
524
 
589
525
        error = dict_index_add_to_cache(table, index,
590
526
                                        FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
794
730
is x-latched */
795
731
static
796
732
page_t*
797
 
ibuf_bitmap_get_map_page_func(
798
 
/*==========================*/
799
 
        ulint           space,  /*!< in: space id of the file page */
800
 
        ulint           page_no,/*!< in: page number of the file page */
801
 
        ulint           zip_size,/*!< in: compressed page size in bytes;
802
 
                                0 for uncompressed pages */
803
 
        const char*     file,   /*!< in: file name */
804
 
        ulint           line,   /*!< in: line where called */
805
 
        mtr_t*          mtr)    /*!< in: mtr */
 
733
ibuf_bitmap_get_map_page(
 
734
/*=====================*/
 
735
        ulint   space,  /*!< in: space id of the file page */
 
736
        ulint   page_no,/*!< in: page number of the file page */
 
737
        ulint   zip_size,/*!< in: compressed page size in bytes;
 
738
                        0 for uncompressed pages */
 
739
        mtr_t*  mtr)    /*!< in: mtr */
806
740
{
807
741
        buf_block_t*    block;
808
742
 
809
 
        block = buf_page_get_gen(space, zip_size,
810
 
                                 ibuf_bitmap_page_no_calc(zip_size, page_no),
811
 
                                 RW_X_LATCH, NULL, BUF_GET,
812
 
                                 file, line, mtr);
 
743
        block = buf_page_get(space, zip_size,
 
744
                             ibuf_bitmap_page_no_calc(zip_size, page_no),
 
745
                             RW_X_LATCH, mtr);
813
746
        buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
814
747
 
815
748
        return(buf_block_get_frame(block));
816
749
}
817
750
 
818
 
/********************************************************************//**
819
 
Gets the ibuf bitmap page where the bits describing a given file page are
820
 
stored.
821
 
@return bitmap page where the file page is mapped, that is, the bitmap
822
 
page containing the descriptor bits for the file page; the bitmap page
823
 
is x-latched
824
 
@param space    in: space id of the file page
825
 
@param page_no  in: page number of the file page
826
 
@param zip_size in: compressed page size in bytes; 0 for uncompressed pages
827
 
@param mtr      in: mini-transaction */
828
 
#define ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr)         \
829
 
        ibuf_bitmap_get_map_page_func(space, page_no, zip_size,         \
830
 
                                      __FILE__, __LINE__, mtr)
831
 
 
832
751
/************************************************************************//**
833
752
Sets the free bits of the page in the ibuf bitmap. This is done in a separate
834
753
mini-transaction, hence this operation does not restrict further work to only
1214
1133
        return(0);
1215
1134
}
1216
1135
 
1217
 
/****************************************************************//**
1218
 
Get various information about an ibuf record in >= 4.1.x format. */
1219
 
static
1220
 
void
1221
 
ibuf_rec_get_info(
1222
 
/*==============*/
1223
 
        const rec_t*    rec,            /*!< in: ibuf record */
1224
 
        ibuf_op_t*      op,             /*!< out: operation type, or NULL */
1225
 
        ibool*          comp,           /*!< out: compact flag, or NULL */
1226
 
        ulint*          info_len,       /*!< out: length of info fields at the
1227
 
                                        start of the fourth field, or
1228
 
                                        NULL */
1229
 
        ulint*          counter)        /*!< in: counter value, or NULL */
1230
 
{
1231
 
        const byte*     types;
1232
 
        ulint           fields;
1233
 
        ulint           len;
1234
 
 
1235
 
        /* Local variables to shadow arguments. */
1236
 
        ibuf_op_t       op_local;
1237
 
        ibool           comp_local;
1238
 
        ulint           info_len_local;
1239
 
        ulint           counter_local;
1240
 
 
1241
 
        ut_ad(ibuf_inside());
1242
 
        fields = rec_get_n_fields_old(rec);
1243
 
        ut_a(fields > 4);
1244
 
 
1245
 
        types = rec_get_nth_field_old(rec, 3, &len);
1246
 
 
1247
 
        info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1248
 
 
1249
 
        switch (info_len_local) {
1250
 
        case 0:
1251
 
        case 1:
1252
 
                op_local = IBUF_OP_INSERT;
1253
 
                comp_local = info_len_local;
1254
 
                ut_ad(!counter);
1255
 
                counter_local = ULINT_UNDEFINED;
1256
 
                break;
1257
 
 
1258
 
        case IBUF_REC_INFO_SIZE:
1259
 
                op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE];
1260
 
                comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT;
1261
 
                counter_local = mach_read_from_2(
1262
 
                        types + IBUF_REC_OFFSET_COUNTER);
1263
 
                break;
1264
 
 
1265
 
        default:
1266
 
                ut_error;
1267
 
        }
1268
 
 
1269
 
        ut_a(op_local < IBUF_OP_COUNT);
1270
 
        ut_a((len - info_len_local) ==
1271
 
             (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1272
 
 
1273
 
        if (op) {
1274
 
                *op = op_local;
1275
 
        }
1276
 
 
1277
 
        if (comp) {
1278
 
                *comp = comp_local;
1279
 
        }
1280
 
 
1281
 
        if (info_len) {
1282
 
                *info_len = info_len_local;
1283
 
        }
1284
 
 
1285
 
        if (counter) {
1286
 
                *counter = counter_local;
1287
 
        }
1288
 
}
1289
 
 
1290
 
/****************************************************************//**
1291
 
Returns the operation type field of an ibuf record.
1292
 
@return operation type */
1293
 
static
1294
 
ibuf_op_t
1295
 
ibuf_rec_get_op_type(
1296
 
/*=================*/
1297
 
        const rec_t*    rec)    /*!< in: ibuf record */
1298
 
{
1299
 
        ulint           len;
1300
 
 
1301
 
        ut_ad(ibuf_inside());
1302
 
        ut_ad(rec_get_n_fields_old(rec) > 2);
1303
 
 
1304
 
        (void) rec_get_nth_field_old(rec, 1, &len);
1305
 
 
1306
 
        if (len > 1) {
1307
 
                /* This is a < 4.1.x format record */
1308
 
 
1309
 
                return(IBUF_OP_INSERT);
1310
 
        } else {
1311
 
                ibuf_op_t       op;
1312
 
 
1313
 
                ibuf_rec_get_info(rec, &op, NULL, NULL, NULL);
1314
 
 
1315
 
                return(op);
1316
 
        }
1317
 
}
1318
 
 
1319
 
/****************************************************************//**
1320
 
Read the first two bytes from a record's fourth field (counter field in new
1321
 
records; something else in older records).
1322
 
@return "counter" field, or ULINT_UNDEFINED if for some reason it
1323
 
can't be read */
1324
 
UNIV_INTERN
1325
 
ulint
1326
 
ibuf_rec_get_counter(
1327
 
/*=================*/
1328
 
        const rec_t*    rec)    /*!< in: ibuf record */
1329
 
{
1330
 
        const byte*     ptr;
1331
 
        ulint           len;
1332
 
 
1333
 
        if (rec_get_n_fields_old(rec) < 4) {
1334
 
 
1335
 
                return(ULINT_UNDEFINED);
1336
 
        }
1337
 
 
1338
 
        ptr = rec_get_nth_field_old(rec, 3, &len);
1339
 
 
1340
 
        if (len >= 2) {
1341
 
 
1342
 
                return(mach_read_from_2(ptr));
1343
 
        } else {
1344
 
 
1345
 
                return(ULINT_UNDEFINED);
1346
 
        }
1347
 
}
1348
 
 
1349
 
/****************************************************************//**
1350
 
Add accumulated operation counts to a permanent array. Both arrays must be
1351
 
of size IBUF_OP_COUNT. */
1352
 
static
1353
 
void
1354
 
ibuf_add_ops(
1355
 
/*=========*/
1356
 
        ulint*          arr,    /*!< in/out: array to modify */
1357
 
        const ulint*    ops)    /*!< in: operation counts */
1358
 
 
1359
 
{
1360
 
#ifndef HAVE_ATOMIC_BUILTINS
1361
 
        ut_ad(mutex_own(&ibuf_mutex));
1362
 
#endif /* !HAVE_ATOMIC_BUILTINS */
1363
 
 
1364
 
        ulint   i;
1365
 
 
1366
 
        for (i = 0; i < IBUF_OP_COUNT; i++) {
1367
 
#ifdef HAVE_ATOMIC_BUILTINS
1368
 
                os_atomic_increment_ulint(&arr[i], ops[i]);
1369
 
#else /* HAVE_ATOMIC_BUILTINS */
1370
 
                arr[i] += ops[i];
1371
 
#endif /* HAVE_ATOMIC_BUILTINS */
1372
 
        }
1373
 
}
1374
 
 
1375
 
/****************************************************************//**
1376
 
Print operation counts. The array must be of size IBUF_OP_COUNT. */
1377
 
static
1378
 
void
1379
 
ibuf_print_ops(
1380
 
/*===========*/
1381
 
        const ulint*    ops,    /*!< in: operation counts */
1382
 
        FILE*           file)   /*!< in: file where to print */
1383
 
{
1384
 
        static const char* op_names[] = {
1385
 
                "insert",
1386
 
                "delete mark",
1387
 
                "delete"
1388
 
        };
1389
 
        ulint   i;
1390
 
 
1391
 
        ut_a(UT_ARR_SIZE(op_names) == IBUF_OP_COUNT);
1392
 
 
1393
 
        for (i = 0; i < IBUF_OP_COUNT; i++) {
1394
 
                fprintf(file, "%s %lu%s", op_names[i],
1395
 
                        (ulong) ops[i], (i < (IBUF_OP_COUNT - 1)) ? ", " : "");
1396
 
        }
1397
 
 
1398
 
        putc('\n', file);
1399
 
}
1400
 
 
1401
1136
/********************************************************************//**
1402
1137
Creates a dummy index for inserting a record to a non-clustered index.
 
1138
 
1403
1139
@return dummy index */
1404
1140
static
1405
1141
dict_index_t*
1510
1246
}
1511
1247
 
1512
1248
/*********************************************************************//**
1513
 
Builds the entry used to
1514
 
 
1515
 
1) IBUF_OP_INSERT: insert into a non-clustered index
1516
 
 
1517
 
2) IBUF_OP_DELETE_MARK: find the record whose delete-mark flag we need to
1518
 
   activate
1519
 
 
1520
 
3) IBUF_OP_DELETE: find the record we need to delete
1521
 
 
1522
 
when we have the corresponding record in an ibuf index.
 
1249
Builds the entry to insert into a non-clustered index when we have the
 
1250
corresponding record in an ibuf index.
1523
1251
 
1524
1252
NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1525
1253
hold a latch to the ibuf_rec page as long as the entry is used!
1540
1268
        const byte*     types;
1541
1269
        const byte*     data;
1542
1270
        ulint           len;
1543
 
        ulint           info_len;
1544
1271
        ulint           i;
1545
 
        ulint           comp;
1546
1272
        dict_index_t*   index;
1547
1273
 
1548
1274
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1565
1291
 
1566
1292
        types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1567
1293
 
1568
 
        ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL);
1569
 
 
1570
 
        index = ibuf_dummy_index_create(n_fields, comp);
1571
 
 
1572
 
        len -= info_len;
1573
 
        types += info_len;
 
1294
        ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
 
1295
        index = ibuf_dummy_index_create(
 
1296
                n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
 
1297
 
 
1298
        if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
 
1299
                /* compact record format */
 
1300
                len--;
 
1301
                ut_a(*types == 0);
 
1302
                types++;
 
1303
        }
1574
1304
 
1575
1305
        ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1576
1306
 
1600
1330
        return(tuple);
1601
1331
}
1602
1332
 
1603
 
/******************************************************************//**
1604
 
Get the data size.
1605
 
@return size of fields */
1606
 
UNIV_INLINE
1607
 
ulint
1608
 
ibuf_rec_get_size(
1609
 
/*==============*/
1610
 
        const rec_t*    rec,                    /*!< in: ibuf record */
1611
 
        const byte*     types,                  /*!< in: fields */
1612
 
        ulint           n_fields,               /*!< in: number of fields */
1613
 
        ibool           pre_4_1,                /*!< in: TRUE=pre-4.1 format,
1614
 
                                                FALSE=newer */
1615
 
        ulint           comp)                   /*!< in: 0=ROW_FORMAT=REDUNDANT,
1616
 
                                                nonzero=ROW_FORMAT=COMPACT */
1617
 
{
1618
 
        ulint   i;
1619
 
        ulint   field_offset;
1620
 
        ulint   types_offset;
1621
 
        ulint   size = 0;
1622
 
 
1623
 
        if (pre_4_1) {
1624
 
                field_offset = 2;
1625
 
                types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE;
1626
 
        } else {
1627
 
                field_offset = 4;
1628
 
                types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1629
 
        }
1630
 
 
1631
 
        for (i = 0; i < n_fields; i++) {
1632
 
                ulint           len;
1633
 
                dtype_t         dtype;
1634
 
 
1635
 
                rec_get_nth_field_offs_old(rec, i + field_offset, &len);
1636
 
 
1637
 
                if (len != UNIV_SQL_NULL) {
1638
 
                        size += len;
1639
 
                } else if (pre_4_1) {
1640
 
                        dtype_read_for_order_and_null_size(&dtype, types);
1641
 
 
1642
 
                        size += dtype_get_sql_null_size(&dtype, comp);
1643
 
                } else {
1644
 
                        dtype_new_read_for_order_and_null_size(&dtype, types);
1645
 
 
1646
 
                        size += dtype_get_sql_null_size(&dtype, comp);
1647
 
                }
1648
 
 
1649
 
                types += types_offset;
1650
 
        }
1651
 
 
1652
 
        return(size);
1653
 
}
1654
 
 
1655
1333
/********************************************************************//**
1656
1334
Returns the space taken by a stored non-clustered index entry if converted to
1657
1335
an index record.
1663
1341
/*================*/
1664
1342
        const rec_t*    ibuf_rec)/*!< in: ibuf record */
1665
1343
{
 
1344
        dtype_t         dtype;
 
1345
        ibool           new_format      = FALSE;
 
1346
        ulint           data_size       = 0;
 
1347
        ulint           n_fields;
 
1348
        const byte*     types;
 
1349
        const byte*     data;
1666
1350
        ulint           len;
1667
 
        const byte*     data;
1668
 
        const byte*     types;
1669
 
        ulint           n_fields;
1670
 
        ulint           data_size;
1671
 
        ibool           pre_4_1;
 
1351
        ulint           i;
1672
1352
        ulint           comp;
1673
1353
 
1674
1354
        ut_ad(ibuf_inside());
1675
1355
        ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
1676
1356
 
1677
1357
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1678
 
        pre_4_1 = (len > 1);
1679
1358
 
1680
 
        if (pre_4_1) {
 
1359
        if (len > 1) {
1681
1360
                /* < 4.1.x format record */
1682
1361
 
1683
1362
                ut_a(trx_doublewrite_must_reset_space_ids);
1691
1370
                comp = 0;
1692
1371
        } else {
1693
1372
                /* >= 4.1.x format record */
1694
 
                ibuf_op_t       op;
1695
 
                ulint           info_len;
1696
1373
 
1697
1374
                ut_a(trx_sys_multiple_tablespace_format);
1698
1375
                ut_a(*data == 0);
1699
1376
 
1700
1377
                types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1701
1378
 
1702
 
                ibuf_rec_get_info(ibuf_rec, &op, &comp, &info_len, NULL);
1703
 
 
1704
 
                if (op == IBUF_OP_DELETE_MARK || op == IBUF_OP_DELETE) {
1705
 
                        /* Delete-marking a record doesn't take any
1706
 
                        additional space, and while deleting a record
1707
 
                        actually frees up space, we have to play it safe and
1708
 
                        pretend it takes no additional space (the record
1709
 
                        might not exist, etc.).  */
1710
 
 
1711
 
                        return(0);
1712
 
                } else if (comp) {
1713
 
                        dtuple_t*       entry;
 
1379
                comp = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
 
1380
 
 
1381
                ut_a(comp <= 1);
 
1382
                if (comp) {
 
1383
                        /* compact record format */
1714
1384
                        ulint           volume;
1715
1385
                        dict_index_t*   dummy_index;
1716
1386
                        mem_heap_t*     heap = mem_heap_create(500);
1717
 
 
1718
 
                        entry = ibuf_build_entry_from_ibuf_rec(
 
1387
                        dtuple_t*       entry = ibuf_build_entry_from_ibuf_rec(
1719
1388
                                ibuf_rec, heap, &dummy_index);
1720
 
 
1721
1389
                        volume = rec_get_converted_size(dummy_index, entry, 0);
1722
 
 
1723
1390
                        ibuf_dummy_index_free(dummy_index);
1724
1391
                        mem_heap_free(heap);
1725
 
 
1726
1392
                        return(volume + page_dir_calc_reserved_space(1));
1727
1393
                }
1728
1394
 
1729
 
                types += info_len;
1730
1395
                n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1731
 
        }
1732
 
 
1733
 
        data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp);
 
1396
 
 
1397
                new_format = TRUE;
 
1398
        }
 
1399
 
 
1400
        for (i = 0; i < n_fields; i++) {
 
1401
                if (new_format) {
 
1402
                        data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
 
1403
 
 
1404
                        dtype_new_read_for_order_and_null_size(
 
1405
                                &dtype, types + i
 
1406
                                * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
 
1407
                } else {
 
1408
                        data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
 
1409
 
 
1410
                        dtype_read_for_order_and_null_size(
 
1411
                                &dtype, types + i
 
1412
                                * DATA_ORDER_NULL_TYPE_BUF_SIZE);
 
1413
                }
 
1414
 
 
1415
                if (len == UNIV_SQL_NULL) {
 
1416
                        data_size += dtype_get_sql_null_size(&dtype, comp);
 
1417
                } else {
 
1418
                        data_size += len;
 
1419
                }
 
1420
        }
1734
1421
 
1735
1422
        return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0)
1736
1423
               + page_dir_calc_reserved_space(1));
1748
1435
dtuple_t*
1749
1436
ibuf_entry_build(
1750
1437
/*=============*/
1751
 
        ibuf_op_t       op,     /*!< in: operation type */
1752
1438
        dict_index_t*   index,  /*!< in: non-clustered index */
1753
1439
        const dtuple_t* entry,  /*!< in: entry for a non-clustered index */
1754
1440
        ulint           space,  /*!< in: space id */
1755
1441
        ulint           page_no,/*!< in: index page number where entry should
1756
1442
                                be inserted */
1757
 
        ulint           counter,/*!< in: counter value;
1758
 
                                ULINT_UNDEFINED=not used */
1759
1443
        mem_heap_t*     heap)   /*!< in: heap into which to build */
1760
1444
{
1761
1445
        dtuple_t*       tuple;
1763
1447
        const dfield_t* entry_field;
1764
1448
        ulint           n_fields;
1765
1449
        byte*           buf;
1766
 
        byte*           ti;
1767
 
        byte*           type_info;
 
1450
        byte*           buf2;
1768
1451
        ulint           i;
1769
1452
 
1770
 
        ut_ad(counter != ULINT_UNDEFINED || op == IBUF_OP_INSERT);
1771
 
        ut_ad(counter == ULINT_UNDEFINED || counter <= 0xFFFF);
1772
 
        ut_ad(op < IBUF_OP_COUNT);
1773
 
 
1774
 
        /* We have to build a tuple with the following fields:
1775
 
 
1776
 
        1-4) These are described at the top of this file.
1777
 
 
1778
 
        5) The rest of the fields are copied from the entry.
1779
 
 
1780
 
        All fields in the tuple are ordered like the type binary in our
1781
 
        insert buffer tree. */
 
1453
        /* Starting from 4.1.x, we have to build a tuple whose
 
1454
        (1) first field is the space id,
 
1455
        (2) the second field a single marker byte (0) to tell that this
 
1456
        is a new format record,
 
1457
        (3) the third contains the page number, and
 
1458
        (4) the fourth contains the relevent type information of each data
 
1459
        field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is
 
1460
        (a) 0 for b-trees in the old format, and
 
1461
        (b) 1 for b-trees in the compact format, the first byte of the field
 
1462
        being the marker (0);
 
1463
        (5) and the rest of the fields are copied from entry. All fields
 
1464
        in the tuple are ordered like the type binary in our insert buffer
 
1465
        tree. */
1782
1466
 
1783
1467
        n_fields = dtuple_get_n_fields(entry);
1784
1468
 
1785
1469
        tuple = dtuple_create(heap, n_fields + 4);
1786
1470
 
1787
 
        /* 1) Space Id */
 
1471
        /* Store the space id in tuple */
1788
1472
 
1789
1473
        field = dtuple_get_nth_field(tuple, 0);
1790
1474
 
1794
1478
 
1795
1479
        dfield_set_data(field, buf, 4);
1796
1480
 
1797
 
        /* 2) Marker byte */
 
1481
        /* Store the marker byte field in tuple */
1798
1482
 
1799
1483
        field = dtuple_get_nth_field(tuple, 1);
1800
1484
 
1806
1490
 
1807
1491
        dfield_set_data(field, buf, 1);
1808
1492
 
1809
 
        /* 3) Page number */
 
1493
        /* Store the page number in tuple */
1810
1494
 
1811
1495
        field = dtuple_get_nth_field(tuple, 2);
1812
1496
 
1816
1500
 
1817
1501
        dfield_set_data(field, buf, 4);
1818
1502
 
1819
 
        /* 4) Type info, part #1 */
1820
 
 
1821
 
        if (counter == ULINT_UNDEFINED) {
1822
 
                i = dict_table_is_comp(index->table) ? 1 : 0;
1823
 
        } else {
1824
 
                ut_ad(counter <= 0xFFFF);
1825
 
                i = IBUF_REC_INFO_SIZE;
1826
 
        }
1827
 
 
1828
 
        ti = type_info = mem_heap_alloc(heap, i + n_fields
1829
 
                                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1830
 
 
1831
 
        switch (i) {
1832
 
        default:
1833
 
                ut_error;
1834
 
                break;
1835
 
        case 1:
1836
 
                /* set the flag for ROW_FORMAT=COMPACT */
1837
 
                *ti++ = 0;
1838
 
                /* fall through */
1839
 
        case 0:
1840
 
                /* the old format does not allow delete buffering */
1841
 
                ut_ad(op == IBUF_OP_INSERT);
1842
 
                break;
1843
 
        case IBUF_REC_INFO_SIZE:
1844
 
                mach_write_to_2(ti + IBUF_REC_OFFSET_COUNTER, counter);
1845
 
 
1846
 
                ti[IBUF_REC_OFFSET_TYPE] = (byte) op;
1847
 
                ti[IBUF_REC_OFFSET_FLAGS] = dict_table_is_comp(index->table)
1848
 
                        ? IBUF_REC_COMPACT : 0;
1849
 
                ti += IBUF_REC_INFO_SIZE;
1850
 
                break;
1851
 
        }
1852
 
 
1853
 
        /* 5+) Fields from the entry */
1854
 
 
 
1503
        /* Store the type info in buf2, and add the fields from entry to
 
1504
        tuple */
 
1505
        buf2 = mem_heap_alloc(heap, n_fields
 
1506
                              * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
 
1507
                              + dict_table_is_comp(index->table));
 
1508
        if (dict_table_is_comp(index->table)) {
 
1509
                *buf2++ = 0; /* write the compact format indicator */
 
1510
        }
1855
1511
        for (i = 0; i < n_fields; i++) {
1856
1512
                ulint                   fixed_len;
1857
1513
                const dict_field_t*     ifield;
1886
1542
#endif /* UNIV_DEBUG */
1887
1543
 
1888
1544
                dtype_new_store_for_order_and_null_size(
1889
 
                        ti, dfield_get_type(entry_field), fixed_len);
1890
 
                ti += DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
 
1545
                        buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
 
1546
                        dfield_get_type(entry_field), fixed_len);
1891
1547
        }
1892
1548
 
1893
 
        /* 4) Type info, part #2 */
 
1549
        /* Store the type info in buf2 to field 3 of tuple */
1894
1550
 
1895
1551
        field = dtuple_get_nth_field(tuple, 3);
1896
1552
 
1897
 
        dfield_set_data(field, type_info, ti - type_info);
 
1553
        if (dict_table_is_comp(index->table)) {
 
1554
                buf2--;
 
1555
        }
1898
1556
 
 
1557
        dfield_set_data(field, buf2, n_fields
 
1558
                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
 
1559
                        + dict_table_is_comp(index->table));
1899
1560
        /* Set all the types in the new tuple binary */
1900
1561
 
1901
1562
        dtuple_set_types_binary(tuple, n_fields + 4);
2032
1693
/*********************************************************************//**
2033
1694
Allocates a new page from the ibuf file segment and adds it to the free
2034
1695
list.
2035
 
@return TRUE on success, FALSE if no space left */
 
1696
@return DB_SUCCESS, or DB_STRONG_FAIL if no space left */
2036
1697
static
2037
 
ibool
 
1698
ulint
2038
1699
ibuf_add_free_page(void)
2039
1700
/*====================*/
2040
1701
{
2070
1731
                header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
2071
1732
                &mtr);
2072
1733
 
2073
 
        if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
 
1734
        if (page_no == FIL_NULL) {
2074
1735
                mtr_commit(&mtr);
2075
1736
 
2076
 
                return(FALSE);
 
1737
                return(DB_STRONG_FAIL);
2077
1738
        }
2078
1739
 
2079
1740
        {
2111
1772
        bitmap_page = ibuf_bitmap_get_map_page(
2112
1773
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
2113
1774
 
2114
 
        mutex_exit(&ibuf_mutex);
2115
 
 
2116
1775
        ibuf_bitmap_page_set_bits(
2117
1776
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
2118
1777
 
2119
1778
        mtr_commit(&mtr);
2120
1779
 
 
1780
        mutex_exit(&ibuf_mutex);
 
1781
 
2121
1782
        ibuf_exit();
2122
1783
 
2123
 
        return(TRUE);
 
1784
        return(DB_SUCCESS);
2124
1785
}
2125
1786
 
2126
1787
/*********************************************************************//**
2150
1811
        header_page = ibuf_header_page_get(&mtr);
2151
1812
 
2152
1813
        /* Prevent pessimistic inserts to insert buffer trees for a while */
2153
 
        ibuf_enter();
2154
1814
        mutex_enter(&ibuf_pessimistic_insert_mutex);
 
1815
 
 
1816
        ibuf_enter();
 
1817
 
2155
1818
        mutex_enter(&ibuf_mutex);
2156
1819
 
2157
1820
        if (!ibuf_data_too_much_free()) {
2158
1821
 
2159
1822
                mutex_exit(&ibuf_mutex);
 
1823
 
 
1824
                ibuf_exit();
 
1825
 
2160
1826
                mutex_exit(&ibuf_pessimistic_insert_mutex);
2161
1827
 
2162
 
                ibuf_exit();
2163
 
 
2164
1828
                mtr_commit(&mtr);
2165
1829
 
2166
1830
                return;
2170
1834
 
2171
1835
        root = ibuf_tree_root_get(&mtr2);
2172
1836
 
2173
 
        mutex_exit(&ibuf_mutex);
2174
 
 
2175
1837
        page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
2176
1838
                                &mtr2).page;
2177
1839
 
2180
1842
        is a level 2 page. */
2181
1843
 
2182
1844
        mtr_commit(&mtr2);
 
1845
        mutex_exit(&ibuf_mutex);
2183
1846
 
2184
1847
        ibuf_exit();
2185
1848
 
2222
1885
        flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
2223
1886
                    page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
2224
1887
 
2225
 
        mutex_exit(&ibuf_pessimistic_insert_mutex);
2226
 
 
2227
1888
        ibuf->seg_size--;
2228
1889
        ibuf->free_list_len--;
2229
1890
 
 
1891
        mutex_exit(&ibuf_pessimistic_insert_mutex);
 
1892
 
2230
1893
        /* Set the bit indicating that this page is no more an ibuf tree page
2231
1894
        (level 2 page) */
2232
1895
 
2233
1896
        bitmap_page = ibuf_bitmap_get_map_page(
2234
1897
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
2235
1898
 
2236
 
        mutex_exit(&ibuf_mutex);
2237
 
 
2238
1899
        ibuf_bitmap_page_set_bits(
2239
1900
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr);
2240
1901
 
2243
1904
#endif
2244
1905
        mtr_commit(&mtr);
2245
1906
 
 
1907
        mutex_exit(&ibuf_mutex);
 
1908
 
2246
1909
        ibuf_exit();
2247
1910
}
2248
1911
 
2283
1946
 
2284
1947
        for (i = 0; i < 4; i++) {
2285
1948
 
2286
 
                ibool   too_much_free;
2287
 
 
2288
1949
                mutex_enter(&ibuf_mutex);
2289
 
                too_much_free = ibuf_data_too_much_free();
2290
 
                mutex_exit(&ibuf_mutex);
2291
 
 
2292
 
                if (!too_much_free) {
 
1950
 
 
1951
                if (!ibuf_data_too_much_free()) {
 
1952
 
 
1953
                        mutex_exit(&ibuf_mutex);
 
1954
 
2293
1955
                        return;
2294
1956
                }
2295
1957
 
 
1958
                mutex_exit(&ibuf_mutex);
 
1959
 
2296
1960
                ibuf_remove_free_page();
2297
1961
        }
2298
1962
}
2335
1999
 
2336
2000
        *n_stored = 0;
2337
2001
 
2338
 
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4);
 
2002
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
2339
2003
 
2340
2004
        if (page_rec_is_supremum(rec)) {
2341
2005
 
2488
2152
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
2489
2153
        ulint           space_ids[IBUF_MAX_N_PAGES_MERGED];
2490
2154
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
 
2155
        ulint           n_stored;
2491
2156
        ulint           sum_sizes;
2492
2157
        mtr_t           mtr;
2493
2158
 
2494
2159
        *n_pages = 0;
2495
2160
        ut_ad(!ibuf_inside());
2496
2161
 
2497
 
        /* We perform a dirty read of ibuf->empty, without latching
2498
 
        the insert buffer root page. We trust this dirty read except
2499
 
        when a slow shutdown is being executed. During a slow
2500
 
        shutdown, the insert buffer merge must be completed. */
 
2162
        mutex_enter(&ibuf_mutex);
2501
2163
 
2502
 
        if (UNIV_UNLIKELY(ibuf->empty)
2503
 
            && UNIV_LIKELY(!srv_shutdown_state)) {
 
2164
        if (ibuf->empty) {
2504
2165
ibuf_is_empty:
2505
 
 
2506
 
#if 0 /* TODO */
2507
 
                if (srv_shutdown_state) {
2508
 
                        /* If the insert buffer becomes empty during
2509
 
                        shutdown, note it in the system tablespace. */
2510
 
 
2511
 
                        trx_sys_set_ibuf_format(TRX_SYS_IBUF_EMPTY);
2512
 
                }
2513
 
 
2514
 
                /* TO DO: call trx_sys_set_ibuf_format() at startup
2515
 
                and whenever ibuf_use is changed to allow buffered
2516
 
                delete-marking or deleting.  Never downgrade the
2517
 
                stamped format except when the insert buffer becomes
2518
 
                empty. */
2519
 
#endif
 
2166
                mutex_exit(&ibuf_mutex);
2520
2167
 
2521
2168
                return(0);
2522
2169
        }
2530
2177
 
2531
2178
        btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr);
2532
2179
 
2533
 
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
2534
 
 
2535
2180
        if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
2536
 
                /* If a B-tree page is empty, it must be the root page
2537
 
                and the whole B-tree must be empty. InnoDB does not
2538
 
                allow empty B-tree pages other than the root. */
2539
 
                ut_ad(ibuf->empty);
2540
 
                ut_ad(page_get_space_id(btr_pcur_get_page(&pcur))
2541
 
                      == IBUF_SPACE_ID);
2542
 
                ut_ad(page_get_page_no(btr_pcur_get_page(&pcur))
2543
 
                      == FSP_IBUF_TREE_ROOT_PAGE_NO);
 
2181
                /* When the ibuf tree is emptied completely, the last record
 
2182
                is removed using an optimistic delete and ibuf_size_update
 
2183
                is not called, causing ibuf->empty to remain FALSE. If we do
 
2184
                not reset it to TRUE here then database shutdown will hang
 
2185
                in the loop in ibuf_contract_for_n_pages. */
 
2186
 
 
2187
                ibuf->empty = TRUE;
2544
2188
 
2545
2189
                ibuf_exit();
2546
2190
 
2550
2194
                goto ibuf_is_empty;
2551
2195
        }
2552
2196
 
 
2197
        mutex_exit(&ibuf_mutex);
 
2198
 
2553
2199
        sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
2554
2200
                                            space_ids, space_versions,
2555
 
                                            page_nos, n_pages);
 
2201
                                            page_nos, &n_stored);
2556
2202
#if 0 /* defined UNIV_IBUF_DEBUG */
2557
2203
        fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
2558
 
                sync, *n_pages, sum_sizes);
 
2204
                sync, n_stored, sum_sizes);
2559
2205
#endif
2560
2206
        ibuf_exit();
2561
2207
 
2563
2209
        btr_pcur_close(&pcur);
2564
2210
 
2565
2211
        buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos,
2566
 
                                  *n_pages);
 
2212
                                  n_stored);
 
2213
        *n_pages = n_stored;
2567
2214
 
2568
2215
        return(sum_sizes + 1);
2569
2216
}
2633
2280
        ibool   sync;
2634
2281
        ulint   sum_sizes;
2635
2282
        ulint   size;
2636
 
        ulint   max_size;
2637
 
 
2638
 
        /* Perform dirty reads of ibuf->size and ibuf->max_size, to
2639
 
        reduce ibuf_mutex contention. ibuf->max_size remains constant
2640
 
        after ibuf_init_at_db_start(), but ibuf->size should be
2641
 
        protected by ibuf_mutex. Given that ibuf->size fits in a
2642
 
        machine word, this should be OK; at worst we are doing some
2643
 
        excessive ibuf_contract() or occasionally skipping a
2644
 
        ibuf_contract(). */
2645
 
        size = ibuf->size;
2646
 
        max_size = ibuf->max_size;
2647
 
 
2648
 
        if (size < max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
 
2283
 
 
2284
        mutex_enter(&ibuf_mutex);
 
2285
 
 
2286
        if (ibuf->size < ibuf->max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
 
2287
                mutex_exit(&ibuf_mutex);
 
2288
 
2649
2289
                return;
2650
2290
        }
2651
2291
 
2652
 
        sync = (size >= max_size + IBUF_CONTRACT_ON_INSERT_SYNC);
 
2292
        sync = FALSE;
 
2293
 
 
2294
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_ON_INSERT_SYNC) {
 
2295
 
 
2296
                sync = TRUE;
 
2297
        }
 
2298
 
 
2299
        mutex_exit(&ibuf_mutex);
2653
2300
 
2654
2301
        /* Contract at least entry_size many bytes */
2655
2302
        sum_sizes = 0;
2656
2303
        size = 1;
2657
2304
 
2658
 
        do {
 
2305
        while ((size > 0) && (sum_sizes < entry_size)) {
2659
2306
 
2660
2307
                size = ibuf_contract(sync);
2661
2308
                sum_sizes += size;
2662
 
        } while (size > 0 && sum_sizes < entry_size);
2663
 
}
2664
 
 
2665
 
/*********************************************************************//**
2666
 
Determine if an insert buffer record has been encountered already.
2667
 
@return TRUE if a new record, FALSE if possible duplicate */
2668
 
static
2669
 
ibool
2670
 
ibuf_get_volume_buffered_hash(
2671
 
/*==========================*/
2672
 
        const rec_t*    rec,    /*!< in: ibuf record in post-4.1 format */
2673
 
        const byte*     types,  /*!< in: fields */
2674
 
        const byte*     data,   /*!< in: start of user record data */
2675
 
        ulint           comp,   /*!< in: 0=ROW_FORMAT=REDUNDANT,
2676
 
                                nonzero=ROW_FORMAT=COMPACT */
2677
 
        ulint*          hash,   /*!< in/out: hash array */
2678
 
        ulint           size)   /*!< in: number of elements in hash array */
2679
 
{
2680
 
        ulint           len;
2681
 
        ulint           fold;
2682
 
        ulint           bitmask;
2683
 
 
2684
 
        len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4,
2685
 
                                FALSE, comp);
2686
 
        fold = ut_fold_binary(data, len);
2687
 
 
2688
 
        hash += (fold / (8 * sizeof *hash)) % size; // 8 = bits in byte
2689
 
        bitmask = 1 << (fold % (8 * sizeof *hash));
2690
 
 
2691
 
        if (*hash & bitmask) {
2692
 
 
2693
 
                return(FALSE);
2694
 
        }
2695
 
 
2696
 
        /* We have not seen this record yet.  Insert it. */
2697
 
        *hash |= bitmask;
2698
 
 
2699
 
        return(TRUE);
2700
 
}
2701
 
 
2702
 
/*********************************************************************//**
2703
 
Update the estimate of the number of records on a page, and
2704
 
get the space taken by merging the buffered record to the index page.
2705
 
@return size of index record in bytes + an upper limit of the space
2706
 
taken in the page directory */
2707
 
static
2708
 
ulint
2709
 
ibuf_get_volume_buffered_count(
2710
 
/*===========================*/
2711
 
        const rec_t*    rec,    /*!< in: insert buffer record */
2712
 
        ulint*          hash,   /*!< in/out: hash array */
2713
 
        ulint           size,   /*!< in: number of elements in hash array */
2714
 
        lint*           n_recs) /*!< in/out: estimated number of records
2715
 
                                on the page that rec points to */
2716
 
{
2717
 
        ulint           len;
2718
 
        ibuf_op_t       ibuf_op;
2719
 
        const byte*     types;
2720
 
        ulint           n_fields        = rec_get_n_fields_old(rec);
2721
 
 
2722
 
        ut_ad(ibuf_inside());
2723
 
        ut_ad(n_fields > 4);
2724
 
        n_fields -= 4;
2725
 
 
2726
 
        rec_get_nth_field_offs_old(rec, 1, &len);
2727
 
        /* This function is only invoked when buffering new
2728
 
        operations.  All pre-4.1 records should have been merged
2729
 
        when the database was started up. */
2730
 
        ut_a(len == 1);
2731
 
        ut_ad(trx_sys_multiple_tablespace_format);
2732
 
 
2733
 
        types = rec_get_nth_field_old(rec, 3, &len);
2734
 
 
2735
 
        switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
2736
 
                            IBUF_REC_INFO_SIZE)) {
2737
 
        default:
2738
 
                ut_error;
2739
 
        case 0:
2740
 
                /* This ROW_TYPE=REDUNDANT record does not include an
2741
 
                operation counter.  Exclude it from the *n_recs,
2742
 
                because deletes cannot be buffered if there are
2743
 
                old-style inserts buffered for the page. */
2744
 
 
2745
 
                len = ibuf_rec_get_size(rec, types, n_fields, FALSE, 0);
2746
 
 
2747
 
                return(len
2748
 
                       + rec_get_converted_extra_size(len, n_fields, 0)
2749
 
                       + page_dir_calc_reserved_space(1));
2750
 
        case 1:
2751
 
                /* This ROW_TYPE=COMPACT record does not include an
2752
 
                operation counter.  Exclude it from the *n_recs,
2753
 
                because deletes cannot be buffered if there are
2754
 
                old-style inserts buffered for the page. */
2755
 
                goto get_volume_comp;
2756
 
 
2757
 
        case IBUF_REC_INFO_SIZE:
2758
 
                ibuf_op = (ibuf_op_t) types[IBUF_REC_OFFSET_TYPE];
2759
 
                break;
2760
 
        }
2761
 
 
2762
 
        switch (ibuf_op) {
2763
 
        case IBUF_OP_INSERT:
2764
 
                /* Inserts can be done by
2765
 
                btr_cur_set_deleted_flag_for_ibuf().  Because
2766
 
                delete-mark and insert operations can be pointing to
2767
 
                the same records, we must not count duplicates. */
2768
 
        case IBUF_OP_DELETE_MARK:
2769
 
                /* There must be a record to delete-mark.
2770
 
                See if this record has been already buffered. */
2771
 
                if (n_recs && ibuf_get_volume_buffered_hash(
2772
 
                            rec, types + IBUF_REC_INFO_SIZE,
2773
 
                            types + len,
2774
 
                            types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT,
2775
 
                            hash, size)) {
2776
 
                        (*n_recs)++;
2777
 
                }
2778
 
 
2779
 
                if (ibuf_op == IBUF_OP_DELETE_MARK) {
2780
 
                        /* Setting the delete-mark flag does not
2781
 
                        affect the available space on the page. */
2782
 
                        return(0);
2783
 
                }
2784
 
                break;
2785
 
        case IBUF_OP_DELETE:
2786
 
                /* A record will be removed from the page. */
2787
 
                if (n_recs) {
2788
 
                        (*n_recs)--;
2789
 
                }
2790
 
                /* While deleting a record actually frees up space,
2791
 
                we have to play it safe and pretend that it takes no
2792
 
                additional space (the record might not exist, etc.). */
2793
 
                return(0);
2794
 
        default:
2795
 
                ut_error;
2796
 
        }
2797
 
 
2798
 
        ut_ad(ibuf_op == IBUF_OP_INSERT);
2799
 
 
2800
 
get_volume_comp:
2801
 
        {
2802
 
                dtuple_t*       entry;
2803
 
                ulint           volume;
2804
 
                dict_index_t*   dummy_index;
2805
 
                mem_heap_t*     heap = mem_heap_create(500);
2806
 
 
2807
 
                entry = ibuf_build_entry_from_ibuf_rec(
2808
 
                        rec, heap, &dummy_index);
2809
 
 
2810
 
                volume = rec_get_converted_size(dummy_index, entry, 0);
2811
 
 
2812
 
                ibuf_dummy_index_free(dummy_index);
2813
 
                mem_heap_free(heap);
2814
 
 
2815
 
                return(volume + page_dir_calc_reserved_space(1));
2816
2309
        }
2817
2310
}
2818
2311
 
2833
2326
                                or BTR_MODIFY_TREE */
2834
2327
        ulint           space,  /*!< in: space id */
2835
2328
        ulint           page_no,/*!< in: page number of an index page */
2836
 
        lint*           n_recs, /*!< in/out: minimum number of records on the
2837
 
                                page after the buffered changes have been
2838
 
                                applied, or NULL to disable the counting */
2839
2329
        mtr_t*          mtr)    /*!< in: mtr */
2840
2330
{
2841
2331
        ulint   volume;
2845
2335
        page_t* prev_page;
2846
2336
        ulint   next_page_no;
2847
2337
        page_t* next_page;
2848
 
        ulint   hash_bitmap[128 / sizeof(ulint)]; /* bitmap of buffered recs */
2849
2338
 
2850
2339
        ut_a(trx_sys_multiple_tablespace_format);
2851
2340
 
2852
2341
        ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
2853
2342
              || (pcur->latch_mode == BTR_MODIFY_TREE));
2854
2343
 
2855
 
        /* Count the volume of inserts earlier in the alphabetical order than
 
2344
        /* Count the volume of records earlier in the alphabetical order than
2856
2345
        pcur */
2857
2346
 
2858
2347
        volume = 0;
2859
2348
 
2860
 
        if (n_recs) {
2861
 
                memset(hash_bitmap, 0, sizeof hash_bitmap);
2862
 
        }
2863
 
 
2864
2349
        rec = btr_pcur_get_rec(pcur);
2865
2350
        page = page_align(rec);
2866
 
        ut_ad(page_validate(page, ibuf->index));
2867
2351
 
2868
2352
        if (page_rec_is_supremum(rec)) {
2869
2353
                rec = page_rec_get_prev(rec);
2881
2365
                        goto count_later;
2882
2366
                }
2883
2367
 
2884
 
                volume += ibuf_get_volume_buffered_count(
2885
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2368
                volume += ibuf_rec_get_volume(rec);
2886
2369
 
2887
2370
                rec = page_rec_get_prev(rec);
2888
 
                ut_ad(page_align(rec) == page);
2889
2371
        }
2890
2372
 
2891
2373
        /* Look at the previous page */
2907
2389
 
2908
2390
 
2909
2391
                prev_page = buf_block_get_frame(block);
2910
 
                ut_ad(page_validate(prev_page, ibuf->index));
2911
2392
        }
2912
2393
 
2913
2394
#ifdef UNIV_BTR_DEBUG
2934
2415
                        goto count_later;
2935
2416
                }
2936
2417
 
2937
 
                volume += ibuf_get_volume_buffered_count(
2938
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2418
                volume += ibuf_rec_get_volume(rec);
2939
2419
 
2940
2420
                rec = page_rec_get_prev(rec);
2941
 
                ut_ad(page_align(rec) == prev_page);
2942
2421
        }
2943
2422
 
2944
2423
count_later:
2960
2439
                        return(volume);
2961
2440
                }
2962
2441
 
2963
 
                volume += ibuf_get_volume_buffered_count(
2964
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2442
                volume += ibuf_rec_get_volume(rec);
2965
2443
 
2966
2444
                rec = page_rec_get_next(rec);
2967
2445
        }
2985
2463
 
2986
2464
 
2987
2465
                next_page = buf_block_get_frame(block);
2988
 
                ut_ad(page_validate(next_page, ibuf->index));
2989
2466
        }
2990
2467
 
2991
2468
#ifdef UNIV_BTR_DEBUG
3009
2486
                        return(volume);
3010
2487
                }
3011
2488
 
3012
 
                volume += ibuf_get_volume_buffered_count(
3013
 
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
 
2489
                volume += ibuf_rec_get_volume(rec);
3014
2490
 
3015
2491
                rec = page_rec_get_next(rec);
3016
 
                ut_ad(page_align(rec) == next_page);
3017
2492
        }
3018
2493
}
3019
2494
 
3041
2516
        btr_pcur_open_at_index_side(
3042
2517
                FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3043
2518
 
3044
 
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
3045
 
 
3046
2519
        btr_pcur_move_to_prev(&pcur, &mtr);
3047
2520
 
3048
2521
        if (btr_pcur_is_before_first_on_page(&pcur)) {
3067
2540
        fil_set_max_space_id_if_bigger(max_space_id);
3068
2541
}
3069
2542
 
3070
 
/****************************************************************//**
3071
 
Helper function for ibuf_set_entry_counter. Checks if rec is for (space,
3072
 
page_no), and if so, reads counter value from it and returns that + 1.
3073
 
Otherwise, returns 0.
3074
 
@return new counter value, or 0 */
3075
 
static
3076
 
ulint
3077
 
ibuf_get_entry_counter_low(
3078
 
/*=======================*/
3079
 
        const rec_t*    rec,            /*!< in: insert buffer record */
3080
 
        ulint           space,          /*!< in: space id */
3081
 
        ulint           page_no)        /*!< in: page number */
3082
 
{
3083
 
        ulint           counter;
3084
 
        const byte*     field;
3085
 
        ulint           len;
3086
 
 
3087
 
        ut_ad(ibuf_inside());
3088
 
        ut_ad(rec_get_n_fields_old(rec) > 2);
3089
 
 
3090
 
        field = rec_get_nth_field_old(rec, 1, &len);
3091
 
 
3092
 
        if (UNIV_UNLIKELY(len != 1)) {
3093
 
                /* pre-4.1 format */
3094
 
                ut_a(trx_doublewrite_must_reset_space_ids);
3095
 
                ut_a(!trx_sys_multiple_tablespace_format);
3096
 
 
3097
 
                return(ULINT_UNDEFINED);
3098
 
        }
3099
 
 
3100
 
        ut_a(trx_sys_multiple_tablespace_format);
3101
 
 
3102
 
        /* Check the tablespace identifier. */
3103
 
        field = rec_get_nth_field_old(rec, 0, &len);
3104
 
        ut_a(len == 4);
3105
 
 
3106
 
        if (mach_read_from_4(field) != space) {
3107
 
 
3108
 
                return(0);
3109
 
        }
3110
 
 
3111
 
        /* Check the page offset. */
3112
 
        field = rec_get_nth_field_old(rec, 2, &len);
3113
 
        ut_a(len == 4);
3114
 
 
3115
 
        if (mach_read_from_4(field) != page_no) {
3116
 
 
3117
 
                return(0);
3118
 
        }
3119
 
 
3120
 
        /* Check if the record contains a counter field. */
3121
 
        field = rec_get_nth_field_old(rec, 3, &len);
3122
 
 
3123
 
        switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
3124
 
        default:
3125
 
                ut_error;
3126
 
        case 0: /* ROW_FORMAT=REDUNDANT */
3127
 
        case 1: /* ROW_FORMAT=COMPACT */
3128
 
                return(ULINT_UNDEFINED);
3129
 
 
3130
 
        case IBUF_REC_INFO_SIZE:
3131
 
                counter = mach_read_from_2(field + IBUF_REC_OFFSET_COUNTER);
3132
 
                ut_a(counter < 0xFFFF);
3133
 
                return(counter + 1);
3134
 
        }
3135
 
}
3136
 
 
3137
 
/****************************************************************//**
3138
 
Set the counter field in entry to the correct value based on the current
3139
 
last record in ibuf for (space, page_no).
3140
 
@return FALSE if we should abort this insertion to ibuf */
3141
 
static
3142
 
ibool
3143
 
ibuf_set_entry_counter(
3144
 
/*===================*/
3145
 
        dtuple_t*       entry,          /*!< in/out: entry to patch */
3146
 
        ulint           space,          /*!< in: space id of entry */
3147
 
        ulint           page_no,        /*!< in: page number of entry */
3148
 
        btr_pcur_t*     pcur,           /*!< in: pcur positioned on the record
3149
 
                                        found by btr_pcur_open(.., entry,
3150
 
                                        PAGE_CUR_LE, ..., pcur, ...) */
3151
 
        ibool           is_optimistic,  /*!< in: is this an optimistic insert */
3152
 
        mtr_t*          mtr)            /*!< in: mtr */
3153
 
{
3154
 
        dfield_t*       field;
3155
 
        byte*           data;
3156
 
        ulint           counter = 0;
3157
 
 
3158
 
        /* pcur points to either a user rec or to a page's infimum record. */
3159
 
        ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index));
3160
 
 
3161
 
        if (btr_pcur_is_on_user_rec(pcur)) {
3162
 
 
3163
 
                counter = ibuf_get_entry_counter_low(
3164
 
                        btr_pcur_get_rec(pcur), space, page_no);
3165
 
 
3166
 
                if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
3167
 
                        /* The record lacks a counter field.
3168
 
                        Such old records must be merged before
3169
 
                        new records can be buffered. */
3170
 
 
3171
 
                        return(FALSE);
3172
 
                }
3173
 
        } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) {
3174
 
                /* Ibuf tree is either completely empty, or the insert
3175
 
                position is at the very first record of a non-empty tree. In
3176
 
                either case we have no previous records for (space,
3177
 
                page_no). */
3178
 
 
3179
 
                counter = 0;
3180
 
        } else if (btr_pcur_is_before_first_on_page(pcur)) {
3181
 
                btr_cur_t*      cursor = btr_pcur_get_btr_cur(pcur);
3182
 
 
3183
 
                if (cursor->low_match < 3) {
3184
 
                        /* If low_match < 3, we know that the father node
3185
 
                        pointer did not contain the searched for (space,
3186
 
                        page_no), which means that the search ended on the
3187
 
                        right page regardless of the counter value, and
3188
 
                        since we're at the infimum record, there are no
3189
 
                        existing records. */
3190
 
 
3191
 
                        counter = 0;
3192
 
                } else {
3193
 
                        rec_t*          rec;
3194
 
                        const page_t*   page;
3195
 
                        buf_block_t*    block;
3196
 
                        page_t*         prev_page;
3197
 
                        ulint           prev_page_no;
3198
 
 
3199
 
                        ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED);
3200
 
 
3201
 
                        page = btr_pcur_get_page(pcur);
3202
 
                        prev_page_no = btr_page_get_prev(page, mtr);
3203
 
 
3204
 
                        ut_a(prev_page_no != FIL_NULL);
3205
 
 
3206
 
                        block = buf_page_get(
3207
 
                                IBUF_SPACE_ID, 0, prev_page_no,
3208
 
                                RW_X_LATCH, mtr);
3209
 
 
3210
 
                        buf_block_dbg_add_level(block, SYNC_TREE_NODE);
3211
 
 
3212
 
                        prev_page = buf_block_get_frame(block);
3213
 
 
3214
 
                        rec = page_rec_get_prev(
3215
 
                                page_get_supremum_rec(prev_page));
3216
 
 
3217
 
                        ut_ad(page_rec_is_user_rec(rec));
3218
 
 
3219
 
                        counter = ibuf_get_entry_counter_low(
3220
 
                                rec, space, page_no);
3221
 
 
3222
 
                        if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
3223
 
                                /* The record lacks a counter field.
3224
 
                                Such old records must be merged before
3225
 
                                new records can be buffered. */
3226
 
 
3227
 
                                return(FALSE);
3228
 
                        }
3229
 
 
3230
 
                        if (counter < cursor->ibuf_cnt) {
3231
 
                                /* Search ended on the wrong page. */
3232
 
 
3233
 
                                if (is_optimistic) {
3234
 
                                        /* In an optimistic insert, we can
3235
 
                                        shift the insert position to the left
3236
 
                                        page, since it only needs an X-latch
3237
 
                                        on the page itself, which the
3238
 
                                        original search acquired for us. */
3239
 
 
3240
 
                                        btr_cur_position(
3241
 
                                                ibuf->index, rec, block,
3242
 
                                                btr_pcur_get_btr_cur(pcur));
3243
 
                                } else {
3244
 
                                        /* We can't shift the insert
3245
 
                                        position to the left page in a
3246
 
                                        pessimistic insert since it would
3247
 
                                        require an X-latch on the left
3248
 
                                        page's left page, so we have to
3249
 
                                        abort. */
3250
 
 
3251
 
                                        return(FALSE);
3252
 
                                }
3253
 
                        } else {
3254
 
                                /* The counter field in the father node is
3255
 
                                the same as we would insert; we don't know
3256
 
                                whether the insert should go to this page or
3257
 
                                the left page (the later fields can differ),
3258
 
                                so refuse the insert. */
3259
 
 
3260
 
                                return(FALSE);
3261
 
                        }
3262
 
                }
3263
 
        } else {
3264
 
                /* The cursor is not positioned at or before a user record. */
3265
 
                return(FALSE);
3266
 
        }
3267
 
 
3268
 
        /* Patch counter value in already built entry. */
3269
 
        field = dtuple_get_nth_field(entry, 3);
3270
 
        data = dfield_get_data(field);
3271
 
 
3272
 
        mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter);
3273
 
 
3274
 
        return(TRUE);
3275
 
}
3276
 
 
3277
2543
/*********************************************************************//**
3278
 
Buffer an operation in the insert/delete buffer, instead of doing it
3279
 
directly to the disk page, if this is possible.
3280
 
@return DB_SUCCESS, DB_STRONG_FAIL or other error */
 
2544
Makes an index insert to the insert buffer, instead of directly to the disk
 
2545
page, if this is possible.
 
2546
@return DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */
3281
2547
static
3282
2548
ulint
3283
2549
ibuf_insert_low(
3284
2550
/*============*/
3285
2551
        ulint           mode,   /*!< in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */
3286
 
        ibuf_op_t       op,     /*!< in: operation type */
3287
 
        ibool           no_counter,
3288
 
                                /*!< in: TRUE=use 5.0.3 format;
3289
 
                                FALSE=allow delete buffering */
3290
2552
        const dtuple_t* entry,  /*!< in: index entry to insert */
3291
2553
        ulint           entry_size,
3292
2554
                                /*!< in: rec_get_converted_size(index, entry) */
3303
2565
        dtuple_t*       ibuf_entry;
3304
2566
        mem_heap_t*     heap;
3305
2567
        ulint           buffered;
3306
 
        lint            min_n_recs;
3307
2568
        rec_t*          ins_rec;
3308
2569
        ibool           old_bit_value;
3309
2570
        page_t*         bitmap_page;
3310
 
        buf_block_t*    block;
3311
2571
        page_t*         root;
3312
2572
        ulint           err;
3313
2573
        ibool           do_merge;
3315
2575
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
3316
2576
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
3317
2577
        ulint           n_stored;
 
2578
        ulint           bits;
3318
2579
        mtr_t           mtr;
3319
2580
        mtr_t           bitmap_mtr;
3320
2581
 
3321
2582
        ut_a(!dict_index_is_clust(index));
3322
2583
        ut_ad(dtuple_check_typed(entry));
3323
2584
        ut_ad(ut_is_2pow(zip_size));
3324
 
        ut_ad(!no_counter || op == IBUF_OP_INSERT);
3325
 
        ut_a(op < IBUF_OP_COUNT);
3326
2585
 
3327
2586
        ut_a(trx_sys_multiple_tablespace_format);
3328
2587
 
3329
2588
        do_merge = FALSE;
3330
2589
 
3331
 
        /* Perform dirty reads of ibuf->size and ibuf->max_size, to
3332
 
        reduce ibuf_mutex contention. ibuf->max_size remains constant
3333
 
        after ibuf_init_at_db_start(), but ibuf->size should be
3334
 
        protected by ibuf_mutex. Given that ibuf->size fits in a
3335
 
        machine word, this should be OK; at worst we are doing some
3336
 
        excessive ibuf_contract() or occasionally skipping a
3337
 
        ibuf_contract(). */
 
2590
        mutex_enter(&ibuf_mutex);
 
2591
 
3338
2592
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
3339
2593
                /* Insert buffer is now too big, contract it but do not try
3340
2594
                to insert */
3341
2595
 
 
2596
                mutex_exit(&ibuf_mutex);
3342
2597
 
3343
2598
#ifdef UNIV_IBUF_DEBUG
3344
2599
                fputs("Ibuf too big\n", stderr);
3349
2604
                return(DB_STRONG_FAIL);
3350
2605
        }
3351
2606
 
 
2607
        mutex_exit(&ibuf_mutex);
 
2608
 
 
2609
        if (mode == BTR_MODIFY_TREE) {
 
2610
                mutex_enter(&ibuf_pessimistic_insert_mutex);
 
2611
 
 
2612
                ibuf_enter();
 
2613
 
 
2614
                mutex_enter(&ibuf_mutex);
 
2615
 
 
2616
                while (!ibuf_data_enough_free_for_insert()) {
 
2617
 
 
2618
                        mutex_exit(&ibuf_mutex);
 
2619
 
 
2620
                        ibuf_exit();
 
2621
 
 
2622
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2623
 
 
2624
                        err = ibuf_add_free_page();
 
2625
 
 
2626
                        if (err == DB_STRONG_FAIL) {
 
2627
 
 
2628
                                return(err);
 
2629
                        }
 
2630
 
 
2631
                        mutex_enter(&ibuf_pessimistic_insert_mutex);
 
2632
 
 
2633
                        ibuf_enter();
 
2634
 
 
2635
                        mutex_enter(&ibuf_mutex);
 
2636
                }
 
2637
        } else {
 
2638
                ibuf_enter();
 
2639
        }
 
2640
 
3352
2641
        heap = mem_heap_create(512);
3353
2642
 
3354
 
        /* Build the entry which contains the space id and the page number
3355
 
        as the first fields and the type information for other fields, and
3356
 
        which will be inserted to the insert buffer. Using a counter value
3357
 
        of 0xFFFF we find the last record for (space, page_no), from which
3358
 
        we can then read the counter value N and use N + 1 in the record we
3359
 
        insert. (We patch the ibuf_entry's counter field to the correct
3360
 
        value just before actually inserting the entry.) */
 
2643
        /* Build the entry which contains the space id and the page number as
 
2644
        the first fields and the type information for other fields, and which
 
2645
        will be inserted to the insert buffer. */
3361
2646
 
3362
 
        ibuf_entry = ibuf_entry_build(
3363
 
                op, index, entry, space, page_no,
3364
 
                no_counter ? ULINT_UNDEFINED : 0xFFFF, heap);
 
2647
        ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap);
3365
2648
 
3366
2649
        /* Open a cursor to the insert buffer tree to calculate if we can add
3367
2650
        the new entry to it without exceeding the free space limit for the
3368
2651
        page. */
3369
2652
 
3370
 
        if (mode == BTR_MODIFY_TREE) {
3371
 
                for (;;) {
3372
 
                        ibuf_enter();
3373
 
                        mutex_enter(&ibuf_pessimistic_insert_mutex);
3374
 
                        mutex_enter(&ibuf_mutex);
3375
 
 
3376
 
                        if (UNIV_LIKELY(ibuf_data_enough_free_for_insert())) {
3377
 
 
3378
 
                                break;
3379
 
                        }
3380
 
 
3381
 
                        mutex_exit(&ibuf_mutex);
3382
 
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
3383
 
                        ibuf_exit();
3384
 
 
3385
 
                        if (UNIV_UNLIKELY(!ibuf_add_free_page())) {
3386
 
 
3387
 
                                mem_heap_free(heap);
3388
 
                                return(DB_STRONG_FAIL);
3389
 
                        }
3390
 
                }
3391
 
        } else {
3392
 
                ibuf_enter();
3393
 
        }
3394
 
 
3395
2653
        mtr_start(&mtr);
3396
2654
 
3397
2655
        btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
3398
 
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
3399
2656
 
3400
2657
        /* Find out the volume of already buffered inserts for the same index
3401
2658
        page */
3402
 
        min_n_recs = 0;
3403
 
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no,
3404
 
                                            op == IBUF_OP_DELETE
3405
 
                                            ? &min_n_recs
3406
 
                                            : NULL, &mtr);
3407
 
 
3408
 
        if (op == IBUF_OP_DELETE
3409
 
            && (min_n_recs < 2
3410
 
                || buf_pool_watch_occurred(space, page_no))) {
3411
 
                /* The page could become empty after the record is
3412
 
                deleted, or the page has been read in to the buffer
3413
 
                pool.  Refuse to buffer the operation. */
3414
 
 
3415
 
                /* The buffer pool watch is needed for IBUF_OP_DELETE
3416
 
                because of latching order considerations.  We can
3417
 
                check buf_pool_watch_occurred() only after latching
3418
 
                the insert buffer B-tree pages that contain buffered
3419
 
                changes for the page.  We never buffer IBUF_OP_DELETE,
3420
 
                unless some IBUF_OP_INSERT or IBUF_OP_DELETE_MARK have
3421
 
                been previously buffered for the page.  Because there
3422
 
                are buffered operations for the page, the insert
3423
 
                buffer B-tree page latches held by mtr will guarantee
3424
 
                that no changes for the user page will be merged
3425
 
                before mtr_commit(&mtr).  We must not mtr_commit(&mtr)
3426
 
                until after the IBUF_OP_DELETE has been buffered. */
3427
 
 
3428
 
fail_exit:
3429
 
                if (mode == BTR_MODIFY_TREE) {
3430
 
                        mutex_exit(&ibuf_mutex);
3431
 
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
3432
 
                }
3433
 
 
3434
 
                err = DB_STRONG_FAIL;
3435
 
                goto func_exit;
3436
 
        }
3437
 
 
3438
 
        /* After this point, the page could still be loaded to the
3439
 
        buffer pool, but we do not have to care about it, since we are
3440
 
        holding a latch on the insert buffer leaf page that contains
3441
 
        buffered changes for (space, page_no).  If the page enters the
3442
 
        buffer pool, buf_page_io_complete() for (space, page_no) will
3443
 
        have to acquire a latch on the same insert buffer leaf page,
3444
 
        which it cannot do until we have buffered the IBUF_OP_DELETE
3445
 
        and done mtr_commit(&mtr) to release the latch. */
 
2659
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
3446
2660
 
3447
2661
#ifdef UNIV_IBUF_COUNT_DEBUG
3448
2662
        ut_a((buffered == 0) || ibuf_count_get(space, page_no));
3456
2670
 
3457
2671
        if (buf_page_peek(space, page_no)
3458
2672
            || lock_rec_expl_exist_on_page(space, page_no)) {
3459
 
 
3460
 
                goto bitmap_fail;
3461
 
        }
3462
 
 
3463
 
        if (op == IBUF_OP_INSERT) {
3464
 
                ulint   bits = ibuf_bitmap_page_get_bits(
3465
 
                        bitmap_page, page_no, zip_size, IBUF_BITMAP_FREE,
3466
 
                        &bitmap_mtr);
3467
 
 
3468
 
                if (buffered + entry_size + page_dir_calc_reserved_space(1)
3469
 
                    > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
3470
 
                        /* Release the bitmap page latch early. */
3471
 
                        mtr_commit(&bitmap_mtr);
3472
 
 
3473
 
                        /* It may not fit */
3474
 
                        do_merge = TRUE;
3475
 
 
3476
 
                        ibuf_get_merge_page_nos(
3477
 
                                FALSE, btr_pcur_get_rec(&pcur),
3478
 
                                space_ids, space_versions,
3479
 
                                page_nos, &n_stored);
3480
 
 
3481
 
                        goto fail_exit;
3482
 
                }
3483
 
        }
3484
 
 
3485
 
        /* Patch correct counter value to the entry to insert. This can
3486
 
        change the insert position, which can result in the need to abort in
3487
 
        some cases. */
3488
 
        if (!no_counter
3489
 
            && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur,
3490
 
                                       mode == BTR_MODIFY_PREV, &mtr)) {
3491
 
bitmap_fail:
3492
 
                mtr_commit(&bitmap_mtr);
3493
 
 
3494
 
                goto fail_exit;
 
2673
                err = DB_STRONG_FAIL;
 
2674
 
 
2675
                mtr_commit(&bitmap_mtr);
 
2676
 
 
2677
                goto function_exit;
 
2678
        }
 
2679
 
 
2680
        bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
 
2681
                                         IBUF_BITMAP_FREE, &bitmap_mtr);
 
2682
 
 
2683
        if (buffered + entry_size + page_dir_calc_reserved_space(1)
 
2684
            > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
 
2685
                mtr_commit(&bitmap_mtr);
 
2686
 
 
2687
                /* It may not fit */
 
2688
                err = DB_STRONG_FAIL;
 
2689
 
 
2690
                do_merge = TRUE;
 
2691
 
 
2692
                ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
 
2693
                                        space_ids, space_versions,
 
2694
                                        page_nos, &n_stored);
 
2695
                goto function_exit;
3495
2696
        }
3496
2697
 
3497
2698
        /* Set the bitmap bit denoting that the insert buffer contains
3515
2716
                err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
3516
2717
                                                ibuf_entry, &ins_rec,
3517
2718
                                                &dummy_big_rec, 0, thr, &mtr);
3518
 
                block = btr_cur_get_block(cursor);
3519
 
                ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
3520
 
 
3521
 
                /* If this is the root page, update ibuf->empty. */
3522
 
                if (UNIV_UNLIKELY(buf_block_get_page_no(block)
3523
 
                                  == FSP_IBUF_TREE_ROOT_PAGE_NO)) {
3524
 
                        const page_t*   root = buf_block_get_frame(block);
3525
 
 
3526
 
                        ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
3527
 
                        ut_ad(page_get_page_no(root)
3528
 
                              == FSP_IBUF_TREE_ROOT_PAGE_NO);
3529
 
 
3530
 
                        ibuf->empty = (page_get_n_recs(root) == 0);
 
2719
                if (err == DB_SUCCESS) {
 
2720
                        /* Update the page max trx id field */
 
2721
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
 
2722
                                               thr_get_trx(thr)->id, &mtr);
3531
2723
                }
3532
2724
        } else {
3533
2725
                ut_ad(mode == BTR_MODIFY_TREE);
3544
2736
                                                 cursor,
3545
2737
                                                 ibuf_entry, &ins_rec,
3546
2738
                                                 &dummy_big_rec, 0, thr, &mtr);
3547
 
                mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2739
                if (err == DB_SUCCESS) {
 
2740
                        /* Update the page max trx id field */
 
2741
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
 
2742
                                               thr_get_trx(thr)->id, &mtr);
 
2743
                }
 
2744
 
3548
2745
                ibuf_size_update(root, &mtr);
3549
 
                mutex_exit(&ibuf_mutex);
3550
 
                ibuf->empty = (page_get_n_recs(root) == 0);
3551
 
 
3552
 
                block = btr_cur_get_block(cursor);
3553
 
                ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
3554
 
        }
3555
 
 
3556
 
        if (err == DB_SUCCESS && op != IBUF_OP_DELETE) {
3557
 
                /* Update the page max trx id field */
3558
 
                page_update_max_trx_id(block, NULL,
3559
 
                                       thr_get_trx(thr)->id, &mtr);
3560
 
        }
3561
 
 
3562
 
func_exit:
 
2746
        }
 
2747
 
 
2748
function_exit:
3563
2749
#ifdef UNIV_IBUF_COUNT_DEBUG
3564
2750
        if (err == DB_SUCCESS) {
3565
2751
                fprintf(stderr,
3571
2757
                               ibuf_count_get(space, page_no) + 1);
3572
2758
        }
3573
2759
#endif
 
2760
        if (mode == BTR_MODIFY_TREE) {
 
2761
 
 
2762
                mutex_exit(&ibuf_mutex);
 
2763
                mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2764
        }
3574
2765
 
3575
2766
        mtr_commit(&mtr);
3576
2767
        btr_pcur_close(&pcur);
3578
2769
 
3579
2770
        mem_heap_free(heap);
3580
2771
 
3581
 
        if (err == DB_SUCCESS && mode == BTR_MODIFY_TREE) {
3582
 
                ibuf_contract_after_insert(entry_size);
 
2772
        if (err == DB_SUCCESS) {
 
2773
                mutex_enter(&ibuf_mutex);
 
2774
 
 
2775
                ibuf->empty = FALSE;
 
2776
                ibuf->n_inserts++;
 
2777
 
 
2778
                mutex_exit(&ibuf_mutex);
 
2779
 
 
2780
                if (mode == BTR_MODIFY_TREE) {
 
2781
                        ibuf_contract_after_insert(entry_size);
 
2782
                }
3583
2783
        }
3584
2784
 
3585
2785
        if (do_merge) {
3594
2794
}
3595
2795
 
3596
2796
/*********************************************************************//**
3597
 
Buffer an operation in the insert/delete buffer, instead of doing it
3598
 
directly to the disk page, if this is possible. Does not do it if the index
3599
 
is clustered or unique.
 
2797
Makes an index insert to the insert buffer, instead of directly to the disk
 
2798
page, if this is possible. Does not do insert if the index is clustered
 
2799
or unique.
3600
2800
@return TRUE if success */
3601
2801
UNIV_INTERN
3602
2802
ibool
3603
2803
ibuf_insert(
3604
2804
/*========*/
3605
 
        ibuf_op_t       op,     /*!< in: operation type */
3606
2805
        const dtuple_t* entry,  /*!< in: index entry to insert */
3607
2806
        dict_index_t*   index,  /*!< in: index where to insert */
3608
2807
        ulint           space,  /*!< in: space id where to insert */
3610
2809
        ulint           page_no,/*!< in: page number where to insert */
3611
2810
        que_thr_t*      thr)    /*!< in: query thread */
3612
2811
{
3613
 
        ulint           err;
3614
 
        ulint           entry_size;
3615
 
        ibool           no_counter;
3616
 
        /* Read the settable global variable ibuf_use only once in
3617
 
        this function, so that we will have a consistent view of it. */
3618
 
        ibuf_use_t      use             = ibuf_use;
 
2812
        ulint   err;
 
2813
        ulint   entry_size;
3619
2814
 
3620
2815
        ut_a(trx_sys_multiple_tablespace_format);
3621
2816
        ut_ad(dtuple_check_typed(entry));
3623
2818
 
3624
2819
        ut_a(!dict_index_is_clust(index));
3625
2820
 
3626
 
        no_counter = use <= IBUF_USE_INSERT;
3627
 
 
3628
 
        switch (op) {
3629
 
        case IBUF_OP_INSERT:
3630
 
                switch (use) {
3631
 
                case IBUF_USE_NONE:
3632
 
                case IBUF_USE_DELETE:
3633
 
                case IBUF_USE_DELETE_MARK:
3634
 
                        return(FALSE);
3635
 
                case IBUF_USE_INSERT:
3636
 
                case IBUF_USE_INSERT_DELETE_MARK:
3637
 
                case IBUF_USE_ALL:
3638
 
                        goto check_watch;
3639
 
                case IBUF_USE_COUNT:
3640
 
                        break;
3641
 
                }
3642
 
                break;
3643
 
        case IBUF_OP_DELETE_MARK:
3644
 
                switch (use) {
3645
 
                case IBUF_USE_NONE:
3646
 
                case IBUF_USE_INSERT:
3647
 
                        return(FALSE);
3648
 
                case IBUF_USE_DELETE_MARK:
3649
 
                case IBUF_USE_DELETE:
3650
 
                case IBUF_USE_INSERT_DELETE_MARK:
3651
 
                case IBUF_USE_ALL:
3652
 
                        ut_ad(!no_counter);
3653
 
                        goto check_watch;
3654
 
                case IBUF_USE_COUNT:
3655
 
                        break;
3656
 
                }
3657
 
                break;
3658
 
        case IBUF_OP_DELETE:
3659
 
                switch (use) {
3660
 
                case IBUF_USE_NONE:
3661
 
                case IBUF_USE_INSERT:
3662
 
                case IBUF_USE_INSERT_DELETE_MARK:
3663
 
                        return(FALSE);
3664
 
                case IBUF_USE_DELETE_MARK:
3665
 
                case IBUF_USE_DELETE:
3666
 
                case IBUF_USE_ALL:
3667
 
                        ut_ad(!no_counter);
3668
 
                        goto skip_watch;
3669
 
                case IBUF_USE_COUNT:
3670
 
                        break;
3671
 
                }
3672
 
                break;
3673
 
        case IBUF_OP_COUNT:
3674
 
                break;
3675
 
        }
3676
 
 
3677
 
        /* unknown op or use */
3678
 
        ut_error;
3679
 
 
3680
 
check_watch:
3681
 
        /* If a thread attempts to buffer an insert on a page while a
3682
 
        purge is in progress on the same page, the purge must not be
3683
 
        buffered, because it could remove a record that was
3684
 
        re-inserted later.  For simplicity, we block the buffering of
3685
 
        all operations on a page that has a purge pending.
3686
 
 
3687
 
        We do not check this in the IBUF_OP_DELETE case, because that
3688
 
        would always trigger the buffer pool watch during purge and
3689
 
        thus prevent the buffering of delete operations.  We assume
3690
 
        that the issuer of IBUF_OP_DELETE has called
3691
 
        buf_pool_watch_set(space, page_no). */
3692
 
 
3693
 
        {
3694
 
                buf_page_t*     bpage;
3695
 
                ulint           fold = buf_page_address_fold(space, page_no);
3696
 
                buf_pool_t*     buf_pool = buf_pool_get(space, page_no);
3697
 
 
3698
 
                buf_pool_mutex_enter(buf_pool);
3699
 
                bpage = buf_page_hash_get_low(buf_pool, space, page_no, fold);
3700
 
                buf_pool_mutex_exit(buf_pool);
3701
 
 
3702
 
                if (UNIV_LIKELY_NULL(bpage)) {
3703
 
                        /* A buffer pool watch has been set or the
3704
 
                        page has been read into the buffer pool.
3705
 
                        Do not buffer the request.  If a purge operation
3706
 
                        is being buffered, have this request executed
3707
 
                        directly on the page in the buffer pool after the
3708
 
                        buffered entries for this page have been merged. */
3709
 
                        return(FALSE);
3710
 
                }
3711
 
        }
3712
 
 
3713
 
skip_watch:
 
2821
        switch (UNIV_EXPECT(ibuf_use, IBUF_USE_INSERT)) {
 
2822
        case IBUF_USE_NONE:
 
2823
                return(FALSE);
 
2824
        case IBUF_USE_INSERT:
 
2825
                goto do_insert;
 
2826
        case IBUF_USE_COUNT:
 
2827
                break;
 
2828
        }
 
2829
 
 
2830
        ut_error; /* unknown value of ibuf_use */
 
2831
 
 
2832
do_insert:
3714
2833
        entry_size = rec_get_converted_size(index, entry, 0);
3715
2834
 
3716
2835
        if (entry_size
3717
 
            >= page_get_free_space_of_empty(dict_table_is_comp(index->table))
3718
 
            / 2) {
3719
 
 
 
2836
            >= (page_get_free_space_of_empty(dict_table_is_comp(index->table))
 
2837
                / 2)) {
3720
2838
                return(FALSE);
3721
2839
        }
3722
2840
 
3723
 
        err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter,
3724
 
                              entry, entry_size,
 
2841
        err = ibuf_insert_low(BTR_MODIFY_PREV, entry, entry_size,
3725
2842
                              index, space, zip_size, page_no, thr);
3726
2843
        if (err == DB_FAIL) {
3727
 
                err = ibuf_insert_low(BTR_MODIFY_TREE, op, no_counter,
3728
 
                                      entry, entry_size,
 
2844
                err = ibuf_insert_low(BTR_MODIFY_TREE, entry, entry_size,
3729
2845
                                      index, space, zip_size, page_no, thr);
3730
2846
        }
3731
2847
 
3777
2893
 
3778
2894
        rec = page_rec_get_next(page_get_infimum_rec(page));
3779
2895
 
3780
 
        if (page_rec_is_supremum(rec)) {
3781
 
                fputs("InnoDB: Trying to insert a record from"
3782
 
                      " the insert buffer to an index page\n"
3783
 
                      "InnoDB: but the index page is empty!\n",
3784
 
                      stderr);
3785
 
                goto dump;
3786
 
        }
3787
 
 
3788
2896
        if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
3789
2897
                          != dtuple_get_n_fields(entry))) {
3790
2898
                fputs("InnoDB: Trying to insert a record from"
3816
2924
                rec = page_cur_get_rec(&page_cur);
3817
2925
                page_zip = buf_block_get_page_zip(block);
3818
2926
 
3819
 
                btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, FALSE, mtr);
 
2927
                btr_cur_del_unmark_for_ibuf(rec, page_zip, mtr);
3820
2928
        } else {
3821
2929
                rec = page_cur_tuple_insert(&page_cur, entry, index, 0, mtr);
3822
2930
 
3878
2986
        }
3879
2987
}
3880
2988
 
3881
 
/****************************************************************//**
3882
 
During merge, sets the delete mark on a record for a secondary index
3883
 
entry. */
3884
 
static
3885
 
void
3886
 
ibuf_set_del_mark(
3887
 
/*==============*/
3888
 
        const dtuple_t*         entry,  /*!< in: entry */
3889
 
        buf_block_t*            block,  /*!< in/out: block */
3890
 
        const dict_index_t*     index,  /*!< in: record descriptor */
3891
 
        mtr_t*                  mtr)    /*!< in: mtr */
3892
 
{
3893
 
        page_cur_t      page_cur;
3894
 
        ulint           low_match;
3895
 
 
3896
 
        ut_ad(ibuf_inside());
3897
 
        ut_ad(dtuple_check_typed(entry));
3898
 
 
3899
 
        low_match = page_cur_search(
3900
 
                block, index, entry, PAGE_CUR_LE, &page_cur);
3901
 
 
3902
 
        if (low_match == dtuple_get_n_fields(entry)) {
3903
 
                rec_t*          rec;
3904
 
                page_zip_des_t* page_zip;
3905
 
 
3906
 
                rec = page_cur_get_rec(&page_cur);
3907
 
                page_zip = page_cur_get_page_zip(&page_cur);
3908
 
 
3909
 
                btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, TRUE, mtr);
3910
 
        } else {
3911
 
                /* This can happen benignly in some situations. */
3912
 
        }
3913
 
}
3914
 
 
3915
 
/****************************************************************//**
3916
 
During merge, delete a record for a secondary index entry. */
3917
 
static
3918
 
void
3919
 
ibuf_delete(
3920
 
/*========*/
3921
 
        const dtuple_t* entry,  /*!< in: entry */
3922
 
        buf_block_t*    block,  /*!< in/out: block */
3923
 
        dict_index_t*   index,  /*!< in: record descriptor */
3924
 
        mtr_t*          mtr)    /*!< in/out: mtr; must be committed
3925
 
                                before latching any further pages */
3926
 
{
3927
 
        page_cur_t      page_cur;
3928
 
        ulint           low_match;
3929
 
 
3930
 
        ut_ad(ibuf_inside());
3931
 
        ut_ad(dtuple_check_typed(entry));
3932
 
 
3933
 
        low_match = page_cur_search(
3934
 
                block, index, entry, PAGE_CUR_LE, &page_cur);
3935
 
 
3936
 
        if (low_match == dtuple_get_n_fields(entry)) {
3937
 
                page_zip_des_t* page_zip= buf_block_get_page_zip(block);
3938
 
                page_t*         page    = buf_block_get_frame(block);
3939
 
                rec_t*          rec     = page_cur_get_rec(&page_cur);
3940
 
 
3941
 
                /* TODO: the below should probably be a separate function,
3942
 
                it's a bastardized version of btr_cur_optimistic_delete. */
3943
 
 
3944
 
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
3945
 
                ulint*          offsets = offsets_;
3946
 
                mem_heap_t*     heap = NULL;
3947
 
                ulint           max_ins_size;
3948
 
 
3949
 
                rec_offs_init(offsets_);
3950
 
 
3951
 
                offsets = rec_get_offsets(
3952
 
                        rec, index, offsets, ULINT_UNDEFINED, &heap);
3953
 
 
3954
 
                /* Refuse to delete the last record. */
3955
 
                ut_a(page_get_n_recs(page) > 1);
3956
 
 
3957
 
                /* The record should have been marked for deletion. */
3958
 
                ut_ad(REC_INFO_DELETED_FLAG
3959
 
                      & rec_get_info_bits(rec, page_is_comp(page)));
3960
 
 
3961
 
                lock_update_delete(block, rec);
3962
 
 
3963
 
                if (!page_zip) {
3964
 
                        max_ins_size
3965
 
                                = page_get_max_insert_size_after_reorganize(
3966
 
                                        page, 1);
3967
 
                }
3968
 
#ifdef UNIV_ZIP_DEBUG
3969
 
                ut_a(!page_zip || page_zip_validate(page_zip, page));
3970
 
#endif /* UNIV_ZIP_DEBUG */
3971
 
                page_cur_delete_rec(&page_cur, index, offsets, mtr);
3972
 
#ifdef UNIV_ZIP_DEBUG
3973
 
                ut_a(!page_zip || page_zip_validate(page_zip, page));
3974
 
#endif /* UNIV_ZIP_DEBUG */
3975
 
 
3976
 
                if (page_zip) {
3977
 
                        ibuf_update_free_bits_zip(block, mtr);
3978
 
                } else {
3979
 
                        ibuf_update_free_bits_low(block, max_ins_size, mtr);
3980
 
                }
3981
 
 
3982
 
                if (UNIV_LIKELY_NULL(heap)) {
3983
 
                        mem_heap_free(heap);
3984
 
                }
3985
 
        } else {
3986
 
                /* This can happen benignly in some situations: either when
3987
 
                we crashed at just the right time, or on database startup
3988
 
                when we redo some old log entries (due to worse stored
3989
 
                position granularity on disk than in memory). */
3990
 
        }
3991
 
}
3992
 
 
3993
 
/*********************************************************************//**
3994
 
Restores insert buffer tree cursor position
3995
 
@return TRUE if the position was restored; FALSE if not */
3996
 
static __attribute__((nonnull))
3997
 
ibool
3998
 
ibuf_restore_pos(
3999
 
/*=============*/
4000
 
        ulint           space,  /*!< in: space id */
4001
 
        ulint           page_no,/*!< in: index page number where the record
4002
 
                                should belong */
4003
 
        const dtuple_t* search_tuple,
4004
 
                                /*!< in: search tuple for entries of page_no */
4005
 
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
4006
 
        btr_pcur_t*     pcur,   /*!< in/out: persistent cursor whose
4007
 
                                position is to be restored */
4008
 
        mtr_t*          mtr)    /*!< in/out: mini-transaction */
4009
 
{
4010
 
        ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE);
4011
 
 
4012
 
        if (btr_pcur_restore_position(mode, pcur, mtr)) {
4013
 
 
4014
 
                return(TRUE);
4015
 
        }
4016
 
 
4017
 
        if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
4018
 
                /* The tablespace has been dropped.  It is possible
4019
 
                that another thread has deleted the insert buffer
4020
 
                entry.  Do not complain. */
4021
 
                btr_pcur_commit_specify_mtr(pcur, mtr);
4022
 
        } else {
4023
 
                fprintf(stderr,
4024
 
                        "InnoDB: ERROR: Submit the output to"
4025
 
                        " http://bugs.mysql.com\n"
4026
 
                        "InnoDB: ibuf cursor restoration fails!\n"
4027
 
                        "InnoDB: ibuf record inserted to page %lu:%lu\n",
4028
 
                        (ulong) space, (ulong) page_no);
4029
 
                fflush(stderr);
4030
 
 
4031
 
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
4032
 
                rec_print_old(stderr, pcur->old_rec);
4033
 
                dtuple_print(stderr, search_tuple);
4034
 
 
4035
 
                rec_print_old(stderr,
4036
 
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
4037
 
                fflush(stderr);
4038
 
 
4039
 
                btr_pcur_commit_specify_mtr(pcur, mtr);
4040
 
 
4041
 
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
4042
 
                if (!btr_validate_index(ibuf->index, NULL)) {
4043
 
                        ut_error;
4044
 
                }
4045
 
 
4046
 
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
4047
 
                fflush(stderr);
4048
 
        }
4049
 
 
4050
 
        return(FALSE);
4051
 
}
4052
 
 
4053
2989
/*********************************************************************//**
4054
2990
Deletes from ibuf the record on which pcur is positioned. If we have to
4055
2991
resort to a pessimistic delete, this function commits mtr and closes
4080
3016
        success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
4081
3017
 
4082
3018
        if (success) {
4083
 
                if (UNIV_UNLIKELY(!page_get_n_recs(btr_pcur_get_page(pcur)))) {
4084
 
                        /* If a B-tree page is empty, it must be the root page
4085
 
                        and the whole B-tree must be empty. InnoDB does not
4086
 
                        allow empty B-tree pages other than the root. */
4087
 
                        root = btr_pcur_get_page(pcur);
4088
 
 
4089
 
                        ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
4090
 
                        ut_ad(page_get_page_no(root)
4091
 
                              == FSP_IBUF_TREE_ROOT_PAGE_NO);
4092
 
 
4093
 
                        /* ibuf->empty is protected by the root page latch.
4094
 
                        Before the deletion, it had to be FALSE. */
4095
 
                        ut_ad(!ibuf->empty);
4096
 
                        ibuf->empty = TRUE;
4097
 
                }
4098
 
 
4099
3019
#ifdef UNIV_IBUF_COUNT_DEBUG
4100
3020
                fprintf(stderr,
4101
3021
                        "Decrementing ibuf count of space %lu page %lu\n"
4120
3040
 
4121
3041
        mtr_start(mtr);
4122
3042
 
4123
 
        if (!ibuf_restore_pos(space, page_no, search_tuple,
4124
 
                              BTR_MODIFY_TREE, pcur, mtr)) {
4125
 
 
4126
 
                mutex_exit(&ibuf_mutex);
 
3043
        success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
 
3044
 
 
3045
        if (!success) {
 
3046
                if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
 
3047
                        /* The tablespace has been dropped.  It is possible
 
3048
                        that another thread has deleted the insert buffer
 
3049
                        entry.  Do not complain. */
 
3050
                        goto commit_and_exit;
 
3051
                }
 
3052
 
 
3053
                fprintf(stderr,
 
3054
                        "InnoDB: ERROR: Submit the output to"
 
3055
                        " http://bugs.mysql.com\n"
 
3056
                        "InnoDB: ibuf cursor restoration fails!\n"
 
3057
                        "InnoDB: ibuf record inserted to page %lu\n",
 
3058
                        (ulong) page_no);
 
3059
                fflush(stderr);
 
3060
 
 
3061
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
 
3062
                rec_print_old(stderr, pcur->old_rec);
 
3063
                dtuple_print(stderr, search_tuple);
 
3064
 
 
3065
                rec_print_old(stderr,
 
3066
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
 
3067
                fflush(stderr);
 
3068
 
 
3069
                btr_pcur_commit_specify_mtr(pcur, mtr);
 
3070
 
 
3071
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
 
3072
                if (!btr_validate_index(ibuf->index, NULL)) {
 
3073
                        ut_error;
 
3074
                }
 
3075
 
 
3076
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
 
3077
                fflush(stderr);
 
3078
 
4127
3079
                goto func_exit;
4128
3080
        }
4129
3081
 
4137
3089
        ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
4138
3090
#endif
4139
3091
        ibuf_size_update(root, mtr);
4140
 
        mutex_exit(&ibuf_mutex);
4141
3092
 
4142
 
        ibuf->empty = (page_get_n_recs(root) == 0);
 
3093
commit_and_exit:
4143
3094
        btr_pcur_commit_specify_mtr(pcur, mtr);
4144
3095
 
4145
3096
func_exit:
4146
3097
        btr_pcur_close(pcur);
4147
3098
 
 
3099
        mutex_exit(&ibuf_mutex);
 
3100
 
4148
3101
        return(TRUE);
4149
3102
}
4150
3103
 
4151
3104
/*********************************************************************//**
4152
3105
When an index page is read from a disk to the buffer pool, this function
4153
 
applies any buffered operations to the page and deletes the entries from the
4154
 
insert buffer. If the page is not read, but created in the buffer pool, this
4155
 
function deletes its buffered entries from the insert buffer; there can
4156
 
exist entries for such a page if the page belonged to an index which
4157
 
subsequently was dropped. */
 
3106
inserts to the page the possible index entries buffered in the insert buffer.
 
3107
The entries are deleted from the insert buffer. If the page is not read, but
 
3108
created in the buffer pool, this function deletes its buffered entries from
 
3109
the insert buffer; there can exist entries for such a page if the page
 
3110
belonged to an index which subsequently was dropped. */
4158
3111
UNIV_INTERN
4159
3112
void
4160
3113
ibuf_merge_or_delete_for_page(
4175
3128
        mem_heap_t*     heap;
4176
3129
        btr_pcur_t      pcur;
4177
3130
        dtuple_t*       search_tuple;
 
3131
        ulint           n_inserts;
4178
3132
#ifdef UNIV_IBUF_DEBUG
4179
 
        ulint           volume                  = 0;
 
3133
        ulint           volume;
4180
3134
#endif
4181
3135
        page_zip_des_t* page_zip                = NULL;
4182
3136
        ibool           tablespace_being_deleted = FALSE;
4183
3137
        ibool           corruption_noticed      = FALSE;
4184
3138
        mtr_t           mtr;
4185
3139
 
4186
 
        /* Counts for merged & discarded operations. */
4187
 
        ulint           mops[IBUF_OP_COUNT];
4188
 
        ulint           dops[IBUF_OP_COUNT];
4189
 
 
4190
3140
        ut_ad(!block || buf_block_get_space(block) == space);
4191
3141
        ut_ad(!block || buf_block_get_page_no(block) == page_no);
4192
3142
        ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
4329
3279
                }
4330
3280
        }
4331
3281
 
4332
 
        memset(mops, 0, sizeof(mops));
4333
 
        memset(dops, 0, sizeof(dops));
4334
 
 
 
3282
        n_inserts = 0;
 
3283
#ifdef UNIV_IBUF_DEBUG
 
3284
        volume = 0;
 
3285
#endif
4335
3286
loop:
4336
3287
        mtr_start(&mtr);
4337
3288
 
4384
3335
                        fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
4385
3336
                } else if (block) {
4386
3337
                        /* Now we have at pcur a record which should be
4387
 
                        applied on the index page; NOTE that the call below
 
3338
                        inserted to the index page; NOTE that the call below
4388
3339
                        copies pointers to fields in rec, and we must
4389
3340
                        keep the latch to the rec page until the
4390
3341
                        insertion is finished! */
4391
3342
                        dtuple_t*       entry;
4392
3343
                        trx_id_t        max_trx_id;
4393
3344
                        dict_index_t*   dummy_index;
4394
 
                        ibuf_op_t       op = ibuf_rec_get_op_type(rec);
4395
3345
 
4396
3346
                        max_trx_id = page_get_max_trx_id(page_align(rec));
4397
3347
                        page_update_max_trx_id(block, page_zip, max_trx_id,
4398
3348
                                               &mtr);
4399
3349
 
4400
 
                        ut_ad(page_validate(page_align(rec), ibuf->index));
4401
 
 
4402
3350
                        entry = ibuf_build_entry_from_ibuf_rec(
4403
3351
                                rec, heap, &dummy_index);
4404
 
 
4405
 
                        ut_ad(page_validate(block->frame, dummy_index));
4406
 
 
4407
 
                        switch (op) {
4408
 
                                ibool   success;
4409
 
                        case IBUF_OP_INSERT:
4410
3352
#ifdef UNIV_IBUF_DEBUG
4411
 
                                volume += rec_get_converted_size(
4412
 
                                        dummy_index, entry, 0);
4413
 
 
4414
 
                                volume += page_dir_calc_reserved_space(1);
4415
 
 
4416
 
                                ut_a(volume <= 4 * UNIV_PAGE_SIZE
4417
 
                                        / IBUF_PAGE_SIZE_PER_FREE_SPACE);
 
3353
                        volume += rec_get_converted_size(dummy_index, entry, 0)
 
3354
                                + page_dir_calc_reserved_space(1);
 
3355
                        ut_a(volume <= 4 * UNIV_PAGE_SIZE
 
3356
                             / IBUF_PAGE_SIZE_PER_FREE_SPACE);
4418
3357
#endif
4419
 
                                ibuf_insert_to_index_page(
4420
 
                                        entry, block, dummy_index, &mtr);
4421
 
                                break;
4422
 
 
4423
 
                        case IBUF_OP_DELETE_MARK:
4424
 
                                ibuf_set_del_mark(
4425
 
                                        entry, block, dummy_index, &mtr);
4426
 
                                break;
4427
 
 
4428
 
                        case IBUF_OP_DELETE:
4429
 
                                ibuf_delete(entry, block, dummy_index, &mtr);
4430
 
                                /* Because ibuf_delete() will latch an
4431
 
                                insert buffer bitmap page, commit mtr
4432
 
                                before latching any further pages.
4433
 
                                Store and restore the cursor position. */
4434
 
                                ut_ad(rec == btr_pcur_get_rec(&pcur));
4435
 
                                ut_ad(page_rec_is_user_rec(rec));
4436
 
                                ut_ad(ibuf_rec_get_page_no(rec) == page_no);
4437
 
                                ut_ad(ibuf_rec_get_space(rec) == space);
4438
 
 
4439
 
                                btr_pcur_store_position(&pcur, &mtr);
4440
 
                                btr_pcur_commit_specify_mtr(&pcur, &mtr);
4441
 
 
4442
 
                                mtr_start(&mtr);
4443
 
 
4444
 
                                success = buf_page_get_known_nowait(
4445
 
                                        RW_X_LATCH, block,
4446
 
                                        BUF_KEEP_OLD,
4447
 
                                        __FILE__, __LINE__, &mtr);
4448
 
                                ut_a(success);
4449
 
 
4450
 
                                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
4451
 
 
4452
 
                                if (!ibuf_restore_pos(space, page_no,
4453
 
                                                      search_tuple,
4454
 
                                                      BTR_MODIFY_LEAF,
4455
 
                                                      &pcur, &mtr)) {
4456
 
 
4457
 
                                        mtr_commit(&mtr);
4458
 
                                        mops[op]++;
4459
 
                                        ibuf_dummy_index_free(dummy_index);
4460
 
                                        goto loop;
4461
 
                                }
4462
 
 
4463
 
                                break;
4464
 
                        default:
4465
 
                                ut_error;
4466
 
                        }
4467
 
 
4468
 
                        mops[op]++;
4469
 
 
 
3358
                        ibuf_insert_to_index_page(entry, block,
 
3359
                                                  dummy_index, &mtr);
4470
3360
                        ibuf_dummy_index_free(dummy_index);
4471
 
                } else {
4472
 
                        dops[ibuf_rec_get_op_type(rec)]++;
4473
3361
                }
4474
3362
 
 
3363
                n_inserts++;
 
3364
 
4475
3365
                /* Delete the record from ibuf */
4476
3366
                if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
4477
3367
                                    &mtr)) {
4488
3378
        }
4489
3379
 
4490
3380
reset_bit:
 
3381
#ifdef UNIV_IBUF_COUNT_DEBUG
 
3382
        if (ibuf_count_get(space, page_no) > 0) {
 
3383
                /* btr_print_tree(ibuf_data->index->tree, 100);
 
3384
                ibuf_print(); */
 
3385
        }
 
3386
#endif
4491
3387
        if (UNIV_LIKELY(update_ibuf_bitmap)) {
4492
3388
                page_t* bitmap_page;
4493
3389
 
4518
3414
        btr_pcur_close(&pcur);
4519
3415
        mem_heap_free(heap);
4520
3416
 
4521
 
#ifdef HAVE_ATOMIC_BUILTINS
4522
 
        os_atomic_increment_ulint(&ibuf->n_merges, 1);
4523
 
        ibuf_add_ops(ibuf->n_merged_ops, mops);
4524
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
4525
 
#else /* HAVE_ATOMIC_BUILTINS */
4526
3417
        /* Protect our statistics keeping from race conditions */
4527
3418
        mutex_enter(&ibuf_mutex);
4528
3419
 
4529
3420
        ibuf->n_merges++;
4530
 
        ibuf_add_ops(ibuf->n_merged_ops, mops);
4531
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
 
3421
        ibuf->n_merged_recs += n_inserts;
4532
3422
 
4533
3423
        mutex_exit(&ibuf_mutex);
4534
 
#endif /* HAVE_ATOMIC_BUILTINS */
4535
3424
 
4536
3425
        if (update_ibuf_bitmap && !tablespace_being_deleted) {
4537
3426
 
4562
3451
        rec_t*          ibuf_rec;
4563
3452
        ulint           page_no;
4564
3453
        ibool           closed;
 
3454
        ulint           n_inserts;
4565
3455
        mtr_t           mtr;
4566
3456
 
4567
 
        /* Counts for discarded operations. */
4568
 
        ulint           dops[IBUF_OP_COUNT];
4569
 
 
4570
3457
        heap = mem_heap_create(512);
4571
3458
 
4572
3459
        /* Use page number 0 to build the search tuple so that we get the
4574
3461
 
4575
3462
        search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
4576
3463
 
4577
 
        memset(dops, 0, sizeof(dops));
 
3464
        n_inserts = 0;
4578
3465
loop:
4579
3466
        ibuf_enter();
4580
3467
 
4605
3492
 
4606
3493
                page_no = ibuf_rec_get_page_no(ibuf_rec);
4607
3494
 
4608
 
                dops[ibuf_rec_get_op_type(ibuf_rec)]++;
 
3495
                n_inserts++;
4609
3496
 
4610
3497
                /* Delete the record from ibuf */
4611
3498
                closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
4633
3520
        mtr_commit(&mtr);
4634
3521
        btr_pcur_close(&pcur);
4635
3522
 
4636
 
#ifdef HAVE_ATOMIC_BUILTINS
4637
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
4638
 
#else /* HAVE_ATOMIC_BUILTINS */
4639
3523
        /* Protect our statistics keeping from race conditions */
4640
3524
        mutex_enter(&ibuf_mutex);
4641
 
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
 
3525
 
 
3526
        ibuf->n_merges++;
 
3527
        ibuf->n_merged_recs += n_inserts;
 
3528
 
4642
3529
        mutex_exit(&ibuf_mutex);
4643
 
#endif /* HAVE_ATOMIC_BUILTINS */
4644
3530
 
4645
3531
        ibuf_exit();
4646
3532
 
4660
3546
        mtr_t           mtr;
4661
3547
 
4662
3548
        ibuf_enter();
 
3549
 
 
3550
        mutex_enter(&ibuf_mutex);
 
3551
 
4663
3552
        mtr_start(&mtr);
4664
3553
 
4665
 
        mutex_enter(&ibuf_mutex);
4666
3554
        root = ibuf_tree_root_get(&mtr);
 
3555
 
 
3556
        if (page_get_n_recs(root) == 0) {
 
3557
 
 
3558
                is_empty = TRUE;
 
3559
 
 
3560
                if (ibuf->empty == FALSE) {
 
3561
                        fprintf(stderr,
 
3562
                                "InnoDB: Warning: insert buffer tree is empty"
 
3563
                                " but the data struct does not\n"
 
3564
                                "InnoDB: know it. This condition is legal"
 
3565
                                " if the master thread has not yet\n"
 
3566
                                "InnoDB: run to completion.\n");
 
3567
                }
 
3568
        } else {
 
3569
                ut_a(ibuf->empty == FALSE);
 
3570
 
 
3571
                is_empty = FALSE;
 
3572
        }
 
3573
 
 
3574
        mtr_commit(&mtr);
 
3575
 
4667
3576
        mutex_exit(&ibuf_mutex);
4668
3577
 
4669
 
        is_empty = (page_get_n_recs(root) == 0);
4670
 
        mtr_commit(&mtr);
4671
3578
        ibuf_exit();
4672
3579
 
4673
 
        ut_a(is_empty == ibuf->empty);
4674
 
 
4675
3580
        return(is_empty);
4676
3581
}
4677
3582
 
4691
3596
        mutex_enter(&ibuf_mutex);
4692
3597
 
4693
3598
        fprintf(file,
4694
 
                "Ibuf: size %lu, free list len %lu,"
4695
 
                " seg size %lu, %lu merges\n",
 
3599
                "Ibuf: size %lu, free list len %lu, seg size %lu,\n"
 
3600
                "%lu inserts, %lu merged recs, %lu merges\n",
4696
3601
                (ulong) ibuf->size,
4697
3602
                (ulong) ibuf->free_list_len,
4698
3603
                (ulong) ibuf->seg_size,
 
3604
                (ulong) ibuf->n_inserts,
 
3605
                (ulong) ibuf->n_merged_recs,
4699
3606
                (ulong) ibuf->n_merges);
4700
 
 
4701
 
        fputs("merged operations:\n ", file);
4702
 
        ibuf_print_ops(ibuf->n_merged_ops, file);
4703
 
 
4704
 
        fputs("discarded operations:\n ", file);
4705
 
        ibuf_print_ops(ibuf->n_discarded_ops, file);
4706
 
 
4707
3607
#ifdef UNIV_IBUF_COUNT_DEBUG
4708
3608
        for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
4709
3609
                for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {