~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2011-02-13 17:26:39 UTC
  • mfrom: (2157.2.2 give-in-to-pkg-config)
  • mto: This revision was merged to the branch mainline in revision 2166.
  • Revision ID: mordred@inaugust.com-20110213172639-nhy7i72sfhoq13ms
Merged in pkg-config fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
 
3
Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
4
4
 
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
11
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
12
 
13
13
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
 
Place, Suite 330, Boston, MA 02111-1307 USA
 
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 
15
St, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
*****************************************************************************/
18
18
 
49
49
#include "btr0cur.h"
50
50
#include "btr0pcur.h"
51
51
#include "btr0btr.h"
 
52
#include "row0upd.h"
52
53
#include "sync0sync.h"
53
54
#include "dict0boot.h"
54
55
#include "fut0lst.h"
55
56
#include "lock0lock.h"
56
57
#include "log0recv.h"
57
58
#include "que0que.h"
 
59
#include "srv0start.h" /* srv_shutdown_state */
58
60
 
59
61
/*      STRUCTURE OF AN INSERT BUFFER RECORD
60
62
 
89
91
looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE.
90
92
 
91
93
The high-order bit of the character set field in the type info is the
92
 
"nullable" flag for the field. */
 
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
*/
93
116
 
94
117
 
95
118
/*      PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM
168
191
#define IBUF_TABLE_NAME         "SYS_IBUF_TABLE"
169
192
 
170
193
/** Operations that can currently be buffered. */
171
 
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_INSERT;
 
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 */
172
200
 
173
201
/** The insert buffer control structure */
174
202
UNIV_INTERN ibuf_t*     ibuf                    = NULL;
176
204
/** Counter for ibuf_should_try() */
177
205
UNIV_INTERN ulint       ibuf_flush_count        = 0;
178
206
 
 
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
 
179
213
#ifdef UNIV_IBUF_COUNT_DEBUG
180
214
/** Number of tablespaces in the ibuf_counts array */
181
215
#define IBUF_COUNT_N_SPACES     4
221
255
                                        list of the ibuf */
222
256
/* @} */
223
257
 
 
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
 
224
284
/** The mutex used to block pessimistic inserts to ibuf trees */
225
285
static mutex_t  ibuf_pessimistic_insert_mutex;
226
286
 
342
402
        mtr_t*          mtr)    /*!< in: mtr */
343
403
{
344
404
        buf_block_t*    block;
 
405
        page_t*         root;
345
406
 
346
407
        ut_ad(ibuf_inside());
 
408
        ut_ad(mutex_own(&ibuf_mutex));
347
409
 
348
410
        mtr_x_lock(dict_index_get_lock(ibuf->index), mtr);
349
411
 
352
414
 
353
415
        buf_block_dbg_add_level(block, SYNC_TREE_NODE);
354
416
 
355
 
        return(buf_block_get_frame(block));
 
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);
356
424
}
357
425
 
358
426
#ifdef UNIV_IBUF_COUNT_DEBUG
390
458
#endif
391
459
 
392
460
/******************************************************************//**
 
461
Closes insert buffer and frees the data structures. */
 
462
UNIV_INTERN
 
463
void
 
464
ibuf_close(void)
 
465
/*============*/
 
466
{
 
467
        mutex_free(&ibuf_pessimistic_insert_mutex);
 
468
        memset(&ibuf_pessimistic_insert_mutex,
 
469
               0x0, sizeof(ibuf_pessimistic_insert_mutex));
 
470
 
 
471
        mutex_free(&ibuf_mutex);
 
472
        memset(&ibuf_mutex, 0x0, sizeof(ibuf_mutex));
 
473
 
 
474
        mutex_free(&ibuf_bitmap_mutex);
 
475
        memset(&ibuf_bitmap_mutex, 0x0, sizeof(ibuf_mutex));
 
476
 
 
477
        mem_free(ibuf);
 
478
        ibuf = NULL;
 
479
}
 
480
 
 
481
/******************************************************************//**
393
482
Updates the size information of the ibuf, assuming the segment size has not
394
483
changed. */
395
484
static
408
497
 
409
498
        /* the '1 +' is the ibuf header page */
410
499
        ibuf->size = ibuf->seg_size - (1 + ibuf->free_list_len);
411
 
 
412
 
        ibuf->empty = page_get_n_recs(root) == 0;
413
500
}
414
501
 
415
502
/******************************************************************//**
429
516
        page_t*         header_page;
430
517
        ulint           error;
431
518
 
432
 
        ibuf = mem_alloc(sizeof(ibuf_t));
 
519
        ibuf = static_cast<ibuf_t *>(mem_alloc(sizeof(ibuf_t)));
433
520
 
434
521
        memset(ibuf, 0, sizeof(*ibuf));
435
522
 
440
527
        ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE
441
528
                / IBUF_POOL_SIZE_PER_MAX_SIZE;
442
529
 
443
 
        mutex_create(&ibuf_pessimistic_insert_mutex,
 
530
        mutex_create(ibuf_pessimistic_insert_mutex_key,
 
531
                     &ibuf_pessimistic_insert_mutex,
444
532
                     SYNC_IBUF_PESS_INSERT_MUTEX);
445
533
 
446
 
        mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX);
 
534
        mutex_create(ibuf_mutex_key,
 
535
                     &ibuf_mutex, SYNC_IBUF_MUTEX);
447
536
 
448
 
        mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
 
537
        mutex_create(ibuf_bitmap_mutex_key,
 
538
                     &ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
449
539
 
450
540
        mtr_start(&mtr);
451
541
 
477
567
        ibuf_size_update(root, &mtr);
478
568
        mutex_exit(&ibuf_mutex);
479
569
 
 
570
        ibuf->empty = (page_get_n_recs(root) == 0);
480
571
        mtr_commit(&mtr);
481
572
 
482
573
        ibuf_exit();
488
579
 
489
580
        dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
490
581
 
491
 
        table->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
 
582
        table->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
492
583
 
493
584
        dict_table_add_to_cache(table, heap);
494
585
        mem_heap_free(heap);
499
590
 
500
591
        dict_mem_index_add_field(index, "DUMMY_COLUMN", 0);
501
592
 
502
 
        index->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID);
 
593
        index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
503
594
 
504
595
        error = dict_index_add_to_cache(table, index,
505
596
                                        FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE);
552
643
ibuf_parse_bitmap_init(
553
644
/*===================*/
554
645
        byte*           ptr,    /*!< in: buffer */
555
 
        byte*           end_ptr __attribute__((unused)), /*!< in: buffer end */
 
646
        byte*           /*end_ptr __attribute__((unused))*/, /*!< in: buffer end */
556
647
        buf_block_t*    block,  /*!< in: block or NULL */
557
648
        mtr_t*          mtr)    /*!< in: mtr or NULL */
558
649
{
578
669
                                0 for uncompressed pages */
579
670
        ulint           bit,    /*!< in: IBUF_BITMAP_FREE,
580
671
                                IBUF_BITMAP_BUFFERED, ... */
581
 
        mtr_t*          mtr __attribute__((unused)))
 
672
        mtr_t*          /*mtr __attribute__((unused))*/)
582
673
                                /*!< in: mtr containing an
583
674
                                x-latch to the bitmap page */
584
675
{
709
800
is x-latched */
710
801
static
711
802
page_t*
712
 
ibuf_bitmap_get_map_page(
713
 
/*=====================*/
714
 
        ulint   space,  /*!< in: space id of the file page */
715
 
        ulint   page_no,/*!< in: page number of the file page */
716
 
        ulint   zip_size,/*!< in: compressed page size in bytes;
717
 
                        0 for uncompressed pages */
718
 
        mtr_t*  mtr)    /*!< in: mtr */
 
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 */
719
812
{
720
813
        buf_block_t*    block;
721
814
 
722
 
        block = buf_page_get(space, zip_size,
723
 
                             ibuf_bitmap_page_no_calc(zip_size, page_no),
724
 
                             RW_X_LATCH, mtr);
 
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);
725
819
        buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
726
820
 
727
821
        return(buf_block_get_frame(block));
728
822
}
729
823
 
 
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
 
730
838
/************************************************************************//**
731
839
Sets the free bits of the page in the ibuf bitmap. This is done in a separate
732
840
mini-transaction, hence this operation does not restrict further work to only
1112
1220
        return(0);
1113
1221
}
1114
1222
 
 
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
 
1115
1407
/********************************************************************//**
1116
1408
Creates a dummy index for inserting a record to a non-clustered index.
1117
 
 
1118
1409
@return dummy index */
1119
1410
static
1120
1411
dict_index_t*
1225
1516
}
1226
1517
 
1227
1518
/*********************************************************************//**
1228
 
Builds the entry to insert into a non-clustered index when we have the
1229
 
corresponding record in an ibuf index.
 
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.
1230
1529
 
1231
1530
NOTE that as we copy pointers to fields in ibuf_rec, the caller must
1232
1531
hold a latch to the ibuf_rec page as long as the entry is used!
1247
1546
        const byte*     types;
1248
1547
        const byte*     data;
1249
1548
        ulint           len;
 
1549
        ulint           info_len;
1250
1550
        ulint           i;
 
1551
        ulint           comp;
1251
1552
        dict_index_t*   index;
1252
1553
 
1253
1554
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
1270
1571
 
1271
1572
        types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1272
1573
 
1273
 
        ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1);
1274
 
        index = ibuf_dummy_index_create(
1275
 
                n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1276
 
 
1277
 
        if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) {
1278
 
                /* compact record format */
1279
 
                len--;
1280
 
                ut_a(*types == 0);
1281
 
                types++;
1282
 
        }
 
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;
1283
1580
 
1284
1581
        ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1285
1582
 
1309
1606
        return(tuple);
1310
1607
}
1311
1608
 
 
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
 
1312
1661
/********************************************************************//**
1313
1662
Returns the space taken by a stored non-clustered index entry if converted to
1314
1663
an index record.
1320
1669
/*================*/
1321
1670
        const rec_t*    ibuf_rec)/*!< in: ibuf record */
1322
1671
{
1323
 
        dtype_t         dtype;
1324
 
        ibool           new_format      = FALSE;
1325
 
        ulint           data_size       = 0;
 
1672
        ulint           len;
 
1673
        const byte*     data;
 
1674
        const byte*     types;
1326
1675
        ulint           n_fields;
1327
 
        const byte*     types;
1328
 
        const byte*     data;
1329
 
        ulint           len;
1330
 
        ulint           i;
 
1676
        ulint           data_size;
 
1677
        ibool           pre_4_1;
1331
1678
        ulint           comp;
1332
1679
 
1333
1680
        ut_ad(ibuf_inside());
1334
1681
        ut_ad(rec_get_n_fields_old(ibuf_rec) > 2);
1335
1682
 
1336
1683
        data = rec_get_nth_field_old(ibuf_rec, 1, &len);
 
1684
        pre_4_1 = (len > 1);
1337
1685
 
1338
 
        if (len > 1) {
 
1686
        if (pre_4_1) {
1339
1687
                /* < 4.1.x format record */
1340
1688
 
1341
1689
                ut_a(trx_doublewrite_must_reset_space_ids);
1349
1697
                comp = 0;
1350
1698
        } else {
1351
1699
                /* >= 4.1.x format record */
 
1700
                ibuf_op_t       op;
 
1701
                ulint           info_len;
1352
1702
 
1353
1703
                ut_a(trx_sys_multiple_tablespace_format);
1354
1704
                ut_a(*data == 0);
1355
1705
 
1356
1706
                types = rec_get_nth_field_old(ibuf_rec, 3, &len);
1357
1707
 
1358
 
                comp = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1359
 
 
1360
 
                ut_a(comp <= 1);
1361
 
                if (comp) {
1362
 
                        /* compact record format */
 
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;
1363
1720
                        ulint           volume;
1364
1721
                        dict_index_t*   dummy_index;
1365
1722
                        mem_heap_t*     heap = mem_heap_create(500);
1366
 
                        dtuple_t*       entry = ibuf_build_entry_from_ibuf_rec(
 
1723
 
 
1724
                        entry = ibuf_build_entry_from_ibuf_rec(
1367
1725
                                ibuf_rec, heap, &dummy_index);
 
1726
 
1368
1727
                        volume = rec_get_converted_size(dummy_index, entry, 0);
 
1728
 
1369
1729
                        ibuf_dummy_index_free(dummy_index);
1370
1730
                        mem_heap_free(heap);
 
1731
 
1371
1732
                        return(volume + page_dir_calc_reserved_space(1));
1372
1733
                }
1373
1734
 
 
1735
                types += info_len;
1374
1736
                n_fields = rec_get_n_fields_old(ibuf_rec) - 4;
1375
 
 
1376
 
                new_format = TRUE;
1377
 
        }
1378
 
 
1379
 
        for (i = 0; i < n_fields; i++) {
1380
 
                if (new_format) {
1381
 
                        data = rec_get_nth_field_old(ibuf_rec, i + 4, &len);
1382
 
 
1383
 
                        dtype_new_read_for_order_and_null_size(
1384
 
                                &dtype, types + i
1385
 
                                * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
1386
 
                } else {
1387
 
                        data = rec_get_nth_field_old(ibuf_rec, i + 2, &len);
1388
 
 
1389
 
                        dtype_read_for_order_and_null_size(
1390
 
                                &dtype, types + i
1391
 
                                * DATA_ORDER_NULL_TYPE_BUF_SIZE);
1392
 
                }
1393
 
 
1394
 
                if (len == UNIV_SQL_NULL) {
1395
 
                        data_size += dtype_get_sql_null_size(&dtype, comp);
1396
 
                } else {
1397
 
                        data_size += len;
1398
 
                }
1399
 
        }
 
1737
        }
 
1738
 
 
1739
        data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp);
1400
1740
 
1401
1741
        return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0)
1402
1742
               + page_dir_calc_reserved_space(1));
1414
1754
dtuple_t*
1415
1755
ibuf_entry_build(
1416
1756
/*=============*/
 
1757
        ibuf_op_t       op,     /*!< in: operation type */
1417
1758
        dict_index_t*   index,  /*!< in: non-clustered index */
1418
1759
        const dtuple_t* entry,  /*!< in: entry for a non-clustered index */
1419
1760
        ulint           space,  /*!< in: space id */
1420
1761
        ulint           page_no,/*!< in: index page number where entry should
1421
1762
                                be inserted */
 
1763
        ulint           counter,/*!< in: counter value;
 
1764
                                ULINT_UNDEFINED=not used */
1422
1765
        mem_heap_t*     heap)   /*!< in: heap into which to build */
1423
1766
{
1424
1767
        dtuple_t*       tuple;
1426
1769
        const dfield_t* entry_field;
1427
1770
        ulint           n_fields;
1428
1771
        byte*           buf;
1429
 
        byte*           buf2;
 
1772
        byte*           ti;
 
1773
        byte*           type_info;
1430
1774
        ulint           i;
1431
1775
 
1432
 
        /* Starting from 4.1.x, we have to build a tuple whose
1433
 
        (1) first field is the space id,
1434
 
        (2) the second field a single marker byte (0) to tell that this
1435
 
        is a new format record,
1436
 
        (3) the third contains the page number, and
1437
 
        (4) the fourth contains the relevent type information of each data
1438
 
        field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is
1439
 
        (a) 0 for b-trees in the old format, and
1440
 
        (b) 1 for b-trees in the compact format, the first byte of the field
1441
 
        being the marker (0);
1442
 
        (5) and the rest of the fields are copied from entry. All fields
1443
 
        in the tuple are ordered like the type binary in our insert buffer
1444
 
        tree. */
 
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. */
1445
1788
 
1446
1789
        n_fields = dtuple_get_n_fields(entry);
1447
1790
 
1448
1791
        tuple = dtuple_create(heap, n_fields + 4);
1449
1792
 
1450
 
        /* Store the space id in tuple */
 
1793
        /* 1) Space Id */
1451
1794
 
1452
1795
        field = dtuple_get_nth_field(tuple, 0);
1453
1796
 
1454
 
        buf = mem_heap_alloc(heap, 4);
 
1797
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1455
1798
 
1456
1799
        mach_write_to_4(buf, space);
1457
1800
 
1458
1801
        dfield_set_data(field, buf, 4);
1459
1802
 
1460
 
        /* Store the marker byte field in tuple */
 
1803
        /* 2) Marker byte */
1461
1804
 
1462
1805
        field = dtuple_get_nth_field(tuple, 1);
1463
1806
 
1464
 
        buf = mem_heap_alloc(heap, 1);
 
1807
        buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
1465
1808
 
1466
1809
        /* We set the marker byte zero */
1467
1810
 
1469
1812
 
1470
1813
        dfield_set_data(field, buf, 1);
1471
1814
 
1472
 
        /* Store the page number in tuple */
 
1815
        /* 3) Page number */
1473
1816
 
1474
1817
        field = dtuple_get_nth_field(tuple, 2);
1475
1818
 
1476
 
        buf = mem_heap_alloc(heap, 4);
 
1819
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1477
1820
 
1478
1821
        mach_write_to_4(buf, page_no);
1479
1822
 
1480
1823
        dfield_set_data(field, buf, 4);
1481
1824
 
1482
 
        /* Store the type info in buf2, and add the fields from entry to
1483
 
        tuple */
1484
 
        buf2 = mem_heap_alloc(heap, n_fields
1485
 
                              * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1486
 
                              + dict_table_is_comp(index->table));
1487
 
        if (dict_table_is_comp(index->table)) {
1488
 
                *buf2++ = 0; /* write the compact format indicator */
1489
 
        }
 
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
 
1490
1861
        for (i = 0; i < n_fields; i++) {
1491
1862
                ulint                   fixed_len;
1492
1863
                const dict_field_t*     ifield;
1521
1892
#endif /* UNIV_DEBUG */
1522
1893
 
1523
1894
                dtype_new_store_for_order_and_null_size(
1524
 
                        buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
1525
 
                        dfield_get_type(entry_field), fixed_len);
 
1895
                        ti, dfield_get_type(entry_field), fixed_len);
 
1896
                ti += DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE;
1526
1897
        }
1527
1898
 
1528
 
        /* Store the type info in buf2 to field 3 of tuple */
 
1899
        /* 4) Type info, part #2 */
1529
1900
 
1530
1901
        field = dtuple_get_nth_field(tuple, 3);
1531
1902
 
1532
 
        if (dict_table_is_comp(index->table)) {
1533
 
                buf2--;
1534
 
        }
 
1903
        dfield_set_data(field, type_info, ti - type_info);
1535
1904
 
1536
 
        dfield_set_data(field, buf2, n_fields
1537
 
                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE
1538
 
                        + dict_table_is_comp(index->table));
1539
1905
        /* Set all the types in the new tuple binary */
1540
1906
 
1541
1907
        dtuple_set_types_binary(tuple, n_fields + 4);
1569
1935
 
1570
1936
        field = dtuple_get_nth_field(tuple, 0);
1571
1937
 
1572
 
        buf = mem_heap_alloc(heap, 4);
 
1938
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1573
1939
 
1574
1940
        mach_write_to_4(buf, page_no);
1575
1941
 
1604
1970
 
1605
1971
        field = dtuple_get_nth_field(tuple, 0);
1606
1972
 
1607
 
        buf = mem_heap_alloc(heap, 4);
 
1973
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1608
1974
 
1609
1975
        mach_write_to_4(buf, space);
1610
1976
 
1614
1980
 
1615
1981
        field = dtuple_get_nth_field(tuple, 1);
1616
1982
 
1617
 
        buf = mem_heap_alloc(heap, 1);
 
1983
        buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
1618
1984
 
1619
1985
        mach_write_to_1(buf, 0);
1620
1986
 
1624
1990
 
1625
1991
        field = dtuple_get_nth_field(tuple, 2);
1626
1992
 
1627
 
        buf = mem_heap_alloc(heap, 4);
 
1993
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1628
1994
 
1629
1995
        mach_write_to_4(buf, page_no);
1630
1996
 
1672
2038
/*********************************************************************//**
1673
2039
Allocates a new page from the ibuf file segment and adds it to the free
1674
2040
list.
1675
 
@return DB_SUCCESS, or DB_STRONG_FAIL if no space left */
 
2041
@return TRUE on success, FALSE if no space left */
1676
2042
static
1677
 
ulint
 
2043
ibool
1678
2044
ibuf_add_free_page(void)
1679
2045
/*====================*/
1680
2046
{
1710
2076
                header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
1711
2077
                &mtr);
1712
2078
 
1713
 
        if (page_no == FIL_NULL) {
 
2079
        if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
1714
2080
                mtr_commit(&mtr);
1715
2081
 
1716
 
                return(DB_STRONG_FAIL);
 
2082
                return(FALSE);
1717
2083
        }
1718
2084
 
1719
2085
        {
1751
2117
        bitmap_page = ibuf_bitmap_get_map_page(
1752
2118
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
1753
2119
 
 
2120
        mutex_exit(&ibuf_mutex);
 
2121
 
1754
2122
        ibuf_bitmap_page_set_bits(
1755
2123
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
1756
2124
 
1757
2125
        mtr_commit(&mtr);
1758
2126
 
1759
 
        mutex_exit(&ibuf_mutex);
1760
 
 
1761
2127
        ibuf_exit();
1762
2128
 
1763
 
        return(DB_SUCCESS);
 
2129
        return(TRUE);
1764
2130
}
1765
2131
 
1766
2132
/*********************************************************************//**
1790
2156
        header_page = ibuf_header_page_get(&mtr);
1791
2157
 
1792
2158
        /* Prevent pessimistic inserts to insert buffer trees for a while */
 
2159
        ibuf_enter();
1793
2160
        mutex_enter(&ibuf_pessimistic_insert_mutex);
1794
 
 
1795
 
        ibuf_enter();
1796
 
 
1797
2161
        mutex_enter(&ibuf_mutex);
1798
2162
 
1799
2163
        if (!ibuf_data_too_much_free()) {
1800
2164
 
1801
2165
                mutex_exit(&ibuf_mutex);
 
2166
                mutex_exit(&ibuf_pessimistic_insert_mutex);
1802
2167
 
1803
2168
                ibuf_exit();
1804
2169
 
1805
 
                mutex_exit(&ibuf_pessimistic_insert_mutex);
1806
 
 
1807
2170
                mtr_commit(&mtr);
1808
2171
 
1809
2172
                return;
1813
2176
 
1814
2177
        root = ibuf_tree_root_get(&mtr2);
1815
2178
 
 
2179
        mutex_exit(&ibuf_mutex);
 
2180
 
1816
2181
        page_no = flst_get_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1817
2182
                                &mtr2).page;
1818
2183
 
1821
2186
        is a level 2 page. */
1822
2187
 
1823
2188
        mtr_commit(&mtr2);
1824
 
        mutex_exit(&ibuf_mutex);
1825
2189
 
1826
2190
        ibuf_exit();
1827
2191
 
1864
2228
        flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
1865
2229
                    page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, &mtr);
1866
2230
 
 
2231
        mutex_exit(&ibuf_pessimistic_insert_mutex);
 
2232
 
1867
2233
        ibuf->seg_size--;
1868
2234
        ibuf->free_list_len--;
1869
2235
 
1870
 
        mutex_exit(&ibuf_pessimistic_insert_mutex);
1871
 
 
1872
2236
        /* Set the bit indicating that this page is no more an ibuf tree page
1873
2237
        (level 2 page) */
1874
2238
 
1875
2239
        bitmap_page = ibuf_bitmap_get_map_page(
1876
2240
                IBUF_SPACE_ID, page_no, zip_size, &mtr);
1877
2241
 
 
2242
        mutex_exit(&ibuf_mutex);
 
2243
 
1878
2244
        ibuf_bitmap_page_set_bits(
1879
2245
                bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr);
1880
2246
 
1883
2249
#endif
1884
2250
        mtr_commit(&mtr);
1885
2251
 
1886
 
        mutex_exit(&ibuf_mutex);
1887
 
 
1888
2252
        ibuf_exit();
1889
2253
}
1890
2254
 
