~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2010-11-26 22:50:54 UTC
  • mfrom: (1953.1.6 build)
  • Revision ID: mordred@inaugust.com-20101126225054-sg90svw8579t5p3i
Stewart - InnoDB 1.1.1
Monty - Fixed some autoconf tests which were returning false positives.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 1997, 2010, 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
89
89
looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
90
90
 
91
91
The high-order bit of the character set field in the type info is the
92
 
"nullable" flag for the field. */
 
92
"nullable" flag for the field.
 
93
 
 
94
In versions >= 5.5:
 
95
 
 
96
The optional marker byte at the start of the fourth field is replaced by
 
97
mandatory 3 fields, totaling 4 bytes:
 
98
 
 
99
 1. 2 bytes: Counter field, used to sort records within a (space id, page
 
100
    no) in the order they were added. This is needed so that for example the
 
101
    sequence of operations "INSERT x, DEL MARK x, INSERT x" is handled
 
102
    correctly.
 
103
 
 
104
 2. 1 byte: Operation type (see ibuf_op_t).
 
105
 
 
106
 3. 1 byte: Flags. Currently only one flag exists, IBUF_REC_COMPACT.
 
107
 
 
108
To ensure older records, which do not have counters to enforce correct
 
109
sorting, are merged before any new records, ibuf_insert checks if we're
 
110
trying to insert to a position that contains old-style records, and if so,
 
111
refuses the insert. Thus, ibuf pages are gradually converted to the new
 
112
format as their corresponding buffer pool pages are read into memory.
 
113
*/
93
114
 
94
115
 
95
116
/*      PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
168
189
#define IBUF_TABLE_NAME         "SYS_IBUF_TABLE"
169
190
 
170
191
/** Operations that can currently be buffered. */
171
 
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_INSERT;
 
192
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_ALL;
172
193
 
173
194
/** The insert buffer control structure */
174
195
UNIV_INTERN ibuf_t*     ibuf                    = NULL;
176
197
/** Counter for ibuf_should_try() */
177
198
UNIV_INTERN ulint       ibuf_flush_count        = 0;
178
199
 
 
200
#ifdef UNIV_PFS_MUTEX
 
201
UNIV_INTERN mysql_pfs_key_t     ibuf_pessimistic_insert_mutex_key;
 
202
UNIV_INTERN mysql_pfs_key_t     ibuf_mutex_key;
 
203
UNIV_INTERN mysql_pfs_key_t     ibuf_bitmap_mutex_key;
 
204
#endif /* UNIV_PFS_MUTEX */
 
205
 
179
206
#ifdef UNIV_IBUF_COUNT_DEBUG
180
207
/** Number of tablespaces in the ibuf_counts array */
181
208
#define IBUF_COUNT_N_SPACES     4
221
248
                                        list of the ibuf */
222
249
/* @} */
223
250
 
 
251
/* Various constants for checking the type of an ibuf record and extracting
 
252
data from it. For details, see the description of the record format at the
 
253
top of this file. */
 
254
 
 
255
/** @name Format of the fourth column of an insert buffer record
 
256
The fourth column in the MySQL 5.5 format contains an operation
 
257
type, counter, and some flags. */
 
258
/* @{ */
 
259
#define IBUF_REC_INFO_SIZE      4       /*!< Combined size of info fields at
 
260
                                        the beginning of the fourth field */
 
261
#if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
 
262
# error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE"
 
263
#endif
 
264
 
 
265
/* Offsets for the fields at the beginning of the fourth field */
 
266
#define IBUF_REC_OFFSET_COUNTER 0       /*!< Operation counter */
 
267
#define IBUF_REC_OFFSET_TYPE    2       /*!< Type of operation */
 
268
#define IBUF_REC_OFFSET_FLAGS   3       /*!< Additional flags */
 
269
 
 
270
/* Record flag masks */
 
271
#define IBUF_REC_COMPACT        0x1     /*!< Set in
 
272
                                        IBUF_REC_OFFSET_FLAGS if the
 
273
                                        user index is in COMPACT
 
274
                                        format or later */
 
275
 
 
276
 
224
277
/** The mutex used to block pessimistic inserts to ibuf trees */
225
278
static mutex_t  ibuf_pessimistic_insert_mutex;
226
279
 
461
514
        ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE
462
515
                / IBUF_POOL_SIZE_PER_MAX_SIZE;
463
516
 
464
 
        mutex_create(&ibuf_pessimistic_insert_mutex,
 
517
        mutex_create(ibuf_pessimistic_insert_mutex_key,
 
518
                     &ibuf_pessimistic_insert_mutex,
465
519
                     SYNC_IBUF_PESS_INSERT_MUTEX);
466
520
 
467
 
        mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX);
 
521
        mutex_create(ibuf_mutex_key,
 
522
                     &ibuf_mutex, SYNC_IBUF_MUTEX);
468
523
 
469
 
        mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
 
524
        mutex_create(ibuf_bitmap_mutex_key,
 
525
                     &ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
470
526
 
471
527
        mtr_start(&mtr);
472
528
 
1150
1206
        return(0);
1151
1207
}
1152
1208
 
 
1209
/****************************************************************//**
 
1210
Get various information about an ibuf record in >= 4.1.x format. */
 
1211
static
 
1212
void
 
1213
ibuf_rec_get_info(
 
1214
/*==============*/
 
1215
        const rec_t*    rec,            /*!< in: ibuf record */
 
1216
        ibuf_op_t*      op,             /*!< out: operation type, or NULL */
 
1217
        ibool*          comp,           /*!< out: compact flag, or NULL */
 
1218
        ulint*          info_len,       /*!< out: length of info fields at the
 
1219
                                        start of the fourth field, or
 
1220
                                        NULL */
 
1221
        ulint*          counter)        /*!< in: counter value, or NULL */
 
1222
{
 
1223
        const byte*     types;
 
1224
        ulint           fields;
 
1225
        ulint           len;
 
1226
 
 
1227
        /* Local variables to shadow arguments. */
 
1228
        ibuf_op_t       op_local;
 
1229
        ibool           comp_local;
 
1230
        ulint           info_len_local;
 
1231
        ulint           counter_local;
 
1232
 
 
1233
        ut_ad(ibuf_inside());
 
1234
        fields = rec_get_n_fields_old(rec);
 
1235
        ut_a(fields > 4);
 
1236
 
 
1237
        types = rec_get_nth_field_old(rec, 3, &len);
 
1238
 
 
1239
        info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
 
1240
 
 
1241
        switch (info_len_local) {
 
1242
        case 0:
 
1243
        case 1:
 
1244
                op_local = IBUF_OP_INSERT;
 
1245
                comp_local = info_len_local;
 
1246
                ut_ad(!counter);
 
1247
                counter_local = ULINT_UNDEFINED;
 
1248
                break;
 
1249
 
 
1250
        case IBUF_REC_INFO_SIZE:
 
1251
                op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE];
 
1252
                comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT;
 
1253
                counter_local = mach_read_from_2(
 
1254
                        types + IBUF_REC_OFFSET_COUNTER);
 
1255
                break;
 
1256
 
 
1257
        default:
 
1258
                ut_error;
 
1259
        }
 
1260
 
 
1261
        ut_a(op_local < IBUF_OP_COUNT);
 
1262
        ut_a((len - info_len_local) ==
 
1263
             (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
 
1264
 
 
1265
        if (op) {
 
1266
                *op = op_local;
 
1267
        }
 
1268
 
 
1269
        if (comp) {
 
1270
                *comp = comp_local;
 
1271
        }
 
1272
 
 
1273
        if (info_len) {
 
1274
                *info_len = info_len_local;
 
1275
        }
 
1276
 
 
1277
        if (counter) {
 
1278
                *counter = counter_local;
 
1279
        }
 
1280
}
 
1281
 
 
1282
/****************************************************************//**
 
1283
Returns the operation type field of an ibuf record.
 
1284
@return operation type */
 
1285
static
 
1286
ibuf_op_t
 
1287
ibuf_rec_get_op_type(
 
1288
/*=================*/
 
1289
        const rec_t*    rec)    /*!< in: ibuf record */
 
1290
{
 
1291
        ulint           len;
 
1292
        const byte*     field;
 
1293
 
 
1294
        ut_ad(ibuf_inside());
 
1295
        ut_ad(rec_get_n_fields_old(rec) > 2);
 
1296
 
 
1297
        field = rec_get_nth_field_old(rec, 1, &len);
 
1298
 
 
1299
        if (len > 1) {
 
1300
                /* This is a < 4.1.x format record */
 
1301
 
 
1302
                return(IBUF_OP_INSERT);
 
1303
        } else {
 
1304
                ibuf_op_t       op;
 
1305
 
 
1306
                ibuf_rec_get_info(rec, &op, NULL, NULL, NULL);
 
1307
 
 
1308
                return(op);
 
1309
        }
 
1310
}
 
1311
 
 
1312
/****************************************************************//**
 
1313
Read the first two bytes from a record's fourth field (counter field in new
 
1314
records; something else in older records).
 
1315
@return "counter" field, or ULINT_UNDEFINED if for some reason it
 
1316
can't be read */
 
1317
UNIV_INTERN
 
1318
ulint
 
1319
ibuf_rec_get_counter(
 
1320
/*=================*/
 
1321
        const rec_t*    rec)    /*!< in: ibuf record */
 
1322
{
 
1323
        const byte*     ptr;
 
1324
        ulint           len;
 
1325
 
 
1326
        if (rec_get_n_fields_old(rec) < 4) {
 
1327
 
 
1328
                return(ULINT_UNDEFINED);
 
1329
        }
 
1330
 
 
1331
        ptr = rec_get_nth_field_old(rec, 3, &len);
 
1332
 
 
1333
        if (len >= 2) {
 
1334
 
 
1335
                return(mach_read_from_2(ptr));
 
1336
        } else {
 
1337
 
 
1338
                return(ULINT_UNDEFINED);
 
1339
        }
 
1340
}
 
1341
 
 
1342
/****************************************************************//**
 
1343
Add accumulated operation counts to a permanent array. Both arrays must be
 
1344
of size IBUF_OP_COUNT. */
 
1345
static
 
1346
void
 
1347
ibuf_add_ops(
 
1348
/*=========*/
 
1349
        ulint*          arr,    /*!< in/out: array to modify */
 
1350
        const ulint*    ops)    /*!< in: operation counts */
 
1351
 
 
1352
{
 
1353
        ulint   i;
 
1354
 
 
1355
        for (i = 0; i < IBUF_OP_COUNT; i++) {
 
1356
                arr[i] += ops[i];
 
1357
        }
 
1358
}
 
1359
 
 
1360
/****************************************************************//**
 
1361
Print operation counts. The array must be of size IBUF_OP_COUNT. */
 
1362
static
 
1363
void
 
1364
ibuf_print_ops(
 
1365
/*===========*/
 
1366
        const ulint*    ops,    /*!< in: operation counts */
 
1367
        FILE*           file)   /*!< in: file where to print */
 
1368
{
 
1369
        static const char* op_names[] = {
 
1370
                "insert",
 
1371
                "delete mark",
 
1372
                "delete"
 
1373
        };
 
1374
        ulint   i;
 
1375
 
 
1376
        ut_a(UT_ARR_SIZE(op_names) == IBUF_OP_COUNT);
 
1377
 
 
1378
        for (i = 0; i < IBUF_OP_COUNT; i++) {
 
1379
                fprintf(file, "%s %lu%s", op_names[i],
 
1380
                        (ulong) ops[i], (i < (IBUF_OP_COUNT - 1)) ? ", " : "");
 
1381
        }
 
1382
 
 
1383
        putc('\n', file);
 
1384
}
 
1385
 
1153
1386
/********************************************************************//**
1154
1387
Creates a dummy index for inserting a record to a non-clustered index.
1155
 
 
1156
1388
@return dummy index */
1157
1389
static
1158
1390
dict_index_t*
1263
1495
}
1264
1496
 
