62
62
/** Set these in order ot enable debug printout. */
64
/** Log the outcome of each row_merge_cmp() call, comparing records. */
64
65
static ibool row_merge_print_cmp;
66
/** Log each record read from temporary file. */
65
67
static ibool row_merge_print_read;
68
/** Log each record write to temporary file. */
66
69
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;
68
78
#endif /* UNIV_DEBUG */
710
728
ib_uint64_t ofs = ((ib_uint64_t) offset)
711
729
* 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 */
713
738
return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf,
714
739
(ulint) (ofs & 0xFFFFFFFF),
715
740
(ulint) (ofs >> 32),
1270
1300
if (!row_merge_write(file->fd, file->offset++,
1272
1302
err = DB_OUT_OF_FILE_SPACE;
1303
trx->error_key_num = i;
1276
1307
UNIV_MEM_INVALID(block[0], sizeof block[0]);
1277
1308
merge_buf[i] = row_merge_buf_empty(buf);
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. */
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. */
1340
1376
/*************************************************************//**
1341
Merge two blocks of linked lists on disk and write a bigger block.
1377
Merge two blocks of records on disk and write a bigger block.
1342
1378
@return DB_SUCCESS or error code */
1345
1381
row_merge_blocks(
1346
1382
/*=============*/
1347
1383
const dict_index_t* index, /*!< in: index being created */
1348
merge_file_t* file, /*!< in/out: file containing
1384
const merge_file_t* file, /*!< in: file containing
1349
1385
index entries */
1350
1386
row_merge_block_t* block, /*!< in/out: 3 buffers */
1351
1387
ulint* foffs0, /*!< in/out: offset of first
1368
1404
ulint* offsets0;/* offsets of mrec0 */
1369
1405
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 */
1371
1418
heap = row_merge_heap_create(index, &offsets0, &offsets1);
1373
1420
/* Write a record and read the next record. Split the output
1442
1489
/*************************************************************//**
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
/*************************************************************//**
1443
1561
Merge disk files.
1444
1562
@return DB_SUCCESS or error code */
1563
static __attribute__((nonnull))
1567
trx_t* trx, /*!< in: transaction */
1449
1568
const dict_index_t* index, /*!< in: index being created */
1450
1569
merge_file_t* file, /*!< in/out: file containing
1451
1570
index entries */
1452
ulint half, /*!< in: half the file */
1571
ulint* half, /*!< in/out: half the file */
1453
1572
row_merge_block_t* block, /*!< in/out: 3 buffers */
1454
1573
int* tmpfd, /*!< in/out: temporary file handle */
1455
1574
TABLE* table) /*!< in/out: MySQL table, for
1460
1579
ulint foffs1; /*!< second input offset */
1461
1580
ulint error; /*!< error code */
1462
1581
merge_file_t of; /*!< output file */
1582
const ulint ihalf = *half;
1583
/*!< half the input file */
1584
ulint ohalf; /*!< half the output file */
1464
1586
UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
1587
ut_ad(ihalf < file->offset);
1467
1589
of.fd = *tmpfd;
1470
1593
/* Merge blocks to the output file. */
1474
for (; foffs0 < half && foffs1 < file->offset; foffs0++, foffs1++) {
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);
1475
1605
error = row_merge_blocks(index, file, block,
1476
1606
&foffs0, &foffs1, &of, table);
1478
1608
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) {
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)) {
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)) {
1487
1637
return(DB_CORRUPTION);
1641
ut_ad(foffs0 == ihalf);
1490
1643
while (foffs1 < file->offset) {
1491
if (!row_merge_read(file->fd, foffs1++, block)
1492
|| !row_merge_write(of.fd, of.offset++, block)) {
1644
if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
1645
return(DB_INTERRUPTED);
1648
if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) {
1493
1649
return(DB_CORRUPTION);
1653
ut_ad(foffs1 == file->offset);
1655
if (UNIV_UNLIKELY(of.n_rec != file->n_rec)) {
1656
return(DB_CORRUPTION);
1497
1659
/* Swap file descriptors for the next pass. */
1498
1660
*tmpfd = file->fd;
1501
1664
UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]);
1519
1683
reporting erroneous key value
1520
1684
if applicable */
1522
ulint blksz; /*!< block size */
1524
for (blksz = 1; blksz < file->offset; blksz *= 2) {
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);
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);
1695
error = row_merge(trx, index, file, &half,
1696
block, tmpfd, table);
1532
1698
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);
1537
1707
return(DB_SUCCESS);
1799
1969
static const char str1[] =
1800
1970
"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. */
1802
1979
"DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
1980
/* Drop the index definition and the B-tree. */
1803
1981
"DELETE FROM SYS_INDEXES WHERE ID = :indexid\n"
1804
1982
" AND TABLE_ID = :tableid;\n"