1925
2289
 
1926
2290
        for (i = 0; i < 4; i++) {
1927
2291
 
 
2292
                ibool   too_much_free;
 
2293
 
1928
2294
                mutex_enter(&ibuf_mutex);
1929
 
 
1930
 
                if (!ibuf_data_too_much_free()) {
1931
 
 
1932
 
                        mutex_exit(&ibuf_mutex);
1933
 
 
 
2295
                too_much_free = ibuf_data_too_much_free();
 
2296
                mutex_exit(&ibuf_mutex);
 
2297
 
 
2298
                if (!too_much_free) {
1934
2299
                        return;
1935
2300
                }
1936
2301
 
1937
 
                mutex_exit(&ibuf_mutex);
1938
 
 
1939
2302
                ibuf_remove_free_page();
1940
2303
        }
1941
2304
}
1978
2341
 
1979
2342
        *n_stored = 0;
1980
2343
 
1981
 
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
 
2344
        limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4);
1982
2345
 
1983
2346
        if (page_rec_is_supremum(rec)) {
1984
2347
 
2131
2494
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
2132
2495
        ulint           space_ids[IBUF_MAX_N_PAGES_MERGED];
2133
2496
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
2134
 
        ulint           n_stored;
2135
2497
        ulint           sum_sizes;
2136
2498
        mtr_t           mtr;
2137
2499
 
2138
2500
        *n_pages = 0;
2139
2501
        ut_ad(!ibuf_inside());
2140
2502
 
2141
 
        mutex_enter(&ibuf_mutex);
 
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. */
2142
2507
 
2143
 
        if (ibuf->empty) {
 
2508
        if (UNIV_UNLIKELY(ibuf->empty)
 
2509
            && UNIV_LIKELY(!srv_shutdown_state)) {
2144
2510
ibuf_is_empty:
2145
 
                mutex_exit(&ibuf_mutex);
 
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
2146
2526
 
2147
2527
                return(0);
2148
2528
        }
2156
2536
 
2157
2537
        btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr);
2158
2538
 
 
2539
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
 
2540
 
2159
2541
        if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
2160
 
                /* When the ibuf tree is emptied completely, the last record
2161
 
                is removed using an optimistic delete and ibuf_size_update
2162
 
                is not called, causing ibuf->empty to remain FALSE. If we do
2163
 
                not reset it to TRUE here then database shutdown will hang
2164
 
                in the loop in ibuf_contract_for_n_pages. */
2165
 
 
2166
 
                ibuf->empty = TRUE;
 
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);
2167
2550
 
2168
2551
                ibuf_exit();
2169
2552
 
2173
2556
                goto ibuf_is_empty;
2174
2557
        }
2175
2558
 
2176
 
        mutex_exit(&ibuf_mutex);
2177
 
 
2178
2559
        sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
2179
2560
                                            space_ids, space_versions,
2180
 
                                            page_nos, &n_stored);
 
2561
                                            page_nos, n_pages);
2181
2562
#if 0 /* defined UNIV_IBUF_DEBUG */
2182
2563
        fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
2183
 
                sync, n_stored, sum_sizes);
 
2564
                sync, *n_pages, sum_sizes);
2184
2565
#endif
2185
2566
        ibuf_exit();
2186
2567
 
2188
2569
        btr_pcur_close(&pcur);
2189
2570
 
2190
2571
        buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos,
2191
 
                                  n_stored);
2192
 
        *n_pages = n_stored;
 
2572
                                  *n_pages);
2193
2573
 
2194
2574
        return(sum_sizes + 1);
2195
2575
}
2259
2639
        ibool   sync;
2260
2640
        ulint   sum_sizes;
2261
2641
        ulint   size;
2262
 
 
2263
 
        mutex_enter(&ibuf_mutex);
2264
 
 
2265
 
        if (ibuf->size < ibuf->max_size + IBUF_CONTRACT_ON_INSERT_NON_SYNC) {
2266
 
                mutex_exit(&ibuf_mutex);
2267
 
 
 
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) {
2268
2655
                return;
2269
2656
        }
2270
2657
 
2271
 
        sync = FALSE;
2272
 
 
2273
 
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_ON_INSERT_SYNC) {
2274
 
 
2275
 
                sync = TRUE;
2276
 
        }
2277
 
 
2278
 
        mutex_exit(&ibuf_mutex);
 
2658
        sync = (size >= max_size + IBUF_CONTRACT_ON_INSERT_SYNC);
2279
2659
 
2280
2660
        /* Contract at least entry_size many bytes */
2281
2661
        sum_sizes = 0;
2282
2662
        size = 1;
2283
2663
 
2284
 
        while ((size > 0) && (sum_sizes < entry_size)) {
 
2664
        do {
2285
2665
 
2286
2666
                size = ibuf_contract(sync);
2287
2667
                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));
2288
2821
        }
2289
2822
}
2290
2823
 
2305
2838
                                or BTR_MODIFY_TREE */
2306
2839
        ulint           space,  /*!< in: space id */
2307
2840
        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 */
2308
2844
        mtr_t*          mtr)    /*!< in: mtr */
2309
2845
{
2310
2846
        ulint   volume;
2314
2850
        page_t* prev_page;
2315
2851
        ulint   next_page_no;
2316
2852
        page_t* next_page;
 
2853
        ulint   hash_bitmap[128 / sizeof(ulint)]; /* bitmap of buffered recs */
2317
2854
 
2318
2855
        ut_a(trx_sys_multiple_tablespace_format);
2319
2856
 
2320
2857
        ut_ad((pcur->latch_mode == BTR_MODIFY_PREV)
2321
2858
              || (pcur->latch_mode == BTR_MODIFY_TREE));
2322
2859
 
2323
 
        /* Count the volume of records earlier in the alphabetical order than
 
2860
        /* Count the volume of inserts earlier in the alphabetical order than
2324
2861
        pcur */
2325
2862
 
2326
2863
        volume = 0;
2327
2864
 
 
2865
        if (n_recs) {
 
2866
                memset(hash_bitmap, 0, sizeof hash_bitmap);
 
2867
        }
 
2868
 
2328
2869
        rec = btr_pcur_get_rec(pcur);
2329
2870
        page = page_align(rec);
 
2871
        ut_ad(page_validate(page, ibuf->index));
2330
2872
 
2331
2873
        if (page_rec_is_supremum(rec)) {
2332
2874
                rec = page_rec_get_prev(rec);
2344
2886
                        goto count_later;
2345
2887
                }
2346
2888
 
2347
 
                volume += ibuf_rec_get_volume(rec);
 
2889
                volume += ibuf_get_volume_buffered_count(
 
2890
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2348
2891
 
2349
2892
                rec = page_rec_get_prev(rec);
 
2893
                ut_ad(page_align(rec) == page);
2350
2894
        }
2351
2895
 
2352
2896
        /* Look at the previous page */
2368
2912
 
2369
2913
 
2370
2914
                prev_page = buf_block_get_frame(block);
 
2915
                ut_ad(page_validate(prev_page, ibuf->index));
2371
2916
        }
2372
2917
 
2373
2918
#ifdef UNIV_BTR_DEBUG
2394
2939
                        goto count_later;
2395
2940
                }
2396
2941
 
2397
 
                volume += ibuf_rec_get_volume(rec);
 