1265
1497
/*********************************************************************//**
1266
 
Builds the entry to insert into a non-clustered index when we have the
1267
 
corresponding record in an ibuf index.
 
1498
Builds the entry used to
 
1499
 
 
1500
1) IBUF_OP_INSERT: insert into a non-clustered index
 
1501
 
 
1502
2) IBUF_OP_DELETE_MARK: find the record whose delete-mark flag we need to
 
1503
   activate
 
1504
 
 
1505
3) IBUF_OP_DELETE: find the record we need to delete
 
1506
 
 
1507
when we have the corresponding record in an ibuf index.
1268
1508
 
1269
1509
NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1270
1510
hold a latch to the ibuf_rec page as long as the entry is used!
1285
1525
        const byte*     types;
1286
1526
        const byte*     data;
1287
1527
        ulint           len;
 
1528
        ulint           info_len;
1288
1529
        ulint           i;
 
1530
        ulint           comp;
1289
1531
        dict_index_t*   index;
1290
1532
 
1291
1533
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1308
1550
 
1309
1551
        types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1310
1552
 
1311
 
        ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
1312
 
        index = ibuf_dummy_index_create(
1313
 
                n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1314
 
 
1315
 
        if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
1316
 
                /* compact record format */
1317
 
                len--;
1318
 
                ut_a(*types == 0);
1319
 
                types++;
1320
 
        }
 
1553
        ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL);
 
1554
 
 
1555
        index = ibuf_dummy_index_create(n_fields, comp);
 
1556
 
 
1557
        len -= info_len;
 
1558
        types += info_len;
1321
1559
 
1322
1560
        ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1323
1561
 
1347
1585
        return(tuple);
1348
1586
}
1349
1587
 
 
1588
/******************************************************************//**
 
1589
Get the data size.
 
1590
@return size of fields */
 
1591
UNIV_INLINE
 
1592
ulint
 
1593
ibuf_rec_get_size(
 
1594
/*==============*/
 
1595
        const rec_t*    rec,                    /*!< in: ibuf record */
 
1596
        const byte*     types,                  /*!< in: fields */
 
1597
        ulint           n_fields,               /*!< in: number of fields */
 
1598
        ibool           pre_4_1,                /*!< in: TRUE=pre-4.1 format,
 
1599
                                                FALSE=newer */
 
1600
        ulint           comp)                   /*!< in: 0=ROW_FORMAT=REDUNDANT,
 
1601
                                                nonzero=ROW_FORMAT=COMPACT */
 
1602
{
 
1603
        ulint   i;
 
1604
        ulint   field_offset;
 
1605
        ulint   types_offset;
 
1606
        ulint   size = 0;
 
1607
 
 
1608
        if (pre_4_1) {
 
1609
                field_offset = 2;
 
1610
                types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE;
 
1611
        } else {
 
1612
                field_offset = 4;
 
1613
                types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
 
1614
        }
 
1615
 
 
1616
        for (i = 0; i < n_fields; i++) {
 
1617
                ulint           len;
 
1618
                dtype_t         dtype;
 
1619
 
 
1620
                rec_get_nth_field_offs_old(rec, i + field_offset, &len);
 
1621
 
 
1622
                if (len != UNIV_SQL_NULL) {
 
1623
                        size += len;
 
1624
                } else if (pre_4_1) {
 
1625
                        dtype_read_for_order_and_null_size(&dtype, types);
 
1626
 
 
1627
                        size += dtype_get_sql_null_size(&dtype, comp);
 
1628
                } else {
 
1629
                        dtype_new_read_for_order_and_null_size(&dtype, types);
 
1630
 
 
1631
                        size += dtype_get_sql_null_size(&dtype, comp);
 
1632
                }
 
1633
 
 
1634
                types += types_offset;
 
1635
        }
 
1636
 
 
1637
        return(size);
 
1638
}
 
1639
 
1350
1640
/********************************************************************//**
1351
1641
Returns the space taken by a stored non-clustered index entry if converted to
1352
1642
an index record.
1358
1648
/*================*/
1359
1649
        const rec_t*    ibuf_rec)/*!< in: ibuf record */
