~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-11-26 22:40:33 UTC
  • mto: This revision was merged to the branch mainline in revision 1958.
  • Revision ID: brian@tangent.org-20101126224033-yt9a3o82w2rhaihp
Adding select for update test with flush locks engaged.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
4
4
 
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
92
92
searched delete is obviously to keep the x-latch for several
93
93
steps of query graph execution. */
94
94
 
95
 
/*************************************************************************
96
 
IMPORTANT NOTE: Any operation that generates redo MUST check that there
97
 
is enough space in the redo log before for that operation. This is
98
 
done by calling log_free_check(). The reason for checking the
99
 
availability of the redo log space before the start of the operation is
100
 
that we MUST not hold any synchonization objects when performing the
101
 
check.
102
 
If you make a change in this module make sure that no codepath is
103
 
introduced where a call to log_free_check() is bypassed. */
104
 
 
105
 
/*************************************************************************
106
 
IMPORTANT NOTE: Any operation that generates redo MUST check that there
107
 
is enough space in the redo log before for that operation. This is
108
 
done by calling log_free_check(). The reason for checking the
109
 
availability of the redo log space before the start of the operation is
110
 
that we MUST not hold any synchonization objects when performing the
111
 
check.
112
 
If you make a change in this module make sure that no codepath is
113
 
introduced where a call to log_free_check() is bypassed. */
114
 
 
115
95
/***********************************************************//**
116
96
Checks if an update vector changes some of the first ordering fields of an
117
97
index record. This is only used in foreign key checks and we can assume
313
293
{
314
294
        upd_node_t*     node;
315
295
 
316
 
        node = static_cast<upd_node_t *>(mem_heap_alloc(heap, sizeof(upd_node_t)));
 
296
        node = mem_heap_alloc(heap, sizeof(upd_node_t));
317
297
        node->common.type = QUE_NODE_UPDATE;
318
298
 
319
299
        node->state = UPD_NODE_UPDATE_CLUSTERED;
381
361
void
382
362
row_upd_index_entry_sys_field(
383
363
/*==========================*/
384
 
        dtuple_t*       entry,  /*!< in/out: index entry, where the memory
385
 
                                buffers for sys fields are already allocated:
 
364
        const dtuple_t* entry,  /*!< in: index entry, where the memory buffers
 
365
                                for sys fields are already allocated:
386
366
                                the function just copies the new values to
387
367
                                them */
388
368
        dict_index_t*   index,  /*!< in: clustered index */
389
369
        ulint           type,   /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
390
 
        ib_uint64_t     val)    /*!< in: value to write */
 
370
        dulint          val)    /*!< in: value to write */
391
371
{
392
372
        dfield_t*       dfield;
393
373
        byte*           field;
398
378
        pos = dict_index_get_sys_col_pos(index, type);
399
379
 
400
380
        dfield = dtuple_get_nth_field(entry, pos);
401
 
        field = static_cast<byte *>(dfield_get_data(dfield));
 
381
        field = dfield_get_data(dfield);
402
382
 
403
383
        if (type == DATA_TRX_ID) {
404
384
                trx_write_trx_id(field, val);
476
456
#endif /* !UNIV_HOTBACKUP */
477
457
 
478
458
/***********************************************************//**
479
 
Replaces the new column values stored in the update vector to the
480
 
record given. No field size changes are allowed. This function is
481
 
usually invoked on a clustered index. The only use case for a
482
 
secondary index is row_ins_sec_index_entry_by_modify() or its
483
 
counterpart in ibuf_insert_to_index_page(). */
 
459
Replaces the new column values stored in the update vector to the record
 
460
given. No field size changes are allowed. */
484
461
UNIV_INTERN
485
462
void
486
463
row_upd_rec_in_place(
537
514
        roll_ptr_t      roll_ptr,/*!< in: roll ptr of the undo log record */
538
515
        byte*           log_ptr,/*!< pointer to a buffer of size > 20 opened
539
516
                                in mlog */
540
 
        mtr_t*          /*mtr __attribute__((unused))*/) /*!< in: mtr */
 
517
        mtr_t*          mtr __attribute__((unused))) /*!< in: mtr */
541
518
{
542
519
        ut_ad(dict_index_is_clust(index));
543
520
        ut_ad(mtr);
549
526
        trx_write_roll_ptr(log_ptr, roll_ptr);
550
527
        log_ptr += DATA_ROLL_PTR_LEN;
551
528
 
552
 
        log_ptr += mach_ull_write_compressed(log_ptr, trx->id);
 
529
        log_ptr += mach_dulint_write_compressed(log_ptr, trx->id);
553
530
 
554
531
        return(log_ptr);
555
532
}
583
560
        *roll_ptr = trx_read_roll_ptr(ptr);
584
561
        ptr += DATA_ROLL_PTR_LEN;
585
562
 
586
 
        ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id);
 
