~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

merged with up to date trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (c) 1997, 2010, 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
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"
192
193
/** Operations that can currently be buffered. */
193
194
UNIV_INTERN ibuf_use_t  ibuf_use                = IBUF_USE_ALL;
194
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 */
 
200
 
195
201
/** The insert buffer control structure */
196
202
UNIV_INTERN ibuf_t*     ibuf                    = NULL;
197
203
 
510
516
        page_t*         header_page;
511
517
        ulint           error;
512
518
 
513
 
        ibuf = mem_alloc(sizeof(ibuf_t));
 
519
        ibuf = static_cast<ibuf_t *>(mem_alloc(sizeof(ibuf_t)));
514
520
 
515
521
        memset(ibuf, 0, sizeof(*ibuf));
516
522
 
637
643
ibuf_parse_bitmap_init(
638
644
/*===================*/
639
645
        byte*           ptr,    /*!< in: buffer */
640
 
        byte*           end_ptr __attribute__((unused)), /*!< in: buffer end */
 
646
        byte*           /*end_ptr __attribute__((unused))*/, /*!< in: buffer end */
641
647
        buf_block_t*    block,  /*!< in: block or NULL */
642
648
        mtr_t*          mtr)    /*!< in: mtr or NULL */
643
649
{
663
669
                                0 for uncompressed pages */
664
670
        ulint           bit,    /*!< in: IBUF_BITMAP_FREE,
665
671
                                IBUF_BITMAP_BUFFERED, ... */
666
 
        mtr_t*          mtr __attribute__((unused)))
 
672
        mtr_t*          /*mtr __attribute__((unused))*/)
667
673
                                /*!< in: mtr containing an
668
674
                                x-latch to the bitmap page */
669
675
{
1357
1363
        const ulint*    ops)    /*!< in: operation counts */
1358
1364
 