1360
1650
{
1361
 
        dtype_t         dtype;
1362
 
        ibool           new_format      = FALSE;
1363
 
        ulint           data_size       = 0;
 
1651
        ulint           len;
 
1652
        const byte*     data;
 
1653
        const byte*     types;
1364
1654
        ulint           n_fields;
1365
 
        const byte*     types;
1366
 
        const byte*     data;
1367
 
        ulint           len;
1368
 
        ulint           i;
 
1655
        ulint           data_size;
 
1656
        ibool           pre_4_1;
1369
1657
        ulint           comp;
1370
1658
 
1371
1659
        ut_ad(ibuf_inside());
1372
1660
        ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
1373
1661
 
1374
1662
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
 
1663
        pre_4_1 = (len > 1);
1375
1664
 
1376
 
        if (len > 1) {
 
1665
        if (pre_4_1) {
1377
1666
                /* < 4.1.x format record */
1378
1667
 
1379
1668
                ut_a(trx_doublewrite_must_reset_space_ids);
1387
1676
                comp = 0;
1388
1677
        } else {
1389
1678
                /* >= 4.1.x format record */
 
1679
                ibuf_op_t       op;
 
1680
                ulint           info_len;
1390
1681
 
1391
1682
                ut_a(trx_sys_multiple_tablespace_format);
1392
1683
                ut_a(*data == 0);
1393
1684
 
1394
1685
                types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1395
1686
 
1396
 
                comp = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1397
 
 
1398
 
                ut_a(comp <= 1);
1399
 
                if (comp) {
1400
 
                        /* compact record format */
 
1687
                ibuf_rec_get_info(ibuf_rec, &op, &comp, &info_len, NULL);
 
1688
 
 
1689
                if (op == IBUF_OP_DELETE_MARK || op == IBUF_OP_DELETE) {
 
1690
                        /* Delete-marking a record doesn't take any
 
1691
                        additional space, and while deleting a record
 
1692
                        actually frees up space, we have to play it safe and
 
1693
                        pretend it takes no additional space (the record
 
1694
                        might not exist, etc.).  */
 
1695
 
 
1696
                        return(0);
 
1697
                } else if (comp) {
 
1698
                        dtuple_t*       entry;
1401
1699
                        ulint           volume;
1402
1700
                        dict_index_t*   dummy_index;
1403
1701
                        mem_heap_t*     heap = mem_heap_create(500);
1404
 
                        dtuple_t*       entry = ibuf_build_entry_from_ibuf_rec(
 
1702
 
 
1703
                        entry = ibuf_build_entry_from_ibuf_rec(
1405
1704
                                ibuf_rec, heap, &dummy_index);
 
1705
 
1406
1706
                        volume = rec_get_converted_size(dummy_index, entry, 0);
 
1707
 
1407
1708
                        ibuf_dummy_index_free(dummy_index);
1408
1709
                        mem_heap_free(heap);
 
1710
 
1409
1711
                        return(volume + page_dir_calc_reserved_space(1));
1410
1712
                }
1411
1713
 
 
1714
                types += info_len;
1412
1715
                n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1413
 
 
1414
 
                new_format = TRUE;
1415
 
        }
1416
 
 
1417
 
        for (i = 0; i < n_fields; i++) {
1418
 
                if (new_format) {
1419
 
                        data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1420
 
 
1421
 
                        dtype_new_read_for_order_and_null_size(
1422
 
                                &dtype, types + i
1423
 
                                * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1424
 
                } else {
1425
 
                        data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1426
 
 
1427
 
                        dtype_read_for_order_and_null_size(
1428
 
                                &dtype, types + i
1429
 
                                * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1430
 
                }
1431
 
 
1432
 
                if (len == UNIV_SQL_NULL) {
1433
 
                        data_size += dtype_get_sql_null_size(&dtype, comp);
1434
 
                } else {
1435
 
                        data_size += len;
1436
 
                }
1437
 
        }
 
1716
        }
 
1717
 
 
1718
        data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp);
1438
1719
 
1439
1720
        return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0)
1440
1721
               + page_dir_calc_reserved_space(1));
1452
1733
dtuple_t*
1453
1734
ibuf_entry_build(
1454
1735
/*=============*/
 
1736
        ibuf_op_t       op,     /*!< in: operation type */
1455
1737
        dict_index_t*   index,  /*!< in: non-clustered index */
1456
1738
        const dtuple_t* entry,  /*!< in: entry for a non-clustered index */
1457
1739
        ulint           space,  /*!< in: space id */
1458
1740
        ulint           page_no,/*!< in: index page number where entry should
1459
1741
                                be inserted */
 
1742
        ulint           counter,/*!< in: counter value;
 
1743
                                ULINT_UNDEFINED=not used */
1460
1744
        mem_heap_t*     heap)   /*!< in: heap into which to build */
1461
1745
{
1462
1746
        dtuple_t*       tuple;
1464
1748
        const dfield_t* entry_field;
1465
1749
        ulint           n_fields;
1466
1750
        byte*           buf;
1467
 
        byte*           buf2;
 
1751
        byte*           ti;
 
1752
        byte*           type_info;
1468
1753
        ulint           i;
1469
1754
 
1470
 
        /* Starting from 4.1.x, we have to build a tuple whose
1471
 
        (1) first field is the space id,
1472
 
        (2) the second field a single marker byte (0) to tell that this
1473
 
        is a new format record,
1474
 
        (3) the third contains the page number, and
1475
 
        (4) the fourth contains the relevent type information of each data
1476
 
        field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is
1477
 
        (a) 0 for b-trees in the old format, and
1478
 
        (b) 1 for b-trees in the compact format, the first byte of the field
1479
 
        being the marker (0);
1480
 
        (5) and the rest of the fields are copied from entry. All fields
1481
 
        in the tuple are ordered like the type binary in our insert buffer
1482
 
        tree. */
 
1755
        ut_ad(counter != ULINT_UNDEFINED || op == IBUF_OP_INSERT);
 
1756
        ut_ad(counter == ULINT_UNDEFINED || counter <= 0xFFFF);
 
1757
        ut_ad(op < IBUF_OP_COUNT);
 
1758
 
 
1759
        /* We have to build a tuple with the following fields:
 
1760
 
 
1761
        1-4) These are described at the top of this file.
 
1762
 
 
1763
        5) The rest of the fields are copied from the entry.
 
1764
 
 
1765
        All fields in the tuple are ordered like the type binary in our
 
1766
        insert buffer tree. */
1483
1767
 
1484
1768
        n_fields = dtuple_get_n_fields(entry);
1485
1769
 
1486
1770
        tuple = dtuple_create(heap, n_fields + 4);
1487
1771
 
1488
 
        /* Store the space id in tuple */
 
1772
        /* 1) Space Id */
1489
1773
 
1490
1774
        field = dtuple_get_nth_field(tuple, 0);
1491
1775
 
1495
1779
 
1496
1780
        dfield_set_data(field, buf, 4);
1497
1781
 
1498
 
        /* Store the marker byte field in tuple */
 
1782
        /* 2) Marker byte */
1499
1783
 
1500
1784
        field = dtuple_get_nth_field(tuple, 1);
1501
1785
 
1507
1791
 
1508
1792
        dfield_set_data(field, buf, 1);
1509
1793
 
1510
 
        /* Store the page number in tuple */
 
1794
        /* 3) Page number */
1511
1795
 
1512
1796
        field = dtuple_get_nth_field(tuple, 2);
1513
1797
 
1517
1801
 
1518
1802
        dfield_set_data(field, buf, 4);
1519
1803
 
1520
 
        /* Store the type info in buf2, and add the fields from entry to
1521
 
        tuple */
1522
 
        buf2 = mem_heap_alloc(heap, n_fields
1523
 
                              * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1524
 
                              + dict_table_is_comp(index->table));
1525
 
        if (dict_table_is_comp(index->table)) {
1526
 
                *buf2++ = 0; /* write the compact format indicator */
1527
 
        }
 
1804
        /* 4) Type info, part #1 */
 
1805
 
 
1806
        if (counter == ULINT_UNDEFINED) {
 
1807
                i = dict_table_is_comp(index->table) ? 1 : 0;
 
1808
        } else {
 
1809
                ut_ad(counter <= 0xFFFF);
 
1810
                i = IBUF_REC_INFO_SIZE;
 
1811
        }
 
1812
 
 
1813
        ti = type_info = mem_heap_alloc(heap, i + n_fields
 
1814
                                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
 
1815
 
 
1816
        switch (i) {
 
1817
        default:
 
1818
                ut_error;
 
1819
                break;
 
1820
        case 1:
 
1821
                /* set the flag for ROW_FORMAT=COMPACT */
 
1822
                *ti++ = 0;
 
1823
                /* fall through */
 
1824
        case 0:
 
1825
                /* the old format does not allow delete buffering */
 
1826
                ut_ad(op == IBUF_OP_INSERT);
 
1827
                break;
 
1828
        case IBUF_REC_INFO_SIZE:
 
1829
                mach_write_to_2(ti + IBUF_REC_OFFSET_COUNTER, counter);
 
1830
 
 
1831
                ti[IBUF_REC_OFFSET_TYPE] = (byte) op;
 
1832
                ti[IBUF_REC_OFFSET_FLAGS] = dict_table_is_comp(index->table)
 
1833
                        ? IBUF_REC_COMPACT : 0;
 
1834
                ti += IBUF_REC_INFO_SIZE;
 
1835
                break;
 
1836
        }
 
1837
 
 
1838
        /* 5+) Fields from the entry */
 
1839
 
1528
1840
        for (i = 0; i < n_fields; i++) {
1529
1841
                ulint                   fixed_len;
1530
1842
                const dict_field_t*     ifield;
1559
1871
#endif /* UNIV_DEBUG */
1560
1872
 
1561
1873
                dtype_new_store_for_order_and_null_size(
1562
 
                        buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
1563
 
                        dfield_get_type(entry_field), fixed_len);
 
1874
                        ti, dfield_get_type(entry_field), fixed_len);
 
1875
                ti += DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1564
1876
        }
1565
1877
 
1566
 
        /* Store the type info in buf2 to field 3 of tuple */
 
1878
        /* 4) Type info, part #2 */
1567
1879
 
1568
1880
        field = dtuple_get_nth_field(tuple, 3);
1569
1881
 
1570
 
        if (dict_table_is_comp(index->table)) {
1571
 
                buf2--;
1572
 
        }
 
1882
        dfield_set_data(field, type_info, ti - type_info);
1573
1883
 
1574
 
        dfield_set_data(field, buf2, n_fields
1575
 
                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1576
 
                        + dict_table_is_comp(index->table));
1577
1884
        /* Set all the types in the new tuple binary */
1578
1885
 
1579
1886
        dtuple_set_types_binary(tuple, n_fields + 4);
2016
2323
 
2017
2324
        *n_stored = 0;
2018
2325
 
2019
 
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
 
2326
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4);
2020
2327
 
2021
2328
        if (page_rec_is_supremum(rec)) {
2022
2329
 
2182
2489
ibuf_is_empty:
2183
2490
                mutex_exit(&ibuf_mutex);
2184
2491
 
 
2492
#if 0 /* TODO */
 
2493
                if (srv_shutdown_state) {
 
2494
                        /* If the insert buffer becomes empty during
 
2495
                        shutdown, note it in the system tablespace. */
 
2496
 
 
2497
                        trx_sys_set_ibuf_format(TRX_SYS_IBUF_EMPTY);
 
2498
                }
 
2499
 
 
2500
                /* TO DO: call trx_sys_set_ibuf_format() at startup
 
2501
                and whenever ibuf_use is changed to allow buffered
 
2502
                delete-marking or deleting.  Never downgrade the
 
2503
                stamped format except when the insert buffer becomes
 
2504
                empty. */
 
2505
#endif
 
2506
 
2185
2507
                return(0);
2186
2508
        }
2187
2509
 
2194
2516
 
2195
2517
        btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr);
2196
2518
 
 
2519
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
 
2520
 
2197
2521
        if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
2198
2522
                /* When the ibuf tree is emptied completely, the last record
2199
2523
                is removed using an optimistic delete and ibuf_size_update
2327
2651
}
2328
2652
 
2329
2653
/*********************************************************************//**
 
2654
Determine if an insert buffer record has been encountered already.
 
2655
@return TRUE if a new record, FALSE if possible duplicate */
 
2656
static
 
2657
ibool
 
2658
ibuf_get_volume_buffered_hash(
 
2659
/*==========================*/
 
2660
        const rec_t*    rec,    /*!< in: ibuf record in post-4.1 format */
 
2661
        const byte*     types,  /*!< in: fields */
 
2662
        const byte*     data,   /*!< in: start of user record data */
 
2663
        ulint           comp,   /*!< in: 0=ROW_FORMAT=REDUNDANT,
 
2664
                                nonzero=ROW_FORMAT=COMPACT */
 
2665
        ulint*          hash,   /*!< in/out: hash array */
 
2666
        ulint           size)   /*!< in: number of elements in hash array */
 
2667
{
 
2668
        ulint           len;
 
2669
        ulint           fold;
 
2670
        ulint           bitmask;
 
2671
 
 
2672
        len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4,
 
2673
                                FALSE, comp);
 
2674
        fold = ut_fold_binary(data, len);
 
2675
 
 
2676
        hash += (fold / (8 * sizeof *hash)) % size; // 8 = bits in byte
 
2677
        bitmask = 1 << (fold % (8 * sizeof *hash));
 
2678
 
 
2679
        if (*hash & bitmask) {
 
2680
 
 
2681
                return(FALSE);
 
2682
        }
 
2683
 
 
2684
        /* We have not seen this record yet.  Insert it. */
 
2685
        *hash |= bitmask;
 
2686
 
 
2687
        return(TRUE);
 
2688
}
 
2689
 
 
2690
/*********************************************************************//**
 
2691
Update the estimate of the number of records on a page, and
 
2692
get the space taken by merging the buffered record to the index page.
 
2693
@return size of index record in bytes + an upper limit of the space
 
2694
taken in the page directory */
 
2695
static
 
2696
ulint
 
2697
ibuf_get_volume_buffered_count(
 
2698
/*===========================*/
 
2699
        const rec_t*    rec,    /*!< in: insert buffer record */
 
2700
        ulint*          hash,   /*!< in/out: hash array */
 
2701
        ulint           size,   /*!< in: number of elements in hash array */
 
2702
        lint*           n_recs) /*!< in/out: estimated number of records
 
2703
                                on the page that rec points to */
 
2704
{
 
2705
        ulint           len;
 
2706
        ibuf_op_t       ibuf_op;
 
2707
        const byte*     types;
 
2708
        ulint           n_fields        = rec_get_n_fields_old(rec);
 
2709
 
 
2710
        ut_ad(ibuf_inside());
 
2711
        ut_ad(n_fields > 4);
 
2712
        n_fields -= 4;
 
2713
 
 
2714
        rec_get_nth_field_offs_old(rec, 1, &len);
 
2715
        /* This function is only invoked when buffering new
 
2716
        operations.  All pre-4.1 records should have been merged
 
2717
        when the database was started up. */
 
2718
        ut_a(len == 1);
 
2719
        ut_ad(trx_sys_multiple_tablespace_format);
 
2720
 
 
2721
        types = rec_get_nth_field_old(rec, 3, &len);
 
2722
 
 
2723
        switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
 
2724
                            IBUF_REC_INFO_SIZE)) {
 
2725
        default:
 
2726
                ut_error;
 
2727
        case 0:
 
2728
                /* This ROW_TYPE=REDUNDANT record does not include an
 
2729
                operation counter.  Exclude it from the *n_recs,
 
2730
                because deletes cannot be buffered if there are
 
2731
                old-style inserts buffered for the page. */
 
2732
 
 
2733
                len = ibuf_rec_get_size(rec, types, n_fields, FALSE, 0);
 
2734
 
 
2735
                return(len
 
2736
                       + rec_get_converted_extra_size(len, n_fields, 0)
 
2737
                       + page_dir_calc_reserved_space(1));
 
2738
        case 1:
 
2739
                /* This ROW_TYPE=COMPACT record does not include an
 
2740
                operation counter.  Exclude it from the *n_recs,
 
2741
                because deletes cannot be buffered if there are
 
2742
                old-style inserts buffered for the page. */
 
2743
                goto get_volume_comp;
 
2744
 
 
2745
        case IBUF_REC_INFO_SIZE:
 
2746
                ibuf_op = (ibuf_op_t) types[IBUF_REC_OFFSET_TYPE];
 
2747
                break;
 
2748
        }
 
