Commit 154fc1e3 authored by Marko Mäkelä's avatar Marko Mäkelä

Implement UNIV_BLOB_DEBUG. An early version of this caught Bug #55284.

This option is known to be broken when tablespaces contain off-page
columns after crash recovery. It has only been tested when creating
the data files from the scratch.

btr_blob_dbg_t: A map from page_no:heap_no:field_no to first_blob_page_no.
This map is instantiated for every clustered index in index->blobs.
It is protected by index->blobs_mutex.

btr_blob_dbg_msg_issue(): Issue a diagnostic message.
Invoked when btr_blob_dbg_msg is set.

btr_blob_dbg_rbt_insert(): Insert a btr_blob_dbg_t into index->blobs.

btr_blob_dbg_rbt_delete(): Remove a btr_blob_dbg_t from index->blobs.

btr_blob_dbg_cmp(): Comparator for btr_blob_dbg_t.

btr_blob_dbg_add_blob(): Add a BLOB reference to the map.

btr_blob_dbg_add_rec(): Add all BLOB references from a record to the map.

btr_blob_dbg_print(): Display the map of BLOB references in an index.

btr_blob_dbg_remove_rec(): Remove all BLOB references of a record from
the map.

btr_blob_dbg_is_empty(): Check that no BLOB references exist to or
from a page. Disowned references from delete-marked records are
tolerated.

btr_blob_dbg_op(): Perform an operation on all BLOB references on a
B-tree page.

btr_blob_dbg_add(): Add all BLOB references from a B-tree page to the
map.

btr_blob_dbg_remove(): Remove all BLOB references from a B-tree page
from the map.

btr_blob_dbg_restore(): Restore the BLOB references after a failed
page reorganize.

btr_blob_dbg_set_deleted_flag(): Modify the 'deleted' flag in the BLOB
references of a record.

btr_blob_dbg_owner(): Own or disown a BLOB reference.

btr_page_create(), btr_page_free_low(): Assert that no BLOB references exist.

btr_create(): Create index->blobs for clustered indexes.

btr_page_reorganize_low(): Invoke btr_blob_dbg_remove() before copying
the records. Invoke btr_blob_dbg_restore() if the operation fails.

btr_page_empty(), btr_lift_page_up(), btr_compress(), btr_discard_page():
Invoke btr_blob_dbg_remove().

btr_cur_del_mark_set_clust_rec(): Invoke btr_blob_dbg_set_deleted_flag().

Other cases of modifying the delete mark are either in the secondary
index or during crash recovery, which we do not promise to support.

btr_cur_set_ownership_of_extern_field(): Invoke btr_blob_dbg_owner().

btr_store_big_rec_extern_fields(): Invoke btr_blob_dbg_add_blob().

btr_free_externally_stored_field(): Invoke btr_blob_dbg_assert_empty()
on the first BLOB page.

page_cur_insert_rec_low(), page_cur_insert_rec_zip(),
page_copy_rec_list_end_to_created_page(): Invoke btr_blob_dbg_add_rec().

page_cur_insert_rec_zip_reorg(), page_copy_rec_list_end(),
page_copy_rec_list_start(): After failure, invoke
btr_blob_dbg_remove() and btr_blob_dbg_add().

page_cur_delete_rec(): Invoke btr_blob_dbg_remove_rec().

page_delete_rec_list_end(): Invoke btr_blob_dbg_op(btr_blob_dbg_remove_rec).

page_zip_reorganize(): Invoke btr_blob_dbg_remove() before copying the records.

page_zip_copy_recs(): Invoke btr_blob_dbg_add().

row_upd_rec_in_place(): Invoke btr_blob_dbg_rbt_delete() and
btr_blob_dbg_rbt_insert().

innobase_start_or_create_for_mysql(): Warn when UNIV_BLOB_DEBUG is enabled.

