~thomir-deactivatedaccount/drizzle/drizzle-fix-bug653747

« back to all changes in this revision

Viewing changes to plugin/innobase/row/row0merge.c

  • Committer: Brian Aker
  • Date: 2010-10-10 02:07:52 UTC
  • mfrom: (1827.2.3 staging)
  • Revision ID: brian@tangent.org-20101010020752-ktv73isay5dxtvp3
Merge in switch on table_share_instance inheritance.

Show diffs side-by-side

added added

removed removed

Lines of Context:
61
61
#ifdef UNIV_DEBUG
62
62
/** Set these in order ot enable debug printout. */
63
63
/* @{ */
64
 
/** Log the outcome of each row_merge_cmp() call, comparing records. */
65
64
static ibool    row_merge_print_cmp;
66
 
/** Log each record read from temporary file. */
67
65
static ibool    row_merge_print_read;
68
 
/** Log each record write to temporary file. */
69
66
static ibool    row_merge_print_write;
70
 
/** Log each row_merge_blocks() call, merging two blocks of records to
71
 
a bigger one. */
72
 
static ibool    row_merge_print_block;
73
 
/** Log each block read from temporary file. */
74
 
static ibool    row_merge_print_block_read;
75
 
/** Log each block read from temporary file. */
76
 
static ibool    row_merge_print_block_write;
77
67
/* @} */
78
68
#endif /* UNIV_DEBUG */
79
69
 
120
110
 
121
111
/** Information about temporary files used in merge sort */
122
112
struct merge_file_struct {
123
 
        int             fd;             /*!< file descriptor */
124
 
        ulint           offset;         /*!< file offset (end of file) */
125
 
        ib_uint64_t     n_rec;          /*!< number of records in the file */
 
113
        int     fd;             /*!< file descriptor */
 
114
        ulint   offset;         /*!< file offset */
126
115
};
127
116
 
128
117
/** Information about temporary files used in merge sort */
694
683
        ib_uint64_t     ofs = ((ib_uint64_t) offset) * sizeof *buf;
695
684
        ibool           success;
696
685
 
697
 
#ifdef UNIV_DEBUG
698
 
        if (row_merge_print_block_read) {
699
 
                fprintf(stderr, "row_merge_read fd=%d ofs=%lu\n",
700
 
                        fd, (ulong) offset);
701
 
        }
702
 
#endif /* UNIV_DEBUG */
703
 
 
704
686
        success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf,
705
687
                                                 (ulint) (ofs & 0xFFFFFFFF),
706
688
                                                 (ulint) (ofs >> 32),
728
710
        ib_uint64_t     ofs = ((ib_uint64_t) offset)
729
711
                * sizeof(row_merge_block_t);
730
712
 
731
 
#ifdef UNIV_DEBUG
732
 
        if (row_merge_print_block_write) {
733
 
                fprintf(stderr, "row_merge_write fd=%d ofs=%lu\n",
734
 
                        fd, (ulong) offset);
735
 
        }
736
 
#endif /* UNIV_DEBUG */
737
 
 
738
713
        return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf,
739
714
                                         (ulint) (ofs & 0xFFFFFFFF),
740
715
                                         (ulint) (ofs >> 32),
744
719
/********************************************************************//**
745
720
Read a merge record.
746
721
@return pointer to next record, or NULL on I/O error or end of list */
747
 
static __attribute__((nonnull))
 