1359
1365
{
 
1366
        ulint   i;
 
1367
 
1360
1368
#ifndef HAVE_ATOMIC_BUILTINS
1361
1369
        ut_ad(mutex_own(&ibuf_mutex));
1362
1370
#endif /* !HAVE_ATOMIC_BUILTINS */
1363
1371
 
1364
 
        ulint   i;
1365
 
 
1366
1372
        for (i = 0; i < IBUF_OP_COUNT; i++) {
1367
1373
#ifdef HAVE_ATOMIC_BUILTINS
1368
1374
                os_atomic_increment_ulint(&arr[i], ops[i]);
1788
1794
 
1789
1795
        field = dtuple_get_nth_field(tuple, 0);
1790
1796
 
1791
 
        buf = mem_heap_alloc(heap, 4);
 
1797
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1792
1798
 
1793
1799
        mach_write_to_4(buf, space);
1794
1800
 
1798
1804
 
1799
1805
        field = dtuple_get_nth_field(tuple, 1);
1800
1806
 
1801
 
        buf = mem_heap_alloc(heap, 1);
 
1807
        buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
1802
1808
 
1803
1809
        /* We set the marker byte zero */
1804
1810
 
1810
1816
 
1811
1817
        field = dtuple_get_nth_field(tuple, 2);
1812
1818
 
1813
 
        buf = mem_heap_alloc(heap, 4);
 
1819
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1814
1820
 
1815
1821
        mach_write_to_4(buf, page_no);
1816
1822
 
1825
1831
                i = IBUF_REC_INFO_SIZE;
1826
1832
        }
1827
1833
 
1828
 
        ti = type_info = mem_heap_alloc(heap, i + n_fields
1829
 
                                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE);
 
1834
        ti = type_info = static_cast<byte *>(mem_heap_alloc(heap, i + n_fields
 
1835
                                        * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE));
1830
1836
 
1831
1837
        switch (i) {
1832
1838
        default:
1929
1935
 
1930
1936
        field = dtuple_get_nth_field(tuple, 0);
1931
1937
 
1932
 
        buf = mem_heap_alloc(heap, 4);
 
1938
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1933
1939
 
1934
1940
        mach_write_to_4(buf, page_no);
1935
1941
 
1964
1970
 
1965
1971
        field = dtuple_get_nth_field(tuple, 0);
1966
1972
 
1967
 
        buf = mem_heap_alloc(heap, 4);
 
1973
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1968
1974
 
1969
1975
        mach_write_to_4(buf, space);
1970
1976
 
1974
1980
 
1975
1981
        field = dtuple_get_nth_field(tuple, 1);
1976
1982
 
1977
 
        buf = mem_heap_alloc(heap, 1);
 
1983
        buf = static_cast<byte *>(mem_heap_alloc(heap, 1));
1978
1984
 
1979
1985
        mach_write_to_1(buf, 0);
1980
1986
 
1984
1990
 
1985
1991
        field = dtuple_get_nth_field(tuple, 2);
1986
1992
 
1987
 
        buf = mem_heap_alloc(heap, 4);
 
1993
        buf = static_cast<byte *>(mem_heap_alloc(heap, 4));
1988
1994
 
1989
1995
        mach_write_to_4(buf, page_no);
1990
1996
 
2761
2767
 
2762
2768
        switch (ibuf_op) {
2763
2769
        case IBUF_OP_INSERT:
2764
 
                /* Inserts can be done by
2765
 
                btr_cur_set_deleted_flag_for_ibuf().  Because
2766
 
                delete-mark and insert operations can be pointing to
 
2770
                /* Inserts can be done by updating a delete-marked record.
 
2771
                Because delete-mark and insert operations can be pointing to
2767
2772
                the same records, we must not count duplicates. */
2768
2773
        case IBUF_OP_DELETE_MARK:
2769
2774
                /* There must be a record to delete-mark.
3267
3272
 
3268
3273
        /* Patch counter value in already built entry. */
3269
3274
        field = dtuple_get_nth_field(entry, 3);
3270
 
        data = dfield_get_data(field);
 
3275
        data = static_cast<byte *>(dfield_get_data(field));
3271
3276
 
3272
3277
        mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter);
3273
3278
 
3521
3526
                /* If this is the root page, update ibuf->empty. */
3522
3527
                if (UNIV_UNLIKELY(buf_block_get_page_no(block)
3523
3528
                                  == FSP_IBUF_TREE_ROOT_PAGE_NO)) {
3524
 
                        const page_t*   root = buf_block_get_frame(block);
 
3529
                        const page_t*   page_root = buf_block_get_frame(block);
3525
3530
 
3526
 
                        ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
3527
 
                        ut_ad(page_get_page_no(root)
 
3531
                        ut_ad(page_get_space_id(page_root) == IBUF_SPACE_ID);
 
3532
                        ut_ad(page_get_page_no(page_root)
3528
3533
                              == FSP_IBUF_TREE_ROOT_PAGE_NO);
3529
3534
 
3530
 
                        ibuf->empty = (page_get_n_recs(root) == 0);
 
3535
                        ibuf->empty = (page_get_n_recs(page_root) == 0);
3531
3536
                }
3532
3537
        } else {
3533
3538
                ut_ad(mode == BTR_MODIFY_TREE);
3748
3753
from the insert buffer. */
3749
3754
static
3750
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
3751
3827
ibuf_insert_to_index_page(
3752
3828
/*======================*/
3753
 
        dtuple_t*       entry,  /*!< in: buffered entry to insert */
 
3829
        const dtuple_t* entry,  /*!< in: buffered entry to insert */
3754
3830
        buf_block_t*    block,  /*!< in/out: index page where the buffered entry
3755
3831
                                should be placed */
3756
3832
        dict_index_t*   index,  /*!< in: record descriptor */
3760
3836
        ulint           low_match;
3761
3837
        page_t*         page            = buf_block_get_frame(block);
3762
3838
        rec_t*          rec;
3763
 
        page_t*         bitmap_page;
3764
 
        ulint           old_bits;
3765
3839
 
3766
3840
        ut_ad(ibuf_inside());
3767
3841
        ut_ad(dtuple_check_typed(entry));
 
3842
        ut_ad(!buf_block_align(page)->is_hashed);
3768
3843
 
3769
3844
        if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
3770
3845
                          != (ibool)!!page_is_comp(page))) {
3810
3885
        low_match = page_cur_search(block, index, entry,
3811
3886
                                    PAGE_CUR_LE, &page_cur);
3812
3887
 
3813
 
        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;
3814
3892
                page_zip_des_t* page_zip;
3815
3893
 
3816
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
 
3817
3907
                page_zip = buf_block_get_page_zip(block);
3818
3908
 
3819
 
                btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, FALSE, mtr);
 
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);
 
3917
                        return;
 
3918
                }
 