563
        ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id);
587
564
 
588
565
        return(ptr);
589
566
}
648
625
                                mlog_close(mtr, log_ptr);
649
626
 
650
627
                                mlog_catenate_string(mtr,
651
 
                                                     static_cast<byte *>(dfield_get_data(new_val)),
 
628
                                                     dfield_get_data(new_val),
652
629
                                                     len);
653
630
 
654
631
                                log_ptr = mlog_open(mtr, MLOG_BUF_MARGIN);
907
884
                                        out: fetched length of the prefix */
908
885
        mem_heap_t*     heap)           /*!< in: heap where to allocate */
909
886
{
910
 
        byte* buf = static_cast<byte *>(mem_heap_alloc(heap, *len));
 
887
        byte*   buf = mem_heap_alloc(heap, *len);
911
888
 
912
889
        *len = btr_copy_externally_stored_field_prefix(buf, *len,
913
890
                                                       zip_size,
945
922
        }
946
923
 
947
924
        len = dfield_get_len(dfield);
948
 
        data = static_cast<const byte *>(dfield_get_data(dfield));
 
925
        data = dfield_get_data(dfield);
949
926
 
950
927
        if (field->prefix_len > 0) {
951
928
                ibool           fetch_ext = dfield_is_ext(dfield)
962
939
                }
963
940
 
964
941
                len = dtype_get_at_most_n_mbchars(col->prtype,
965
 
                                                  col->mbminmaxlen,
 
942
                                                  col->mbminlen, col->mbmaxlen,
966
943
                                                  field->prefix_len, len,
967
944
                                                  (const char*) data);
968
945
 
996
973
                stored part of the column.  The data
997
974
                will have to be copied. */
998
975
                ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
999
 
                buf = static_cast<byte *>(mem_heap_alloc(heap, uf->orig_len));
 
976
                buf = mem_heap_alloc(heap, uf->orig_len);
1000
977
                /* Copy the locally stored prefix. */
1001
978
                memcpy(buf, data,
1002
979
                       uf->orig_len - BTR_EXTERN_FIELD_REF_SIZE);
1146
1123
        table = index->table;
1147
1124
        ut_ad(n_cols == dict_table_get_n_cols(table));
1148
1125
 
1149
 
        ext_cols = static_cast<ulint *>(mem_heap_alloc(heap, n_cols * sizeof *ext_cols));
 
1126
        ext_cols = mem_heap_alloc(heap, n_cols * sizeof *ext_cols);
1150
1127
        n_ext_cols = 0;
1151
1128
 
1152
1129
        dtuple_set_info_bits(row, update->info_bits);
1411
1388
        dict_index_t*   clust_index;
1412
1389
        rec_t*          rec;
1413
1390
        mem_heap_t*     heap            = NULL;
1414
 
        row_ext_t**     ext;
1415
1391
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1416
1392
        const ulint*    offsets;
1417
1393
        rec_offs_init(offsets_);
1428
1404
 
1429
1405
        offsets = rec_get_offsets(rec, clust_index, offsets_,
1430
1406
                                  ULINT_UNDEFINED, &heap);
1431
 
 
1432
 
        if (dict_table_get_format(node->table) >= DICT_TF_FORMAT_ZIP) {
1433
 
                /* In DYNAMIC or COMPRESSED format, there is no prefix
1434
 
                of externally stored columns in the clustered index
1435
 
                record. Build a cache of column prefixes. */
1436
 
                ext = &node->ext;
1437
 
        } else {
1438
 
                /* REDUNDANT and COMPACT formats store a local
1439
 
                768-byte prefix of each externally stored column.
1440
 
                No cache is needed. */
1441
 
                ext = NULL;
1442
 
                node->ext = NULL;
1443
 
        }
1444
 
 
1445
1407
        node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
1446
 
                              NULL, ext, node->heap);
 
1408
                              NULL, &node->ext, node->heap);
1447
1409
        if (node->is_delete) {
1448
1410
                node->upd_row = NULL;
1449
1411
                node->upd_ext = NULL;
1469
1431
        upd_node_t*     node,   /*!< in: row update node */
1470
1432
        que_thr_t*      thr)    /*!< in: query thread */