2749
 
 
2750
        switch (ibuf_op) {
 
2751
        case IBUF_OP_INSERT:
 
2752
                /* Inserts can be done by
 
2753
                btr_cur_set_deleted_flag_for_ibuf().  Because
 
2754
                delete-mark and insert operations can be pointing to
 
2755
                the same records, we must not count duplicates. */
 
2756
        case IBUF_OP_DELETE_MARK:
 
2757
                /* There must be a record to delete-mark.
 
2758
                See if this record has been already buffered. */
 
2759
                if (n_recs && ibuf_get_volume_buffered_hash(
 
2760
                            rec, types + IBUF_REC_INFO_SIZE,
 
2761
                            types + len,
 
2762
                            types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT,
 
2763
                            hash, size)) {
 
2764
                        (*n_recs)++;
 
2765
                }
 
2766
 
 
2767
                if (ibuf_op == IBUF_OP_DELETE_MARK) {
 
2768
                        /* Setting the delete-mark flag does not
 
2769
                        affect the available space on the page. */
 
2770
                        return(0);
 
2771
                }
 
2772
                break;
 
2773
        case IBUF_OP_DELETE:
 
2774
                /* A record will be removed from the page. */
 
2775
                if (n_recs) {
 
2776
                        (*n_recs)--;
 
2777
                }
 
2778
                /* While deleting a record actually frees up space,
 
2779
                we have to play it safe and pretend that it takes no
 
2780
                additional space (the record might not exist, etc.). */
 
2781
                return(0);
 
2782
        default:
 
2783
                ut_error;
 
2784
        }
 
2785
 
 
2786
        ut_ad(ibuf_op == IBUF_OP_INSERT);
 
2787
 
 
2788
get_volume_comp:
 
2789
        {
 
2790
                dtuple_t*       entry;
 
2791
                ulint           volume;
 
2792
                dict_index_t*   dummy_index;
 
2793
                mem_heap_t*     heap = mem_heap_create(500);
 
2794
 
 
2795
                entry = ibuf_build_entry_from_ibuf_rec(
 
2796
                        rec, heap, &dummy_index);
 
2797
 
 
2798
                volume = rec_get_converted_size(dummy_index, entry, 0);
 
2799
 
 
2800
                ibuf_dummy_index_free(dummy_index);
 
2801
                mem_heap_free(heap);
 
2802
 
 
2803
                return(volume + page_dir_calc_reserved_space(1));
 
2804
        }
 
2805
}
 
2806
 
 
2807
/*********************************************************************//**
2330
2808
Gets an upper limit for the combined size of entries buffered in the insert
2331
2809
buffer for a given page.
2332
2810
@return upper limit for the volume of buffered inserts for the index
2343
2821
                                or BTR_MODIFY_TREE */
2344
2822
        ulint           space,  /*!< in: space id */
2345
2823
        ulint           page_no,/*!< in: page number of an index page */
 
2824
        lint*           n_recs, /*!< in/out: minimum number of records on the
 
2825
                                page after the buffered changes have been
 
2826
                                applied, or NULL to disable the counting */
2346
2827
        mtr_t*          mtr)    /*!< in: mtr */
2347
2828
{
2348
2829
        ulint   volume;
2352
2833
        page_t* prev_page;
2353
2834
        ulint   next_page_no;
2354
2835
        page_t* next_page;
 
2836
        ulint   hash_bitmap[128 / sizeof(ulint)]; /* bitmap of buffered recs */
2355
2837
 
2356
2838
        ut_a(trx_sys_multiple_tablespace_format);
2357
2839
 
2358
2840
        ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
2359
2841
              || (pcur->latch_mode == BTR_MODIFY_TREE));
2360
2842
 
2361
 
        /* Count the volume of records earlier in the alphabetical order than
 
2843
        /* Count the volume of inserts earlier in the alphabetical order than
2362
2844
        pcur */
2363
2845
 
2364
2846
        volume = 0;
2365
2847
 
 
2848
        if (n_recs) {
 
2849
                memset(hash_bitmap, 0, sizeof hash_bitmap);
 
2850
        }
 
2851
 
2366
2852
        rec = btr_pcur_get_rec(pcur);
2367
2853
        page = page_align(rec);
 
2854
        ut_ad(page_validate(page, ibuf->index));
2368
2855
 
2369
2856
        if (page_rec_is_supremum(rec)) {
2370
2857
                rec = page_rec_get_prev(rec);
2382
2869
                        goto count_later;
2383
2870
                }
2384
2871
 
2385
 
                volume += ibuf_rec_get_volume(rec);
 
2872
                volume += ibuf_get_volume_buffered_count(
 
2873
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2386
2874
 
2387
2875
                rec = page_rec_get_prev(rec);
 
2876
                ut_ad(page_align(rec) == page);
2388
2877
        }
2389
2878
 
2390
2879
        /* Look at the previous page */
2406
2895
 
2407
2896
 
2408
2897
                prev_page = buf_block_get_frame(block);
 
2898
                ut_ad(page_validate(prev_page, ibuf->index));
2409
2899
        }
2410
2900
 
2411
2901
#ifdef UNIV_BTR_DEBUG
2432
2922
                        goto count_later;
2433
2923
                }
2434
2924
 
2435
 
                volume += ibuf_rec_get_volume(rec);
 
2925
                volume += ibuf_get_volume_buffered_count(
 
2926
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2436
2927
 
2437
2928
                rec = page_rec_get_prev(rec);
 
2929
                ut_ad(page_align(rec) == prev_page);
2438
2930
        }
2439
2931
 
2440
2932
count_later:
2456
2948
                        return(volume);
2457
2949
                }
2458
2950
 
2459
 
                volume += ibuf_rec_get_volume(rec);
 
2951
                volume += ibuf_get_volume_buffered_count(
 
2952
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2460
2953
 
2461
2954
                rec = page_rec_get_next(rec);
2462
2955
        }
2480
2973
 
2481
2974
 
2482
2975
                next_page = buf_block_get_frame(block);
 
2976
                ut_ad(page_validate(next_page, ibuf->index));
2483
2977
        }
2484
2978
 
2485
2979
#ifdef UNIV_BTR_DEBUG
2503
2997
                        return(volume);
2504
2998
                }
2505
2999
 
2506
 
                volume += ibuf_rec_get_volume(rec);
 
3000
                volume += ibuf_get_volume_buffered_count(
 
3001
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2507
3002
 
2508
3003
                rec = page_rec_get_next(rec);
 
3004
                ut_ad(page_align(rec) == next_page);
2509
3005
        }
2510
3006
}
2511
3007
 
2533
3029
        btr_pcur_open_at_index_side(
2534
3030
                FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
2535
3031
 
 
3032
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
 
3033
 
2536
3034
        btr_pcur_move_to_prev(&pcur, &mtr);
2537
3035
 
2538
3036
        if (btr_pcur_is_before_first_on_page(&pcur)) {
2557
3055
        fil_set_max_space_id_if_bigger(max_space_id);
2558
3056
}
2559
3057
 
 
3058
/****************************************************************//**
 
3059
Helper function for ibuf_set_entry_counter. Checks if rec is for (space,
 
3060
page_no), and if so, reads counter value from it and returns that + 1.
 
3061
Otherwise, returns 0.
 
3062
@return new counter value, or 0 */
 
3063
static
 
3064
ulint
 
3065
ibuf_get_entry_counter_low(
 
3066
/*=======================*/
 
3067
        const rec_t*    rec,            /*!< in: insert buffer record */
 
3068
        ulint           space,          /*!< in: space id */
 
3069
        ulint           page_no)        /*!< in: page number */
 
3070
{
 
3071
        ulint           counter;
 
3072
        const byte*     field;
 
3073
        ulint           len;
 
3074
 
 
3075
        ut_ad(ibuf_inside());
 
3076
        ut_ad(rec_get_n_fields_old(rec) > 2);
 
3077
 
 
3078
        field = rec_get_nth_field_old(rec, 1, &len);
 
3079
 
 
3080
        if (UNIV_UNLIKELY(len != 1)) {
 
3081
                /* pre-4.1 format */
 
3082
                ut_a(trx_doublewrite_must_reset_space_ids);
 
3083
                ut_a(!trx_sys_multiple_tablespace_format);
 
3084
 
 
3085
                return(ULINT_UNDEFINED);
 
3086
        }
 
3087
 
 
3088
        ut_a(trx_sys_multiple_tablespace_format);
 
3089
 
 
3090
        /* Check the tablespace identifier. */
 
3091
        field = rec_get_nth_field_old(rec, 0, &len);
 
3092
        ut_a(len == 4);
 
3093
 
 
3094
        if (mach_read_from_4(field) != space) {
 
3095
 
 
3096
                return(0);
 
3097
        }
 
3098
 
 
3099
        /* Check the page offset. */
 
3100
        field = rec_get_nth_field_old(rec, 2, &len);
 
3101
        ut_a(len == 4);
 
3102
 
 
3103
        if (mach_read_from_4(field) != page_no) {
 
3104
 
 
3105
                return(0);
 
3106
        }
 
3107
 
 
3108
        /* Check if the record contains a counter field. */
 
3109
        field = rec_get_nth_field_old(rec, 3, &len);
 
3110
 
 
3111
        switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
 
3112
        default:
 
3113
                ut_error;
 
3114
        case 0: /* ROW_FORMAT=REDUNDANT */
 
3115
        case 1: /* ROW_FORMAT=COMPACT */
 
3116
                return(ULINT_UNDEFINED);
 
3117
 
 
3118
        case IBUF_REC_INFO_SIZE:
 
3119
                counter = mach_read_from_2(field + IBUF_REC_OFFSET_COUNTER);
 
3120
                ut_a(counter < 0xFFFF);
 
3121
                return(counter + 1);
 
3122
        }
 
3123
}
 
3124
 
 
3125
/****************************************************************//**
 
3126
Set the counter field in entry to the correct value based on the current
 
3127
last record in ibuf for (space, page_no).
 
3128
@return FALSE if we should abort this insertion to ibuf */
 
3129
static
 
3130
ibool
 
3131
ibuf_set_entry_counter(
 
3132
/*===================*/
 
3133
        dtuple_t*       entry,          /*!< in/out: entry to patch */
 
3134
        ulint           space,          /*!< in: space id of entry */
 
3135
        ulint           page_no,        /*!< in: page number of entry */
 
3136
        btr_pcur_t*     pcur,           /*!< in: pcur positioned on the record
 
3137
                                        found by btr_pcur_open(.., entry,
 
3138
                                        PAGE_CUR_LE, ..., pcur, ...) */
 
3139
        ibool           is_optimistic,  /*!< in: is this an optimistic insert */
 
3140
        mtr_t*          mtr)            /*!< in: mtr */
 
3141
{
 
3142
        dfield_t*       field;
 
3143
        byte*           data;
 
3144
        ulint           counter = 0;
 
3145
 
 
3146
        /* pcur points to either a user rec or to a page's infimum record. */
 
3147
        ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index));
 
