~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/btr/btr0cur.c

  • Committer: Stewart Smith
  • Author(s): Marko Mäkelä, Stewart Smith
  • Date: 2010-11-17 05:52:09 UTC
  • mto: (2021.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 1971.
  • Revision ID: stewart@flamingspork.com-20101117055209-69m035q6h7e1txrc
Merge Revision revid:marko.makela@oracle.com-20100629113248-fvl48lnzr44z94gg from MySQL InnoDB

Original revid:marko.makela@oracle.com-20100629113248-fvl48lnzr44z94gg

Original Authors: Marko Mkel <marko.makela@oracle.com>
Original commit message:
Bug#52199 utf32: mbminlen=4, mbmaxlen=4, type->mbminlen=0, type->mbmaxlen=4

Merge and adjust a forgotten change to fix this bug.
rb://393 approved by Jimmy Yang
  ------------------------------------------------------------------------
  r3794 | marko | 2009-01-07 14:14:53 +0000 (Wed, 07 Jan 2009) | 18 lines

  branches/6.0: Allow the minimum length of a multi-byte character to be
  up to 4 bytes. (Bug #35391)

  dtype_t, dict_col_t: Replace mbminlen:2, mbmaxlen:3 with mbminmaxlen:5.
  In this way, the 5 bits can hold two values of 0..4, and the storage size
  of the fields will not cross the 64-bit boundary.  Encode the values as
  DATA_MBMAX * mbmaxlen + mbminlen.  Define the auxiliary macros
  DB_MBMINLEN(mbminmaxlen), DB_MBMAXLEN(mbminmaxlen), and
  DB_MINMAXLEN(mbminlen, mbmaxlen).

  Try to trim and pad UTF-16 and UTF-32 with spaces as appropriate.

  Alexander Barkov suggested the use of cs->cset->fill(cs, buff, len, 0x20).
  ha_innobase::store_key_val_for_row() now does that, but the added function
  row_mysql_pad_col() does not, because it doesn't have the MySQL TABLE object.

  rb://49 approved by Heikki Tuuri
  ------------------------------------------------------------------------

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (C) 1994, 2010, Innobase Oy. All Rights Reserved.
4
 
Copyright (C) 2008, Google Inc.
 
3
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
 
4
Copyright (c) 2008, Google Inc.
5
5
 
6
6
Portions of this file contain modifications contributed and copyrighted by
7
7
Google, Inc. Those modifications are gratefully acknowledged and are described
117
117
/** A BLOB field reference full of zero, for use in assertions and tests.
118
118
Initially, BLOB field references are set to zero, in
119
119
dtuple_convert_big_rec(). */
120
 
const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE]= {0};
 
120
UNIV_INTERN const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE]= {0};
121
121
 
122
122
#ifndef UNIV_HOTBACKUP
123
123
/*******************************************************************//**
1071
1071
                                not zero, the parameters index and thr
1072
1072
                                should be specified */
1073
1073
        btr_cur_t*      cursor, /*!< in: cursor on page after which to insert */
1074
 
        dtuple_t*       entry,  /*!< in/out: entry to insert */
 
1074
        const dtuple_t* entry,  /*!< in: entry to insert */
1075
1075
        que_thr_t*      thr,    /*!< in: query thread or NULL */
1076
1076
        mtr_t*          mtr,    /*!< in/out: mini-transaction */
1077
1077
        ibool*          inherit)/*!< out: TRUE if the inserted new record maybe
1744
1744
See if there is enough place in the page modification log to log
1745
1745
an update-in-place.
1746
1746
@return TRUE if enough place */
1747
 
UNIV_INTERN
 