3919
 
 
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);
3820
3966
        } else {
3821
 
                rec = page_cur_tuple_insert(&page_cur, entry, index, 0, mtr);
3822
 
 
3823
 
                if (UNIV_LIKELY(rec != NULL)) {
3824
 
                        return;
3825
 
                }
3826
 
 
3827
 
                /* If the record did not fit, reorganize */
3828
 
 
3829
 
                btr_page_reorganize(block, index, mtr);
3830
 
                page_cur_search(block, index, entry, PAGE_CUR_LE, &page_cur);
3831
 
 
3832
 
                /* This time the record must fit */
3833
 
                if (UNIV_UNLIKELY
3834
 
                    (!page_cur_tuple_insert(&page_cur, entry, index,
3835
 
                                            0, mtr))) {
3836
 
                        ulint   space;
3837
 
                        ulint   page_no;
3838
 
                        ulint   zip_size;
3839
 
 
3840
 
                        ut_print_timestamp(stderr);
3841
 
 
3842
 
                        fprintf(stderr,
3843
 
                                "  InnoDB: Error: Insert buffer insert"
3844
 
                                " fails; page free %lu,"
3845
 
                                " dtuple size %lu\n",
3846
 
                                (ulong) page_get_max_insert_size(
3847
 
                                        page, 1),
3848
 
                                (ulong) rec_get_converted_size(
3849
 
                                        index, entry, 0));
3850
 
                        fputs("InnoDB: Cannot insert index record ",
3851
 
                              stderr);
3852
 
                        dtuple_print(stderr, entry);
3853
 
                        fputs("\nInnoDB: The table where"
3854
 
                              " this index record belongs\n"
3855
 
                              "InnoDB: is now probably corrupt."
3856
 
                              " Please run CHECK TABLE on\n"
3857
 
                              "InnoDB: that table.\n", stderr);
3858
 
 
3859
 
                        space = page_get_space_id(page);
3860
 
                        zip_size = buf_block_get_zip_size(block);
3861
 
                        page_no = page_get_page_no(page);
3862
 
 
3863
 
                        bitmap_page = ibuf_bitmap_get_map_page(
3864
 
                                space, page_no, zip_size, mtr);
3865
 
                        old_bits = ibuf_bitmap_page_get_bits(
3866
 
                                bitmap_page, page_no, zip_size,
3867
 
                                IBUF_BITMAP_FREE, mtr);
3868
 
 
3869
 
                        fprintf(stderr,
3870
 
                                "InnoDB: space %lu, page %lu,"
3871
 
                                " zip_size %lu, bitmap bits %lu\n",
3872
 
                                (ulong) space, (ulong) page_no,
3873
 
                                (ulong) zip_size, (ulong) old_bits);
3874
 
 
3875
 
                        fputs("InnoDB: Submit a detailed bug report"
3876
 
                              " to http://bugs.mysql.com\n", stderr);
3877
 
                }
 
3967
                ibuf_insert_to_index_page_low(entry, block, index, mtr,
 
3968
                                              &page_cur);
3878
3969
        }
3879
3970
}
3880
3971
 
3906
3997
                rec = page_cur_get_rec(&page_cur);
3907
3998
                page_zip = page_cur_get_page_zip(&page_cur);
3908
3999
 
3909
 
                btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, TRUE, mtr);
 
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
                }
3910
4012
        } else {
3911
 
                /* This can happen benignly in some situations. */
 
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);
3912
4026
        }
3913
4027
}
3914
4028
 
3983
4097
                        mem_heap_free(heap);
3984
4098
                }
3985
4099
        } else {
3986
 
                /* This can happen benignly in some situations: either when
3987
 
                we crashed at just the right time, or on database startup
3988
 
                when we redo some old log entries (due to worse stored
3989
 
                position granularity on disk than in memory). */
 
4100
                /* The record must have been purged already. */
3990
4101
        }
3991
4102
}
3992
4103