722
static
748
723
const byte*
749
724
row_merge_read_rec(
750
725
/*===============*/
1096
1071
Reads clustered index of the table and create temporary files
1097
1072
containing the index entries for the indexes to be built.
1098
1073
@return DB_SUCCESS or error */
1099
 
static __attribute__((nonnull))
 
1074
static
1100
1075
ulint
1101
1076
row_merge_read_clustered_index(
1102
1077
/*===========================*/
1201
1176
                in order to release the latch on the old page. */
1202
1177
 
1203
1178
                if (btr_pcur_is_after_last_on_page(&pcur)) {
1204
 
                        if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1205
 
                                err = DB_INTERRUPTED;
1206
 
                                trx->error_key_num = 0;
1207
 
                                goto func_exit;
1208
 
                        }
1209
 
 
1210
1179
                        btr_pcur_store_position(&pcur, &mtr);
1211
1180
                        mtr_commit(&mtr);
1212
1181
                        mtr_start(&mtr);
1246
1215
 
1247
1216
                                        if (dfield_is_null(field)) {
1248
1217
                                                err = DB_PRIMARY_KEY_IS_NULL;
1249
 
                                                trx->error_key_num = 0;
 
1218
                                                i = 0;
 
1219
                                                trx->error_key_num = i;
1250
1220
                                                goto func_exit;
1251
1221
                                        }
1252
1222
 
1265
1235
 
1266
1236
                        if (UNIV_LIKELY
1267
1237
                            (row && row_merge_buf_add(buf, row, ext))) {
1268
 
                                file->n_rec++;
1269
1238
                                continue;
1270
1239
                        }
1271
1240
 
1287
1256
 
1288
1257
                                        if (dup.n_dup) {
1289
1258
                                                err = DB_DUPLICATE_KEY;
 
1259
err_exit:
1290
1260
                                                trx->error_key_num = i;
1291
1261
                                                goto func_exit;
1292
1262
                                        }
1300
1270
                        if (!row_merge_write(file->fd, file->offset++,
1301
1271
                                             block)) {
1302
1272
                                err = DB_OUT_OF_FILE_SPACE;
1303
 
                                trx->error_key_num = i;
1304
 
                                goto func_exit;
 
1273
                                goto err_exit;
1305
1274
                        }
1306
1275
 
1307
1276
                        UNIV_MEM_INVALID(block[0], sizeof block[0]);
1308
1277
                        merge_buf[i] = row_merge_buf_empty(buf);
1309
1278
 
1310
 
                        if (UNIV_LIKELY(row != NULL)) {
1311
 
                                /* Try writing the record again, now
1312
 
                                that the buffer has been written out
1313
 
                                and emptied. */
1314
 
 
1315
 
                                if (UNIV_UNLIKELY
1316
 
                                    (!row_merge_buf_add(buf, row, ext))) {
1317
 
                                        /* An empty buffer should have enough
1318
 
                                        room for at least one record. */
1319
 
                                        ut_error;
1320
 
                                }
1321
 
 
1322
 
                                file->n_rec++;
 
1279
                        /* Try writing the record again, now that
 
1280
                        the buffer has been written out and emptied. */
 
1281
 
 
1282
                        if (UNIV_UNLIKELY
 
1283
                            (row && !row_merge_buf_add(buf, row, ext))) {
 
1284
                                /* An empty buffer should have enough
 
1285
                                room for at least one record. */
 
1286
                                ut_error;
1323
1287
                        }
1324
1288
                }
1325
1289
 
1358
1322
                b2 = row_merge_write_rec(&block[2], &buf[2], b2,        \
1359
1323
                                         of->fd, &of->offset,           \
1360
1324
                                         mrec##N, offsets##N);          \
1361
 
                if (UNIV_UNLIKELY(!b2 || ++of->n_rec > file->n_rec)) {  \
 
1325
                if (UNIV_UNLIKELY(!b2)) {                               \
1362
1326
                        goto corrupt;                                   \
1363
1327
                }                                                       \
1364
1328
                b##N = row_merge_read_rec(&block[N], &buf[N],           \
1374
1338
        } while (0)
1375
1339
 
1376
1340
/*************************************************************//**
1377
 
Merge two blocks of records on disk and write a bigger block.
 
1341
Merge two blocks of linked lists on disk and write a bigger block.
1378
1342
@return DB_SUCCESS or error code */
1379
1343
static
1380
1344
ulint
1381
1345
row_merge_blocks(
1382
1346
/*=============*/
1383
1347
        const dict_index_t*     index,  /*!< in: index being created */
1384
 
        const merge_file_t*     file,   /*!< in: file containing
 
1348
        merge_file_t*           file,   /*!< in/out: file containing
1385
1349
                                        index entries */
1386
1350
        row_merge_block_t*      block,  /*!< in/out: 3 buffers */
1387
1351
        ulint*                  foffs0, /*!< in/out: offset of first
1404
1368
        ulint*          offsets0;/* offsets of mrec0 */
1405
1369
        ulint*          offsets1;/* offsets of mrec1 */
1406
1370
 
1407
 
#ifdef UNIV_DEBUG
1408
 
        if (row_merge_print_block) {
1409
 
                fprintf(stderr,
1410
 
                        "row_merge_blocks fd=%d ofs=%lu + fd=%d ofs=%lu"
1411
 
                        " = fd=%d ofs=%lu\n",
1412
 
                        file->fd, (ulong) *foffs0,
1413
 
                        file->fd, (ulong) *foffs1,
1414
 
                        of->fd, (ulong) of->offset);
1415
 
        }
1416
 
#endif /* UNIV_DEBUG */
1417
 
 
1418
1371
        heap = row_merge_heap_create(index, &offsets0, &offsets1);
1419
1372
 
1420
1373
        /* Write a record and read the next record.  Split the output
1487
1440
}
1488
1441
 
1489
1442
/*************************************************************//**
1490
 
Copy a block of index entries.
1491
 
@return TRUE on success, FALSE on failure */
1492
 
static __attribute__((nonnull))
1493
 
ibool
1494
 
row_merge_blocks_copy(
1495
 
/*==================*/
1496
 
        const dict_index_t*     index,  /*!< in: index being created */
1497
 
        const merge_file_t*     file,   /*!< in: input file */
1498
 
        row_merge_block_t*      block,  /*!< in/out: 3 buffers */
1499
 
        ulint*                  foffs0, /*!< in/out: input file offset */
1500
 
        merge_file_t*           of)     /*!< in/out: output file */
1501
 
{
1502
 
        mem_heap_t*     heap;   /*!< memory heap for offsets0, offsets1 */
1503
 
 
1504
 
        mrec_buf_t      buf[3]; /*!< buffer for handling
1505
 
                                split mrec in block[] */
1506
 
        const byte*     b0;     /*!< pointer to block[0] */
1507
 
        byte*           b2;     /*!< pointer to block[2] */
1508
 
        const mrec_t*   mrec0;  /*!< merge rec, points to block[0] */
1509
 
        ulint*          offsets0;/* offsets of mrec0 */
1510
 
        ulint*          offsets1;/* dummy offsets */
1511
 
 
1512
 
#ifdef UNIV_DEBUG
1513
 
        if (row_merge_print_block) {
1514
 
                fprintf(stderr,
1515
 
                        "row_merge_blocks_copy fd=%d ofs=%lu"
1516
 
                        " = fd=%d ofs=%lu\n",
1517
 
                        file->fd, (ulong) foffs0,
1518
 
                        of->fd, (ulong) of->offset);
1519
 
        }
1520
 
#endif /* UNIV_DEBUG */
1521
 
 
1522
 
        heap = row_merge_heap_create(index, &offsets0, &offsets1);
1523
 
 
1524
 
        /* Write a record and read the next record.  Split the output
1525
 
        file in two halves, which can be merged on the following pass. */
1526
 
 
1527
 
        if (!row_merge_read(file->fd, *foffs0, &block[0])) {
1528
 
corrupt:
1529
 
                mem_heap_free(heap);
1530
 
                return(FALSE);
1531
 
        }
1532
 
 
1533
 
        b0 = block[0];
1534
 
        b2 = block[2];
1535
 
 
1536
 
        b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd,
1537
 
                                foffs0, &mrec0, offsets0);
1538
 
        if (UNIV_UNLIKELY(!b0 && mrec0)) {
1539
 
 
1540
 
                goto corrupt;
1541
 
        }
1542
 
 
1543
 
        if (mrec0) {
1544
 
                /* append all mrec0 to output */
1545
 
                for (;;) {
1546
 
                        ROW_MERGE_WRITE_GET_NEXT(0, goto done0);
1547
 
                }
1548
 
        }
1549
 
done0:
1550
 
 
1551
 
        /* The file offset points to the beginning of the last page
1552
 
        that has been read.  Update it to point to the next block. */
1553
 
        (*foffs0)++;
1554
 
 
1555
 
        mem_heap_free(heap);
1556
 
        return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset)
1557
 
               != NULL);
1558
 
}
1559
 
 
1560
 
/*************************************************************//**
1561
1443
Merge disk files.
1562
1444
@return DB_SUCCESS or error code */
1563
 
static __attribute__((nonnull))
 
1445
static
1564
1446
ulint
1565
1447
row_merge(
1566
1448
/*======*/
1567
 
        trx_t*                  trx,    /*!< in: transaction */
1568
1449
        const dict_index_t*     index,  /*!< in: index being created */
1569
1450
        merge_file_t*           file,   /*!< in/out: file containing
1570
1451
                                        index entries */
1571
 
        ulint*                  half,   /*!< in/out: half the file */
 
1452
        ulint                   half,   /*!< in: half the file */
1572
1453
        row_merge_block_t*      block,  /*!< in/out: 3 buffers */
1573
1454
        int*                    tmpfd,  /*!< in/out: temporary file handle */
1574
1455
        TABLE*                  table)  /*!< in/out: MySQL table, for
1579
1460
        ulint           foffs1; /*!< second input offset */
1580
1461
        ulint           error;  /*!< error code */
1581
1462
        merge_file_t    of;     /*!< output file */
1582
 
        const ulint     ihalf   = *half;
1583
 
                                /*!< half the input file */
1584
 
        ulint           ohalf;  /*!< half the output file */
1585
1463
 
1586
1464
        UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
1587
 
        ut_ad(ihalf < file->offset);
 
1465
        ut_ad(half > 0);
1588
1466
 
1589
1467
        of.fd = *tmpfd;
1590
1468
        of.offset = 0;
1591
 
        of.n_rec = 0;
1592
1469
 
1593
1470
        /* Merge blocks to the output file. */
1594
 
        ohalf = 0;
1595
1471
        foffs0 = 0;
1596
 
        foffs1 = ihalf;
1597
 
 
1598
 
        for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) {
1599
 
                ulint   ahalf;  /*!< arithmetic half the input file */
1600
 
 
1601
 
                if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1602
 
                        return(DB_INTERRUPTED);
1603
 
                }