1747
static
1748
1748
ibool
1749
1749
btr_cur_update_alloc_zip(
1750
1750
/*=====================*/
1954
1954
        page_t*         page;
1955
1955
        page_zip_des_t* page_zip;
1956
1956
        rec_t*          rec;
 
1957
        rec_t*          orig_rec;
1957
1958
        ulint           max_size;
1958
1959
        ulint           new_rec_size;
1959
1960
        ulint           old_rec_size;
1967
1968
 
1968
1969
        block = btr_cur_get_block(cursor);
1969
1970
        page = buf_block_get_frame(block);
1970
 
        rec = btr_cur_get_rec(cursor);
 
1971
        orig_rec = rec = btr_cur_get_rec(cursor);
1971
1972
        index = cursor->index;
1972
1973
        ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
1973
1974
        ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
3152
3153
{
3153
3154
        btr_path_t*     slot;
3154
3155
        rec_t*          rec;
3155
 
        page_t*         page;
3156
3156
 
3157
3157
        ut_a(cursor->path_arr);
3158
3158
 
3175
3175
 
3176
3176
        slot = cursor->path_arr + (root_height - height);
3177
3177
 
3178
 
        page = page_align(rec);
3179
 
 
3180
3178
        slot->nth_rec = page_rec_get_n_recs_before(rec);
3181
 
        slot->n_recs = page_get_n_recs(page);
3182
 
        slot->page_no = page_get_page_no(page);
3183
 
        slot->page_level = btr_page_get_level_low(page);
3184
 
}
3185
 
 
3186
 
/*******************************************************************//**
3187
 
Estimate the number of rows between slot1 and slot2 for any level on a
3188
 
B-tree. This function starts from slot1->page and reads a few pages to
3189
 
the right, counting their records. If we reach slot2->page quickly then
3190
 
we know exactly how many records there are between slot1 and slot2 and
3191
 
we set is_n_rows_exact to TRUE. If we cannot reach slot2->page quickly
3192
 
then we calculate the average number of records in the pages scanned
3193
 
so far and assume that all pages that we did not scan up to slot2->page
3194
 
contain the same number of records, then we multiply that average to
3195
 
the number of pages between slot1->page and slot2->page (which is
3196
 
n_rows_on_prev_level). In this case we set is_n_rows_exact to FALSE.
3197
 
@return number of rows (exact or estimated) */
3198
 
static
3199
 
ib_int64_t
3200
 
btr_estimate_n_rows_in_range_on_level(
3201
 
/*==================================*/
3202
 
        dict_index_t*   index,                  /*!< in: index */
3203
 
        btr_path_t*     slot1,                  /*!< in: left border */
3204
 
        btr_path_t*     slot2,                  /*!< in: right border */
3205
 
        ib_int64_t      n_rows_on_prev_level,   /*!< in: number of rows
3206
 
                                                on the previous level for the
3207
 
                                                same descend paths; used to
3208
 
                                                determine the numbe of pages
3209
 
                                                on this level */
3210
 
        ibool*          is_n_rows_exact)        /*!< out: TRUE if the returned
3211
 
                                                value is exact i.e. not an
3212
 
                                                estimation */
3213
 
{
3214
 
        ulint           space;
3215
 
        ib_int64_t      n_rows;
3216
 
        ulint           n_pages_read;
3217
 
        ulint           page_no;
3218
 
        ulint           zip_size;
3219
 
        ulint           level;
3220
 
 
3221
 
        space = dict_index_get_space(index);
3222
 
 
3223
 
        n_rows = 0;
3224
 
        n_pages_read = 0;
3225
 
 
3226
 
        /* Assume by default that we will scan all pages between
3227
 
        slot1->page_no and slot2->page_no */
3228
 
        *is_n_rows_exact = TRUE;
3229
 
 
3230
 
        /* add records from slot1->page_no which are to the right of
3231
 
        the record which serves as a left border of the range, if any */
3232
 
        if (slot1->nth_rec < slot1->n_recs) {
3233
 
                n_rows += slot1->n_recs - slot1->nth_rec;
3234
 
        }
3235
 
 
3236
 
        /* add records from slot2->page_no which are to the left of
3237
 
        the record which servers as a right border of the range, if any */
3238
 
        if (slot2->nth_rec > 1) {
3239
 
                n_rows += slot2->nth_rec - 1;
3240
 
        }
3241
 
 
3242
 
        /* count the records in the pages between slot1->page_no and
3243
 
        slot2->page_no (non inclusive), if any */
3244
 
 
3245
 
        zip_size = fil_space_get_zip_size(space);
3246
 
 
3247
 
        /* Do not read more than this number of pages in order not to hurt
3248
 
        performance with this code which is just an estimation. If we read
3249
 
        this many pages before reaching slot2->page_no then we estimate the
3250
 
        average from the pages scanned so far */
3251
 
#       define N_PAGES_READ_LIMIT       10
3252
 
 
3253
 
        page_no = slot1->page_no;
3254
 
        level = slot1->page_level;
3255
 
 
3256
 
        do {
3257
 
                mtr_t           mtr;
3258
 
                page_t*         page;
3259
 
                buf_block_t*    block;
3260
 
 
3261
 
                mtr_start(&mtr);
3262
 
 
3263
 
                /* fetch the page */
3264
 
                block = buf_page_get(space, zip_size, page_no, RW_S_LATCH,
3265
 
                                     &mtr);
3266
 
 
3267
 
                page = buf_block_get_frame(block);
3268
 
 
3269
 
                /* It is possible that the tree has been reorganized in the
3270
 
                meantime and this is a different page. If this happens the
3271
 
                calculated estimate will be bogus, which is not fatal as
3272
 
                this is only an estimate. We are sure that a page with
3273
 
                page_no exists because InnoDB never frees pages, only
3274
 
                reuses them. */
3275
 
                if (fil_page_get_type(page) != FIL_PAGE_INDEX
3276
 
                    || btr_page_get_index_id(page) != index->id
3277
 
                    || btr_page_get_level_low(page) != level) {
3278
 
 
3279
 
                        /* The page got reused for something else */
3280
 
                        mtr_commit(&mtr);
3281
 
                        goto inexact;
3282
 
                }
3283
 
 
3284
 
                n_pages_read++;
3285
 
 
3286
 
                if (page_no != slot1->page_no) {
3287
 
                        /* Do not count the records on slot1->page_no,
3288
 
                        we already counted them before this loop. */
3289
 
                        n_rows += page_get_n_recs(page);
3290
 
                }
3291
 
 
3292
 
                page_no = btr_page_get_next(page, &mtr);
3293
 
 
3294
 
                mtr_commit(&mtr);
3295
 
 
3296
 
                if (n_pages_read == N_PAGES_READ_LIMIT
3297
 
                    || page_no == FIL_NULL) {
3298
 
                        /* Either we read too many pages or
3299
 
                        we reached the end of the level without passing
3300
 
                        through slot2->page_no, the tree must have changed
3301
 
                        in the meantime */
3302
 
                        goto inexact;
3303
 
                }
3304
 
 
3305
 
        } while (page_no != slot2->page_no);
3306
 
 
3307
 
        return(n_rows);
3308
 
 
3309
 
inexact:
3310
 
 
3311
 
        *is_n_rows_exact = FALSE;
3312
 
 
3313
 
        /* We did interrupt before reaching slot2->page */
3314
 
 
3315
 
        if (n_pages_read > 0) {
3316
 
                /* The number of pages on this level is
3317
 
                n_rows_on_prev_level, multiply it by the
3318
 
                average number of recs per page so far */
3319
 
                n_rows = n_rows_on_prev_level
3320
 
                        * n_rows / n_pages_read;
3321
 
        } else {
3322
 
                /* The tree changed before we could even
3323
 
                start with slot1->page_no */
3324
 
                n_rows = 10;
3325
 
        }
3326
 
 
3327
 
        return(n_rows);
 
3179
        slot->n_recs = page_get_n_recs(page_align(rec));
3328
3180
}
3329
3181
 
3330
3182
/*******************************************************************//**
3349
3201
        ibool           diverged_lot;
3350
3202
        ulint           divergence_level;
3351
3203
        ib_int64_t      n_rows;
3352
 
        ibool           is_n_rows_exact;
3353
3204
        ulint           i;
3354
3205
        mtr_t           mtr;
3355
3206
 
3392
3243
        /* We have the path information for the range in path1 and path2 */
3393
3244
 
3394
3245
        n_rows = 1;
3395
 
        is_n_rows_exact = TRUE;
3396
3246
        diverged = FALSE;           /* This becomes true when the path is not
3397
3247
                                    the same any more */
3398
3248
        diverged_lot = FALSE;       /* This becomes true when the paths are
3408
3258
                if (slot1->nth_rec == ULINT_UNDEFINED
3409
3259
                    || slot2->nth_rec == ULINT_UNDEFINED) {
3410
3260
 
3411
 
                        if (i > divergence_level + 1 && !is_n_rows_exact) {
 
3261
                        if (i > divergence_level + 1) {
3412
3262
                                /* In trees whose height is > 1 our algorithm
3413
3263
                                tends to underestimate: multiply the estimate
3414
3264
                                by 2: */
3420
3270
                        to over 1 / 2 of the estimated rows in the whole
3421
3271
                        table */
3422
3272
 
3423
 
                        if (n_rows > index->table->stat_n_rows / 2
3424
 
                            && !is_n_rows_exact) {
3425
 
 
 
3273
                        if (n_rows > index->table->stat_n_rows / 2) {
3426
3274
                                n_rows = index->table->stat_n_rows / 2;
3427
3275
 
3428
3276
                                /* If there are just 0 or 1 rows in the table,
3448
3296
                                        divergence_level = i;
3449
3297
                                }
3450
3298
                        } else {
3451
 
                                /* It is possible that
3452
 
                                slot1->nth_rec >= slot2->nth_rec
3453
 
                                if, for example, we have a single page
3454
 
                                tree which contains (inf, 5, 6, supr)
3455
 
                                and we select where x > 20 and x < 30;
3456
 
                                in this case slot1->nth_rec will point
3457
 
                                to the supr record and slot2->nth_rec
3458
 
                                will point to 6 */
3459
 
                                n_rows = 0;
 
3299
                                /* Maybe the tree has changed between
 
3300
                                searches */
 
3301
 
 
3302
                                return(10);
3460
3303
                        }
3461
3304
 
3462
3305
                } else if (diverged && !diverged_lot) {
3480
3323
                        }
3481
3324
                } else if (diverged_lot) {
3482
3325
 
3483
 
                        n_rows = btr_estimate_n_rows_in_range_on_level(
3484
 
                                index, slot1, slot2, n_rows,
3485
 
                                &is_n_rows_exact);
 
3326
                        n_rows = (n_rows * (slot1->n_recs + slot2->n_recs))
 
3327
                                / 2;
3486
3328
                }
