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);
2508
2536
btr_cur_del_mark_set_clust_rec(
2509
2537
/*===========================*/
2510
2538
ulint flags, /*!< in: undo logging and locking flags */
2511
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) */
2512
2543
ibool val, /*!< in: value to set */
2513
2544
que_thr_t* thr, /*!< in: query thread */
2514
2545
mtr_t* mtr) /*!< in: mtr */
2516
dict_index_t* index;
2518
2547
roll_ptr_t roll_ptr;
2521
2549
page_zip_des_t* page_zip;
2523
mem_heap_t* heap = NULL;
2524
ulint offsets_[REC_OFFS_NORMAL_SIZE];
2525
ulint* offsets = offsets_;
2526
rec_offs_init(offsets_);
2528
rec = btr_cur_get_rec(cursor);
2529
index = cursor->index;
2552
ut_ad(dict_index_is_clust(index));
2553
ut_ad(rec_offs_validate(rec, index, offsets));
2530
2554
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
2531
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)));
2533
2558
#ifdef UNIV_DEBUG
2534
2559
if (btr_cur_print_record_ops && thr) {
2540
2565
ut_ad(dict_index_is_clust(index));
2541
2566
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
2543
err = lock_clust_rec_modify_check_and_lock(flags,
2544
btr_cur_get_block(cursor),
2568
err = lock_clust_rec_modify_check_and_lock(flags, block,
2545
2569
rec, index, offsets, thr);
2547
2571
if (err != DB_SUCCESS) {
2552
2576
err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
2705
2721
ut_ad(!!page_rec_is_comp(rec)
2706
2722
== dict_table_is_comp(cursor->index->table));
2708
if (block->is_hashed) {
2709
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. */
2712
2727
btr_rec_set_deleted_flag(rec, buf_block_get_page_zip(block), val);
2714
if (block->is_hashed) {
2715
rw_lock_x_unlock(&btr_search_latch);
2718
2729
btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
2720
2731
return(DB_SUCCESS);
3212
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
/*******************************************************************//**
3213
3262
Estimates the number of different key values in a given index, for
3214
3263
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
3215
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. */
3218
3270
btr_estimate_number_of_different_key_vals(
3236
3290
mem_heap_t* heap = NULL;
3237
ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
3238
ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
3239
ulint* offsets_rec = offsets_rec_;
3240
ulint* offsets_next_rec= offsets_next_rec_;
3241
rec_offs_init(offsets_rec_);
3242
rec_offs_init(offsets_next_rec_);
3291
ulint* offsets_rec = NULL;
3292
ulint* offsets_next_rec = NULL;
3244
3294
n_cols = dict_index_get_n_unique(index);
3246
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;
3248
3329
/* It makes no sense to test more pages than are contained
3249
3330
in the index, thus we lower the number if it is too high */
3274
3354
page = btr_cur_get_page(&cursor);
3276
supremum = page_get_supremum_rec(page);
3277
3356
rec = page_rec_get_next(page_get_infimum_rec(page));
3279
if (rec != supremum) {
3358
if (!page_rec_is_supremum(rec)) {
3280
3359
not_empty_flag = 1;
3281
3360
offsets_rec = rec_get_offsets(rec, index, offsets_rec,
3282
3361
ULINT_UNDEFINED, &heap);
3364
btr_record_not_null_field_in_rec(
3365
n_cols, offsets_rec, n_not_null);
3285
while (rec != supremum) {
3369
while (!page_rec_is_supremum(rec)) {
3286
3370
rec_t* next_rec = page_rec_get_next(rec);
3287
if (next_rec == supremum) {
3371
if (page_rec_is_supremum(next_rec)) {
3372
total_external_size +=
3373
btr_rec_get_externally_stored_len(
3384
3470
index->stat_n_diff_key_vals[j] += add_on;
3388
if (UNIV_LIKELY_NULL(heap)) {
3389
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);
3393
3487
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
3395
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
/***********************************************************//**
3396
3519
Gets the externally stored size of a record, in units of a database page.
3397
3520
@return externally stored part, in units of a database page */
3400
3523
btr_rec_get_externally_stored_len(
3401
3524
/*==============================*/
3402
rec_t* rec, /*!< in: record */
3525
const rec_t* rec, /*!< in: record */
3403
3526
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
3405
3528
ulint n_fields;
3409
3529
ulint total_extern_len = 0;
3412
3532
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
3534
if (!rec_offs_any_extern(offsets)) {
3413
3538
n_fields = rec_offs_n_fields(offsets);
3415
3540
for (i = 0; i < n_fields; i++) {
3416
3541
if (rec_offs_nth_extern(offsets, i)) {
3418
data = rec_get_nth_field(rec, offsets, i, &local_len);
3420
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
3422
extern_len = mach_read_from_4(data + local_len
3423
+ 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);
3425
3547
total_extern_len += ut_calc_align(extern_len,
3426
3548
UNIV_PAGE_SIZE);
3474
3599
mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
3602
btr_blob_dbg_owner(rec, index, offsets, i, val);
3478
3605
/*******************************************************************//**
3479
Marks not updated extern fields as not-owned by this record. The ownership
3480
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
3481
3608
index tree. In purge only the owner of externally stored field is allowed
3483
@return TRUE if BLOB ownership was transferred */
3609
to free the field. */
3486
btr_cur_mark_extern_inherited_fields(
3487
/*=================================*/
3612
btr_cur_disown_inherited_fields(
3613
/*============================*/
3488
3614
page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
3489
3615
part will be updated, or NULL */
3490
3616
rec_t* rec, /*!< in/out: record in a clustered index */
3491
3617
dict_index_t* index, /*!< in: index of the page */
3492
3618
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
3493
3619
const upd_t* update, /*!< in: update vector */
3494
mtr_t* mtr) /*!< in: mtr, or NULL if not logged */
3620
mtr_t* mtr) /*!< in/out: mini-transaction */
3499
ibool change_ownership = FALSE;
3501
ut_ad(rec_offs_validate(rec, NULL, offsets));
3624
ut_ad(rec_offs_validate(rec, index, offsets));
3502
3625
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
3504
if (!rec_offs_any_extern(offsets)) {
3509
n = rec_offs_n_fields(offsets);
3511
for (i = 0; i < n; i++) {
3512
if (rec_offs_nth_extern(offsets, i)) {
3514
/* Check it is not in updated fields */
3517
for (j = 0; j < upd_get_n_fields(update);
3519
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)) {
3527
3632
btr_cur_set_ownership_of_extern_field(
3528
3633
page_zip, rec, index, offsets, i, FALSE, mtr);
3530
change_ownership = TRUE;
3536
return(change_ownership);
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);
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;
3875
3929
UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data,
4152
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 */
4155
4236
return(DB_SUCCESS);
4232
4315
ulint next_page_no;
4235
4318
ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
4236
4319
MTR_MEMO_X_LOCK));
4237
4320
ut_ad(mtr_memo_contains_page(local_mtr, field_ref,
4238
4321
MTR_MEMO_PAGE_X_FIX));
4239
4322
ut_ad(!rec || rec_offs_validate(rec, index, offsets));
4243
const byte* f = rec_get_nth_field(rec, offsets,
4245
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
4246
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
4248
ut_ad(f == field_ref);
4250
#endif /* UNIV_DEBUG */
4323
ut_ad(!rec || field_ref == btr_rec_get_field_ref(rec, offsets, i));
4252
4325
if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
4253
4326
BTR_EXTERN_FIELD_REF_SIZE))) {
4279
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 */
4283
4387
#ifdef UNIV_SYNC_DEBUG
4284
4388
buf_block_t* rec_block;
4413
4517
for (i = 0; i < n_fields; i++) {
4414
4518
if (rec_offs_nth_extern(offsets, i)) {
4417
= rec_get_nth_field(rec, offsets, i, &len);
4418
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
4420
4519
btr_free_externally_stored_field(
4421
index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
4520
index, btr_rec_get_field_ref(rec, offsets, i),
4422
4521
rec, offsets, page_zip, i, rb_ctx, mtr);
4531
4630
/*******************************************************************//**
4532
4631
Copies the prefix of a compressed BLOB. The clustered index record
4533
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 */
4536
4636
btr_copy_zblob_prefix(
4537
4637
/*==================*/
4538
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 */
4539
4641
ulint zip_size,/*!< in: compressed BLOB page size */
4540
4642
ulint space_id,/*!< in: space id of the BLOB pages */
4541
4643
ulint page_no,/*!< in: page number of the first BLOB page */
4542
4644
ulint offset) /*!< in: offset on the first BLOB page */
4544
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);
4546
4661
ut_ad(ut_is_2pow(zip_size));
4547
4662
ut_ad(zip_size >= PAGE_ZIP_MIN_SIZE);
4548
4663
ut_ad(zip_size <= UNIV_PAGE_SIZE);
4549
4664
ut_ad(space_id);
4666
err = inflateInit(&d_stream);
4552
4670
buf_page_t* bpage;
4554
4671
ulint next_page_no;
4556
4673
/* There is no latch on bpage directly. Instead,
4681
4804
if (UNIV_UNLIKELY(zip_size)) {
4686
/* Zlib inflate needs 32 kilobytes for the default
4687
window size, plus a few kilobytes for small objects. */
4688
heap = mem_heap_create(40000);
4689
page_zip_set_alloc(&d_stream, heap);
4691
err = inflateInit(&d_stream);
4694
d_stream.next_out = buf;
4695
d_stream.avail_out = len;
4696
d_stream.avail_in = 0;
4698
btr_copy_zblob_prefix(&d_stream, zip_size,
4699
space_id, page_no, offset);
4700
inflateEnd(&d_stream);
4701
mem_heap_free(heap);
4702
UNIV_MEM_ASSERT_RW(buf, d_stream.total_out);
4703
return(d_stream.total_out);
4805
return(btr_copy_zblob_prefix(buf, len, zip_size,
4806
space_id, page_no, offset));
4705
4808
return(btr_copy_blob_prefix(buf, len, space_id,
4706
4809
page_no, offset));