3148
 
 
3149
        if (btr_pcur_is_on_user_rec(pcur)) {
 
3150
 
 
3151
                counter = ibuf_get_entry_counter_low(
 
3152
                        btr_pcur_get_rec(pcur), space, page_no);
 
3153
 
 
3154
                if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
 
3155
                        /* The record lacks a counter field.
 
3156
                        Such old records must be merged before
 
3157
                        new records can be buffered. */
 
3158
 
 
3159
                        return(FALSE);
 
3160
                }
 
3161
        } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) {
 
3162
                /* Ibuf tree is either completely empty, or the insert
 
3163
                position is at the very first record of a non-empty tree. In
 
3164
                either case we have no previous records for (space,
 
3165
                page_no). */
 
3166
 
 
3167
                counter = 0;
 
3168
        } else if (btr_pcur_is_before_first_on_page(pcur)) {
 
3169
                btr_cur_t*      cursor = btr_pcur_get_btr_cur(pcur);
 
3170
 
 
3171
                if (cursor->low_match < 3) {
 
3172
                        /* If low_match < 3, we know that the father node
 
3173
                        pointer did not contain the searched for (space,
 
3174
                        page_no), which means that the search ended on the
 
3175
                        right page regardless of the counter value, and
 
3176
                        since we're at the infimum record, there are no
 
3177
                        existing records. */
 
3178
 
 
3179
                        counter = 0;
 
3180
                } else {
 
3181
                        rec_t*          rec;
 
3182
                        const page_t*   page;
 
3183
                        buf_block_t*    block;
 
3184
                        page_t*         prev_page;
 
3185
                        ulint           prev_page_no;
 
3186
 
 
3187
                        ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED);
 
3188
 
 
3189
                        page = btr_pcur_get_page(pcur);
 
3190
                        prev_page_no = btr_page_get_prev(page, mtr);
 
3191
 
 
3192
                        ut_a(prev_page_no != FIL_NULL);
 
3193
 
 
3194
                        block = buf_page_get(
 
3195
                                IBUF_SPACE_ID, 0, prev_page_no,
 
3196
                                RW_X_LATCH, mtr);
 
3197
 
 
3198
                        buf_block_dbg_add_level(block, SYNC_TREE_NODE);
 
3199
 
 
3200
                        prev_page = buf_block_get_frame(block);
 
3201
 
 
3202
                        rec = page_rec_get_prev(
 
3203
                                page_get_supremum_rec(prev_page));
 
3204
 
 
3205
                        ut_ad(page_rec_is_user_rec(rec));
 
3206
 
 
3207
                        counter = ibuf_get_entry_counter_low(
 
3208
                                rec, space, page_no);
 
3209
 
 
3210
                        if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) {
 
3211
                                /* The record lacks a counter field.
 
3212
                                Such old records must be merged before
 
3213
                                new records can be buffered. */
 
3214
 
 
3215
                                return(FALSE);
 
3216
                        }
 
3217
 
 
3218
                        if (counter < cursor->ibuf_cnt) {
 
3219
                                /* Search ended on the wrong page. */
 
3220
 
 
3221
                                if (is_optimistic) {
 
3222
                                        /* In an optimistic insert, we can
 
3223
                                        shift the insert position to the left
 
3224
                                        page, since it only needs an X-latch
 
3225
                                        on the page itself, which the
 
3226
                                        original search acquired for us. */
 
3227
 
 
3228
                                        btr_cur_position(
 
3229
                                                ibuf->index, rec, block,
 
3230
                                                btr_pcur_get_btr_cur(pcur));
 
3231
                                } else {
 
3232
                                        /* We can't shift the insert
 
3233
                                        position to the left page in a
 
3234
                                        pessimistic insert since it would
 
3235
                                        require an X-latch on the left
 
3236
                                        page's left page, so we have to
 
3237
                                        abort. */
 
3238
 
 
3239
                                        return(FALSE);
 
3240
                                }
 
3241
                        } else {
 
3242
                                /* The counter field in the father node is
 
3243
                                the same as we would insert; we don't know
 
3244
                                whether the insert should go to this page or
 
3245
                                the left page (the later fields can differ),
 
3246
                                so refuse the insert. */
 
3247
 
 
3248
                                return(FALSE);
 
3249
                        }
 
3250
                }
 
3251
        } else {
 
3252
                /* The cursor is not positioned at or before a user record. */
 
3253
                return(FALSE);
 
3254
        }
 
3255
 
 
3256
        /* Patch counter value in already built entry. */
 
3257
        field = dtuple_get_nth_field(entry, 3);
 
3258
        data = dfield_get_data(field);
 
3259
 
 
3260
        mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter);
 
3261
 
 
3262
        return(TRUE);
 
3263
}
 
3264
 
2560
3265
/*********************************************************************//**
2561
 
Makes an index insert to the insert buffer, instead of directly to the disk
2562
 
page, if this is possible.
 
3266
Buffer an operation in the insert/delete buffer, instead of doing it
 
3267
directly to the disk page, if this is possible.
2563
3268
@return DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */
2564
3269
static
2565
3270
ulint
2566
3271
ibuf_insert_low(
2567
3272
/*============*/
2568
3273
        ulint           mode,   /*!< in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */
 
3274
        ibuf_op_t       op,     /*!< in: operation type */
 
3275
        ibool           no_counter,
 
3276
                                /*!< in: TRUE=use 5.0.3 format;
 
3277
                                FALSE=allow delete buffering */
2569
3278
        const dtuple_t* entry,  /*!< in: index entry to insert */
2570
3279
        ulint           entry_size,
2571
3280
                                /*!< in: rec_get_converted_size(index, entry) */
2582
3291
        dtuple_t*       ibuf_entry;
2583
3292
        mem_heap_t*     heap;
2584
3293
        ulint           buffered;
 
3294
        lint            min_n_recs;
2585
3295
        rec_t*          ins_rec;
2586
3296
        ibool           old_bit_value;
2587
3297
        page_t*         bitmap_page;
2592
3302
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
2593
3303
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
2594
3304
        ulint           n_stored;
2595
 
        ulint           bits;
2596
3305
        mtr_t           mtr;
2597
3306
        mtr_t           bitmap_mtr;
2598
3307
 
2599
3308
        ut_a(!dict_index_is_clust(index));
2600
3309
        ut_ad(dtuple_check_typed(entry));
2601
3310
        ut_ad(ut_is_2pow(zip_size));
 
3311
        ut_ad(!no_counter || op == IBUF_OP_INSERT);
 
3312
        ut_a(op < IBUF_OP_COUNT);
2602
3313
 
2603
3314
        ut_a(trx_sys_multiple_tablespace_format);
2604
3315
 
2657
3368
 
2658
3369
        heap = mem_heap_create(512);
2659
3370
 
2660
 
        /* Build the entry which contains the space id and the page number as
2661
 
        the first fields and the type information for other fields, and which
2662
 
        will be inserted to the insert buffer. */
 
3371
        /* Build the entry which contains the space id and the page number
 
3372
        as the first fields and the type information for other fields, and
 
3373
        which will be inserted to the insert buffer. Using a counter value
 
3374
        of 0xFFFF we find the last record for (space, page_no), from which
 
3375
        we can then read the counter value N and use N + 1 in the record we
 
3376
        insert. (We patch the ibuf_entry's counter field to the correct
 
3377
        value just before actually inserting the entry.) */
2663
3378
 
2664
 
        ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap);
 
3379
        ibuf_entry = ibuf_entry_build(
 
3380
                op, index, entry, space, page_no,
 
3381
                no_counter ? ULINT_UNDEFINED : 0xFFFF, heap);
2665
3382
 
2666
3383
        /* Open a cursor to the insert buffer tree to calculate if we can add
2667
3384
        the new entry to it without exceeding the free space limit for the
2670
3387
        mtr_start(&mtr);
2671
3388
 
2672
3389
        btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
 
3390
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
2673
3391
 
2674
3392
        /* Find out the volume of already buffered inserts for the same index
2675
3393
        page */
2676
 
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
 
3394
        min_n_recs = 0;
 
3395
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no,
 
3396
                                            op == IBUF_OP_DELETE
 
3397
                                            ? &min_n_recs
 
3398
                                            : NULL, &mtr);
 
3399
 
 
3400
        if (op == IBUF_OP_DELETE
 
3401
            && (min_n_recs < 2
 
3402
                || buf_pool_watch_occurred(space, page_no))) {
 
3403
                /* The page could become empty after the record is
 
3404
                deleted, or the page has been read in to the buffer
 
3405
                pool.  Refuse to buffer the operation. */
 
3406
 
 
3407
                /* The buffer pool watch is needed for IBUF_OP_DELETE
 
3408
                because of latching order considerations.  We can
 
3409
                check buf_pool_watch_occurred() only after latching
 
3410
                the insert buffer B-tree pages that contain buffered
 
3411
                changes for the page.  We never buffer IBUF_OP_DELETE,
 
3412
                unless some IBUF_OP_INSERT or IBUF_OP_DELETE_MARK have
 
3413
                been previously buffered for the page.  Because there
 
3414
                are buffered operations for the page, the insert
 
3415
                buffer B-tree page latches held by mtr will guarantee
 
3416
                that no changes for the user page will be merged
 
3417
                before mtr_commit(&mtr).  We must not mtr_commit(&mtr)
 
3418
                until after the IBUF_OP_DELETE has been buffered. */
 
3419
 
 
3420
                err = DB_STRONG_FAIL;
 
3421
 
 
3422
                goto function_exit;
 
3423
        }
 
3424
 
 
3425
        /* After this point, the page could still be loaded to the
 
3426
        buffer pool, but we do not have to care about it, since we are
 
3427
        holding a latch on the insert buffer leaf page that contains
 
3428
        buffered changes for (space, page_no).  If the page enters the
 
3429
        buffer pool, buf_page_io_complete() for (space, page_no) will
 
3430
        have to acquire a latch on the same insert buffer leaf page,
 
3431
        which it cannot do until we have buffered the IBUF_OP_DELETE
 
3432
        and done mtr_commit(&mtr) to release the latch. */
2677
3433
 
2678
3434
#ifdef UNIV_IBUF_COUNT_DEBUG
2679
3435
        ut_a((buffered == 0) || ibuf_count_get(space, page_no));
2687
3443
 
2688
3444
        if (buf_page_peek(space, page_no)
2689
3445
            || lock_rec_expl_exist_on_page(space, page_no)) {
2690
 
                err = DB_STRONG_FAIL;
2691
 
 
2692
 
                mtr_commit(&bitmap_mtr);
2693
 
 
2694
 
                goto function_exit;
2695
 
        }
2696
 
 
2697
 
        bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
2698
 
                                         IBUF_BITMAP_FREE, &bitmap_mtr);