2942
                volume += ibuf_get_volume_buffered_count(
 
2943
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2398
2944
 
2399
2945
                rec = page_rec_get_prev(rec);
 
2946
                ut_ad(page_align(rec) == prev_page);
2400
2947
        }
2401
2948
 
2402
2949
count_later:
2418
2965
                        return(volume);
2419
2966
                }
2420
2967
 
2421
 
                volume += ibuf_rec_get_volume(rec);
 
2968
                volume += ibuf_get_volume_buffered_count(
 
2969
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2422
2970
 
2423
2971
                rec = page_rec_get_next(rec);
2424
2972
        }
2442
2990
 
2443
2991
 
2444
2992
                next_page = buf_block_get_frame(block);
 
2993
                ut_ad(page_validate(next_page, ibuf->index));
2445
2994
        }
2446
2995
 
2447
2996
#ifdef UNIV_BTR_DEBUG
2465
3014
                        return(volume);
2466
3015
                }
2467
3016
 
2468
 
                volume += ibuf_rec_get_volume(rec);
 
3017
                volume += ibuf_get_volume_buffered_count(
 
3018
                        rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs);
2469
3019
 
2470
3020
                rec = page_rec_get_next(rec);
 
3021
                ut_ad(page_align(rec) == next_page);
2471
3022
        }
2472
3023
}
2473
3024
 
2495
3046
        btr_pcur_open_at_index_side(
2496
3047
                FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
2497
3048
 
 
3049
        ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
 
3050
 
2498
3051
        btr_pcur_move_to_prev(&pcur, &mtr);
2499
3052
 
2500
3053
        if (btr_pcur_is_before_first_on_page(&pcur)) {
2519
3072
        fil_set_max_space_id_if_bigger(max_space_id);
2520
3073
}
2521
3074
 
 
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
 
2522
3282
/*********************************************************************//**
2523
 
Makes an index insert to the insert buffer, instead of directly to the disk
2524
 
page, if this is possible.
2525
 
@return DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */
 
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 */
2526
3286
static
2527
3287
ulint
2528
3288
ibuf_insert_low(
2529
3289
/*============*/
2530
3290
        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 */
2531
3295
        const dtuple_t* entry,  /*!< in: index entry to insert */
2532
3296
        ulint           entry_size,
2533
3297
                                /*!< in: rec_get_converted_size(index, entry) */
2544
3308
        dtuple_t*       ibuf_entry;
2545
3309
        mem_heap_t*     heap;
2546
3310
        ulint           buffered;
 
3311
        lint            min_n_recs;
2547
3312
        rec_t*          ins_rec;
2548
3313
        ibool           old_bit_value;
2549
3314
        page_t*         bitmap_page;
 
3315
        buf_block_t*    block;
2550
3316
        page_t*         root;
2551
3317
        ulint           err;
2552
3318
        ibool           do_merge;
2554
3320
        ib_int64_t      space_versions[IBUF_MAX_N_PAGES_MERGED];
2555
3321
        ulint           page_nos[IBUF_MAX_N_PAGES_MERGED];
2556
3322
        ulint           n_stored;
2557
 
        ulint           bits;
2558
3323
        mtr_t           mtr;
2559
3324
        mtr_t           bitmap_mtr;
2560
3325
 
2561
3326
        ut_a(!dict_index_is_clust(index));
2562
3327
        ut_ad(dtuple_check_typed(entry));
2563
3328
        ut_ad(ut_is_2pow(zip_size));
 
3329
        ut_ad(!no_counter || op == IBUF_OP_INSERT);
 
3330
        ut_a(op < IBUF_OP_COUNT);
2564
3331
 
2565
3332
        ut_a(trx_sys_multiple_tablespace_format);
2566
3333
 
2567
3334
        do_merge = FALSE;
2568
3335
 
2569
 
        mutex_enter(&ibuf_mutex);
2570
 
 
 
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(). */
2571
3343
        if (ibuf->size >= ibuf->max_size + IBUF_CONTRACT_DO_NOT_INSERT) {
2572
3344
                /* Insert buffer is now too big, contract it but do not try
2573
3345
                to insert */
2574
3346
 
2575
 
                mutex_exit(&ibuf_mutex);
2576
3347
 
2577
3348
#ifdef UNIV_IBUF_DEBUG
2578
3349
                fputs("Ibuf too big\n", stderr);
2583
3354
                return(DB_STRONG_FAIL);
2584
3355
        }
2585
3356
 
2586
 
        mutex_exit(&ibuf_mutex);
2587
 
 
2588
 
        if (mode == BTR_MODIFY_TREE) {
2589
 
                mutex_enter(&ibuf_pessimistic_insert_mutex);
2590
 
 
2591
 
                ibuf_enter();
2592
 
 
2593
 
                mutex_enter(&ibuf_mutex);
2594
 
 
2595
 
                while (!ibuf_data_enough_free_for_insert()) {
2596
 
 
2597
 
                        mutex_exit(&ibuf_mutex);
2598
 
 
2599
 
                        ibuf_exit();
2600
 
 
2601
 
                        mutex_exit(&ibuf_pessimistic_insert_mutex);
2602
 
 
2603
 
                        err = ibuf_add_free_page();
2604
 
 
2605
 
                        if (err == DB_STRONG_FAIL) {
2606
 
 
2607
 
                                return(err);
2608
 
                        }
2609
 
 
2610
 
                        mutex_enter(&ibuf_pessimistic_insert_mutex);
2611
 
 
2612
 
                        ibuf_enter();
2613
 
 
2614
 
                        mutex_enter(&ibuf_mutex);
2615
 
                }
2616
 
        } else {
2617
 
                ibuf_enter();
2618
 
        }
2619
 
 
2620
3357
        heap = mem_heap_create(512);
2621
3358
 
2622
 
        /* Build the entry which contains the space id and the page number as
2623
 
        the first fields and the type information for other fields, and which
2624
 
        will be inserted to the insert buffer. */
 
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.) */
2625
3366
 
2626
 
        ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap);
 
3367
        ibuf_entry = ibuf_entry_build(
 
3368
                op, index, entry, space, page_no,
 
3369
                no_counter ? ULINT_UNDEFINED : 0xFFFF, heap);
2627
3370
 
2628
3371
        /* Open a cursor to the insert buffer tree to calculate if we can add
2629
3372
        the new entry to it without exceeding the free space limit for the
2630
3373
        page. */
2631
3374
 
 
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
 
2632
3400
        mtr_start(&mtr);
2633
3401
 
2634
3402
        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));
2635
3404
 
2636
3405
        /* Find out the volume of already buffered inserts for the same index
2637
3406
        page */
2638
 
        buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr);
 
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. */
2639
3451
 
2640
3452
#ifdef UNIV_IBUF_COUNT_DEBUG
2641
3453
        ut_a((buffered == 0) || ibuf_count_get(space, page_no));
2649
3461
 
2650
3462
        if (buf_page_peek(space, page_no)
2651
3463
            || lock_rec_expl_exist_on_page(space, page_no)) {
2652
 
                err = DB_STRONG_FAIL;
2653
 
 
2654
 
                mtr_commit(&bitmap_mtr);
2655
 
 
2656
 
                goto function_exit;
2657
 
        }
2658
 
 
2659
 
        bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size,
2660
 
                                         IBUF_BITMAP_FREE, &bitmap_mtr);
2661
 
 
2662
 
        if (buffered + entry_size + page_dir_calc_reserved_space(1)
2663
 
            > ibuf_index_page_calc_free_from_bits(zip_size, bits)) {
2664
 
                mtr_commit(&bitmap_mtr);
2665
 
 
2666
 
                /* It may not fit */
2667
 
                err = DB_STRONG_FAIL;
2668
 
 
2669
 
                do_merge = TRUE;
2670
 
 
2671
 
                ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur),
2672
 
                                        space_ids, space_versions,
2673
 
                                        page_nos, &n_stored);
2674
 
                goto function_exit;
 
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;
2675
3500
        }
2676
3501
 