1471
1433
{
1472
 
        mtr_t                   mtr;
1473
 
        const rec_t*            rec;
1474
 
        btr_pcur_t              pcur;
1475
 
        mem_heap_t*             heap;
1476
 
        dtuple_t*               entry;
1477
 
        dict_index_t*           index;
1478
 
        btr_cur_t*              btr_cur;
1479
 
        ibool                   referenced;
1480
 
        ulint                   err     = DB_SUCCESS;
1481
 
        trx_t*                  trx     = thr_get_trx(thr);
1482
 
        ulint                   mode    = BTR_MODIFY_LEAF;
1483
 
        enum row_search_result  search_result;
 
1434
        ibool           check_ref;
 
1435
        ibool           found;
 
1436
        dict_index_t*   index;
 
1437
        dtuple_t*       entry;
 
1438
        btr_pcur_t      pcur;
 
1439
        btr_cur_t*      btr_cur;
 
1440
        mem_heap_t*     heap;
 
1441
        rec_t*          rec;
 
1442
        ulint           err     = DB_SUCCESS;
 
1443
        mtr_t           mtr;
 
1444
        trx_t*          trx     = thr_get_trx(thr);
1484
1445
 
1485
1446
        index = node->index;
1486
1447
 
1487
 
        referenced = row_upd_index_is_referenced(index, trx);
 
1448
        check_ref = row_upd_index_is_referenced(index, trx);
1488
1449
 
1489
1450
        heap = mem_heap_create(1024);
1490
1451
 
1492
1453
        entry = row_build_index_entry(node->row, node->ext, index, heap);
1493
1454
        ut_a(entry);
1494
1455
 
 
1456
        log_free_check();
1495
1457
        mtr_start(&mtr);
1496
1458
 
1497
 
        /* Set the query thread, so that ibuf_insert_low() will be
1498
 
        able to invoke thd_get_trx(). */
1499
 
        btr_pcur_get_btr_cur(&pcur)->thr = thr;
1500
 
 
1501
 
        /* We can only try to use the insert/delete buffer to buffer
1502
 
        delete-mark operations if the index we're modifying has no foreign
1503
 
        key constraints referring to it. */
1504
 
        if (!referenced) {
1505
 
                mode |= BTR_DELETE_MARK;
1506
 
        }
1507
 
 
1508
 
        search_result = row_search_index_entry(index, entry, mode,
1509
 
                                               &pcur, &mtr);
1510
 
 
 
1459
        found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur,
 
1460
                                       &mtr);
1511
1461
        btr_cur = btr_pcur_get_btr_cur(&pcur);
1512
1462
 
1513
1463
        rec = btr_cur_get_rec(btr_cur);
1514
1464
 
