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)
1753
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? */
1754
1787
/* The function row_upd_changes_ord_field_binary works only
1755
1788
if the update vector was built for a clustered index, we must
1756
1789
NOT call it if index is secondary */
1758
1791
if (!dict_index_is_clust(index)
1759
|| row_upd_changes_ord_field_binary(NULL, index, update)) {
1792
|| row_upd_changes_ord_field_binary(index, update, thr,
1761
1795
/* Remove possible hash index pointer to this record */
1762
1796
btr_search_update_hash_on_delete(cursor);
1765
1799
rw_lock_x_lock(&btr_search_latch);
1768
if (!(flags & BTR_KEEP_SYS_FLAG)) {
1769
row_upd_rec_sys_fields(rec, NULL,
1770
index, offsets, trx, roll_ptr);
1773
was_delete_marked = rec_get_deleted_flag(
1774
rec, page_is_comp(buf_block_get_frame(block)));
1776
1802
row_upd_rec_in_place(rec, index, offsets, update, page_zip);
1778
if (block->is_hashed) {
1779
1805
rw_lock_x_unlock(&btr_search_latch);
2509
2536
btr_cur_del_mark_set_clust_rec(
2510
2537
/*===========================*/
2511
2538
ulint flags, /*!< in: undo logging and locking flags */
2512
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) */
2513
2543
ibool val, /*!< in: value to set */
2514
2544
que_thr_t* thr, /*!< in: query thread */
2515
2545
mtr_t* mtr) /*!< in: mtr */
2517
dict_index_t* index;
2519
2547
roll_ptr_t roll_ptr;
2522
2549
page_zip_des_t* page_zip;
2524
mem_heap_t* heap = NULL;
2525
ulint offsets_[REC_OFFS_NORMAL_SIZE];
2526
ulint* offsets = offsets_;
2527
rec_offs_init(offsets_);
2529
rec = btr_cur_get_rec(cursor);
2530
index = cursor->index;
2552
ut_ad(dict_index_is_clust(index));
2553
ut_ad(rec_offs_validate(rec, index, offsets));
2531
2554
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
2532
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)));
2534
2558
#ifdef UNIV_DEBUG
2535
2559
if (btr_cur_print_record_ops && thr) {
2541
2565
ut_ad(dict_index_is_clust(index));
2542
2566
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
2544
err = lock_clust_rec_modify_check_and_lock(flags,
2545
btr_cur_get_block(cursor),
2568
err = lock_clust_rec_modify_check_and_lock(flags, block,
2546
2569
rec, index, offsets, thr);
2548
2571
if (err != DB_SUCCESS) {
2553
2576
err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
2556
2579
if (err != DB_SUCCESS) {
2561
block = btr_cur_get_block(cursor);
2563
if (block->is_hashed) {
2564
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. */
2567
2588
page_zip = buf_block_get_page_zip(block);
2590
btr_blob_dbg_set_deleted_flag(rec, index, offsets, val);
2569
2591
btr_rec_set_deleted_flag(rec, page_zip, val);
2571
2593
trx = thr_get_trx(thr);
2706
2721
ut_ad(!!page_rec_is_comp(rec)
2707
2722
== dict_table_is_comp(cursor->index->table));
2709
if (block->is_hashed) {
2710
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. */
2713
2727
btr_rec_set_deleted_flag(rec, buf_block_get_page_zip(block), val);
2715
if (block->is_hashed) {
2716
rw_lock_x_unlock(&btr_search_latch);
2719
2729
btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
2721
2731
return(DB_SUCCESS);
2735
2745
uncompressed */
2736
2746
mtr_t* mtr) /*!< in: mtr */
2738
/* We do not need to reserve btr_search_latch, as the page has just
2739
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
2741
2754
btr_rec_set_deleted_flag(rec, page_zip, FALSE);
3213
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
/*******************************************************************//**
3214
3262
Estimates the number of different key values in a given index, for
3215
3263
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
3216
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. */
3219
3270
btr_estimate_number_of_different_key_vals(
3237
3290
mem_heap_t* heap = NULL;
3238
ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
3239
ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
3240
ulint* offsets_rec = offsets_rec_;
3241
ulint* offsets_next_rec= offsets_next_rec_;
3242
rec_offs_init(offsets_rec_);
3243
rec_offs_init(offsets_next_rec_);
3291
ulint* offsets_rec = NULL;
3292
ulint* offsets_next_rec = NULL;
3245
3294
n_cols = dict_index_get_n_unique(index);
3247
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;
3249
3329
/* It makes no sense to test more pages than are contained
3250
3330
in the index, thus we lower the number if it is too high */
3275
3354
page = btr_cur_get_page(&cursor);
3277
supremum = page_get_supremum_rec(page);
3278
3356
rec = page_rec_get_next(page_get_infimum_rec(page));
3280
if (rec != supremum) {
3358
if (!page_rec_is_supremum(rec)) {
3281
3359
not_empty_flag = 1;
3282
3360
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
3283
3361
ULINT_UNDEFINED, &heap);
3364
btr_record_not_null_field_in_rec(
3365
n_cols, offsets_rec, n_not_null);
3286
while (rec != supremum) {
3369
while (!page_rec_is_supremum(rec)) {
3287
3370
rec_t* next_rec = page_rec_get_next(rec);
3288
if (next_rec == supremum) {
3371
if (page_rec_is_supremum(next_rec)) {
3372
total_external_size +=
3373
btr_rec_get_externally_stored_len(
3356
3445
also the pages used for external storage of fields (those pages are
3357
3446
included in index->stat_n_leaf_pages) */
3359
dict_index_stat_mutex_enter(index);
3361
3448
for (j = 0; j <= n_cols; j++) {
3362
3449
index->stat_n_diff_key_vals[j]
3364
* (ib_int64_t)index->stat_n_leaf_pages
3365
+ n_sample_pages - 1
3366
+ total_external_size
3369
+ total_external_size));
3450
= BTR_TABLE_STATS_FROM_SAMPLE(
3451
n_diff[j], index, n_sample_pages,
3452
total_external_size, not_empty_flag);
3371
3454
/* If the tree is small, smaller than
3372
3455
10 * n_sample_pages + total_external_size, then
3387
3470
index->stat_n_diff_key_vals[j] += add_on;
3390
dict_index_stat_mutex_exit(index);
3393
if (UNIV_LIKELY_NULL(heap)) {
3394
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);
3398
3487
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
3400
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
/***********************************************************//**
3401
3519
Gets the externally stored size of a record, in units of a database page.
3402
3520
@return externally stored part, in units of a database page */
3405
3523
btr_rec_get_externally_stored_len(
3406
3524
/*==============================*/
3407
rec_t* rec, /*!< in: record */
3525
const rec_t* rec, /*!< in: record */
3408
3526
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
3410
3528
ulint n_fields;
3414
3529
ulint total_extern_len = 0;
3417
3532
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
3534
if (!rec_offs_any_extern(offsets)) {
3418
3538
n_fields = rec_offs_n_fields(offsets);
3420
3540
for (i = 0; i < n_fields; i++) {
3421
3541
if (rec_offs_nth_extern(offsets, i)) {
3423
data = rec_get_nth_field(rec, offsets, i, &local_len);
3425
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
3427
extern_len = mach_read_from_4(data + local_len
3428
+ 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);
3430
3547
total_extern_len += ut_calc_align(extern_len,
3431
3548
UNIV_PAGE_SIZE);
3479
3599
mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
3602
btr_blob_dbg_owner(rec, index, offsets, i, val);
3483
3605
/*******************************************************************//**
3484
Marks not updated extern fields as not-owned by this record. The ownership
3485
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
3486
3608
index tree. In purge only the owner of externally stored field is allowed
3487
3609
to free the field. */
3490
btr_cur_mark_extern_inherited_fields(
3491
/*=================================*/
3612
btr_cur_disown_inherited_fields(
3613
/*============================*/
3492
3614
page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
3493
3615
part will be updated, or NULL */
3494
3616
rec_t* rec, /*!< in/out: record in a clustered index */
3495
3617
dict_index_t* index, /*!< in: index of the page */
3496
3618
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
3497
3619
const upd_t* update, /*!< in: update vector */
3498
mtr_t* mtr) /*!< in: mtr, or NULL if not logged */
3620
mtr_t* mtr) /*!< in/out: mini-transaction */
3504
ut_ad(rec_offs_validate(rec, NULL, offsets));
3624
ut_ad(rec_offs_validate(rec, index, offsets));
3505
3625
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
3507
if (!rec_offs_any_extern(offsets)) {
3512
n = rec_offs_n_fields(offsets);
3514
for (i = 0; i < n; i++) {
3515
if (rec_offs_nth_extern(offsets, i)) {
3517
/* Check it is not in updated fields */
3520
for (j = 0; j < upd_get_n_fields(update);
3522
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)) {
3530
3632
btr_cur_set_ownership_of_extern_field(
3531
3633
page_zip, rec, index, offsets, i, FALSE, mtr);
3538
/*******************************************************************//**
3539
The complement of the previous function: in an update entry may inherit
3540
some externally stored fields from a record. We must mark them as inherited
3541
in entry, so that they are not freed in a rollback. */
3544
btr_cur_mark_dtuple_inherited_extern(
3545
/*=================================*/
3546
dtuple_t* entry, /*!< in/out: updated entry to be
3547
inserted to clustered index */
3548
const upd_t* update) /*!< in: update vector */
3552
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
3554
dfield_t* dfield = dtuple_get_nth_field(entry, i);
3559
if (!dfield_is_ext(dfield)) {
3563
/* Check if it is in updated fields */
3565
for (j = 0; j < upd_get_n_fields(update); j++) {
3566
if (upd_get_nth_field(update, j)->field_no == i) {
3572
data = dfield_get_data(dfield);
3573
len = dfield_get_len(dfield);
3574
data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
3575
|= BTR_EXTERN_INHERITED_FLAG;
3617
3673
/*******************************************************************//**
3618
Marks all extern fields in a dtuple as owned by the record. */
3621
btr_cur_unmark_dtuple_extern_fields(
3622
/*================================*/
3623
dtuple_t* entry) /*!< in/out: clustered index entry */
3627
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
3628
dfield_t* dfield = dtuple_get_nth_field(entry, i);
3630
if (dfield_is_ext(dfield)) {
3631
byte* data = dfield_get_data(dfield);
3632
ulint len = dfield_get_len(dfield);
3634
data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
3635
&= ~BTR_EXTERN_OWNER_FLAG;
3640
/*******************************************************************//**
3641
3674
Flags the data tuple fields that are marked as extern storage in the
3642
3675
update vector. We use this function to remember which fields we must
3643
3676
mark as extern storage in a record inserted for an update.
3770
3803
&& buf_block_get_space(block) == space
3771
3804
&& buf_block_get_page_no(block) == page_no) {
3773
if (buf_LRU_free_block(&block->page, all, NULL)
3806
if (!buf_LRU_free_block(&block->page, all)
3775
3807
&& all && block->page.zip.data) {
3776
3808
/* Attempt to deallocate the uncompressed page
3777
3809
if the whole block cannot be deallocted. */
3779
buf_LRU_free_block(&block->page, FALSE, NULL);
3811
buf_LRU_free_block(&block->page, FALSE);
3789
3821
them in rec. The extern flags in rec will have to be set beforehand.
3790
3822
The fields are stored on pages allocated from leaf node
3791
3823
file segment of the index tree.
3792
@return DB_SUCCESS or error */
3824
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
3795
btr_store_big_rec_extern_fields(
3796
/*============================*/
3827
btr_store_big_rec_extern_fields_func(
3828
/*=================================*/
3797
3829
dict_index_t* index, /*!< in: index of rec; the index tree
3798
3830
MUST be X-latched */
3799
3831
buf_block_t* rec_block, /*!< in/out: block containing rec */
3802
3834
the "external storage" flags in offsets
3803
3835
will not correspond to rec when
3804
3836
this function returns */
3805
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
3806
3846
to be stored externally */
3807
mtr_t* local_mtr __attribute__((unused))) /*!< in: mtr
3808
containing the latch to rec and to the
3811
3849
ulint rec_page_no;
3812
3850
byte* field_ref;
3855
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 */
3858
3917
/* We have to create a file segment to the tablespace
3859
3918
for each field and put the pointer to the field in rec */
3861
3920
for (i = 0; i < big_rec_vec->n_fields; i++) {
3862
ut_ad(rec_offs_nth_extern(offsets,
3863
big_rec_vec->fields[i].field_no));
3866
field_ref = rec_get_nth_field(
3867
rec, offsets, big_rec_vec->fields[i].field_no,
3869
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
3870
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
3871
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 */
3873
3928
extern_len = big_rec_vec->fields[i].len;
3874
3929
UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data,
4151
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 */
4154
4236
return(DB_SUCCESS);
4231
4315
ulint next_page_no;
4234
4318
ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
4235
4319
MTR_MEMO_X_LOCK));
4236
4320
ut_ad(mtr_memo_contains_page(local_mtr, field_ref,
4237
4321
MTR_MEMO_PAGE_X_FIX));
4238
4322
ut_ad(!rec || rec_offs_validate(rec, index, offsets));
4242
const byte* f = rec_get_nth_field(rec, offsets,
4244
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
4245
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
4247
ut_ad(f == field_ref);
4249
#endif /* UNIV_DEBUG */
4323
ut_ad(!rec || field_ref == btr_rec_get_field_ref(rec, offsets, i));
4251
4325
if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
4252
4326
BTR_EXTERN_FIELD_REF_SIZE))) {
4278
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
4282
4388
buf_block_t* rec_block;
4389
#endif /* UNIV_SYNC_DEBUG */
4283
4390
buf_block_t* ext_block;
4285
4392
mtr_start(&mtr);
4287
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(
4288
4398
page_align(field_ref)),
4290
4400
page_get_page_no(
4407
4517
for (i = 0; i < n_fields; i++) {
4408
4518
if (rec_offs_nth_extern(offsets, i)) {
4411
= rec_get_nth_field(rec, offsets, i, &len);
4412
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
4414
4519
btr_free_externally_stored_field(
4415
index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
4520
index, btr_rec_get_field_ref(rec, offsets, i),
4416
4521
rec, offsets, page_zip, i, rb_ctx, mtr);
4525
4630
/*******************************************************************//**
4526
4631
Copies the prefix of a compressed BLOB. The clustered index record
4527
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 */
4530
4636
btr_copy_zblob_prefix(
4531
4637
/*==================*/
4532
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 */
4533
4641
ulint zip_size,/*!< in: compressed BLOB page size */
4534
4642
ulint space_id,/*!< in: space id of the BLOB pages */
4535
4643
ulint page_no,/*!< in: page number of the first BLOB page */
4536
4644
ulint offset) /*!< in: offset on the first BLOB page */
4538
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);
4540
4661
ut_ad(ut_is_2pow(zip_size));
4541
4662
ut_ad(zip_size >= PAGE_ZIP_MIN_SIZE);
4542
4663
ut_ad(zip_size <= UNIV_PAGE_SIZE);
4543
4664
ut_ad(space_id);
4666
err = inflateInit(&d_stream);
4546
4670
buf_page_t* bpage;
4548
4671
ulint next_page_no;
4550
4673
/* There is no latch on bpage directly. Instead,
4675
4804
if (UNIV_UNLIKELY(zip_size)) {
4680
/* Zlib inflate needs 32 kilobytes for the default
4681
window size, plus a few kilobytes for small objects. */
4682
heap = mem_heap_create(40000);
4683
page_zip_set_alloc(&d_stream, heap);
4685
err = inflateInit(&d_stream);
4688
d_stream.next_out = buf;
4689
d_stream.avail_out = len;
4690
d_stream.avail_in = 0;
4692
btr_copy_zblob_prefix(&d_stream, zip_size,
4693
space_id, page_no, offset);
4694
inflateEnd(&d_stream);
4695
mem_heap_free(heap);
4696
UNIV_MEM_ASSERT_RW(buf, d_stream.total_out);
4697
return(d_stream.total_out);
4805
return(btr_copy_zblob_prefix(buf, len, zip_size,
4806
space_id, page_no, offset));
4699
4808
return(btr_copy_blob_prefix(buf, len, space_id,
4700
4809
page_no, offset));
4845
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. */
4847
4968
return(btr_copy_externally_stored_field(len, data,
4848
4969
zip_size, local_len, heap));