2677
3502
        /* Set the bitmap bit denoting that the insert buffer contains
2695
3520
                err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor,
2696
3521
                                                ibuf_entry, &ins_rec,
2697
3522
                                                &dummy_big_rec, 0, thr, &mtr);
2698
 
                if (err == DB_SUCCESS) {
2699
 
                        /* Update the page max trx id field */
2700
 
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
2701
 
                                               thr_get_trx(thr)->id, &mtr);
 
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);
2702
3536
                }
2703
3537
        } else {
2704
3538
                ut_ad(mode == BTR_MODIFY_TREE);
2715
3549
                                                 cursor,
2716
3550
                                                 ibuf_entry, &ins_rec,
2717
3551
                                                 &dummy_big_rec, 0, thr, &mtr);
2718
 
                if (err == DB_SUCCESS) {
2719
 
                        /* Update the page max trx id field */
2720
 
                        page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
2721
 
                                               thr_get_trx(thr)->id, &mtr);
2722
 
                }
2723
 
 
 
3552
                mutex_exit(&ibuf_pessimistic_insert_mutex);
2724
3553
                ibuf_size_update(root, &mtr);
2725
 
        }
2726
 
 
2727
 
function_exit:
 
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:
2728
3568
#ifdef UNIV_IBUF_COUNT_DEBUG
2729
3569
        if (err == DB_SUCCESS) {
2730
3570
                fprintf(stderr,
2736
3576
                               ibuf_count_get(space, page_no) + 1);
2737
3577
        }
2738
3578
#endif
2739
 
        if (mode == BTR_MODIFY_TREE) {
2740
 
 
2741
 
                mutex_exit(&ibuf_mutex);
2742
 
                mutex_exit(&ibuf_pessimistic_insert_mutex);
2743
 
        }
2744
3579
 
2745
3580
        mtr_commit(&mtr);
2746
3581
        btr_pcur_close(&pcur);
2748
3583
 
2749
3584
        mem_heap_free(heap);
2750
3585
 
2751
 
        if (err == DB_SUCCESS) {
2752
 
                mutex_enter(&ibuf_mutex);
2753
 
 
2754
 
                ibuf->empty = FALSE;
2755
 
                ibuf->n_inserts++;
2756
 
 
2757
 
                mutex_exit(&ibuf_mutex);
2758
 
 
2759
 
                if (mode == BTR_MODIFY_TREE) {
2760
 
                        ibuf_contract_after_insert(entry_size);
2761
 
                }
 
3586
        if (err == DB_SUCCESS && mode == BTR_MODIFY_TREE) {
 
3587
                ibuf_contract_after_insert(entry_size);
2762
3588
        }
2763
3589
 
2764
3590
        if (do_merge) {
2773
3599
}
2774
3600
 
2775
3601
/*********************************************************************//**
2776
 
Makes an index insert to the insert buffer, instead of directly to the disk
2777
 
page, if this is possible. Does not do insert if the index is clustered
2778
 
or unique.
 
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.
2779
3605
@return TRUE if success */
2780
3606
UNIV_INTERN
2781
3607
ibool
2782
3608
ibuf_insert(
2783
3609
/*========*/
 
3610
        ibuf_op_t       op,     /*!< in: operation type */
2784
3611
        const dtuple_t* entry,  /*!< in: index entry to insert */
2785
3612
        dict_index_t*   index,  /*!< in: index where to insert */
2786
3613
        ulint           space,  /*!< in: space id where to insert */
2788
3615
        ulint           page_no,/*!< in: page number where to insert */
2789
3616
        que_thr_t*      thr)    /*!< in: query thread */
2790
3617
{
2791
 
        ulint   err;
2792
 
        ulint   entry_size;
 
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;
2793
3624
 
2794
3625
        ut_a(trx_sys_multiple_tablespace_format);
2795
3626
        ut_ad(dtuple_check_typed(entry));
2797
3628
 
2798
3629
        ut_a(!dict_index_is_clust(index));
2799
3630
 
2800
 
        switch (UNIV_EXPECT(ibuf_use, IBUF_USE_INSERT)) {
2801
 
        case IBUF_USE_NONE:
2802
 
                return(FALSE);
2803
 
        case IBUF_USE_INSERT:
2804
 
                goto do_insert;
2805
 
        case IBUF_USE_COUNT:
2806
 
                break;
2807
 
        }
2808
 
 
2809
 
        ut_error; /* unknown value of ibuf_use */
2810
 
 
2811
 
do_insert:
 
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:
2812
3719
        entry_size = rec_get_converted_size(index, entry, 0);
2813
3720
 
2814
3721
        if (entry_size
2815
 
            >= (page_get_free_space_of_empty(dict_table_is_comp(index->table))
2816
 
                / 2)) {
 
3722
            >= page_get_free_space_of_empty(dict_table_is_comp(index->table))
 
3723
            / 2) {
 
3724
 
2817
3725
                return(FALSE);
2818
3726
        }
2819
3727
 
2820
 
        err = ibuf_insert_low(BTR_MODIFY_PREV, entry, entry_size,
 
3728
        err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter,
 
3729
                              entry, entry_size,
2821
3730
                              index, space, zip_size, page_no, thr);
2822
3731
        if (err == DB_FAIL) {
2823
 
                err = ibuf_insert_low(BTR_MODIFY_TREE, entry, entry_size,
 
3732
                err = ibuf_insert_low(BTR_MODIFY_TREE, op, no_counter,
 
3733
                                      entry, entry_size,
2824
3734
                                      index, space, zip_size, page_no, thr);
2825
3735
        }
2826
3736
 
2843
3753
from the insert buffer. */
2844
3754
static
2845
3755
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
2846
3827
ibuf_insert_to_index_page(
2847
3828
/*======================*/
2848
 
        dtuple_t*       entry,  /*!< in: buffered entry to insert */
 
3829
        const dtuple_t* entry,  /*!< in: buffered entry to insert */
2849
3830
        buf_block_t*    block,  /*!< in/out: index page where the buffered entry
2850
3831
                                should be placed */
2851
3832
        dict_index_t*   index,  /*!< in: record descriptor */
2855
3836
        ulint           low_match;
2856
3837
        page_t*         page            = buf_block_get_frame(block);
2857
3838
        rec_t*          rec;
2858
 
        page_t*         bitmap_page;
2859
 
        ulint           old_bits;
2860
3839
 
2861
3840
        ut_ad(ibuf_inside());
2862
3841
        ut_ad(dtuple_check_typed(entry));
 
3842
        ut_ad(!buf_block_align(page)->is_hashed);
2863
3843
 
2864
3844
        if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
2865
3845
                          != (ibool)!!page_is_comp(page))) {
2872
3852
 
2873
3853
        rec = page_rec_get_next(page_get_infimum_rec(page));
2874
3854
 
 
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
 
2875
3863
        if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
2876
3864
                          != dtuple_get_n_fields(entry))) {
2877
3865
                fputs("InnoDB: Trying to insert a record from"
2897
3885
        low_match = page_cur_search(block, index, entry,
2898
3886
                                    PAGE_CUR_LE, &page_cur);
2899
3887
 
2900
 
        if (low_match == dtuple_get_n_fields(entry)) {
 
3888
        if (UNIV_UNLIKELY(low_match == dtuple_get_n_fields(entry))) {
 
3889
                mem_heap_t*     heap;
 
3890
                upd_t*          update;
 
3891
                ulint*          offsets;
2901
3892
                page_zip_des_t* page_zip;
2902
3893
 
2903
3894
                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
 
2904
3907
                page_zip = buf_block_get_page_zip(block);
2905
3908
 
2906
 
                btr_cur_del_unmark_for_ibuf(rec, page_zip, mtr);
2907
 
        } else {
2908
 
                rec = page_cur_tuple_insert(&page_cur, entry, index, 0, mtr);
2909
 
 
2910
 
                if (UNIV_LIKELY(rec != NULL)) {
 
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);
2911
3917
                        return;
2912
3918
                }
2913
3919
 
2914
 
                /* If the record did not fit, reorganize */
2915
 
 
2916
 
                btr_page_reorganize(block, index, mtr);
2917
 
                page_cur_search(block, index, entry, PAGE_CUR_LE, &page_cur);
2918
 
 
2919
 
                /* This time the record must fit */
2920
 
                if (UNIV_UNLIKELY
2921
 
                    (!page_cur_tuple_insert(&page_cur, entry, index,
2922
 
                                            0, mtr))) {
2923
 
                        ulint   space;
2924
 
                        ulint   page_no;
2925
 
                        ulint   zip_size;
2926
 
 
2927
 
                        ut_print_timestamp(stderr);
2928
 
 
2929
 
                        fprintf(stderr,
2930
 
                                "  InnoDB: Error: Insert buffer insert"
2931
 
                                " fails; page free %lu,"
2932
 
                                " dtuple size %lu\n",
2933
 
                                (ulong) page_get_max_insert_size(
2934
 
                                        page, 1),
2935
 
                                (ulong) rec_get_converted_size(
2936
 
                                        index, entry, 0));
2937
 
                        fputs("InnoDB: Cannot insert index record ",
2938
 
                              stderr);
2939
 
                        dtuple_print(stderr, entry);
2940
 
                        fputs("\nInnoDB: The table where"
2941
 
                              " this index record belongs\n"
2942
 
                              "InnoDB: is now probably corrupt."
2943
 
                              " Please run CHECK TABLE on\n"
2944
 
                              "InnoDB: that table.\n", stderr);
2945
 
 
2946
 
                        space = page_get_space_id(page);
2947
 
                        zip_size = buf_block_get_zip_size(block);
2948
 
                        page_no = page_get_page_no(page);
2949
 
 
2950
 
                        bitmap_page = ibuf_bitmap_get_map_page(
2951
 
                                space, page_no, zip_size, mtr);
2952
 
                        old_bits = ibuf_bitmap_page_get_bits(
2953
 
                                bitmap_page, page_no, zip_size,
2954
 
                                IBUF_BITMAP_FREE, mtr);
2955
 
 
2956
 
                        fprintf(stderr,
2957
 
                                "InnoDB: space %lu, page %lu,"
2958
 
                                " zip_size %lu, bitmap bits %lu\n",
2959
 
                                (ulong) space, (ulong) page_no,
2960
 
                                (ulong) zip_size, (ulong) old_bits);
2961
 
 
2962
 
                        fputs("InnoDB: Submit a detailed bug report"
2963
 
                              " to http://bugs.mysql.com\n", stderr);
2964
 
                }
2965
 
        }
 
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);
2966
4162
}
2967
4163
 
2968
4164
/*********************************************************************//**
2995
4191
        success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
2996
4192
 
2997
4193
        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
 
2998
4210
#ifdef UNIV_IBUF_COUNT_DEBUG
2999
4211
                fprintf(stderr,
3000
4212
                        "Decrementing ibuf count of space %lu page %lu\n"
3019
4231
 
3020
4232
        mtr_start(mtr);
3021
4233
 
3022
 
        success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
3023
 
 
3024
 
        if (!success) {
3025
 
                if (fil_space_get_flags(space) == ULINT_UNDEFINED) {
3026
 
                        /* The tablespace has been dropped.  It is possible
3027
 
                        that another thread has deleted the insert buffer
3028
 
                        entry.  Do not complain. */
3029
 
                        goto commit_and_exit;
3030
 
                }
