62
62
/** Set these in order ot enable debug printout. */
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
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;
78
68
#endif /* UNIV_DEBUG */
728
710
ib_uint64_t ofs = ((ib_uint64_t) offset)
729
711
* sizeof(row_merge_block_t);
732
if (row_merge_print_block_write) {
733
fprintf(stderr, "row_merge_write fd=%d ofs=%lu\n",
736
#endif /* UNIV_DEBUG */
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),
1300
1270
if (!row_merge_write(file->fd, file->offset++,
1302
1272
err = DB_OUT_OF_FILE_SPACE;
1303
trx->error_key_num = i;
1307
1276
UNIV_MEM_INVALID(block[0], sizeof block[0]);
1308
1277
merge_buf[i] = row_merge_buf_empty(buf);
1310
if (UNIV_LIKELY(row != NULL)) {
1311
/* Try writing the record again, now
1312
that the buffer has been written out
1316
(!row_merge_buf_add(buf, row, ext))) {
1317
/* An empty buffer should have enough
1318
room for at least one record. */
1279
/* Try writing the record again, now that
1280
the buffer has been written out and emptied. */
1283
(row && !row_merge_buf_add(buf, row, ext))) {
1284
/* An empty buffer should have enough
1285
room for at least one record. */
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 */
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 */
1408
if (row_merge_print_block) {
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);
1416
#endif /* UNIV_DEBUG */
1418
1371
heap = row_merge_heap_create(index, &offsets0, &offsets1);
1420
1373
/* Write a record and read the next record. Split the output
1489
1442
/*************************************************************//**
1490
Copy a block of index entries.
1491
@return TRUE on success, FALSE on failure */
1492
static __attribute__((nonnull))
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 */
1502
mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */
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 */
1513
if (row_merge_print_block) {
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);
1520
#endif /* UNIV_DEBUG */
1522
heap = row_merge_heap_create(index, &offsets0, &offsets1);
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. */
1527
if (!row_merge_read(file->fd, *foffs0, &block[0])) {
1529
mem_heap_free(heap);
1536
b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd,
1537
foffs0, &mrec0, offsets0);
1538
if (UNIV_UNLIKELY(!b0 && mrec0)) {
1544
/* append all mrec0 to output */
1546
ROW_MERGE_WRITE_GET_NEXT(0, goto done0);
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. */
1555
mem_heap_free(heap);
1556
return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset)
1560
/*************************************************************//**
1561
1443
Merge disk files.
1562
1444
@return DB_SUCCESS or error code */
1563
static __attribute__((nonnull))
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 */
1586
1464
UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
1587
ut_ad(ihalf < file->offset);
1589
1467
of.fd = *tmpfd;
1593
1470
/* Merge blocks to the output file. */
1598
for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) {
1599
ulint ahalf; /*!< arithmetic half the input file */
1601
if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1602
return(DB_INTERRUPTED);
1474
for (; foffs0 < half && foffs1 < file->offset; foffs0++, foffs1++) {
1605
1475
error = row_merge_blocks(index, file, block,
1606
1476
&foffs0, &foffs1, &of, table);
1608
1478
if (error != DB_SUCCESS) {
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);
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) {
1629
/* Copy the last blocks, if there are any. */
1631
while (foffs0 < ihalf) {
1632
if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1633
return(DB_INTERRUPTED);
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);
1641
ut_ad(foffs0 == ihalf);
1643
1490
while (foffs1 < file->offset) {
1644
if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1645
return(DB_INTERRUPTED);
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);
1653
ut_ad(foffs1 == file->offset);
1655
if (UNIV_UNLIKELY(of.n_rec != file->n_rec)) {
1656
return(DB_CORRUPTION);
1659
1497
/* Swap file descriptors for the next pass. */
1660
1498
*tmpfd = file->fd;
1664
1501
UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]);
1683
1519
reporting erroneous key value
1684
1520
if applicable */
1686
ulint half = file->offset / 2;
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);
1522
ulint blksz; /*!< block size */
1524
for (blksz = 1; blksz < file->offset; blksz *= 2) {
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);
1698
1532
if (error != DB_SUCCESS) {
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);
1707
1537
return(DB_SUCCESS);
1969
1799
static const char str1[] =
1970
1800
"PROCEDURE DROP_INDEX_PROC () IS\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"
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"