1515
 
        switch (search_result) {
1516
 
        case ROW_NOT_DELETED_REF:       /* should only occur for BTR_DELETE */
1517
 
                ut_error;
1518
 
                break;
1519
 
        case ROW_BUFFERED:
1520
 
                /* Entry was delete marked already. */
1521
 
                break;
1522
 
 
1523
 
        case ROW_NOT_FOUND:
 
1465
        if (UNIV_UNLIKELY(!found)) {
1524
1466
                fputs("InnoDB: error in sec index entry update in\n"
1525
1467
                      "InnoDB: ", stderr);
1526
1468
                dict_index_name_print(stderr, trx, index);
1537
1479
                fputs("\n"
1538
1480
                      "InnoDB: Submit a detailed bug report"
1539
1481
                      " to http://bugs.mysql.com\n", stderr);
1540
 
                break;
1541
 
        case ROW_FOUND:
 
1482
        } else {
1542
1483
                /* Delete mark the old index record; it can already be
1543
1484
                delete marked if we return after a lock wait in
1544
1485
                row_ins_index_entry below */
1545
1486
 
1546
 
                if (!rec_get_deleted_flag(
1547
 
                        rec, dict_table_is_comp(index->table))) {
1548
 
 
1549
 
                        err = btr_cur_del_mark_set_sec_rec(
1550
 
                                0, btr_cur, TRUE, thr, &mtr);
1551
 
 
1552
 
                        if (err == DB_SUCCESS && referenced) {
1553
 
 
1554
 
                                ulint*  offsets;
1555
 
 
1556
 
                                offsets = rec_get_offsets(
1557
 
                                        rec, index, NULL, ULINT_UNDEFINED,
1558
 
                                        &heap);
1559
 
 
 
1487
                if (!rec_get_deleted_flag(rec,
 
1488
                                          dict_table_is_comp(index->table))) {
 
1489
                        err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
 
1490
                                                           thr, &mtr);
 
1491
                        if (err == DB_SUCCESS && check_ref) {
 
1492
 
 
1493
                                ulint*  offsets = rec_get_offsets(
 
1494
                                        rec, index, NULL,
 
1495
                                        ULINT_UNDEFINED, &heap);
1560
1496
                                /* NOTE that the following call loses
1561
1497
                                the position of pcur ! */
1562
1498
                                err = row_upd_check_references_constraints(
1564
1500
                                        index, offsets, thr, &mtr);
1565
1501
                        }
1566
1502
                }
1567
 
                break;
1568
1503
        }
1569
1504
 
1570
1505
        btr_pcur_close(&pcur);
1594
1529
deletes it if this is a delete.
1595
1530
@return DB_SUCCESS if operation successfully completed, else error
1596
1531
code or DB_LOCK_WAIT */
1597
 
static
 
1532
UNIV_INLINE
1598
1533
ulint
1599
1534
row_upd_sec_step(
1600
1535
/*=============*/
1625
1560
ulint
1626
1561
row_upd_clust_rec_by_insert(
1627
1562
/*========================*/
1628
 
        upd_node_t*     node,   /*!< in/out: row update node */
 
1563
        upd_node_t*     node,   /*!< in: row update node */
1629
1564
        dict_index_t*   index,  /*!< in: clustered index of the record */
1630
1565
        que_thr_t*      thr,    /*!< in: query thread */
1631
 
        ibool           referenced,/*!< in: TRUE if index may be referenced in
 
1566
        ibool           check_ref,/*!< in: TRUE if index may be referenced in
1632
1567
                                a foreign key constraint */
1633
 
        mtr_t*          mtr)    /*!< in/out: mtr; gets committed here */
 
1568
        mtr_t*          mtr)    /*!< in: mtr; gets committed here */
1634
1569
{
1635
1570
        mem_heap_t*     heap    = NULL;
1636
1571
        btr_pcur_t*     pcur;
1639
1574
        dict_table_t*   table;
1640
1575
        dtuple_t*       entry;
1641
1576
        ulint           err;
1642
 
        ibool           change_ownership = FALSE;
1643
1577
 
1644
1578
        ut_ad(node);
1645
1579
        ut_ad(dict_index_is_clust(index));
1651
1585
 
1652
1586
        if (node->state != UPD_NODE_INSERT_CLUSTERED) {
1653
1587
                rec_t*          rec;
1654
 
                dict_index_t*   node_index;
 
1588
                dict_index_t*   index;
1655
1589
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1656
1590
                ulint*          offsets;
1657
1591
                rec_offs_init(offsets_);
1669
1603
                record is removed from the index tree, or updated. */
1670
1604
 
1671
1605
                rec = btr_cur_get_rec(btr_cur);
1672
 
                node_index = dict_table_get_first_index(table);
1673
 
                offsets = rec_get_offsets(rec, node_index, offsets_,
 
1606
                index = dict_table_get_first_index(table);
 
1607
                offsets = rec_get_offsets(rec, index, offsets_,
1674
1608
                                          ULINT_UNDEFINED, &heap);
1675
 
                change_ownership = btr_cur_mark_extern_inherited_fields(
1676
 
                        btr_cur_get_page_zip(btr_cur), rec, node_index, offsets,
1677
 
                        node->update, mtr);
1678
 
                if (referenced) {
 
1609
                btr_cur_mark_extern_inherited_fields(
 
1610
                        btr_cur_get_page_zip(btr_cur),
 
1611
                        rec, index, offsets, node->update, mtr);
 
1612
                if (check_ref) {
1679
1613
                        /* NOTE that the following call loses
1680
1614
                        the position of pcur ! */
1681
 
 
1682
1615
                        err = row_upd_check_references_constraints(
1683
 
                                node, pcur, table, node_index, offsets, thr, mtr);
1684
 
 
 
1616
                                node, pcur, table, index, offsets, thr, mtr);
1685
1617
                        if (err != DB_SUCCESS) {
1686
 
 
1687
1618
                                mtr_commit(mtr);
1688
 
 
1689
1619
                                if (UNIV_LIKELY_NULL(heap)) {
1690
1620
                                        mem_heap_free(heap);
1691
1621
                                }
1692
 
 
1693
1622
                                return(err);
1694
1623
                        }
1695
1624
                }
1708
1637
 
1709
1638
        row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
1710
1639
 
1711
 
        if (change_ownership) {
 
1640
        if (node->upd_ext) {
1712
1641
                /* If we return from a lock wait, for example, we may have
1713
1642
                extern fields marked as not-owned in entry (marked in the
1714
 
                if-branch above). We must unmark them, take the ownership
1715
 
                back. */
 
1643
                if-branch above). We must unmark them. */
1716
1644
 
1717
1645
                btr_cur_unmark_dtuple_extern_fields(entry);
1718
1646
 
1845
1773
        ulint*          offsets,/*!< in/out: rec_get_offsets() for the
1846
1774
                                record under the cursor */
1847
1775
        que_thr_t*      thr,    /*!< in: query thread */
1848
 
        ibool           referenced,
1849
 
                                /*!< in: TRUE if index may be referenced in
 
1776
        ibool           check_ref,/*!< in: TRUE if index may be referenced in
1850
1777
                                a foreign key constraint */
1851
1778
        mtr_t*          mtr)    /*!< in: mtr; gets committed here */
1852
1779
{
1871
1798
 
1872
1799
        err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
1873
1800
                                             btr_cur, TRUE, thr, mtr);
1874
 
        if (err == DB_SUCCESS && referenced) {
 
1801
        if (err == DB_SUCCESS && check_ref) {
1875
1802
                /* NOTE that the following call loses the position of pcur ! */
1876
1803
 
1877
 
                err = row_upd_check_references_constraints(
1878
 
                        node, pcur, index->table, index, offsets, thr, mtr);
 
1804
                err = row_upd_check_references_constraints(node,
 
1805
                                                           pcur, index->table,
 
1806
                                                           index, offsets,
 
1807
                                                           thr, mtr);
1879
1808
        }
1880
1809
 
1881
1810
        mtr_commit(mtr);
1897
1826
        dict_index_t*   index;
1898
1827
        btr_pcur_t*     pcur;
1899
1828
        ibool           success;
 
1829
        ibool           check_ref;
1900
1830
        ulint           err;
1901
1831
        mtr_t*          mtr;
1902
1832
        mtr_t           mtr_buf;
1904
1834
        mem_heap_t*     heap            = NULL;
1905
1835
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1906
1836
        ulint*          offsets;
1907
 
        ibool           referenced;
1908
1837
        rec_offs_init(offsets_);
1909
1838
 
1910
1839
        index = dict_table_get_first_index(node->table);
1911
1840
 
1912
 
        referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
 
1841
        check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
1913
1842
 
1914
1843
        pcur = node->pcur;
1915
1844
 
1942
1871
        then we have to free the file segments of the index tree associated
1943
1872
        with the index */
1944
1873
 
1945
 
        if (node->is_delete && node->table->id == DICT_INDEXES_ID) {
 
1874
        if (node->is_delete
 
1875
            && ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) {
1946
1876
 
1947
1877
                dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr);
1948
1878
 
1978
1908
        /* NOTE: the following function calls will also commit mtr */
1979
1909
 
1980
1910
        if (node->is_delete) {
1981
 
                err = row_upd_del_mark_clust_rec(
1982
 
                        node, index, offsets, thr, referenced, mtr);
1983
 
 
 
1911
                err = row_upd_del_mark_clust_rec(node, index, offsets,
 
1912
                                                 thr, check_ref, mtr);
1984
1913
                if (err == DB_SUCCESS) {
1985
1914
                        node->state = UPD_NODE_UPDATE_ALL_SEC;
1986
1915
                        node->index = dict_table_get_next_index(index);
2028
1957
                choosing records to update. MySQL solves now the problem
2029
1958
                externally! */
2030
1959
 
2031
 
                err = row_upd_clust_rec_by_insert(
2032
 
                        node, index, thr, referenced, mtr);
2033
 
 
 
1960
                err = row_upd_clust_rec_by_insert(node, index, thr, check_ref,
 
1961
                                                  mtr);
2034
1962
                if (err != DB_SUCCESS) {
2035
1963
 
2036
1964
                        return(err);
2087
2015
        if (node->state == UPD_NODE_UPDATE_CLUSTERED
2088
2016
            || node->state == UPD_NODE_INSERT_CLUSTERED) {
2089
2017
 
2090
 
                log_free_check();
2091
2018
                err = row_upd_clust_step(node, thr);
2092
2019
 
2093
2020
                if (err != DB_SUCCESS) {
2102
2029
        }
2103
2030
 
2104
2031
        while (node->index != NULL) {
2105
 
 
2106
 
                log_free_check();
2107
2032
                err = row_upd_sec_step(node, thr);
2108
2033
 
2109
2034
                if (err != DB_SUCCESS) {
2154
2079
 
2155
2080
        trx_start_if_not_started(trx);
2156
2081
 
2157
 
        node = static_cast<upd_node_t *>(thr->run_node);
 
2082
        node = thr->run_node;
2158
2083
 
2159
2084
        sel_node = node->select;
2160
2085