3031
 
 
3032
 
                fprintf(stderr,
3033
 
                        "InnoDB: ERROR: Submit the output to"
3034
 
                        " http://bugs.mysql.com\n"
3035
 
                        "InnoDB: ibuf cursor restoration fails!\n"
3036
 
                        "InnoDB: ibuf record inserted to page %lu\n",
3037
 
                        (ulong) page_no);
3038
 
                fflush(stderr);
3039
 
 
3040
 
                rec_print_old(stderr, btr_pcur_get_rec(pcur));
3041
 
                rec_print_old(stderr, pcur->old_rec);
3042
 
                dtuple_print(stderr, search_tuple);
3043
 
 
3044
 
                rec_print_old(stderr,
3045
 
                              page_rec_get_next(btr_pcur_get_rec(pcur)));
3046
 
                fflush(stderr);
3047
 
 
3048
 
                btr_pcur_commit_specify_mtr(pcur, mtr);
3049
 
 
3050
 
                fputs("InnoDB: Validating insert buffer tree:\n", stderr);
3051
 
                if (!btr_validate_index(ibuf->index, NULL)) {
3052
 
                        ut_error;
3053
 
                }
3054
 
 
3055
 
                fprintf(stderr, "InnoDB: ibuf tree ok\n");
3056
 
                fflush(stderr);
3057
 
 
 
4234
        if (!ibuf_restore_pos(space, page_no, search_tuple,
 
4235
                              BTR_MODIFY_TREE, pcur, mtr)) {
 
4236
 
 
4237
                mutex_exit(&ibuf_mutex);
3058
4238
                goto func_exit;
3059
4239
        }
3060
4240
 
3068
4248
        ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1);
3069
4249
#endif
3070
4250
        ibuf_size_update(root, mtr);
 
4251
        mutex_exit(&ibuf_mutex);
3071
4252
 
3072
 
commit_and_exit:
 
4253
        ibuf->empty = (page_get_n_recs(root) == 0);
3073
4254
        btr_pcur_commit_specify_mtr(pcur, mtr);
3074
4255
 
3075
4256
func_exit:
3076
4257
        btr_pcur_close(pcur);
3077
4258
 
3078
 
        mutex_exit(&ibuf_mutex);
3079
 
 
3080
4259
        return(TRUE);
3081
4260
}
3082
4261
 
3083
4262
/*********************************************************************//**
3084
4263
When an index page is read from a disk to the buffer pool, this function
3085
 
inserts to the page the possible index entries buffered in the insert buffer.
3086
 
The entries are deleted from the insert buffer. If the page is not read, but
3087
 
created in the buffer pool, this function deletes its buffered entries from
3088
 
the insert buffer; there can exist entries for such a page if the page
3089
 
belonged to an index which subsequently was dropped. */
 
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. */
3090
4269
UNIV_INTERN
3091
4270
void
3092
4271
ibuf_merge_or_delete_for_page(
3107
4286
        mem_heap_t*     heap;
3108
4287
        btr_pcur_t      pcur;
3109
4288
        dtuple_t*       search_tuple;
3110
 
        ulint           n_inserts;
3111
4289
#ifdef UNIV_IBUF_DEBUG
3112
 
        ulint           volume;
 
4290
        ulint           volume                  = 0;
3113
4291
#endif
3114
4292
        page_zip_des_t* page_zip                = NULL;
3115
4293
        ibool           tablespace_being_deleted = FALSE;
3116
4294
        ibool           corruption_noticed      = FALSE;
3117
4295
        mtr_t           mtr;
3118
4296
 
 
4297
        /* Counts for merged & discarded operations. */
 
4298
        ulint           mops[IBUF_OP_COUNT];
 
4299
        ulint           dops[IBUF_OP_COUNT];
 
4300
 
3119
4301
        ut_ad(!block || buf_block_get_space(block) == space);
3120
4302
        ut_ad(!block || buf_block_get_page_no(block) == page_no);
3121
4303
        ut_ad(!block || buf_block_get_zip_size(block) == zip_size);
3258
4440
                }
3259
4441
        }
3260
4442
 
3261
 
        n_inserts = 0;
3262
 
#ifdef UNIV_IBUF_DEBUG
3263
 
        volume = 0;
3264
 
#endif
 
4443
        memset(mops, 0, sizeof(mops));
 
4444
        memset(dops, 0, sizeof(dops));
 
4445
 
3265
4446
loop:
3266
4447
        mtr_start(&mtr);
3267
4448
 
3314
4495
                        fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