rb://550 approved by Jimmy Yang
parent b7cc4aa0
This diff is collapsed.
...@@ -2572,6 +2572,7 @@ btr_cur_del_mark_set_clust_rec( ...@@ -2572,6 +2572,7 @@ btr_cur_del_mark_set_clust_rec(
page_zip = buf_block_get_page_zip(block); page_zip = buf_block_get_page_zip(block);
btr_blob_dbg_set_deleted_flag(rec, index, offsets, val);
btr_rec_set_deleted_flag(rec, page_zip, val); btr_rec_set_deleted_flag(rec, page_zip, val);
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
...@@ -3595,6 +3596,8 @@ btr_cur_set_ownership_of_extern_field( ...@@ -3595,6 +3596,8 @@ btr_cur_set_ownership_of_extern_field(
} else { } else {
mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val); mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
} }
btr_blob_dbg_owner(rec, index, offsets, i, val);
} }
/*******************************************************************//** /*******************************************************************//**
...@@ -4094,6 +4097,11 @@ btr_store_big_rec_extern_fields_func( ...@@ -4094,6 +4097,11 @@ btr_store_big_rec_extern_fields_func(
} }
if (prev_page_no == FIL_NULL) { if (prev_page_no == FIL_NULL) {
btr_blob_dbg_add_blob(
rec, big_rec_vec->fields[i]
.field_no, page_no, index,
"store");
mach_write_to_4(field_ref mach_write_to_4(field_ref
+ BTR_EXTERN_SPACE_ID, + BTR_EXTERN_SPACE_ID,
space_id); space_id);
...@@ -4169,6 +4177,11 @@ btr_store_big_rec_extern_fields_func( ...@@ -4169,6 +4177,11 @@ btr_store_big_rec_extern_fields_func(
MLOG_4BYTES, &mtr); MLOG_4BYTES, &mtr);
if (prev_page_no == FIL_NULL) { if (prev_page_no == FIL_NULL) {
btr_blob_dbg_add_blob(
rec, big_rec_vec->fields[i]
.field_no, page_no, index,
"store");
mlog_write_ulint(field_ref mlog_write_ulint(field_ref
+ BTR_EXTERN_SPACE_ID, + BTR_EXTERN_SPACE_ID,
space_id, space_id,
...@@ -4337,6 +4350,37 @@ btr_free_externally_stored_field( ...@@ -4337,6 +4350,37 @@ btr_free_externally_stored_field(
rec_zip_size = 0; rec_zip_size = 0;
} }
#ifdef UNIV_BLOB_DEBUG
if (!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG)
&& !((field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
&& (rb_ctx == RB_NORMAL || rb_ctx == RB_RECOVERY))) {
/* This off-page column will be freed.
Check that no references remain. */
btr_blob_dbg_t b;
b.blob_page_no = mach_read_from_4(
field_ref + BTR_EXTERN_PAGE_NO);
if (rec) {
/* Remove the reference from the record to the
BLOB. If the BLOB were not freed, the
reference would be removed when the record is
removed. Freeing the BLOB will overwrite the
BTR_EXTERN_PAGE_NO in the field_ref of the
record with FIL_NULL, which would make the
btr_blob_dbg information inconsistent with the
record. */
b.ref_page_no = page_get_page_no(page_align(rec));
b.ref_heap_no = page_rec_get_heap_no(rec);
b.ref_field_no = i;
btr_blob_dbg_rbt_delete(index, &b, "free");
}
btr_blob_dbg_assert_empty(index, b.blob_page_no);
}
#endif /* UNIV_BLOB_DEBUG */
for (;;) { for (;;) {
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
buf_block_t* rec_block; buf_block_t* rec_block;
......
...@@ -36,6 +36,9 @@ Created 1/8/1996 Heikki Tuuri ...@@ -36,6 +36,9 @@ Created 1/8/1996 Heikki Tuuri
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
# include "lock0lock.h" # include "lock0lock.h"
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_BLOB_DEBUG
# include "ut0rbt.h"
#endif /* UNIV_BLOB_DEBUG */
#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
creating a table or index object */ creating a table or index object */
...@@ -316,6 +319,12 @@ dict_mem_index_free( ...@@ -316,6 +319,12 @@ dict_mem_index_free(
{ {
ut_ad(index); ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
#ifdef UNIV_BLOB_DEBUG
if (index->blobs) {
mutex_free(&index->blobs_mutex);
rbt_free(index->blobs);
}
#endif /* UNIV_BLOB_DEBUG */
mem_heap_free(index->heap); mem_heap_free(index->heap);
} }
...@@ -81,6 +81,91 @@ UNIQUE definition on secondary indexes when we decide if we can use ...@@ -81,6 +81,91 @@ UNIQUE definition on secondary indexes when we decide if we can use
the insert buffer to speed up inserts */ the insert buffer to speed up inserts */
#define BTR_IGNORE_SEC_UNIQUE 2048 #define BTR_IGNORE_SEC_UNIQUE 2048
#ifdef UNIV_BLOB_DEBUG
# include "ut0rbt.h"
/** An index->blobs entry for keeping track of off-page column references */
struct btr_blob_dbg_struct
{
unsigned blob_page_no:32; /*!< first BLOB page number */
unsigned ref_page_no:32; /*!< referring page number */
unsigned ref_heap_no:16; /*!< referring heap number */
unsigned ref_field_no:10; /*!< referring field number */
unsigned owner:1; /*!< TRUE if BLOB owner */
unsigned always_owner:1; /*!< TRUE if always
has been the BLOB owner;
reset to TRUE on B-tree
page splits and merges */
unsigned del:1; /*!< TRUE if currently
delete-marked */
};
/**************************************************************//**
Add a reference to an off-page column to the index->blobs map. */
UNIV_INTERN
void
btr_blob_dbg_add_blob(
/*==================*/
const rec_t* rec, /*!< in: clustered index record */
ulint field_no, /*!< in: number of off-page column */
ulint page_no, /*!< in: start page of the column */
dict_index_t* index, /*!< in/out: index tree */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/**************************************************************//**
Display the references to off-page columns.
This function is to be called from a debugger,
for example when a breakpoint on ut_dbg_assertion_failed is hit. */
UNIV_INTERN
void
btr_blob_dbg_print(
/*===============*/
const dict_index_t* index) /*!< in: index tree */
__attribute__((nonnull));
/**************************************************************//**
Check that there are no references to off-page columns from or to
the given page. Invoked when freeing or clearing a page.
@return TRUE when no orphan references exist */
UNIV_INTERN
ibool
btr_blob_dbg_is_empty(
/*==================*/
dict_index_t* index, /*!< in: index */
ulint page_no) /*!< in: page number */
__attribute__((nonnull, warn_unused_result));
/**************************************************************//**
Modify the 'deleted' flag of a record. */
UNIV_INTERN
void
btr_blob_dbg_set_deleted_flag(
/*==========================*/
const rec_t* rec, /*!< in: record */
dict_index_t* index, /*!< in/out: index */
const ulint* offsets,/*!< in: rec_get_offs(rec, index) */
ibool del) /*!< in: TRUE=deleted, FALSE=exists */
__attribute__((nonnull));
/**************************************************************//**
Change the ownership of an off-page column. */
UNIV_INTERN
void
btr_blob_dbg_owner(
/*===============*/
const rec_t* rec, /*!< in: record */
dict_index_t* index, /*!< in/out: index */
const ulint* offsets,/*!< in: rec_get_offs(rec, index) */
ulint i, /*!< in: ith field in rec */
ibool own) /*!< in: TRUE=owned, FALSE=disowned */
__attribute__((nonnull));
/** Assert that there are no BLOB references to or from the given page. */
# define btr_blob_dbg_assert_empty(index, page_no) \
ut_a(btr_blob_dbg_is_empty(index, page_no))
#else /* UNIV_BLOB_DEBUG */
# define btr_blob_dbg_add_blob(rec, field_no, page, index, ctx) ((void) 0)
# define btr_blob_dbg_set_deleted_flag(rec, index, offsets, del)((void) 0)
# define btr_blob_dbg_owner(rec, index, offsets, i, val) ((void) 0)
# define btr_blob_dbg_assert_empty(index, page_no) ((void) 0)
#endif /* UNIV_BLOB_DEBUG */
/**************************************************************//** /**************************************************************//**
Gets the root node of a tree and x-latches it. Gets the root node of a tree and x-latches it.
@return root page, x-latched */ @return root page, x-latched */
......
...@@ -38,6 +38,131 @@ typedef struct btr_cur_struct btr_cur_t; ...@@ -38,6 +38,131 @@ typedef struct btr_cur_struct btr_cur_t;
/** B-tree search information for the adaptive hash index */ /** B-tree search information for the adaptive hash index */
typedef struct btr_search_struct btr_search_t; typedef struct btr_search_struct btr_search_t;
#ifdef UNIV_BLOB_DEBUG
# include "buf0types.h"
/** An index->blobs entry for keeping track of off-page column references */
typedef struct btr_blob_dbg_struct btr_blob_dbg_t;
/** Insert to index->blobs a reference to an off-page column.
@param index the index tree
@param b the reference
@param ctx context (for logging) */
UNIV_INTERN
void
btr_blob_dbg_rbt_insert(
/*====================*/
dict_index_t* index, /*!< in/out: index tree */
const btr_blob_dbg_t* b, /*!< in: the reference */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/** Remove from index->blobs a reference to an off-page column.
@param index the index tree
@param b the reference
@param ctx context (for logging) */
UNIV_INTERN
void
btr_blob_dbg_rbt_delete(
/*====================*/
dict_index_t* index, /*!< in/out: index tree */
const btr_blob_dbg_t* b, /*!< in: the reference */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/**************************************************************//**
Add to index->blobs any references to off-page columns from a record.
@return number of references added */
UNIV_INTERN
ulint
btr_blob_dbg_add_rec(
/*=================*/
const rec_t* rec, /*!< in: record */
dict_index_t* index, /*!< in/out: index */
const ulint* offsets,/*!< in: offsets */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/**************************************************************//**
Remove from index->blobs any references to off-page columns from a record.
@return number of references removed */
UNIV_INTERN
ulint
btr_blob_dbg_remove_rec(
/*====================*/
const rec_t* rec, /*!< in: record */
dict_index_t* index, /*!< in/out: index */
const ulint* offsets,/*!< in: offsets */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/**************************************************************//**
Count and add to index->blobs any references to off-page columns
from records on a page.
@return number of references added */
UNIV_INTERN
ulint
btr_blob_dbg_add(
/*=============*/
const page_t* page, /*!< in: rewritten page */
dict_index_t* index, /*!< in/out: index */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/**************************************************************//**
Count and remove from index->blobs any references to off-page columns
from records on a page.
Used when reorganizing a page, before copying the records.
@return number of references removed */
UNIV_INTERN
ulint
btr_blob_dbg_remove(
/*================*/
const page_t* page, /*!< in: b-tree page */
dict_index_t* index, /*!< in/out: index */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/**************************************************************//**
Restore in index->blobs any references to off-page columns
Used when page reorganize fails due to compressed page overflow. */
UNIV_INTERN
void
btr_blob_dbg_restore(
/*=================*/
const page_t* npage, /*!< in: page that failed to compress */
const page_t* page, /*!< in: copy of original page */
dict_index_t* index, /*!< in/out: index */
const char* ctx) /*!< in: context (for logging) */
__attribute__((nonnull));
/** Operation that processes the BLOB references of an index record
@param[in] rec record on index page
@param[in/out] index the index tree of the record
@param[in] offsets rec_get_offsets(rec,index)
@param[in] ctx context (for logging)
@return number of BLOB references processed */
typedef ulint (*btr_blob_dbg_op_f)
(const rec_t* rec,dict_index_t* index,const ulint* offsets,const char* ctx);
/**************************************************************//**
Count and process all references to off-page columns on a page.
@return number of references processed */
UNIV_INTERN
ulint
btr_blob_dbg_op(
/*============*/
const page_t* page, /*!< in: B-tree leaf page */
const rec_t* rec, /*!< in: record to start from
(NULL to process the whole page) */
dict_index_t* index, /*!< in/out: index */
const char* ctx, /*!< in: context (for logging) */
const btr_blob_dbg_op_f op) /*!< in: operation on records */
__attribute__((nonnull(1,3,4,5)));
#else /* UNIV_BLOB_DEBUG */
# define btr_blob_dbg_add_rec(rec, index, offsets, ctx) ((void) 0)
# define btr_blob_dbg_add(page, index, ctx) ((void) 0)
# define btr_blob_dbg_remove_rec(rec, index, offsets, ctx) ((void) 0)
# define btr_blob_dbg_remove(page, index, ctx) ((void) 0)
# define btr_blob_dbg_restore(npage, page, index, ctx) ((void) 0)
# define btr_blob_dbg_op(page, rec, index, ctx, op) ((void) 0)
#endif /* UNIV_BLOB_DEBUG */
/** The size of a reference to data stored on a different page. /** The size of a reference to data stored on a different page.
The reference is stored at the end of the prefix of the field The reference is stored at the end of the prefix of the field
in the index record. */ in the index record. */
......
...@@ -340,6 +340,13 @@ struct dict_index_struct{ ...@@ -340,6 +340,13 @@ struct dict_index_struct{
index, or 0 if the index existed index, or 0 if the index existed
when InnoDB was started up */ when InnoDB was started up */
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_BLOB_DEBUG
mutex_t blobs_mutex;
/*!< mutex protecting blobs */
void* blobs; /*!< map of (page_no,heap_no,field_no)
to first_blob_page_no; protected by
blobs_mutex; @see btr_blob_dbg_t */
#endif /* UNIV_BLOB_DEBUG */
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
ulint magic_n;/*!< magic number */ ulint magic_n;/*!< magic number */
/** Value of dict_index_struct::magic_n */ /** Value of dict_index_struct::magic_n */
......
...@@ -420,7 +420,7 @@ page_zip_copy_recs( ...@@ -420,7 +420,7 @@ page_zip_copy_recs(
const page_t* src, /*!< in: page */ const page_t* src, /*!< in: page */
dict_index_t* index, /*!< in: index of the B-tree */ dict_index_t* index, /*!< in: index of the B-tree */
mtr_t* mtr) /*!< in: mini-transaction */ mtr_t* mtr) /*!< in: mini-transaction */
__attribute__((nonnull(1,2,3,4))); __attribute__((nonnull));
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
/**********************************************************************//** /**********************************************************************//**
......
...@@ -194,6 +194,8 @@ this will break redo log file compatibility, but it may be useful when ...@@ -194,6 +194,8 @@ this will break redo log file compatibility, but it may be useful when
debugging redo log application problems. */ debugging redo log application problems. */
#define UNIV_MEM_DEBUG /* detect memory leaks etc */ #define UNIV_MEM_DEBUG /* detect memory leaks etc */
#define UNIV_IBUF_DEBUG /* debug the insert buffer */ #define UNIV_IBUF_DEBUG /* debug the insert buffer */
#define UNIV_BLOB_DEBUG /* track BLOB ownership;
assumes that no BLOBs survive server restart */
#define UNIV_IBUF_COUNT_DEBUG /* debug the insert buffer; #define UNIV_IBUF_COUNT_DEBUG /* debug the insert buffer;
this limits the database to IBUF_COUNT_N_SPACES and IBUF_COUNT_N_PAGES, this limits the database to IBUF_COUNT_N_SPACES and IBUF_COUNT_N_PAGES,
and the insert buffer must be empty when the database is started */ and the insert buffer must be empty when the database is started */
......
...@@ -1149,6 +1149,8 @@ page_cur_insert_rec_low( ...@@ -1149,6 +1149,8 @@ page_cur_insert_rec_low(
current_rec, index, mtr); current_rec, index, mtr);
} }
btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert");
return(insert_rec); return(insert_rec);
} }
...@@ -1195,10 +1197,12 @@ page_cur_insert_rec_zip_reorg( ...@@ -1195,10 +1197,12 @@ page_cur_insert_rec_zip_reorg(
} }
/* Out of space: restore the page */ /* Out of space: restore the page */
btr_blob_dbg_remove(page, index, "insert_zip_fail");
if (!page_zip_decompress(page_zip, page, FALSE)) { if (!page_zip_decompress(page_zip, page, FALSE)) {
ut_error; /* Memory corrupted? */ ut_error; /* Memory corrupted? */
} }
ut_ad(page_validate(page, index)); ut_ad(page_validate(page, index));
btr_blob_dbg_add(page, index, "insert_zip_fail");
return(NULL); return(NULL);
} }
...@@ -1490,6 +1494,8 @@ page_cur_insert_rec_zip( ...@@ -1490,6 +1494,8 @@ page_cur_insert_rec_zip(
page_zip_write_rec(page_zip, insert_rec, index, offsets, 1); page_zip_write_rec(page_zip, insert_rec, index, offsets, 1);
btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert_zip_ok");
/* 9. Write log record of the insert */ /* 9. Write log record of the insert */
if (UNIV_LIKELY(mtr != NULL)) { if (UNIV_LIKELY(mtr != NULL)) {
page_cur_insert_rec_write_log(insert_rec, rec_size, page_cur_insert_rec_write_log(insert_rec, rec_size,
...@@ -1697,6 +1703,9 @@ page_copy_rec_list_end_to_created_page( ...@@ -1697,6 +1703,9 @@ page_copy_rec_list_end_to_created_page(
heap_top += rec_size; heap_top += rec_size;
rec_offs_make_valid(insert_rec, index, offsets);
btr_blob_dbg_add_rec(insert_rec, index, offsets, "copy_end");
page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec, page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec,
index, mtr); index, mtr);
prev_rec = insert_rec; prev_rec = insert_rec;
...@@ -1944,6 +1953,7 @@ page_cur_delete_rec( ...@@ -1944,6 +1953,7 @@ page_cur_delete_rec(
page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1); page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1);
/* 6. Free the memory occupied by the record */ /* 6. Free the memory occupied by the record */
btr_blob_dbg_remove_rec(current_rec, index, offsets, "delete");
page_mem_free(page, page_zip, current_rec, index, offsets); page_mem_free(page, page_zip, current_rec, index, offsets);
/* 7. Now we have decremented the number of owned records of the slot. /* 7. Now we have decremented the number of owned records of the slot.
......
...@@ -685,12 +685,16 @@ page_copy_rec_list_end( ...@@ -685,12 +685,16 @@ page_copy_rec_list_end(
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(!page_zip_reorganize(new_block, index, mtr))) { (!page_zip_reorganize(new_block, index, mtr))) {
btr_blob_dbg_remove(new_page, index,
"copy_end_reorg_fail");
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip, (!page_zip_decompress(new_page_zip,
new_page, FALSE))) { new_page, FALSE))) {
ut_error; ut_error;
} }
ut_ad(page_validate(new_page, index)); ut_ad(page_validate(new_page, index));
btr_blob_dbg_add(new_page, index,
"copy_end_reorg_fail");
return(NULL); return(NULL);
} else { } else {
/* The page was reorganized: /* The page was reorganized:
...@@ -803,12 +807,16 @@ page_copy_rec_list_start( ...@@ -803,12 +807,16 @@ page_copy_rec_list_start(
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(!page_zip_reorganize(new_block, index, mtr))) { (!page_zip_reorganize(new_block, index, mtr))) {
btr_blob_dbg_remove(new_page, index,
"copy_start_reorg_fail");
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip, (!page_zip_decompress(new_page_zip,
new_page, FALSE))) { new_page, FALSE))) {
ut_error; ut_error;
} }
ut_ad(page_validate(new_page, index)); ut_ad(page_validate(new_page, index));
btr_blob_dbg_add(new_page, index,
"copy_start_reorg_fail");
return(NULL); return(NULL);
} else { } else {
/* The page was reorganized: /* The page was reorganized:
...@@ -1080,6 +1088,9 @@ page_delete_rec_list_end( ...@@ -1080,6 +1088,9 @@ page_delete_rec_list_end(
/* Remove the record chain segment from the record chain */ /* Remove the record chain segment from the record chain */
page_rec_set_next(prev_rec, page_get_supremum_rec(page)); page_rec_set_next(prev_rec, page_get_supremum_rec(page));
btr_blob_dbg_op(page, rec, index, "delete_end",
btr_blob_dbg_remove_rec);
/* Catenate the deleted chain segment to the page free list */ /* Catenate the deleted chain segment to the page free list */
page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE)); page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE));
......
...@@ -4451,6 +4451,8 @@ page_zip_reorganize( ...@@ -4451,6 +4451,8 @@ page_zip_reorganize(
/* Copy the old page to temporary space */ /* Copy the old page to temporary space */
buf_frame_copy(temp_page, page); buf_frame_copy(temp_page, page);
btr_blob_dbg_remove(page, index, "zip_reorg");
/* Recreate the page: note that global data on page (possible /* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */ segment headers, next page-field, etc.) is preserved intact */
...@@ -4509,7 +4511,7 @@ page_zip_copy_recs( ...@@ -4509,7 +4511,7 @@ page_zip_copy_recs(
mtr_t* mtr) /*!< in: mini-transaction */ mtr_t* mtr) /*!< in: mini-transaction */
{ {
ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
ut_ad(mtr_memo_contains_page(mtr, (page_t*) src, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr_memo_contains_page(mtr, src, MTR_MEMO_PAGE_X_FIX));
ut_ad(!dict_index_is_ibuf(index)); ut_ad(!dict_index_is_ibuf(index));
#ifdef UNIV_ZIP_DEBUG #ifdef UNIV_ZIP_DEBUG
/* The B-tree operations that call this function may set /* The B-tree operations that call this function may set
...@@ -4579,6 +4581,7 @@ page_zip_copy_recs( ...@@ -4579,6 +4581,7 @@ page_zip_copy_recs(
#ifdef UNIV_ZIP_DEBUG #ifdef UNIV_ZIP_DEBUG
ut_a(page_zip_validate(page_zip, page)); ut_a(page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */ #endif /* UNIV_ZIP_DEBUG */
btr_blob_dbg_add(page, index, "page_zip_copy_recs");
page_zip_compress_write_log(page_zip, page, index, mtr); page_zip_compress_write_log(page_zip, page, index, mtr);
} }
......
...@@ -498,14 +498,49 @@ row_upd_rec_in_place( ...@@ -498,14 +498,49 @@ row_upd_rec_in_place(
n_fields = upd_get_n_fields(update); n_fields = upd_get_n_fields(update);
for (i = 0; i < n_fields; i++) { for (i = 0; i < n_fields; i++) {
#ifdef UNIV_BLOB_DEBUG
btr_blob_dbg_t b;
const byte* field_ref = NULL;
#endif /* UNIV_BLOB_DEBUG */
upd_field = upd_get_nth_field(update, i); upd_field = upd_get_nth_field(update, i);
new_val = &(upd_field->new_val); new_val = &(upd_field->new_val);
ut_ad(!dfield_is_ext(new_val) == ut_ad(!dfield_is_ext(new_val) ==
!rec_offs_nth_extern(offsets, upd_field->field_no)); !rec_offs_nth_extern(offsets, upd_field->field_no));
#ifdef UNIV_BLOB_DEBUG
if (dfield_is_ext(new_val)) {
ulint len;
field_ref = rec_get_nth_field(rec, offsets, i, &len);
ut_a(len != UNIV_SQL_NULL);
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
b.ref_page_no = page_get_page_no(page_align(rec));
b.ref_heap_no = page_rec_get_heap_no(rec);
b.ref_field_no = i;
b.blob_page_no = mach_read_from_4(
field_ref + BTR_EXTERN_PAGE_NO);
ut_a(b.ref_field_no >= index->n_uniq);
btr_blob_dbg_rbt_delete(index, &b, "upd_in_place");
}
#endif /* UNIV_BLOB_DEBUG */
rec_set_nth_field(rec, offsets, upd_field->field_no, rec_set_nth_field(rec, offsets, upd_field->field_no,
dfield_get_data(new_val), dfield_get_data(new_val),
dfield_get_len(new_val)); dfield_get_len(new_val));
#ifdef UNIV_BLOB_DEBUG
if (dfield_is_ext(new_val)) {
b.blob_page_no = mach_read_from_4(
field_ref + BTR_EXTERN_PAGE_NO);
b.always_owner = b.owner = !(field_ref[BTR_EXTERN_LEN]
& BTR_EXTERN_OWNER_FLAG);
b.del = rec_get_deleted_flag(
rec, rec_offs_comp(offsets));
btr_blob_dbg_rbt_insert(index, &b, "upd_in_place");
}
#endif /* UNIV_BLOB_DEBUG */
} }
if (UNIV_LIKELY_NULL(page_zip)) { if (UNIV_LIKELY_NULL(page_zip)) {
......
...@@ -1061,6 +1061,12 @@ innobase_start_or_create_for_mysql(void) ...@@ -1061,6 +1061,12 @@ innobase_start_or_create_for_mysql(void)
); );
#endif #endif
#ifdef UNIV_BLOB_DEBUG
fprintf(stderr,
"InnoDB: !!!!!!!! UNIV_BLOB_DEBUG switched on !!!!!!!!!\n"
"InnoDB: Server restart may fail with UNIV_BLOB_DEBUG\n");
#endif /* UNIV_BLOB_DEBUG */
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
fprintf(stderr, fprintf(stderr,
"InnoDB: !!!!!!!! UNIV_SYNC_DEBUG switched on !!!!!!!!!\n"); "InnoDB: !!!!!!!! UNIV_SYNC_DEBUG switched on !!!!!!!!!\n");
......
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