2699
 
 
2700
 
        if (buffered + entry_size + page_dir_calc_reserved_space(1)
2701
 
            > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
2702
 
                mtr_commit(&bitmap_mtr);
2703
 
 
2704
 
                /* It may not fit */
2705
 
                err = DB_STRONG_FAIL;
2706
 
 
2707
 
                do_merge = TRUE;
2708
 
 
2709
 
                ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
2710
 
                                        space_ids, space_versions,
2711
 
                                        page_nos, &n_stored);
 
3446
 
 
3447
                goto bitmap_fail;
 
3448
        }
 
3449
 
 
3450
        if (op == IBUF_OP_INSERT) {
 
3451
                ulint   bits = ibuf_bitmap_page_get_bits(
 
3452
                        bitmap_page, page_no, zip_size, IBUF_BITMAP_FREE,
 
3453
                        &bitmap_mtr);
 
3454
 
 
3455
                if (buffered + entry_size + page_dir_calc_reserved_space(1)
 
3456
                    > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
 
3457
                        /* Release the bitmap page latch early. */
 
3458
                        mtr_commit(&bitmap_mtr);
 
3459
 
 
3460
                        /* It may not fit */
 
3461
                        do_merge = TRUE;
 
3462
 
 
3463
                        ibuf_get_merge_page_nos(
 
3464
                                FALSE, btr_pcur_get_rec(&pcur),
 
3465
                                space_ids, space_versions,
 
3466
                                page_nos, &n_stored);
 
3467
 
 
3468
                        err = DB_STRONG_FAIL;
 
3469
 
 
3470
                        goto function_exit;
 
3471
                }
 
3472
        }
 
3473
 
 
3474
        /* Patch correct counter value to the entry to insert. This can
 
3475
        change the insert position, which can result in the need to abort in
 
3476
        some cases. */
 
3477
        if (!no_counter
 
3478
            && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur,
 
3479
                                       mode == BTR_MODIFY_PREV, &mtr)) {
 
3480
bitmap_fail:
 
3481
                err = DB_STRONG_FAIL;
 
3482
 
 
3483
                mtr_commit(&bitmap_mtr);
 
3484
 
2712
3485
                goto function_exit;
2713
3486
        }
2714
3487
 
2733
3506
                err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
2734
3507
                                                ibuf_entry, &ins_rec,
2735
3508
                                                &dummy_big_rec, 0, thr, &mtr);
2736
 
                if (err == DB_SUCCESS) {
 
3509
                if (err == DB_SUCCESS && op != IBUF_OP_DELETE) {
2737
3510
                        /* Update the page max trx id field */
2738
3511
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
2739
3512
                                               thr_get_trx(thr)->id, &mtr);
2753
3526
                                                 cursor,
2754
3527
                                                 ibuf_entry, &ins_rec,
2755
3528
                                                 &dummy_big_rec, 0, thr, &mtr);
2756
 
                if (err == DB_SUCCESS) {
 
3529
                if (err == DB_SUCCESS && op != IBUF_OP_DELETE) {
2757
3530
                        /* Update the page max trx id field */
2758
3531
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
2759
3532
                                               thr_get_trx(thr)->id, &mtr);
2790
3563
                mutex_enter(&ibuf_mutex);
2791
3564
 
2792
3565
                ibuf->empty = FALSE;
2793
 
                ibuf->n_inserts++;
2794
3566
 
2795
3567
                mutex_exit(&ibuf_mutex);
2796
3568
 
2811
3583
}
2812
3584
 
2813
3585
/*********************************************************************//**
2814
 
Makes an index insert to the insert buffer, instead of directly to the disk
2815
 
page, if this is possible. Does not do insert if the index is clustered
2816
 
or unique.
 
3586
Buffer an operation in the insert/delete buffer, instead of doing it
 
3587
directly to the disk page, if this is possible. Does not do it if the index
 
3588
is clustered or unique.
2817
3589
@return TRUE if success */
2818
3590
UNIV_INTERN
2819
3591
ibool
2820
3592
ibuf_insert(
2821
3593
/*========*/
 
3594
        ibuf_op_t       op,     /*!< in: operation type */
2822
3595
        const dtuple_t* entry,  /*!< in: index entry to insert */
2823
3596
        dict_index_t*   index,  /*!< in: index where to insert */
2824
3597
        ulint           space,  /*!< in: space id where to insert */
2826
3599
        ulint           page_no,/*!< in: page number where to insert */
2827
3600
        que_thr_t*      thr)    /*!< in: query thread */
2828
3601
{
2829
 
        ulint   err;
2830
 
        ulint   entry_size;
 
3602
        ulint           err;
 
3603
        ulint           entry_size;
 
3604
        ibool           no_counter;
 
3605
        /* Read the settable global variable ibuf_use only once in
 
3606
        this function, so that we will have a consistent view of it. */
 
3607
        ibuf_use_t      use             = ibuf_use;
2831
3608
 
2832
3609
        ut_a(trx_sys_multiple_tablespace_format);
2833
3610
        ut_ad(dtuple_check_typed(entry));
2835
3612
 
2836
3613
        ut_a(!dict_index_is_clust(index));
2837
3614
 
2838
 
        switch (UNIV_EXPECT(ibuf_use, IBUF_USE_INSERT)) {
2839
 
        case IBUF_USE_NONE:
2840
 
                return(FALSE);
2841
 
        case IBUF_USE_INSERT:
2842
 
                goto do_insert;
2843
 
        case IBUF_USE_COUNT:
2844
 
                break;
2845
 
        }
2846
 
 
2847
 
        ut_error; /* unknown value of ibuf_use */
2848
 
 
2849
 
do_insert:
 
3615
        no_counter = use <= IBUF_USE_INSERT;
 
3616
 
 
3617
        switch (op) {
 
3618
        case IBUF_OP_INSERT:
 
3619
                switch (use) {
 
3620
                case IBUF_USE_NONE:
 
3621
                case IBUF_USE_DELETE:
 
3622
                case IBUF_USE_DELETE_MARK:
 
3623
                        return(FALSE);
 
3624
                case IBUF_USE_INSERT:
 
3625
                case IBUF_USE_INSERT_DELETE_MARK:
 
3626
                case IBUF_USE_ALL:
 
3627
                        goto check_watch;
 
3628
                case IBUF_USE_COUNT:
 
3629
                        break;
 
3630
                }
 
3631
                break;
 
3632
        case IBUF_OP_DELETE_MARK:
 
3633
                switch (use) {
 
3634
                case IBUF_USE_NONE:
 
3635
                case IBUF_USE_INSERT:
 
3636
                        return(FALSE);
 
3637
                case IBUF_USE_DELETE_MARK:
 
3638
                case IBUF_USE_DELETE:
 
3639
                case IBUF_USE_INSERT_DELETE_MARK:
 
3640
                case IBUF_USE_ALL:
 
3641
                        ut_ad(!no_counter);
 
3642
                        goto check_watch;
 
3643
                case IBUF_USE_COUNT:
 
3644
                        break;
 
3645
                }
 
3646
                break;
 
3647
        case IBUF_OP_DELETE:
 
3648
                switch (use) {
 
3649
                case IBUF_USE_NONE:
 
3650
                case IBUF_USE_INSERT:
 
3651
                case IBUF_USE_INSERT_DELETE_MARK:
 
3652
                        return(FALSE);
 
3653
                case IBUF_USE_DELETE_MARK:
 
3654
                case IBUF_USE_DELETE:
 
3655
                case IBUF_USE_ALL:
 
3656
                        ut_ad(!no_counter);
 
3657
                        goto skip_watch;
 
3658
                case IBUF_USE_COUNT:
 
3659
                        break;
 
3660
                }
 
3661
                break;
 
3662
        case IBUF_OP_COUNT:
 
3663
                break;
 
3664
        }
 
3665
 
 
3666
        /* unknown op or use */
 
3667
        ut_error;
 
3668
 
 
3669
check_watch:
 
3670
        /* If a thread attempts to buffer an insert on a page while a
 
3671
        purge is in progress on the same page, the purge must not be
 
3672
        buffered, because it could remove a record that was
 
3673
        re-inserted later.  For simplicity, we block the buffering of
 
3674
        all operations on a page that has a purge pending.
 
3675
 
 
3676
        We do not check this in the IBUF_OP_DELETE case, because that
 
3677
        would always trigger the buffer pool watch during purge and
 
3678
        thus prevent the buffering of delete operations.  We assume
 
3679
        that the issuer of IBUF_OP_DELETE has called
 
3680
        buf_pool_watch_set(space, page_no). */
 
3681
 
 
3682
        {
 
3683
                buf_page_t*     bpage;
 
3684
                ulint           fold = buf_page_address_fold(space, page_no);
 
3685
                buf_pool_t*     buf_pool = buf_pool_get(space, page_no);
 
3686
 
 
3687
                buf_pool_mutex_enter(buf_pool);
 
3688
                bpage = buf_page_hash_get_low(buf_pool, space, page_no, fold);
 
3689
                buf_pool_mutex_exit(buf_pool);
 
3690
 
 
3691
                if (UNIV_LIKELY_NULL(bpage)) {
 
3692
                        /* A buffer pool watch has been set or the
 
3693
                        page has been read into the buffer pool.
 
3694
                        Do not buffer the request.  If a purge operation
 
3695
                        is being buffered, have this request executed
 
3696
                        directly on the page in the buffer pool after the
 
3697
                        buffered entries for this page have been merged. */
 
3698
                        return(FALSE);
 
3699
                }
 
3700
        }
 
3701
 
 
3702
skip_watch:
2850
3703
        entry_size = rec_get_converted_size(index, entry, 0);
2851
3704
 
2852
3705
        if (entry_size
2853
 
            >= (page_get_free_space_of_empty(dict_table_is_comp(index->table))
2854
 
                / 2)) {
 
3706
            >= page_get_free_space_of_empty(dict_table_is_comp(index->table))
 
3707
            / 2) {
 
3708
 
2855
3709
                return(FALSE);
2856
3710
        }
2857
3711
 
2858
 
        err = ibuf_insert_low(BTR_MODIFY_PREV, entry, entry_size,
 
3712
        err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter,
 
3713
                              entry, entry_size,
2859
3714
                              index, space, zip_size, page_no, thr);
2860
3715
        if (err == DB_FAIL) {
2861
 
                err = ibuf_insert_low(BTR_MODIFY_TREE, entry, entry_size,
 
3716
                err = ibuf_insert_low(BTR_MODIFY_TREE, op, no_counter,
 
3717
                                      entry, entry_size,
2862
3718
                                      index, space, zip_size, page_no, thr);
2863
3719
        }
2864
3720
 
2910
3766
 
2911
3767
        rec = page_rec_get_next(page_get_infimum_rec(page));
2912
3768
 
 
3769
        if (page_rec_is_supremum(rec)) {
 
3770
                /* Empty pages can result from buffered delete operations.
 
3771
                The first record from the free list can be used to find the
 
3772
                father node. */
 
3773
                rec = page_header_get_ptr(page, PAGE_FREE);
 
3774
                if (UNIV_UNLIKELY(rec == NULL)) {
 
3775
                        fputs("InnoDB: Trying to insert a record from"
 
3776
                              " the insert buffer to an index page\n"
 
3777
                              "InnoDB: but the index page is empty!\n",
 
3778
                              stderr);
 
3779
                        goto dump;
 
3780
                }
 
3781
        }
 
3782
 
2913
3783
        if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
2914
3784
                          != dtuple_get_n_fields(entry))) {
2915
3785
                fputs("InnoDB: Trying to insert a record from"
2941
3811
                rec = page_cur_get_rec(&page_cur);
2942
3812
                page_zip = buf_block_get_page_zip(block);
2943
3813
 
2944
 
                btr_cur_del_unmark_for_ibuf(rec, page_zip, mtr);
 
3814
                btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, FALSE, mtr);
2945
3815
        } else {
2946
3816
                rec = page_cur_tuple_insert(&page_cur, entry, index, 0, mtr);
2947
3817
 
3003
3873
        }
3004
3874
}
3005
3875
 
 
3876
/****************************************************************//**
 
3877
During merge, sets the delete mark on a record for a secondary index
 
3878
entry. */
 
3879
static
 
3880
void
 
3881
ibuf_set_del_mark(
 
3882
/*==============*/
 
3883
        const dtuple_t*         entry,  /*!< in: entry */
 
3884
        buf_block_t*            block,  /*!< in/out: block */
 
3885
        const dict_index_t*     index,  /*!< in: record descriptor */
 
3886
        mtr_t*                  mtr)    /*!< in: mtr */
 
3887
{
 
3888
        page_cur_t      page_cur;
 
3889
        ulint           low_match;
 
3890
 
 
3891
        ut_ad(ibuf_inside());
 
3892
        ut_ad(dtuple_check_typed(entry));
 
3893
 
 
3894
        low_match = page_cur_search(
 
3895
                block, index, entry, PAGE_CUR_LE, &page_cur);
 
3896
 
 
3897
        if (low_match == dtuple_get_n_fields(entry)) {
 
3898
                rec_t*          rec;
 
3899
                page_zip_des_t* page_zip;
 
3900
 
 
3901
                rec = page_cur_get_rec(&page_cur);
 
3902
                page_zip = page_cur_get_page_zip(&page_cur);
 
3903
 
 
3904
                btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, TRUE, mtr);
 
3905
        } else {
 
3906
                /* This can happen benignly in some situations. */
 
3907
        }
 
3908
}
 
3909
 
 
3910
/****************************************************************//**
 
3911
During merge, delete a record for a secondary index entry. */
 
3912
static
 
3913
void
 
3914
ibuf_delete(
 
3915
/*========*/
 
3916
        const dtuple_t* entry,  /*!< in: entry */
 
3917
        buf_block_t*    block,  /*!< in/out: block */
 
3918
        dict_index_t*   index,  /*!< in: record descriptor */
 
3919
        mtr_t*          mtr)    /*!< in/out: mtr; must be committed
 
3920
                                before latching any further pages */
 
3921
{
 
3922
        page_cur_t      page_cur;
 
3923
        ulint           low_match;
 
3924
 
 
3925
        ut_ad(ibuf_inside());
 
3926
        ut_ad(dtuple_check_typed(entry));
 
3927
 
 
3928
        low_match = page_cur_search(
 
3929
                block, index, entry, PAGE_CUR_LE, &page_cur);
 
3930
 
 
3931
        if (low_match == dtuple_get_n_fields(entry)) {
 
3932
                page_zip_des_t* page_zip= buf_block_get_page_zip(block);
 
3933
                page_t*         page    = buf_block_get_frame(block);
 
3934
                rec_t*          rec     = page_cur_get_rec(&page_cur);
 
3935
 
 
3936
                /* TODO: the below should probably be a separate function,
 
3937
                it's a bastardized version of btr_cur_optimistic_delete. */
 
3938
 
 
3939
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
3940
                ulint*          offsets = offsets_;
 
3941
                mem_heap_t*     heap = NULL;
 
3942
                ulint           max_ins_size;
 
3943
 
 
3944
                rec_offs_init(offsets_);
 
3945
 
 
3946
                offsets = rec_get_offsets(
 
3947
                        rec, index, offsets, ULINT_UNDEFINED, &heap);
 
3948
 
 
3949
                /* Refuse to delete the last record. */
 
3950
                ut_a(page_get_n_recs(page) > 1);
 
3951
 
 
3952
                /* The record should have been marked for deletion. */
 
3953
                ut_ad(REC_INFO_DELETED_FLAG
 
3954
                      & rec_get_info_bits(rec, page_is_comp(page)));
 
3955
 
 
3956
                lock_update_delete(block, rec);
 
3957
 
 
3958
                if (!page_zip) {
 
3959
                        max_ins_size
 
3960
                                = page_get_max_insert_size_after_reorganize(
 
3961
                                        page, 1);
 
3962
                }
 
3963
#ifdef UNIV_ZIP_DEBUG
 
3964
                ut_a(!page_zip || page_zip_validate(page_zip, page));
 
3965
#endif /* UNIV_ZIP_DEBUG */
 
3966
                page_cur_delete_rec(&page_cur, index, offsets, mtr);
 
3967
#ifdef UNIV_ZIP_DEBUG
 
3968
                ut_a(!page_zip || page_zip_validate(page_zip, page));
 
3969
#endif /* UNIV_ZIP_DEBUG */
 
3970
 
 
3971
                if (page_zip) {
 
3972
                        ibuf_update_free_bits_zip(block, mtr);
 
3973
                } else {
 
3974
                        ibuf_update_free_bits_low(block, max_ins_size, mtr);
 
3975
                }
 
3976
 
 
3977
                if (UNIV_LIKELY_NULL(heap)) {
 
3978
                        mem_heap_free(heap);
 
3979
                }
 
3980
        } else {
 
3981
                /* This can happen benignly in some situations: either when
 
3982
                we crashed at just the right time, or on database startup
 
3983
                when we redo some old log entries (due to worse stored
 
3984
                position granularity on disk than in memory). */
 
3985
        }
 
3986
}
 
3987
 
 
3988
/*********************************************************************//**
 
3989
Restores insert buffer tree cursor position
 
3990
@return TRUE if the position was restored; FALSE if not */
 
3991
static __attribute__((nonnull))
 
3992
ibool
 
3993
ibuf_restore_pos(
 
3994
/*=============*/
 
3995
        ulint           space,  /*!< in: space id */
 
3996
        ulint           page_no,/*!< in: index page number where the record
 
3997
                                should belong */
 
3998
        const dtuple_t* search_tuple,
 
3999
                                /*!< in: search tuple for entries of page_no */
 
4000
        ulint           mode,   /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
 
4001
        btr_pcur_t*     pcur,   /*!< in/out: persistent cursor whose
 
4002
                                position is to be restored */
 
4003
        mtr_t*          mtr)    /*!< in/out: mini-transaction */
 
4004
{
 
4005
        ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE);
 
4006
 
 
4007
        if (btr_pcur_restore_position(mode, pcur, mtr)) {
 
4008
 
 
4009
                return(TRUE);
 
4010
        }
 
4011
 
 
4012
        if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
 
4013
                /* The tablespace has been dropped.  It is possible
 
4014
                that another thread has deleted the insert buffer
 
4015
                entry.  Do not complain. */
 
4016
                btr_pcur_commit_specify_mtr(pcur, mtr);
 
4017
        } else {
 
4018
                fprintf(stderr,
 
4019
                        "InnoDB: ERROR: Submit the output to"
 
4020
                        " http://bugs.mysql.com\n"
 
4021
                        "InnoDB: ibuf cursor restoration fails!\n"
 
4022
                        "InnoDB: ibuf record inserted to page %lu:%lu\n",
 
4023
                        (ulong) space, (ulong) page_no);
 
4024
                fflush(stderr);
 
4025
 
 
4026
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
 
4027
                rec_print_old(stderr, pcur->old_rec);
 
4028
                dtuple_print(stderr, search_tuple);
 
4029
 
 
4030
                rec_print_old(stderr,
 
4031
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
 
4032
                fflush(stderr);
 
4033
 
 
4034
                btr_pcur_commit_specify_mtr(pcur, mtr);
 
4035
 
 
4036
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
 
4037
                if (!btr_validate_index(ibuf->index, NULL)) {
 
4038
                        ut_error;
 
4039
                }
 
4040
 
 
4041
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
 
4042
                fflush(stderr);
 
4043
        }
 
4044
 
 
4045
        return(FALSE);
 
4046
}
 
4047
 
3006
4048
/*********************************************************************//**
3007
4049
Deletes from ibuf the record on which pcur is positioned. If we have to
3008
4050
resort to a pessimistic delete, this function commits mtr and closes
3057
4099
 
3058
4100
        mtr_start(mtr);
3059
4101
 
3060
 
        success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
3061
 
 
3062
 
        if (!success) {
3063
 
                if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
3064
 
                        /* The tablespace has been dropped.  It is possible
3065
 
                        that another thread has deleted the insert buffer
3066
 
                        entry.  Do not complain. */
3067
 
                        goto commit_and_exit;
3068
 
                }
3069
 
 
3070
 
                fprintf(stderr,
3071
 
                        "InnoDB: ERROR: Submit the output to"
3072
 
                        " http://bugs.mysql.com\n"
3073
 
                        "InnoDB: ibuf cursor restoration fails!\n"
3074
 
                        "InnoDB: ibuf record inserted to page %lu\n",
3075
 
                        (ulong) page_no);
3076
 
                fflush(stderr);
3077
 
 
3078
 
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
3079
 
                rec_print_old(stderr, pcur->old_rec);
3080
 
                dtuple_print(stderr, search_tuple);