3315
4496
                } else if (block) {
3316
4497
                        /* Now we have at pcur a record which should be
3317
 
                        inserted to the index page; NOTE that the call below
 
4498
                        applied on the index page; NOTE that the call below
3318
4499
                        copies pointers to fields in rec, and we must
3319
4500
                        keep the latch to the rec page until the
3320
4501
                        insertion is finished! */
3321
4502
                        dtuple_t*       entry;
3322
4503
                        trx_id_t        max_trx_id;
3323
4504
                        dict_index_t*   dummy_index;
 
4505
                        ibuf_op_t       op = ibuf_rec_get_op_type(rec);
3324
4506
 
3325
4507
                        max_trx_id = page_get_max_trx_id(page_align(rec));
3326
4508
                        page_update_max_trx_id(block, page_zip, max_trx_id,
3327
4509
                                               &mtr);
3328
4510
 
 
4511
                        ut_ad(page_validate(page_align(rec), ibuf->index));
 
4512
 
3329
4513
                        entry = ibuf_build_entry_from_ibuf_rec(
3330
4514
                                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:
3331
4521
#ifdef UNIV_IBUF_DEBUG
3332
 
                        volume += rec_get_converted_size(dummy_index, entry, 0)
3333
 
                                + page_dir_calc_reserved_space(1);
3334
 
                        ut_a(volume <= 4 * UNIV_PAGE_SIZE
3335
 
                             / IBUF_PAGE_SIZE_PER_FREE_SPACE);
 
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);
3336
4529
#endif
3337
 
                        ibuf_insert_to_index_page(entry, block,
3338
 
                                                  dummy_index, &mtr);
 
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
 
3339
4581
                        ibuf_dummy_index_free(dummy_index);
 
4582
                } else {
 
4583
                        dops[ibuf_rec_get_op_type(rec)]++;
3340
4584
                }
3341
4585
 
3342
 
                n_inserts++;
3343
 
 
3344
4586
                /* Delete the record from ibuf */
3345
4587
                if (ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3346
4588
                                    &mtr)) {
3357
4599
        }
3358
4600
 
3359
4601
reset_bit:
3360
 
#ifdef UNIV_IBUF_COUNT_DEBUG
3361
 
        if (ibuf_count_get(space, page_no) > 0) {
3362
 
                /* btr_print_tree(ibuf_data->index->tree, 100);
3363
 
                ibuf_print(); */
3364
 
        }
3365
 
#endif
3366
4602
        if (UNIV_LIKELY(update_ibuf_bitmap)) {
3367
4603
                page_t* bitmap_page;
3368
4604
 
3393
4629
        btr_pcur_close(&pcur);
3394
4630
        mem_heap_free(heap);
3395
4631
 
 
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 */
3396
4637
        /* Protect our statistics keeping from race conditions */
3397
4638
        mutex_enter(&ibuf_mutex);
3398
4639
 
3399
4640
        ibuf->n_merges++;
3400
 
        ibuf->n_merged_recs += n_inserts;
 
4641
        ibuf_add_ops(ibuf->n_merged_ops, mops);
 
4642
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
3401
4643
 
3402
4644
        mutex_exit(&ibuf_mutex);
 
4645
#endif /* HAVE_ATOMIC_BUILTINS */
3403
4646
 
3404
4647
        if (update_ibuf_bitmap && !tablespace_being_deleted) {
3405
4648
 
3430
4673
        rec_t*          ibuf_rec;
3431
4674
        ulint           page_no;
3432
4675
        ibool           closed;
3433
 
        ulint           n_inserts;
3434
4676
        mtr_t           mtr;
3435
4677
 
 
4678
        /* Counts for discarded operations. */
 
4679
        ulint           dops[IBUF_OP_COUNT];
 
4680
 
3436
4681
        heap = mem_heap_create(512);
3437
4682
 
3438
4683
        /* Use page number 0 to build the search tuple so that we get the
3440
4685
 
3441
4686
        search_tuple = ibuf_new_search_tuple_build(space, 0, heap);
3442
4687
 
3443
 
        n_inserts = 0;
 
4688
        memset(dops, 0, sizeof(dops));
3444
4689
loop:
3445
4690
        ibuf_enter();
3446
4691
 
3471
4716
 
3472
4717
                page_no = ibuf_rec_get_page_no(ibuf_rec);
3473
4718
 
3474
 
                n_inserts++;
 
4719
                dops[ibuf_rec_get_op_type(ibuf_rec)]++;
3475
4720
 
3476
4721
                /* Delete the record from ibuf */
3477
4722
                closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
3499
4744
        mtr_commit(&mtr);
3500
4745
        btr_pcur_close(&pcur);
3501
4746
 
 
4747
#ifdef HAVE_ATOMIC_BUILTINS
 
4748
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
 
4749
#else /* HAVE_ATOMIC_BUILTINS */
3502
4750
        /* Protect our statistics keeping from race conditions */
3503
4751
        mutex_enter(&ibuf_mutex);
3504
 
 
3505
 
        ibuf->n_merges++;
3506
 
        ibuf->n_merged_recs += n_inserts;
3507
 
 
 
4752
        ibuf_add_ops(ibuf->n_discarded_ops, dops);
3508
4753
        mutex_exit(&ibuf_mutex);
 
4754
#endif /* HAVE_ATOMIC_BUILTINS */
3509
4755
 
3510
4756
        ibuf_exit();
3511
4757
 
3525
4771
        mtr_t           mtr;
3526
4772
 
3527
4773
        ibuf_enter();
 
4774
        mtr_start(&mtr);
3528
4775
 
3529
4776
        mutex_enter(&ibuf_mutex);
3530
 
 
3531
 
        mtr_start(&mtr);
3532
 
 
3533
4777
        root = ibuf_tree_root_get(&mtr);
3534
 
 
3535
 
        if (page_get_n_recs(root) == 0) {
3536
 
 
3537
 
                is_empty = TRUE;
3538
 
 
3539
 
                if (ibuf->empty == FALSE) {
3540
 
                        fprintf(stderr,
3541
 
                                "InnoDB: Warning: insert buffer tree is empty"
3542
 
                                " but the data struct does not\n"
3543
 
                                "InnoDB: know it. This condition is legal"
3544
 
                                " if the master thread has not yet\n"
3545
 
                                "InnoDB: run to completion.\n");
3546
 
                }
3547
 
        } else {
3548
 
                ut_a(ibuf->empty == FALSE);
3549
 
 
3550
 
                is_empty = FALSE;
3551
 
        }
3552
 
 
 
4778
        mutex_exit(&ibuf_mutex);
 
4779
 
 
4780
        is_empty = (page_get_n_recs(root) == 0);
3553
4781
        mtr_commit(&mtr);
3554
 
 
3555
 
        mutex_exit(&ibuf_mutex);
3556
 
 
3557
4782
        ibuf_exit();
3558
4783
 
 
4784
        ut_a(is_empty == ibuf->empty);
 
4785
 
3559
4786
        return(is_empty);
3560
4787
}
3561
4788
 
3575
4802
        mutex_enter(&ibuf_mutex);
3576
4803
 
3577
4804
        fprintf(file,
3578
 
                "Ibuf: size %lu, free list len %lu, seg size %lu,\n"
3579
 
                "%lu inserts, %lu merged recs, %lu merges\n",
 
4805
                "Ibuf: size %lu, free list len %lu,"
 
4806
                " seg size %lu, %lu merges\n",
3580
4807
                (ulong) ibuf->size,
3581
4808
                (ulong) ibuf->free_list_len,
3582
4809
                (ulong) ibuf->seg_size,
3583
 
                (ulong) ibuf->n_inserts,
3584
 
                (ulong) ibuf->n_merged_recs,
3585
4810
                (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
 
3586
4818
#ifdef UNIV_IBUF_COUNT_DEBUG
3587
4819
        for (i = 0; i < IBUF_COUNT_N_SPACES; i++) {
3588
4820
                for (j = 0; j < IBUF_COUNT_N_PAGES; j++) {