Commit 5adf2313 authored by Marko Mäkelä's avatar Marko Mäkelä

Bug #55284 diagnostics: Introduce UNIV_BLOB_LIGHT_DEBUG, enabled by UNIV_DEBUG

btr_rec_get_field_ref_offs(), btr_rec_get_field_ref(): New functions.
Get the pointer to an externally stored field.

btr_cur_set_ownership_of_extern_field(): Assert that the BLOB has not
already been disowned.

btr_store_big_rec_extern_fields(): Rename to
btr_store_big_rec_extern_fields_func() and add the debug parameter
update_in_place. All pointers to externally stored columns in the
record must either be zero or they must be pointers to inherited
columns, owned by this record or an earlier record version. For any
BLOB that is stored, the BLOB pointer must previously have been
zero. When the function completes, all BLOB pointers must be nonzero
and owned by the record.

rb://549 approved by Jimmy Yang
parent 7c45708f
...@@ -186,7 +186,7 @@ static ...@@ -186,7 +186,7 @@ static
ulint ulint
btr_rec_get_externally_stored_len( btr_rec_get_externally_stored_len(
/*==============================*/ /*==============================*/
rec_t* rec, /*!< in: record */ const rec_t* rec, /*!< in: record */
const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
...@@ -3483,6 +3483,35 @@ btr_estimate_number_of_different_key_vals( ...@@ -3483,6 +3483,35 @@ btr_estimate_number_of_different_key_vals(
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/ /*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
/***********************************************************//**
Gets the offset of the pointer to the externally stored part of a field.
@return offset of the pointer to the externally stored part */
static
ulint
btr_rec_get_field_ref_offs(
/*=======================*/
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
ulint n) /*!< in: index of the external field */
{
ulint field_ref_offs;
ulint local_len;
ut_a(rec_offs_nth_extern(offsets, n));
field_ref_offs = rec_get_nth_field_offs(offsets, n, &local_len);
ut_a(local_len != UNIV_SQL_NULL);
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
return(field_ref_offs + local_len - BTR_EXTERN_FIELD_REF_SIZE);
}
/** Gets a pointer to the externally stored part of a field.
@param rec record
@param offsets rec_get_offsets(rec)
@param n index of the externally stored field
@return pointer to the externally stored part */
#define btr_rec_get_field_ref(rec, offsets, n) \
((rec) + btr_rec_get_field_ref_offs(offsets, n))
/***********************************************************//** /***********************************************************//**
Gets the externally stored size of a record, in units of a database page. Gets the externally stored size of a record, in units of a database page.
@return externally stored part, in units of a database page */ @return externally stored part, in units of a database page */
...@@ -3490,28 +3519,27 @@ static ...@@ -3490,28 +3519,27 @@ static
ulint ulint
btr_rec_get_externally_stored_len( btr_rec_get_externally_stored_len(
/*==============================*/ /*==============================*/
rec_t* rec, /*!< in: record */ const rec_t* rec, /*!< in: record */
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
{ {
ulint n_fields; ulint n_fields;
byte* data;
ulint local_len;
ulint extern_len;
ulint total_extern_len = 0; ulint total_extern_len = 0;
ulint i; ulint i;
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec)); ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
if (!rec_offs_any_extern(offsets)) {
return(0);
}
n_fields = rec_offs_n_fields(offsets); n_fields = rec_offs_n_fields(offsets);
for (i = 0; i < n_fields; i++) { for (i = 0; i < n_fields; i++) {
if (rec_offs_nth_extern(offsets, i)) { if (rec_offs_nth_extern(offsets, i)) {
data = rec_get_nth_field(rec, offsets, i, &local_len); ulint extern_len = mach_read_from_4(
btr_rec_get_field_ref(rec, offsets, i)
local_len -= BTR_EXTERN_FIELD_REF_SIZE; + BTR_EXTERN_LEN + 4);
extern_len = mach_read_from_4(data + local_len
+ BTR_EXTERN_LEN + 4);
total_extern_len += ut_calc_align(extern_len, total_extern_len += ut_calc_align(extern_len,
UNIV_PAGE_SIZE); UNIV_PAGE_SIZE);
...@@ -3541,7 +3569,7 @@ btr_cur_set_ownership_of_extern_field( ...@@ -3541,7 +3569,7 @@ btr_cur_set_ownership_of_extern_field(
ulint byte_val; ulint byte_val;
data = rec_get_nth_field(rec, offsets, i, &local_len); data = rec_get_nth_field(rec, offsets, i, &local_len);
ut_ad(rec_offs_nth_extern(offsets, i));
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE; local_len -= BTR_EXTERN_FIELD_REF_SIZE;
...@@ -3551,6 +3579,9 @@ btr_cur_set_ownership_of_extern_field( ...@@ -3551,6 +3579,9 @@ btr_cur_set_ownership_of_extern_field(
if (val) { if (val) {
byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG); byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG);
} else { } else {
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ut_a(!(byte_val & BTR_EXTERN_OWNER_FLAG));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
byte_val = byte_val | BTR_EXTERN_OWNER_FLAG; byte_val = byte_val | BTR_EXTERN_OWNER_FLAG;
} }
...@@ -3788,8 +3819,8 @@ file segment of the index tree. ...@@ -3788,8 +3819,8 @@ file segment of the index tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN UNIV_INTERN
ulint ulint
btr_store_big_rec_extern_fields( btr_store_big_rec_extern_fields_func(
/*============================*/ /*=================================*/
dict_index_t* index, /*!< in: index of rec; the index tree dict_index_t* index, /*!< in: index of rec; the index tree
MUST be X-latched */ MUST be X-latched */
buf_block_t* rec_block, /*!< in/out: block containing rec */ buf_block_t* rec_block, /*!< in/out: block containing rec */
...@@ -3798,11 +3829,17 @@ btr_store_big_rec_extern_fields( ...@@ -3798,11 +3829,17 @@ btr_store_big_rec_extern_fields(
the "external storage" flags in offsets the "external storage" flags in offsets
will not correspond to rec when will not correspond to rec when
this function returns */ this function returns */
big_rec_t* big_rec_vec, /*!< in: vector containing fields #ifdef UNIV_DEBUG
mtr_t* local_mtr, /*!< in: mtr containing the
latch to rec and to the tree */
#endif /* UNIV_DEBUG */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ibool update_in_place,/*! in: TRUE if the record is updated
in place (not delete+insert) */
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
const big_rec_t*big_rec_vec) /*!< in: vector containing fields
to be stored externally */ to be stored externally */
mtr_t* local_mtr __attribute__((unused))) /*!< in: mtr
containing the latch to rec and to the
tree */
{ {
ulint rec_page_no; ulint rec_page_no;
byte* field_ref; byte* field_ref;
...@@ -3820,6 +3857,7 @@ btr_store_big_rec_extern_fields( ...@@ -3820,6 +3857,7 @@ btr_store_big_rec_extern_fields(
z_stream c_stream; z_stream c_stream;
ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(rec_offs_any_extern(offsets));
ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
MTR_MEMO_X_LOCK)); MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
...@@ -3851,21 +3889,37 @@ btr_store_big_rec_extern_fields( ...@@ -3851,21 +3889,37 @@ btr_store_big_rec_extern_fields(
ut_a(err == Z_OK); ut_a(err == Z_OK);
} }
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/* All pointers to externally stored columns in the record
must either be zero or they must be pointers to inherited
columns, owned by this record or an earlier record version. */
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
if (!rec_offs_nth_extern(offsets, i)) {
continue;
}
field_ref = btr_rec_get_field_ref(rec, offsets, i);
ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
/* Either this must be an update in place,
or the BLOB must be inherited, or the BLOB pointer
must be zero (will be written in this function). */
ut_a(update_in_place
|| (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
|| !memcmp(field_ref, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE));
}
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
/* We have to create a file segment to the tablespace /* We have to create a file segment to the tablespace
for each field and put the pointer to the field in rec */ for each field and put the pointer to the field in rec */
for (i = 0; i < big_rec_vec->n_fields; i++) { for (i = 0; i < big_rec_vec->n_fields; i++) {
ut_ad(rec_offs_nth_extern(offsets, field_ref = btr_rec_get_field_ref(
big_rec_vec->fields[i].field_no)); rec, offsets, big_rec_vec->fields[i].field_no);
{ #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ulint local_len; /* A zero BLOB pointer should have been initially inserted. */
field_ref = rec_get_nth_field( ut_a(!memcmp(field_ref, field_ref_zero,
rec, offsets, big_rec_vec->fields[i].field_no, BTR_EXTERN_FIELD_REF_SIZE));
&local_len); #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
field_ref += local_len;
}
extern_len = big_rec_vec->fields[i].len; extern_len = big_rec_vec->fields[i].len;
UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data, UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data,
extern_len); extern_len);
...@@ -4147,6 +4201,23 @@ next_zip_page: ...@@ -4147,6 +4201,23 @@ next_zip_page:
mem_heap_free(heap); mem_heap_free(heap);
} }
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/* All pointers to externally stored columns in the record
must be valid. */
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
if (!rec_offs_nth_extern(offsets, i)) {
continue;
}
field_ref = btr_rec_get_field_ref(rec, offsets, i);
/* The pointer must not be zero. */
ut_a(0 != memcmp(field_ref, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE));
/* The column must not be disowned by this record. */
ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
}
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
return(DB_SUCCESS); return(DB_SUCCESS);
} }
...@@ -4228,23 +4299,13 @@ btr_free_externally_stored_field( ...@@ -4228,23 +4299,13 @@ btr_free_externally_stored_field(
ulint page_no; ulint page_no;
ulint next_page_no; ulint next_page_no;
mtr_t mtr; mtr_t mtr;
#ifdef UNIV_DEBUG
ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index), ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
MTR_MEMO_X_LOCK)); MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains_page(local_mtr, field_ref, ut_ad(mtr_memo_contains_page(local_mtr, field_ref,
MTR_MEMO_PAGE_X_FIX)); MTR_MEMO_PAGE_X_FIX));
ut_ad(!rec || rec_offs_validate(rec, index, offsets)); ut_ad(!rec || rec_offs_validate(rec, index, offsets));
ut_ad(!rec || field_ref == btr_rec_get_field_ref(rec, offsets, i));
if (rec) {
ulint local_len;
const byte* f = rec_get_nth_field(rec, offsets,
i, &local_len);
ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
f += local_len;
ut_ad(f == field_ref);
}
#endif /* UNIV_DEBUG */
if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero, if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE))) { BTR_EXTERN_FIELD_REF_SIZE))) {
...@@ -4409,13 +4470,8 @@ btr_rec_free_externally_stored_fields( ...@@ -4409,13 +4470,8 @@ btr_rec_free_externally_stored_fields(
for (i = 0; i < n_fields; i++) { for (i = 0; i < n_fields; i++) {
if (rec_offs_nth_extern(offsets, i)) { if (rec_offs_nth_extern(offsets, i)) {
ulint len;
byte* data
= rec_get_nth_field(rec, offsets, i, &len);
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
btr_free_externally_stored_field( btr_free_externally_stored_field(
index, data + len - BTR_EXTERN_FIELD_REF_SIZE, index, btr_rec_get_field_ref(rec, offsets, i),
rec, offsets, page_zip, i, rb_ctx, mtr); rec, offsets, page_zip, i, rb_ctx, mtr);
} }
} }
......
...@@ -512,8 +512,8 @@ file segment of the index tree. ...@@ -512,8 +512,8 @@ file segment of the index tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN UNIV_INTERN
ulint ulint
btr_store_big_rec_extern_fields( btr_store_big_rec_extern_fields_func(
/*============================*/ /*=================================*/
dict_index_t* index, /*!< in: index of rec; the index tree dict_index_t* index, /*!< in: index of rec; the index tree
MUST be X-latched */ MUST be X-latched */
buf_block_t* rec_block, /*!< in/out: block containing rec */ buf_block_t* rec_block, /*!< in/out: block containing rec */
...@@ -522,10 +522,42 @@ btr_store_big_rec_extern_fields( ...@@ -522,10 +522,42 @@ btr_store_big_rec_extern_fields(
the "external storage" flags in offsets the "external storage" flags in offsets
will not correspond to rec when will not correspond to rec when
this function returns */ this function returns */
big_rec_t* big_rec_vec, /*!< in: vector containing fields #ifdef UNIV_DEBUG
mtr_t* local_mtr, /*!< in: mtr containing the
latch to rec and to the tree */
#endif /* UNIV_DEBUG */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ibool update_in_place,/*! in: TRUE if the record is updated
in place (not delete+insert) */
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
const big_rec_t*big_rec_vec) /*!< in: vector containing fields
to be stored externally */ to be stored externally */
mtr_t* local_mtr); /*!< in: mtr containing the latch to __attribute__((nonnull));
rec and to the tree */
/** Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand.
The fields are stored on pages allocated from leaf node
file segment of the index tree.
@param index in: clustered index; MUST be X-latched by mtr
@param b in/out: block containing rec; MUST be X-latched by mtr
@param rec in/out: clustered index record
@param offsets in: rec_get_offsets(rec, index);
the "external storage" flags in offsets will not be adjusted
@param mtr in: mini-transaction that holds x-latch on index and b
@param upd in: TRUE if the record is updated in place (not delete+insert)
@param big in: vector containing fields to be stored externally
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
#ifdef UNIV_DEBUG
# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big)
#elif defined UNIV_BLOB_LIGHT_DEBUG
# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big)
#else
# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big)
#endif
/*******************************************************************//** /*******************************************************************//**
Frees the space in an externally stored field to the file space Frees the space in an externally stored field to the file space
management if the field in data is owned the externally stored field, management if the field in data is owned the externally stored field,
......
...@@ -177,6 +177,8 @@ command. Not tested on Windows. */ ...@@ -177,6 +177,8 @@ command. Not tested on Windows. */
debugging without UNIV_DEBUG */ debugging without UNIV_DEBUG */
#define UNIV_BUF_DEBUG /* Enable buffer pool #define UNIV_BUF_DEBUG /* Enable buffer pool
debugging without UNIV_DEBUG */ debugging without UNIV_DEBUG */
#define UNIV_BLOB_LIGHT_DEBUG /* Enable off-page column
debugging without UNIV_DEBUG */
#define UNIV_DEBUG /* Enable ut_ad() assertions #define UNIV_DEBUG /* Enable ut_ad() assertions
and disable UNIV_INLINE */ and disable UNIV_INLINE */
#define UNIV_DEBUG_LOCK_VALIDATE /* Enable #define UNIV_DEBUG_LOCK_VALIDATE /* Enable
......
...@@ -2130,7 +2130,7 @@ function_exit: ...@@ -2130,7 +2130,7 @@ function_exit:
err = btr_store_big_rec_extern_fields( err = btr_store_big_rec_extern_fields(
index, btr_cur_get_block(&cursor), index, btr_cur_get_block(&cursor),
rec, offsets, big_rec, &mtr); rec, offsets, &mtr, FALSE, big_rec);
if (modify) { if (modify) {
dtuple_big_rec_free(big_rec); dtuple_big_rec_free(big_rec);
......
...@@ -1952,7 +1952,7 @@ row_upd_clust_rec( ...@@ -1952,7 +1952,7 @@ row_upd_clust_rec(
index, btr_cur_get_block(btr_cur), rec, index, btr_cur_get_block(btr_cur), rec,
rec_get_offsets(rec, index, offsets_, rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap), ULINT_UNDEFINED, &heap),
big_rec, mtr); mtr, TRUE, big_rec);
mtr_commit(mtr); mtr_commit(mtr);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment