100
100
/*--------------------------------------*/
101
101
#define BTR_BLOB_HDR_SIZE 8 /*!< Size of a BLOB
102
102
part header, in bytes */
104
/** Estimated table level stats from sampled value.
105
@param value sampled stats
106
@param index index being sampled
107
@param sample number of sampled rows
108
@param ext_size external stored data size
109
@param not_empty table not empty
110
@return estimated table wide stats from sampled value */
111
#define BTR_TABLE_STATS_FROM_SAMPLE(value, index, sample, ext_size, not_empty)\
112
(((value) * (ib_int64_t) index->stat_n_leaf_pages \
113
+ (sample) - 1 + (ext_size) + (not_empty)) / ((sample) + (ext_size)))
104
116
#endif /* !UNIV_HOTBACKUP */
280
294
left_page_no = btr_page_get_prev(page, mtr);
282
296
if (left_page_no != FIL_NULL) {
283
get_block = btr_block_get(space, zip_size,
284
left_page_no, mode, mtr);
297
get_block = btr_block_get(
299
left_page_no, mode, cursor->index, mtr);
285
300
cursor->left_block = get_block;
286
301
#ifdef UNIV_BTR_DEBUG
287
302
ut_a(page_is_comp(get_block->frame)
677
697
Opens a cursor at either end of an index. */
680
btr_cur_open_at_index_side(
681
/*=======================*/
700
btr_cur_open_at_index_side_func(
701
/*============================*/
682
702
ibool from_left, /*!< in: TRUE if open to the low end,
683
703
FALSE if to the high end */
684
704
dict_index_t* index, /*!< in: index */
685
705
ulint latch_mode, /*!< in: latch mode */
686
706
btr_cur_t* cursor, /*!< in: cursor */
707
const char* file, /*!< in: file name */
708
ulint line, /*!< in: line where called */
687
709
mtr_t* mtr) /*!< in: mtr */
689
711
page_cur_t* page_cursor;
808
830
Positions a cursor at a randomly chosen position within a B-tree. */
811
btr_cur_open_at_rnd_pos(
812
/*====================*/
833
btr_cur_open_at_rnd_pos_func(
834
/*=========================*/
813
835
dict_index_t* index, /*!< in: index */
814
836
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
815
837
btr_cur_t* cursor, /*!< in/out: B-tree cursor */
838
const char* file, /*!< in: file name */
839
ulint line, /*!< in: line where called */
816
840
mtr_t* mtr) /*!< in: mtr */
818
842
page_cur_t* page_cursor;
1760
if (block->is_hashed) {
1772
if (!(flags & BTR_KEEP_SYS_FLAG)) {
1773
row_upd_rec_sys_fields(rec, NULL,
1774
index, offsets, trx, roll_ptr);
1777
was_delete_marked = rec_get_deleted_flag(
1778
rec, page_is_comp(buf_block_get_frame(block)));
1780
is_hashed = (block->index != NULL);
1783
/* TO DO: Can we skip this if none of the fields
1784
index->search_info->curr_n_fields
1785
are being updated? */
1761
1787
/* The function row_upd_changes_ord_field_binary works only
1762
1788
if the update vector was built for a clustered index, we must
1763
1789
NOT call it if index is secondary */
1765
1791
if (!dict_index_is_clust(index)
1766
|| row_upd_changes_ord_field_binary(NULL, index, update)) {
1792
|| row_upd_changes_ord_field_binary(index, update, thr,
1768
1795
/* Remove possible hash index pointer to this record */
1769
1796
btr_search_update_hash_on_delete(cursor);
1772
1799
rw_lock_x_lock(&btr_search_latch);
1775
if (!(flags & BTR_KEEP_SYS_FLAG)) {
1776
row_upd_rec_sys_fields(rec, NULL,
1777
index, offsets, trx, roll_ptr);
1780
was_delete_marked = rec_get_deleted_flag(
1781
rec, page_is_comp(buf_block_get_frame(block)));
1783
1802
row_upd_rec_in_place(rec, index, offsets, update, page_zip);
1785
if (block->is_hashed) {
1786
1805
rw_lock_x_unlock(&btr_search_latch);
2516
2536
btr_cur_del_mark_set_clust_rec(
2517
2537
/*===========================*/
2518
2538
ulint flags, /*!< in: undo logging and locking flags */
2519
btr_cur_t* cursor, /*!< in: cursor */
2539
buf_block_t* block, /*!< in/out: buffer block of the record */
2540
rec_t* rec, /*!< in/out: record */
2541
dict_index_t* index, /*!< in: clustered index of the record */
2542
const ulint* offsets,/*!< in: rec_get_offsets(rec) */
2520
2543
ibool val, /*!< in: value to set */
2521
2544
que_thr_t* thr, /*!< in: query thread */
2522
2545
mtr_t* mtr) /*!< in: mtr */
2524
dict_index_t* index;
2526
2547
roll_ptr_t roll_ptr;
2529
2549
page_zip_des_t* page_zip;
2531
mem_heap_t* heap = NULL;
2532
ulint offsets_[REC_OFFS_NORMAL_SIZE];
2533
ulint* offsets = offsets_;
2534
rec_offs_init(offsets_);
2536
rec = btr_cur_get_rec(cursor);
2537
index = cursor->index;
2552
ut_ad(dict_index_is_clust(index));
2553
ut_ad(rec_offs_validate(rec, index, offsets));
2538
2554
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
2539
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
2555
ut_ad(buf_block_get_frame(block) == page_align(rec));
2556
ut_ad(page_is_leaf(page_align(rec)));
2541
2558
#ifdef UNIV_DEBUG
2542
2559
if (btr_cur_print_record_ops && thr) {
2548
2565
ut_ad(dict_index_is_clust(index));
2549
2566
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
2551
err = lock_clust_rec_modify_check_and_lock(flags,
2552
btr_cur_get_block(cursor),
2568
err = lock_clust_rec_modify_check_and_lock(flags, block,
2553
2569
rec, index, offsets, thr);
2555
2571
if (err != DB_SUCCESS) {
2560
2576
err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
2563
2579
if (err != DB_SUCCESS) {
2568
block = btr_cur_get_block(cursor);
2570
if (block->is_hashed) {
2571
rw_lock_x_lock(&btr_search_latch);
2584
/* The btr_search_latch is not needed here, because
2585
the adaptive hash index does not depend on the delete-mark
2586
and the delete-mark is being updated in place. */
2574
2588
page_zip = buf_block_get_page_zip(block);
2590
btr_blob_dbg_set_deleted_flag(rec, index, offsets, val);
2576
2591
btr_rec_set_deleted_flag(rec, page_zip, val);
2578
2593
trx = thr_get_trx(thr);
2713
2721
ut_ad(!!page_rec_is_comp(rec)
2714
2722
== dict_table_is_comp(cursor->index->table));
2716
if (block->is_hashed) {
2717
rw_lock_x_lock(&btr_search_latch);
2724
/* We do not need to reserve btr_search_latch, as the
2725
delete-mark flag is being updated in place and the adaptive
2726
hash index does not depend on it. */
2720
2727
btr_rec_set_deleted_flag(rec, buf_block_get_page_zip(block), val);
2722
if (block->is_hashed) {
2723
rw_lock_x_unlock(&btr_search_latch);
2726
2729
btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
2728
2731
return(DB_SUCCESS);
2742
2745
uncompressed */
2743
2746
mtr_t* mtr) /*!< in: mtr */
2745
/* We do not need to reserve btr_search_latch, as the page has just
2746
been read to the buffer pool and there cannot be a hash index to it. */
2748
/* We do not need to reserve btr_search_latch, as the page
2749
has just been read to the buffer pool and there cannot be
2750
a hash index to it. Besides, the delete-mark flag is being
2751
updated in place and the adaptive hash index does not depend
2748
2754
btr_rec_set_deleted_flag(rec, page_zip, FALSE);
3218
3226
/*******************************************************************//**
3227
Record the number of non_null key values in a given index for
3228
each n-column prefix of the index where n < dict_index_get_n_unique(index).
3229
The estimates are eventually stored in the array:
3230
index->stat_n_non_null_key_vals. */
3233
btr_record_not_null_field_in_rec(
3234
/*=============================*/
3235
ulint n_unique, /*!< in: dict_index_get_n_unique(index),
3236
number of columns uniquely determine
3238
const ulint* offsets, /*!< in: rec_get_offsets(rec, index),
3239
its size could be for all fields or
3240
that of "n_unique" */
3241
ib_int64_t* n_not_null) /*!< in/out: array to record number of
3242
not null rows for n-column prefix */
3246
ut_ad(rec_offs_n_fields(offsets) >= n_unique);
3248
if (n_not_null == NULL) {
3252
for (i = 0; i < n_unique; i++) {
3253
if (rec_offs_nth_sql_null(offsets, i)) {
3261
/*******************************************************************//**
3219
3262
Estimates the number of different key values in a given index, for
3220
3263
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
3221
The estimates are stored in the array index->stat_n_diff_key_vals. */
3264
The estimates are stored in the array index->stat_n_diff_key_vals.
3265
If innodb_stats_method is "nulls_ignored", we also record the number of
3266
non-null values for each prefix and store the estimates in
3267
array index->stat_n_non_null_key_vals. */
3224
3270
btr_estimate_number_of_different_key_vals(
3242
3290
mem_heap_t* heap = NULL;
3243
ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
3244
ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
3245
ulint* offsets_rec = offsets_rec_;
3246
ulint* offsets_next_rec= offsets_next_rec_;
3247
rec_offs_init(offsets_rec_);
3248
rec_offs_init(offsets_next_rec_);
3291
ulint* offsets_rec = NULL;
3292
ulint* offsets_next_rec = NULL;
3250
3294
n_cols = dict_index_get_n_unique(index);
3252
n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
3296
heap = mem_heap_create((sizeof *n_diff + sizeof *n_not_null)
3298
+ dict_index_get_n_fields(index)
3299
* (sizeof *offsets_rec
3300
+ sizeof *offsets_next_rec));
3302
n_diff = mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t));
3306
/* Check srv_innodb_stats_method setting, and decide whether we
3307
need to record non-null value and also decide if NULL is
3308
considered equal (by setting stats_null_not_equal value) */
3309
switch (srv_innodb_stats_method) {
3310
case SRV_STATS_NULLS_IGNORED:
3311
n_not_null = mem_heap_zalloc(heap, (n_cols + 1)
3312
* sizeof *n_not_null);
3315
case SRV_STATS_NULLS_UNEQUAL:
3316
/* for both SRV_STATS_NULLS_IGNORED and SRV_STATS_NULLS_UNEQUAL
3317
case, we will treat NULLs as unequal value */
3318
stats_null_not_equal = TRUE;
3321
case SRV_STATS_NULLS_EQUAL:
3322
stats_null_not_equal = FALSE;
3254
3329
/* It makes no sense to test more pages than are contained
3255
3330
in the index, thus we lower the number if it is too high */
3280
3354
page = btr_cur_get_page(&cursor);
3282
supremum = page_get_supremum_rec(page);
3283
3356
rec = page_rec_get_next(page_get_infimum_rec(page));
3285
if (rec != supremum) {
3358
if (!page_rec_is_supremum(rec)) {
3286
3359
not_empty_flag = 1;
3287
3360
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
3288
3361
ULINT_UNDEFINED, &heap);
3364
btr_record_not_null_field_in_rec(
3365
n_cols, offsets_rec, n_not_null);
3291
while (rec != supremum) {
3369
while (!page_rec_is_supremum(rec)) {
3292
3370
rec_t* next_rec = page_rec_get_next(rec);
3293
if (next_rec == supremum) {
3371
if (page_rec_is_supremum(next_rec)) {
3372
total_external_size +=
3373
btr_rec_get_externally_stored_len(
3390
3470
index->stat_n_diff_key_vals[j] += add_on;
3394
if (UNIV_LIKELY_NULL(heap)) {
3395
mem_heap_free(heap);
3472
/* Update the stat_n_non_null_key_vals[] with our
3473
sampled result. stat_n_non_null_key_vals[] is created
3474
and initialized to zero in dict_index_add_to_cache(),
3475
along with stat_n_diff_key_vals[] array */
3476
if (n_not_null != NULL && (j < n_cols)) {
3477
index->stat_n_non_null_key_vals[j] =
3478
BTR_TABLE_STATS_FROM_SAMPLE(
3479
n_not_null[j], index, n_sample_pages,
3480
total_external_size, not_empty_flag);
3484
mem_heap_free(heap);
3399
3487
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
3401
3489
/***********************************************************//**
3490
Gets the offset of the pointer to the externally stored part of a field.
3491
@return offset of the pointer to the externally stored part */
3494
btr_rec_get_field_ref_offs(
3495
/*=======================*/
3496
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
3497
ulint n) /*!< in: index of the external field */
3499
ulint field_ref_offs;
3502
ut_a(rec_offs_nth_extern(offsets, n));
3503
field_ref_offs = rec_get_nth_field_offs(offsets, n, &local_len);
3504
ut_a(local_len != UNIV_SQL_NULL);
3505
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
3507
return(field_ref_offs + local_len - BTR_EXTERN_FIELD_REF_SIZE);
3510
/** Gets a pointer to the externally stored part of a field.
3512
@param offsets rec_get_offsets(rec)
3513
@param n index of the externally stored field
3514
@return pointer to the externally stored part */
3515
#define btr_rec_get_field_ref(rec, offsets, n) \
3516
((rec) + btr_rec_get_field_ref_offs(offsets, n))
3518
/***********************************************************//**
3402
3519
Gets the externally stored size of a record, in units of a database page.
3403
3520
@return externally stored part, in units of a database page */
3406
3523
btr_rec_get_externally_stored_len(
3407
3524
/*==============================*/
3408
rec_t* rec, /*!< in: record */
3525
const rec_t* rec, /*!< in: record */
3409
3526
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
3411
3528
ulint n_fields;
3415
3529
ulint total_extern_len = 0;
3418
3532
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
3534
if (!rec_offs_any_extern(offsets)) {
3419
3538
n_fields = rec_offs_n_fields(offsets);
3421
3540
for (i = 0; i < n_fields; i++) {
3422
3541
if (rec_offs_nth_extern(offsets, i)) {
3424
data = rec_get_nth_field(rec, offsets, i, &local_len);
3426
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
3428
extern_len = mach_read_from_4(data + local_len
3429
+ BTR_EXTERN_LEN + 4);
3543
ulint extern_len = mach_read_from_4(
3544
btr_rec_get_field_ref(rec, offsets, i)
3545
+ BTR_EXTERN_LEN + 4);
3431
3547
total_extern_len += ut_calc_align(extern_len,
3432
3548
UNIV_PAGE_SIZE);
3480
3599
mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
3602
btr_blob_dbg_owner(rec, index, offsets, i, val);
3484
3605
/*******************************************************************//**
3485
Marks not updated extern fields as not-owned by this record. The ownership
3486
is transferred to the updated record which is inserted elsewhere in the
3606
Marks non-updated off-page fields as disowned by this record. The ownership
3607
must be transferred to the updated record which is inserted elsewhere in the
3487
3608
index tree. In purge only the owner of externally stored field is allowed
3488
3609
to free the field. */
3491
btr_cur_mark_extern_inherited_fields(
3492
/*=================================*/
3612
btr_cur_disown_inherited_fields(
3613
/*============================*/
3493
3614
page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
3494
3615
part will be updated, or NULL */
3495
3616
rec_t* rec, /*!< in/out: record in a clustered index */
3496
3617
dict_index_t* index, /*!< in: index of the page */
3497
3618
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
3498
3619
const upd_t* update, /*!< in: update vector */
3499
mtr_t* mtr) /*!< in: mtr, or NULL if not logged */
3620
mtr_t* mtr) /*!< in/out: mini-transaction */
3505
ut_ad(rec_offs_validate(rec, NULL, offsets));
3624
ut_ad(rec_offs_validate(rec, index, offsets));
3506
3625
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
3508
if (!rec_offs_any_extern(offsets)) {
3513
n = rec_offs_n_fields(offsets);
3515
for (i = 0; i < n; i++) {
3516
if (rec_offs_nth_extern(offsets, i)) {
3518
/* Check it is not in updated fields */
3521
for (j = 0; j < upd_get_n_fields(update);
3523
if (upd_get_nth_field(update, j)
3626
ut_ad(rec_offs_any_extern(offsets));
3629
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
3630
if (rec_offs_nth_extern(offsets, i)
3631
&& !upd_get_field_by_field_no(update, i)) {
3531
3632
btr_cur_set_ownership_of_extern_field(
3532
3633
page_zip, rec, index, offsets, i, FALSE, mtr);
3539
/*******************************************************************//**
3540
The complement of the previous function: in an update entry may inherit
3541
some externally stored fields from a record. We must mark them as inherited
3542
in entry, so that they are not freed in a rollback. */
3545
btr_cur_mark_dtuple_inherited_extern(
3546
/*=================================*/
3547
dtuple_t* entry, /*!< in/out: updated entry to be
3548
inserted to clustered index */
3549
const upd_t* update) /*!< in: update vector */
3553
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
3555
dfield_t* dfield = dtuple_get_nth_field(entry, i);
3560
if (!dfield_is_ext(dfield)) {
3564
/* Check if it is in updated fields */
3566
for (j = 0; j < upd_get_n_fields(update); j++) {
3567
if (upd_get_nth_field(update, j)->field_no == i) {
3573
data = dfield_get_data(dfield);
3574
len = dfield_get_len(dfield);
3575
data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
3576
|= BTR_EXTERN_INHERITED_FLAG;
3618
3673
/*******************************************************************//**
3619
Marks all extern fields in a dtuple as owned by the record. */
3622
btr_cur_unmark_dtuple_extern_fields(
3623
/*================================*/
3624
dtuple_t* entry) /*!< in/out: clustered index entry */
3628
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
3629
dfield_t* dfield = dtuple_get_nth_field(entry, i);
3631
if (dfield_is_ext(dfield)) {
3632
byte* data = dfield_get_data(dfield);
3633
ulint len = dfield_get_len(dfield);
3635
data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
3636
&= ~BTR_EXTERN_OWNER_FLAG;
3641
/*******************************************************************//**
3642
3674
Flags the data tuple fields that are marked as extern storage in the
3643
3675
update vector. We use this function to remember which fields we must
3644
3676
mark as extern storage in a record inserted for an update.
3771
3803
&& buf_block_get_space(block) == space
3772
3804
&& buf_block_get_page_no(block) == page_no) {
3774
if (buf_LRU_free_block(&block->page, all, NULL)
3806
if (!buf_LRU_free_block(&block->page, all)
3776
3807
&& all && block->page.zip.data) {
3777
3808
/* Attempt to deallocate the uncompressed page
3778
3809
if the whole block cannot be deallocted. */
3780
buf_LRU_free_block(&block->page, FALSE, NULL);
3811
buf_LRU_free_block(&block->page, FALSE);
3790
3821
them in rec. The extern flags in rec will have to be set beforehand.
3791
3822
The fields are stored on pages allocated from leaf node
3792
3823
file segment of the index tree.
3793
@return DB_SUCCESS or error */
3824
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
3796
btr_store_big_rec_extern_fields(
3797
/*============================*/
3827
btr_store_big_rec_extern_fields_func(
3828
/*=================================*/
3798
3829
dict_index_t* index, /*!< in: index of rec; the index tree
3799
3830
MUST be X-latched */
3800
3831
buf_block_t* rec_block, /*!< in/out: block containing rec */
3803
3834
the "external storage" flags in offsets
3804
3835
will not correspond to rec when
3805
3836
this function returns */
3806
big_rec_t* big_rec_vec, /*!< in: vector containing fields
3838
mtr_t* local_mtr, /*!< in: mtr containing the
3839
latch to rec and to the tree */
3840
#endif /* UNIV_DEBUG */
3841
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
3842
ibool update_in_place,/*! in: TRUE if the record is updated
3843
in place (not delete+insert) */
3844
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
3845
const big_rec_t*big_rec_vec) /*!< in: vector containing fields
3807
3846
to be stored externally */
3808
mtr_t* local_mtr __attribute__((unused))) /*!< in: mtr
3809
containing the latch to rec and to the
3812
3849
ulint rec_page_no;
3813
3850
byte* field_ref;
3856
3894
ut_a(err == Z_OK);
3897
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
3898
/* All pointers to externally stored columns in the record
3899
must either be zero or they must be pointers to inherited
3900
columns, owned by this record or an earlier record version. */
3901
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
3902
if (!rec_offs_nth_extern(offsets, i)) {
3905
field_ref = btr_rec_get_field_ref(rec, offsets, i);
3907
ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
3908
/* Either this must be an update in place,
3909
or the BLOB must be inherited, or the BLOB pointer
3910
must be zero (will be written in this function). */
3911
ut_a(update_in_place
3912
|| (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
3913
|| !memcmp(field_ref, field_ref_zero,
3914
BTR_EXTERN_FIELD_REF_SIZE));
3916
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
3859
3917
/* We have to create a file segment to the tablespace
3860
3918
for each field and put the pointer to the field in rec */
3862
3920
for (i = 0; i < big_rec_vec->n_fields; i++) {
3863
ut_ad(rec_offs_nth_extern(offsets,
3864
big_rec_vec->fields[i].field_no));
3867
field_ref = rec_get_nth_field(
3868
rec, offsets, big_rec_vec->fields[i].field_no,
3870
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
3871
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
3872
field_ref += local_len;
3921
field_ref = btr_rec_get_field_ref(
3922
rec, offsets, big_rec_vec->fields[i].field_no);
3923
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
3924
/* A zero BLOB pointer should have been initially inserted. */
3925
ut_a(!memcmp(field_ref, field_ref_zero,
3926
BTR_EXTERN_FIELD_REF_SIZE));
3927
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
3874
3928
extern_len = big_rec_vec->fields[i].len;
3929
UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data,
3876
3932
ut_a(extern_len > 0);
4150
4216
mem_heap_free(heap);
4219
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
4220
/* All pointers to externally stored columns in the record
4222
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
4223
if (!rec_offs_nth_extern(offsets, i)) {
4227
field_ref = btr_rec_get_field_ref(rec, offsets, i);
4229
/* The pointer must not be zero. */
4230
ut_a(0 != memcmp(field_ref, field_ref_zero,
4231
BTR_EXTERN_FIELD_REF_SIZE));
4232
/* The column must not be disowned by this record. */
4233
ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
4235
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
4153
4236
return(DB_SUCCESS);
4230
4315
ulint next_page_no;
4233
4318
ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
4234
4319
MTR_MEMO_X_LOCK));
4235
4320
ut_ad(mtr_memo_contains_page(local_mtr, field_ref,
4236
4321
MTR_MEMO_PAGE_X_FIX));
4237
4322
ut_ad(!rec || rec_offs_validate(rec, index, offsets));
4241
const byte* f = rec_get_nth_field(rec, offsets,
4243
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
4244
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
4246
ut_ad(f == field_ref);
4248
#endif /* UNIV_DEBUG */
4323
ut_ad(!rec || field_ref == btr_rec_get_field_ref(rec, offsets, i));
4250
4325
if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
4251
4326
BTR_EXTERN_FIELD_REF_SIZE))) {
4252
4327
/* In the rollback of uncommitted transactions, we may
4253
4328
encounter a clustered index record whose BLOBs have
4254
4329
not been written. There is nothing to free then. */
4255
ut_a(rb_ctx == RB_RECOVERY);
4330
ut_a(rb_ctx == RB_RECOVERY || rb_ctx == RB_RECOVERY_PURGE_REC);
4277
4352
rec_zip_size = 0;
4355
#ifdef UNIV_BLOB_DEBUG
4356
if (!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG)
4357
&& !((field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
4358
&& (rb_ctx == RB_NORMAL || rb_ctx == RB_RECOVERY))) {
4359
/* This off-page column will be freed.
4360
Check that no references remain. */
4364
b.blob_page_no = mach_read_from_4(
4365
field_ref + BTR_EXTERN_PAGE_NO);
4368
/* Remove the reference from the record to the
4369
BLOB. If the BLOB were not freed, the
4370
reference would be removed when the record is
4371
removed. Freeing the BLOB will overwrite the
4372
BTR_EXTERN_PAGE_NO in the field_ref of the
4373
record with FIL_NULL, which would make the
4374
btr_blob_dbg information inconsistent with the
4376
b.ref_page_no = page_get_page_no(page_align(rec));
4377
b.ref_heap_no = page_rec_get_heap_no(rec);
4379
btr_blob_dbg_rbt_delete(index, &b, "free");
4382
btr_blob_dbg_assert_empty(index, b.blob_page_no);
4384
#endif /* UNIV_BLOB_DEBUG */
4387
#ifdef UNIV_SYNC_DEBUG
4281
4388
buf_block_t* rec_block;
4389
#endif /* UNIV_SYNC_DEBUG */
4282
4390
buf_block_t* ext_block;
4284
4392
mtr_start(&mtr);
4286
rec_block = buf_page_get(page_get_space_id(
4394
#ifdef UNIV_SYNC_DEBUG
4396
#endif /* UNIV_SYNC_DEBUG */
4397
buf_page_get(page_get_space_id(
4287
4398
page_align(field_ref)),
4289
4400
page_get_page_no(
4406
4517
for (i = 0; i < n_fields; i++) {
4407
4518
if (rec_offs_nth_extern(offsets, i)) {
4410
= rec_get_nth_field(rec, offsets, i, &len);
4411
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
4413
4519
btr_free_externally_stored_field(
4414
index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
4520
index, btr_rec_get_field_ref(rec, offsets, i),
4415
4521
rec, offsets, page_zip, i, rb_ctx, mtr);
4523
4630
/*******************************************************************//**
4524
4631
Copies the prefix of a compressed BLOB. The clustered index record
4525
that points to this BLOB must be protected by a lock or a page latch. */
4632
that points to this BLOB must be protected by a lock or a page latch.
4633
@return number of bytes written to buf */
4528
4636
btr_copy_zblob_prefix(
4529
4637
/*==================*/
4530
z_stream* d_stream,/*!< in/out: the decompressing stream */
4638
byte* buf, /*!< out: the externally stored part of
4639
the field, or a prefix of it */
4640
ulint len, /*!< in: length of buf, in bytes */
4531
4641
ulint zip_size,/*!< in: compressed BLOB page size */
4532
4642
ulint space_id,/*!< in: space id of the BLOB pages */
4533
4643
ulint page_no,/*!< in: page number of the first BLOB page */
4534
4644
ulint offset) /*!< in: offset on the first BLOB page */
4536
ulint page_type = FIL_PAGE_TYPE_ZBLOB;
4646
ulint page_type = FIL_PAGE_TYPE_ZBLOB;
4651
d_stream.next_out = buf;
4652
d_stream.avail_out = len;
4653
d_stream.next_in = Z_NULL;
4654
d_stream.avail_in = 0;
4656
/* Zlib inflate needs 32 kilobytes for the default
4657
window size, plus a few kilobytes for small objects. */
4658
heap = mem_heap_create(40000);
4659
page_zip_set_alloc(&d_stream, heap);
4538
4661
ut_ad(ut_is_2pow(zip_size));
4539
4662
ut_ad(zip_size >= PAGE_ZIP_MIN_SIZE);
4540
4663
ut_ad(zip_size <= UNIV_PAGE_SIZE);
4541
4664
ut_ad(space_id);
4666
err = inflateInit(&d_stream);
4544
4670
buf_page_t* bpage;
4546
4671
ulint next_page_no;
4548
4673
/* There is no latch on bpage directly. Instead,
4673
4804
if (UNIV_UNLIKELY(zip_size)) {
4678
/* Zlib inflate needs 32 kilobytes for the default
4679
window size, plus a few kilobytes for small objects. */
4680
heap = mem_heap_create(40000);
4681
page_zip_set_alloc(&d_stream, heap);
4683
err = inflateInit(&d_stream);
4686
d_stream.next_out = buf;
4687
d_stream.avail_out = len;
4688
d_stream.avail_in = 0;
4690
btr_copy_zblob_prefix(&d_stream, zip_size,
4691
space_id, page_no, offset);
4692
inflateEnd(&d_stream);
4693
mem_heap_free(heap);
4694
return(d_stream.total_out);
4805
return(btr_copy_zblob_prefix(buf, len, zip_size,
4806
space_id, page_no, offset));
4696
4808
return(btr_copy_blob_prefix(buf, len, space_id,
4697
4809
page_no, offset));
4842
4954
data = rec_get_nth_field(rec, offsets, no, &local_len);
4956
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
4959
(!memcmp(data + local_len - BTR_EXTERN_FIELD_REF_SIZE,
4960
field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) {
4961
/* The externally stored field was not written yet.
4962
This record should only be seen by
4963
recv_recovery_rollback_active() or any
4964
TRX_ISO_READ_UNCOMMITTED transactions. */
4844
4968
return(btr_copy_externally_stored_field(len, data,
4845
4969
zip_size, local_len, heap));