3487
3329
        }
3488
3330
}
3521
3363
 
3522
3364
        n_cols = dict_index_get_n_unique(index);
3523
3365
 
3524
 
        n_diff = (ib_int64_t *)mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
 
3366
        n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
3525
3367
 
3526
3368
        /* It makes no sense to test more pages than are contained
3527
3369
        in the index, thus we lower the number if it is too high */
3633
3475
        also the pages used for external storage of fields (those pages are
3634
3476
        included in index->stat_n_leaf_pages) */
3635
3477
 
 
3478
        dict_index_stat_mutex_enter(index);
 
3479
 
3636
3480
        for (j = 0; j <= n_cols; j++) {
3637
3481
                index->stat_n_diff_key_vals[j]
3638
3482
                        = ((n_diff[j]
3662
3506
                index->stat_n_diff_key_vals[j] += add_on;
3663
3507
        }
3664
3508
 
 
3509
        dict_index_stat_mutex_exit(index);
 
3510
 
3665
3511
        mem_free(n_diff);
3666
3512
        if (UNIV_LIKELY_NULL(heap)) {
3667
3513
                mem_heap_free(heap);
3757
3603
Marks not updated extern fields as not-owned by this record. The ownership
3758
3604
is transferred to the updated record which is inserted elsewhere in the
3759
3605
index tree. In purge only the owner of externally stored field is allowed
3760
 
to free the field.
3761
 
@return TRUE if BLOB ownership was transferred */
 
3606
to free the field. */
3762
3607
UNIV_INTERN
3763
 
ibool
 
3608
void
3764
3609
btr_cur_mark_extern_inherited_fields(
3765
3610
/*=================================*/
3766
3611
        page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
3774
3619
        ulint   n;
3775
3620
        ulint   j;
3776
3621
        ulint   i;
3777
 
        ibool   change_ownership = FALSE;
3778
3622
 
3779
3623
        ut_ad(rec_offs_validate(rec, NULL, offsets));
3780
3624
        ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
3781
3625
 
3782
3626
        if (!rec_offs_any_extern(offsets)) {
3783
3627
 
3784
 
                return(FALSE);
 
3628
                return;
3785
3629
        }
3786
3630
 
3787
3631
        n = rec_offs_n_fields(offsets);
3804
3648
 
3805
3649
                        btr_cur_set_ownership_of_extern_field(
3806
3650
                                page_zip, rec, index, offsets, i, FALSE, mtr);
3807
 
 
3808
 
                        change_ownership = TRUE;
3809
3651
updated:
3810
3652
                        ;
3811
3653
                }
3812
3654
        }
3813
 
 
3814
 
        return(change_ownership);
3815
3655
}
3816
3656
 
3817
3657
/*******************************************************************//**
3848
3688
                        }
3849
3689
                }
3850
3690
 
3851
 
                data = (unsigned char *)dfield_get_data(dfield);
 
3691
                data = dfield_get_data(dfield);
3852
3692
                len = dfield_get_len(dfield);
3853
3693
                data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
3854
3694
                        |= BTR_EXTERN_INHERITED_FLAG;
3907
3747
                dfield_t* dfield = dtuple_get_nth_field(entry, i);
3908
3748
 
3909
3749
                if (dfield_is_ext(dfield)) {
3910
 
                        byte*   data = (unsigned char *)dfield_get_data(dfield);
 
3750
                        byte*   data = dfield_get_data(dfield);
3911
3751
                        ulint   len = dfield_get_len(dfield);
3912
3752
 
3913
3753
                        data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
3973
3813
                                will have to be copied. */
3974
3814
                                ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
3975
3815
 
3976
 
                                data = (unsigned char *)dfield_get_data(field);
 
3816
                                data = dfield_get_data(field);
3977
3817
                                len = dfield_get_len(field);
3978
3818
 
3979
 
                                buf = (unsigned char *)mem_heap_alloc(heap, uf->orig_len);
 
3819
                                buf = mem_heap_alloc(heap, uf->orig_len);
3980
3820
                                /* Copy the locally stored prefix. */
3981
3821
                                memcpy(buf, data,
3982
3822
                                       uf->orig_len
4069
3909
them in rec.  The extern flags in rec will have to be set beforehand.
4070
3910
The fields are stored on pages allocated from leaf node
4071
3911
file segment of the index tree.
4072
 
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
3912
@return DB_SUCCESS or error */
4073
3913
UNIV_INTERN
4074
3914
ulint
4075
3915
btr_store_big_rec_extern_fields(
4084
3924
                                        this function returns */
4085
3925
        big_rec_t*      big_rec_vec,    /*!< in: vector containing fields
4086
3926
                                        to be stored externally */
4087
 
        mtr_t*          /*local_mtr __attribute__((unused))*/) /*!< in: mtr
 
3927
        mtr_t*          local_mtr __attribute__((unused))) /*!< in: mtr
4088
3928
                                        containing the latch to rec and to the
4089
3929
                                        tree */
4090
3930
{
4162
4002
                        int     err = deflateReset(&c_stream);
4163
4003
                        ut_a(err == Z_OK);
4164
4004
 
4165
 
                        c_stream.next_in = (Bytef *) big_rec_vec->fields[i].data;
 
4005
                        c_stream.next_in = (void*) big_rec_vec->fields[i].data;
4166
4006
                        c_stream.avail_in = extern_len;
4167
4007
                }
4168
4008
 
4499
4339
        ulint           i,              /*!< in: field number of field_ref;
4500
4340
                                        ignored if rec == NULL */
4501
4341
        enum trx_rb_ctx rb_ctx,         /*!< in: rollback context */
4502
 
        mtr_t*          /*local_mtr __attribute__((unused))*/) /*!< in: mtr
 
4342
        mtr_t*          local_mtr __attribute__((unused))) /*!< in: mtr
4503
4343
                                        containing the latch to data an an
4504
4344
                                        X-latch to the index tree */
4505
4345
{
4559
4399
        }
4560
4400
 
4561
4401
        for (;;) {
4562
 
#ifdef UNIV_SYNC_DEBUG
4563
4402
                buf_block_t*    rec_block;
4564
 
#endif /* UNIV_SYNC_DEBUG */
4565
4403
                buf_block_t*    ext_block;
4566
4404
 
4567
4405
                mtr_start(&mtr);
4568
4406
 
4569
 
#ifdef UNIV_SYNC_DEBUG
4570
 
                rec_block =
4571
 
#endif /* UNIV_SYNC_DEBUG */
4572
 
                        buf_page_get(page_get_space_id(
 
4407
                rec_block = buf_page_get(page_get_space_id(
4573
4408
                                                 page_align(field_ref)),
4574
4409
                                         rec_zip_size,
4575
4410
                                         page_get_page_no(
5084
4919
 
5085
4920
        extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
5086
4921
 
5087
 
        buf = (unsigned char *)mem_heap_alloc(heap, local_len + extern_len);
 
4922
        buf = mem_heap_alloc(heap, local_len + extern_len);
5088
4923
 
5089
4924
        memcpy(buf, data, local_len);
5090
4925
        *len = local_len
5099
4934
 
5100
4935
/*******************************************************************//**
5101
4936
Copies an externally stored field of a record to mem heap.
5102
 
@return the field copied to heap, or NULL if the field is incomplete */
 
4937
@return the field copied to heap */
5103
4938
UNIV_INTERN
5104
4939
byte*
5105
4940
btr_rec_copy_externally_stored_field(
5129
4964
 
5130
4965
        data = rec_get_nth_field(rec, offsets, no, &local_len);
5131
4966
 
5132
 
        ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
5133
 
 
5134
 
        if (UNIV_UNLIKELY
5135
 
            (!memcmp(data + local_len - BTR_EXTERN_FIELD_REF_SIZE,
5136
 
                     field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) {
5137
 
                /* The externally stored field was not written yet.
5138
 
                This record should only be seen by
5139
 
                recv_recovery_rollback_active() or any
5140
 
                TRX_ISO_READ_UNCOMMITTED transactions. */
5141
 
                return(NULL);
5142
 
        }
5143
 
 
5144
4967
        return(btr_copy_externally_stored_field(len, data,
5145
4968
                                                zip_size, local_len, heap));
5146
4969
}