1604
 
 
 
1472
        foffs1 = half;
 
1473
 
 
1474
        for (; foffs0 < half && foffs1 < file->offset; foffs0++, foffs1++) {
1605
1475
                error = row_merge_blocks(index, file, block,
1606
1476
                                         &foffs0, &foffs1, &of, table);
1607
1477
 
1608
1478
                if (error != DB_SUCCESS) {
1609
1479
                        return(error);
1610
1480
                }
1611
 
 
1612
 
                /* Record the offset of the output file when
1613
 
                approximately half the output has been generated.  In
1614
 
                this way, the next invocation of row_merge() will
1615
 
                spend most of the time in this loop.  The initial
1616
 
                estimate is ohalf==0. */
1617
 
                ahalf = file->offset / 2;
1618
 
                ut_ad(ohalf <= of.offset);
1619
 
 
1620
 
                /* Improve the estimate until reaching half the input
1621
 
                file size, or we can not get any closer to it.  All
1622
 
                comparands should be non-negative when !(ohalf < ahalf)
1623
 
                because ohalf <= of.offset. */
1624
 
                if (ohalf < ahalf || of.offset - ahalf < ohalf - ahalf) {
1625
 
                        ohalf = of.offset;
1626
 
                }
1627
1481
        }
1628
1482
 