3081
 
 
3082
 
                rec_print_old(stderr,
3083
 
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
3084
 
                fflush(stderr);
3085
 
 
3086
 
                btr_pcur_commit_specify_mtr(pcur, mtr);
3087
 
 
3088
 
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
3089
 
                if (!btr_validate_index(ibuf->index, NULL)) {
3090
 
                        ut_error;
3091
 
                }
3092
 
 
3093
 
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
3094
 
                fflush(stderr);
 
4102
        if (!ibuf_restore_pos(space, page_no, search_tuple,
 
4103
                              BTR_MODIFY_TREE, pcur, mtr)) {
3095
4104
 
3096
4105
                goto func_exit;
3097
4106
        }
3106
4115
        ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
3107
4116
#endif
3108
4117
        ibuf_size_update(root, mtr);
3109
 
 
3110
 
commit_and_exit:
3111
4118
        btr_pcur_commit_specify_mtr(pcur, mtr);
3112
4119
 
3113
4120
func_exit:
3120
4127
 
3121
4128
/*********************************************************************//**
3122
4129
When an index page is read from a disk to the buffer pool, this function
3123
 
inserts to the page the possible index entries buffered in the insert buffer.
3124
 
The entries are deleted from the insert buffer. If the page is not read, but
3125
 
created in the buffer pool, this function deletes its buffered entries from
3126
 
the insert buffer; there can exist entries for such a page if the page
3127
 
belonged to an index which subsequently was dropped. */
 
4130
applies any buffered operations to the page and deletes the entries from the
 
4131
insert buffer. If the page is not read, but created in the buffer pool, this
 
4132
function deletes its buffered entries from the insert buffer; there can
 
4133
exist entries for such a page if the page belonged to an index which
 
4134
subsequently was dropped. */
3128
4135
UNIV_INTERN
3129
4136
void
3130
4137
ibuf_merge_or_delete_for_page(
3145
4152
        mem_heap_t*     heap;
3146
4153
        btr_pcur_t      pcur;
3147
4154
        dtuple_t*       search_tuple;
3148
 
        ulint           n_inserts;
3149
4155
#ifdef UNIV_IBUF_DEBUG
3150
 
        ulint           volume;
 
4156
        ulint           volume                  = 0;
3151
4157
#endif
3152
4158
        page_zip_des_t* page_zip                = NULL;
3153
4159
        ibool           tablespace_being_deleted = FALSE;
3154
4160
        ibool           corruption_noticed      = FALSE;
3155
4161
        mtr_t           mtr;
3156
4162
 
 
4163
        /* Counts for merged & discarded operations. */
 
4164
        ulint           mops[IBUF_OP_COUNT];
 
4165
        ulint           dops[IBUF_OP_COUNT];
 
4166
 
3157
4167
        ut_ad(!block || buf_block_get_space(block) == space);
3158
4168
        ut_ad(!block || buf_block_get_page_no(block) == page_no);
3159
4169
        ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
3296
4306
                }
3297
4307
        }
3298
4308
 
3299
 
        n_inserts = 0;
3300
 
#ifdef UNIV_IBUF_DEBUG
3301
 
        volume = 0;
3302
 
#endif
 
4309
        memset(mops, 0, sizeof(mops));
 
4310
        memset(dops, 0, sizeof(dops));
 
4311
 
3303
4312
loop:
3304
4313
        mtr_start(&mtr);
3305
4314
 
3352
4361
                        fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
3353
4362
                } else if (block) {
3354
4363
                        /* Now we have at pcur a record which should be
3355
 
                        inserted to the index page; NOTE that the call below
 
4364
                        applied on the index page; NOTE that the call below
3356
4365
                        copies pointers to fields in rec, and we must
3357
4366
                        keep the latch to the rec page until the
3358
4367
                        insertion is finished! */
3359
4368
                        dtuple_t*       entry;
3360
4369
                        trx_id_t        max_trx_id;
3361
4370
                        dict_index_t*   dummy_index;
 
4371
                        ibuf_op_t       op = ibuf_rec_get_op_type(rec);
3362
4372
 
3363
4373
                        max_trx_id = page_get_max_trx_id(page_align(rec));
3364
4374
                        page_update_max_trx_id(block, page_zip, max_trx_id,
3365
4375
                                               &mtr);
3366
4376
 
 
4377
                        ut_ad(page_validate(page_align(rec), ibuf->index));
 
4378
 
3367
4379
                        entry = ibuf_build_entry_from_ibuf_rec(
3368
4380
                                rec, heap, &dummy_index);
 
4381
 
 
4382
                        ut_ad(page_validate(block->frame, dummy_index));
 
4383
 
 
4384
                        switch (op) {
 
4385
                                ibool   success;
 
4386
                        case IBUF_OP_INSERT:
3369
4387
#ifdef UNIV_IBUF_DEBUG
3370
 
                        volume += rec_get_converted_size(dummy_index, entry, 0)
3371
 
                                + page_dir_calc_reserved_space(1);
3372
 
                        ut_a(volume <= 4 * UNIV_PAGE_SIZE
3373
 
                             / IBUF_PAGE_SIZE_PER_FREE_SPACE);
 
4388
                                volume += rec_get_converted_size(
 
4389
                                        dummy_index, entry, 0);
 
4390
 
 
4391
                                volume += page_dir_calc_reserved_space(1);
 
4392
 
 
4393
                                ut_a(volume <= 4 * UNIV_PAGE_SIZE
 
4394
                                        / IBUF_PAGE_SIZE_PER_FREE_SPACE);
3374
4395
#endif
3375
 
                        ibuf_insert_to_index_page(entry, block,
3376
 
                                                  dummy_index, &mtr);
 
4396
                                ibuf_insert_to_index_page(
 
4397
                                        entry, block, dummy_index, &mtr);
 
4398
                                break;
 
4399
 
 
4400
                        case IBUF_OP_DELETE_MARK:
 
4401
                                ibuf_set_del_mark(
 
4402
                                        entry, block, dummy_index, &mtr);
 
4403
                                break;
 
4404
 
 
4405
                        case IBUF_OP_DELETE:
 
4406
                                ibuf_delete(entry, block, dummy_index, &mtr);
 
4407
                                /* Because ibuf_delete() will latch an
 
4408
                                insert buffer bitmap page, commit mtr
 
4409
                                before latching any further pages.
 
4410
                                Store and restore the cursor position. */
 
4411
                                ut_ad(rec == btr_pcur_get_rec(&pcur));
 
4412
                                ut_ad(page_rec_is_user_rec(rec));
 
4413
                                ut_ad(ibuf_rec_get_page_no(rec) == page_no);
 
4414
                                ut_ad(ibuf_rec_get_space(rec) == space);
 
4415
 
 
4416
                                btr_pcur_store_position(&pcur, &mtr);
 
4417
                                btr_pcur_commit_specify_mtr(&pcur, &mtr);
 
4418
 
 
4419
                                mtr_start(&mtr);
 
4420
 
 
4421
                                success = buf_page_get_known_nowait(
 
4422
                                        RW_X_LATCH, block,
 
4423
                                        BUF_KEEP_OLD,
 
4424
                                        __FILE__, __LINE__, &mtr);
 
4425
                                ut_a(success);
 
4426
 
 
4427
                                buf_block_dbg_add_level(block, SYNC_TREE_NODE);
 
4428
 
 
4429
                                if (!ibuf_restore_pos(space, page_no,
 
4430
                                                      search_tuple,
 
4431
                                                      BTR_MODIFY_LEAF,
 
4432
                                                      &pcur, &mtr)) {
 
4433
 
 
4434
                                        mtr_commit(&mtr);
 
4435
                                        mops[op]++;
 
4436
                                        ibuf_dummy_index_free(dummy_index);
 
4437
                                        goto loop;
 
4438
                                }
 
4439
 
 
4440
                                break;
 
4441
                        default:
 
4442
                                ut_error;
 
4443
                        }
 
4444
 
 
4445
                        mops[op]++;
 
4446
 
3377
4447
                        ibuf_dummy_index_free(dummy_index);
 
4448
                } else {
 
4449
                        dops[ibuf_rec_get_op_type(rec)]++;
3378
4450
                }
3379
4451
 
3380
 
                n_inserts++;
3381
 
 
3382
4452
                /* Delete the record from ibuf */
3383
4453
                if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3384
4454
                                    &mtr)) {
3395
4465
        }
3396
4466
 
3397
4467
reset_bit:
3398
 
#ifdef UNIV_IBUF_COUNT_DEBUG
3399
 
        if (ibuf_count_get(space, page_no) > 0) {
3400
 
                /* btr_print_tree(ibuf_data->index->tree, 100);
3401
 
                ibuf_print(); */
3402
 
        }
3403
 
#endif
3404
4468
        if (UNIV_LIKELY(update_ibuf_bitmap)) {
3405
4469
                page_t* bitmap_page;
3406
4470
 
3435
4499
        mutex_enter(&ibuf_mutex);
3436
4500
 
3437
4501
        ibuf->n_merges++;
3438
 
        ibuf->n_merged_recs += n_inserts;
 
4502
        ibuf_add_ops(ibuf->n_merged_ops, mops);
 
4503
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
3439
4504
 
3440
4505
        mutex_exit(&ibuf_mutex);
3441
4506
 
3468
4533
        rec_t*          ibuf_rec;
3469
4534
        ulint           page_no;
3470
4535
        ibool           closed;
3471
 
        ulint           n_inserts;
3472
4536
        mtr_t           mtr;
3473
4537
 
 
4538
        /* Counts for discarded operations. */
 
4539
        ulint           dops[IBUF_OP_COUNT];
 
4540
 
3474
4541
        heap = mem_heap_create(512);
3475
4542
 
3476
4543
        /* Use page number 0 to build the search tuple so that we get the
3478
4545
 
3479
4546
        search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
3480
4547
 
3481
 
        n_inserts = 0;
 
4548
        memset(dops, 0, sizeof(dops));
3482
4549
loop:
3483
4550
        ibuf_enter();
3484
4551
 
3509
4576
 
3510
4577
                page_no = ibuf_rec_get_page_no(ibuf_rec);
3511
4578
 
3512
 
                n_inserts++;
 
4579
                dops[ibuf_rec_get_op_type(ibuf_rec)]++;
3513
4580
 
3514
4581
                /* Delete the record from ibuf */
3515
4582
                closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3539
4606
 
3540
4607
        /* Protect our statistics keeping from race conditions */
3541
4608
        mutex_enter(&ibuf_mutex);
3542
 
 
3543
 
        ibuf->n_merges++;
3544
 
        ibuf->n_merged_recs += n_inserts;
3545
 
 
 
4609
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
3546
4610
        mutex_exit(&ibuf_mutex);
3547
4611
 
3548
4612
        ibuf_exit();
3613
4677
        mutex_enter(&ibuf_mutex);
3614
4678
 
3615
4679
        fprintf(file,
3616
 
                "Ibuf: size %lu, free list len %lu, seg size %lu,\n"
3617
 
                "%lu inserts, %lu merged recs, %lu merges\n",
 
4680
                "Ibuf: size %lu, free list len %lu,"
 
4681
                " seg size %lu, %lu merges\n",
3618
4682
                (ulong) ibuf->size,
3619
4683
                (ulong) ibuf->free_list_len,
3620
4684
                (ulong) ibuf->seg_size,
3621
 
                (ulong) ibuf->n_inserts,
3622
 
                (ulong) ibuf->n_merged_recs,
3623
4685
                (ulong) ibuf->n_merges);
 
4686
 
 
4687
        fputs("merged operations:\n ", file);
 
4688
        ibuf_print_ops(ibuf->n_merged_ops, file);
 
4689
 
 
4690
        fputs("discarded operations:\n ", file);
 
4691
        ibuf_print_ops(ibuf->n_discarded_ops, file);
 
4692
 
3624
4693
#ifdef UNIV_IBUF_COUNT_DEBUG
3625
4694
        for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
3626
4695
                for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {