~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-27 21:00:49 UTC
  • mto: This revision was merged to the branch mainline in revision 1886.
  • Revision ID: brian@tangent.org-20101027210049-zfpgx2cfbrh8maq9
A couple of fixes to documentation.

Show diffs side-by-side

added added

removed removed

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