1629
 
        /* Copy the last blocks, if there are any. */
1630
 
 
1631
 
        while (foffs0 < ihalf) {
1632
 
                if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1633
 
                        return(DB_INTERRUPTED);
1634
 
                }
1635
 
 
1636
 
                if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) {
 
1483
        /* Copy the last block, if there is one. */
 
1484
        while (foffs0 < half) {
 
1485
                if (!row_merge_read(file->fd, foffs0++, block)
 
1486
                    || !row_merge_write(of.fd, of.offset++, block)) {
1637
1487
                        return(DB_CORRUPTION);
1638
1488
                }
1639
1489
        }
1640
 
 
1641
 
        ut_ad(foffs0 == ihalf);
1642
 
 
1643
1490
        while (foffs1 < file->offset) {
1644
 
                if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1645
 
                        return(DB_INTERRUPTED);
1646
 
                }
1647
 
 
1648
 
                if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) {
 
1491
                if (!row_merge_read(file->fd, foffs1++, block)
 
1492
                    || !row_merge_write(of.fd, of.offset++, block)) {
1649
1493
                        return(DB_CORRUPTION);
1650
1494
                }
1651
1495
        }
1652
1496
 
1653
 
        ut_ad(foffs1 == file->offset);
1654
 
 
1655
 
        if (UNIV_UNLIKELY(of.n_rec != file->n_rec)) {
1656
 
                return(DB_CORRUPTION);
1657
 
        }
1658
 
 
1659
1497
        /* Swap file descriptors for the next pass. */
1660
1498
        *tmpfd = file->fd;
1661
1499
        *file = of;
1662
 
        *half = ohalf;
1663
1500
 
1664
1501
        UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]);
1665
1502
 
1673
1510
ulint
1674
1511
row_merge_sort(
1675
1512
/*===========*/
1676
 
        trx_t*                  trx,    /*!< in: transaction */
1677
1513
        const dict_index_t*     index,  /*!< in: index being created */
1678
1514
        merge_file_t*           file,   /*!< in/out: file containing
1679
1515
                                        index entries */
1683
1519
                                        reporting erroneous key value
1684
1520
                                        if applicable */
1685
1521
{
1686
 
        ulint   half = file->offset / 2;
1687
 
 
1688
 
        /* The file should always contain at least one byte (the end
1689
 
        of file marker).  Thus, it must be at least one block. */
1690
 
        ut_ad(file->offset > 0);
1691
 
 
1692
 
        do {
 
1522
        ulint   blksz;  /*!< block size */
 
1523
 
 
1524
        for (blksz = 1; blksz < file->offset; blksz *= 2) {
 
1525
                ulint   half;
1693
1526
                ulint   error;
1694
1527
 
1695
 
                error = row_merge(trx, index, file, &half,
1696
 
                                  block, tmpfd, table);
 
1528
                ut_ad(ut_is_2pow(blksz));
 
1529
                half = ut_2pow_round((file->offset + (blksz - 1)) / 2, blksz);
 
1530
                error = row_merge(index, file, half, block, tmpfd, table);
1697
1531
 
1698
1532
                if (error != DB_SUCCESS) {
1699
1533
                        return(error);
1700
1534
                }
1701
 
 
1702
 
                /* half > 0 should hold except when the file consists
1703
 
                of one block.  No need to merge further then. */
1704
 
                ut_ad(half > 0 || file->offset == 1);
1705
 
        } while (half < file->offset && half > 0);
 
1535
        }
1706
1536
 
1707
1537
        return(DB_SUCCESS);
1708
1538
}
1969
1799
        static const char str1[] =
1970
1800
                "PROCEDURE DROP_INDEX_PROC () IS\n"
1971
1801
                "BEGIN\n"
1972
 
                /* Rename the index, so that it will be dropped by
1973
 
                row_merge_drop_temp_indexes() at crash recovery
1974
 
                if the server crashes before this trx is committed. */
1975
 
                "UPDATE SYS_INDEXES SET NAME=CONCAT('"
1976
 
                TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
1977
 
                "COMMIT WORK;\n"
1978
 
                /* Drop the field definitions of the index. */
1979
1802
                "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
1980
 
                /* Drop the index definition and the B-tree. */
1981
1803
                "DELETE FROM SYS_INDEXES WHERE ID = :indexid\n"
1982
1804
                "               AND TABLE_ID = :tableid;\n"
1983
1805
                "END;\n";
2090
1912
{
2091
1913
        merge_file->fd = innobase_mysql_tmpfile();
2092
1914
        merge_file->offset = 0;
2093
 
        merge_file->n_rec = 0;
2094
1915
}
2095
1916
 
2096
1917
/*********************************************************************//**
2311
2132
        if (err != DB_SUCCESS) {
2312
2133
err_exit:
2313
2134
                trx->error_state = DB_SUCCESS;
2314
 
                trx_general_rollback_for_mysql(trx, NULL);
 
2135
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
2315
2136
                trx->error_state = DB_SUCCESS;
2316
2137
        }
2317
2138
 
2513
2334
        sorting and inserting. */
2514
2335
 
2515
2336
        for (i = 0; i < n_indexes; i++) {
2516
 
                error = row_merge_sort(trx, indexes[i], &merge_files[i],
 
2337
                error = row_merge_sort(indexes[i], &merge_files[i],
2517
2338
                                       block, &tmpfd, table);
2518
2339
 
2519
2340
                if (error == DB_SUCCESS) {