summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorVasil Dimov <vasil.dimov@oracle.com>2011-02-17 13:56:05 +0200
committerVasil Dimov <vasil.dimov@oracle.com>2011-02-17 13:56:05 +0200
commit0bbaf6e8a7086aaf7eb6ca6fd350b8d5e591f2fe (patch)
tree2a280f8a6264c726494e54153019a4bab876dfb5 /storage
parentaa8ebbee0b1e2e50c225673e469755021994265c (diff)
parent61449541fb8aec7f82d8ab8e64688a4c5118e923 (diff)
downloadmariadb-git-0bbaf6e8a7086aaf7eb6ca6fd350b8d5e591f2fe.tar.gz
Merge mysql-5.1-innodb -> mysql-5.1
Diffstat (limited to 'storage')
-rw-r--r--storage/innodb_plugin/ChangeLog12
-rw-r--r--storage/innodb_plugin/btr/btr0btr.c571
-rw-r--r--storage/innodb_plugin/btr/btr0cur.c44
-rw-r--r--storage/innodb_plugin/dict/dict0mem.c9
-rw-r--r--storage/innodb_plugin/handler/handler0alter.cc12
-rw-r--r--storage/innodb_plugin/include/btr0btr.h85
-rw-r--r--storage/innodb_plugin/include/btr0types.h125
-rw-r--r--storage/innodb_plugin/include/dict0mem.h7
-rw-r--r--storage/innodb_plugin/include/page0zip.h2
-rw-r--r--storage/innodb_plugin/include/univ.i4
-rw-r--r--storage/innodb_plugin/page/page0cur.c10
-rw-r--r--storage/innodb_plugin/page/page0page.c11
-rw-r--r--storage/innodb_plugin/page/page0zip.c5
-rw-r--r--storage/innodb_plugin/row/row0upd.c35
-rw-r--r--storage/innodb_plugin/srv/srv0start.c6
-rw-r--r--storage/innodb_plugin/sync/sync0rw.c3
16 files changed, 934 insertions, 7 deletions
diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog
index 102db3d7824..18d15bbaeb4 100644
--- a/storage/innodb_plugin/ChangeLog
+++ b/storage/innodb_plugin/ChangeLog
@@ -1,3 +1,15 @@
+2011-02-15 The InnoDB Team
+
+ * sync/sync0rw.c, innodb_bug59307.test:
+ Bug#59307 Valgrind: uninitialized value in
+ rw_lock_set_writer_id_and_recursion_flag()
+
+2011-02-14 The InnoDB Team
+
+ * handler/handler0alter.cc:
+ Bug#59749 Enabling concurrent reads while creating non-primary
+ unique index gives failures
+
2011-01-31 The InnoDB Team
* btr/btr0cur.c, include/row0upd.h,
diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c
index 3d8d6048603..46810c011c4 100644
--- a/storage/innodb_plugin/btr/btr0btr.c
+++ b/storage/innodb_plugin/btr/btr0btr.c
@@ -42,6 +42,560 @@ Created 6/2/1994 Heikki Tuuri
#include "ibuf0ibuf.h"
#include "trx0trx.h"
+#ifdef UNIV_BLOB_DEBUG
+# include "srv0srv.h"
+# include "ut0rbt.h"
+
+/** TRUE when messages about index->blobs modification are enabled. */
+static ibool btr_blob_dbg_msg;
+
+/** Issue a message about an operation on index->blobs.
+@param op operation
+@param b the entry being subjected to the operation
+@param ctx the context of the operation */
+#define btr_blob_dbg_msg_issue(op, b, ctx) \
+ fprintf(stderr, op " %u:%u:%u->%u %s(%u,%u,%u)\n", \
+ (b)->ref_page_no, (b)->ref_heap_no, \
+ (b)->ref_field_no, (b)->blob_page_no, ctx, \
+ (b)->owner, (b)->always_owner, (b)->del)
+
+/** 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) */
+{
+ if (btr_blob_dbg_msg) {
+ btr_blob_dbg_msg_issue("insert", b, ctx);
+ }
+ mutex_enter(&index->blobs_mutex);
+ rbt_insert(index->blobs, b, b);
+ mutex_exit(&index->blobs_mutex);
+}
+
+/** 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) */
+{
+ if (btr_blob_dbg_msg) {
+ btr_blob_dbg_msg_issue("delete", b, ctx);
+ }
+ mutex_enter(&index->blobs_mutex);
+ ut_a(rbt_delete(index->blobs, b));
+ mutex_exit(&index->blobs_mutex);
+}
+
+/**************************************************************//**
+Comparator for items (btr_blob_dbg_t) in index->blobs.
+The key in index->blobs is (ref_page_no, ref_heap_no, ref_field_no).
+@return negative, 0 or positive if *a<*b, *a=*b, *a>*b */
+static
+int
+btr_blob_dbg_cmp(
+/*=============*/
+ const void* a, /*!< in: first btr_blob_dbg_t to compare */
+ const void* b) /*!< in: second btr_blob_dbg_t to compare */
+{
+ const btr_blob_dbg_t* aa = a;
+ const btr_blob_dbg_t* bb = b;
+
+ ut_ad(aa != NULL);
+ ut_ad(bb != NULL);
+
+ if (aa->ref_page_no != bb->ref_page_no) {
+ return(aa->ref_page_no < bb->ref_page_no ? -1 : 1);
+ }
+ if (aa->ref_heap_no != bb->ref_heap_no) {
+ return(aa->ref_heap_no < bb->ref_heap_no ? -1 : 1);
+ }
+ if (aa->ref_field_no != bb->ref_field_no) {
+ return(aa->ref_field_no < bb->ref_field_no ? -1 : 1);
+ }
+ return(0);
+}
+
+/**************************************************************//**
+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: off-page column number */
+ ulint page_no, /*!< in: start page of the column */
+ dict_index_t* index, /*!< in/out: index tree */
+ const char* ctx) /*!< in: context (for logging) */
+{
+ btr_blob_dbg_t b;
+ const page_t* page = page_align(rec);
+
+ ut_a(index->blobs);
+
+ b.blob_page_no = page_no;
+ b.ref_page_no = page_get_page_no(page);
+ b.ref_heap_no = page_rec_get_heap_no(rec);
+ b.ref_field_no = field_no;
+ ut_a(b.ref_field_no >= index->n_uniq);
+ b.always_owner = b.owner = TRUE;
+ b.del = FALSE;
+ ut_a(!rec_get_deleted_flag(rec, page_is_comp(page)));
+ btr_blob_dbg_rbt_insert(index, &b, ctx);
+}
+
+/**************************************************************//**
+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) */
+{
+ ulint count = 0;
+ ulint i;
+ btr_blob_dbg_t b;
+ ibool del;
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
+ if (!rec_offs_any_extern(offsets)) {
+ return(0);
+ }
+
+ b.ref_page_no = page_get_page_no(page_align(rec));
+ b.ref_heap_no = page_rec_get_heap_no(rec);
+ del = (rec_get_deleted_flag(rec, rec_offs_comp(offsets)) != 0);
+
+ for (i = 0; i < rec_offs_n_fields(offsets); i++) {
+ if (rec_offs_nth_extern(offsets, i)) {
+ ulint len;
+ const byte* 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;
+
+ if (!memcmp(field_ref, field_ref_zero,
+ BTR_EXTERN_FIELD_REF_SIZE)) {
+ /* the column has not been stored yet */
+ continue;
+ }
+
+ 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);
+ b.always_owner = b.owner
+ = !(field_ref[BTR_EXTERN_LEN]
+ & BTR_EXTERN_OWNER_FLAG);
+ b.del = del;
+
+ btr_blob_dbg_rbt_insert(index, &b, ctx);
+ count++;
+ }
+ }
+
+ return(count);
+}
+
+/**************************************************************//**
+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 */
+{
+ const ib_rbt_node_t* node;
+
+ if (!index->blobs) {
+ return;
+ }
+
+ /* We intentionally do not acquire index->blobs_mutex here.
+ This function is to be called from a debugger, and the caller
+ should make sure that the index->blobs_mutex is held. */
+
+ for (node = rbt_first(index->blobs);
+ node != NULL; node = rbt_next(index->blobs, node)) {
+ const btr_blob_dbg_t* b
+ = rbt_value(btr_blob_dbg_t, node);
+ fprintf(stderr, "%u:%u:%u->%u%s%s%s\n",
+ b->ref_page_no, b->ref_heap_no, b->ref_field_no,
+ b->blob_page_no,
+ b->owner ? "" : "(disowned)",
+ b->always_owner ? "" : "(has disowned)",
+ b->del ? "(deleted)" : "");
+ }
+}
+
+/**************************************************************//**
+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) */
+{
+ ulint i;
+ ulint count = 0;
+ btr_blob_dbg_t b;
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+
+ if (!rec_offs_any_extern(offsets)) {
+ return(0);
+ }
+
+ b.ref_page_no = page_get_page_no(page_align(rec));
+ b.ref_heap_no = page_rec_get_heap_no(rec);
+
+ for (i = 0; i < rec_offs_n_fields(offsets); i++) {
+ if (rec_offs_nth_extern(offsets, i)) {
+ ulint len;
+ const byte* 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_field_no = i;
+ b.blob_page_no = mach_read_from_4(
+ field_ref + BTR_EXTERN_PAGE_NO);
+
+ switch (b.blob_page_no) {
+ case 0:
+ /* The column has not been stored yet.
+ The BLOB pointer must be all zero.
+ There cannot be a BLOB starting at
+ page 0, because page 0 is reserved for
+ the tablespace header. */
+ ut_a(!memcmp(field_ref, field_ref_zero,
+ BTR_EXTERN_FIELD_REF_SIZE));
+ /* fall through */
+ case FIL_NULL:
+ /* the column has been freed already */
+ continue;
+ }
+
+ btr_blob_dbg_rbt_delete(index, &b, ctx);
+ count++;
+ }
+ }
+
+ return(count);
+}
+
+/**************************************************************//**
+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 */
+{
+ const ib_rbt_node_t* node;
+ ibool success = TRUE;
+
+ if (!index->blobs) {
+ return(success);
+ }
+
+ mutex_enter(&index->blobs_mutex);
+
+ for (node = rbt_first(index->blobs);
+ node != NULL; node = rbt_next(index->blobs, node)) {
+ const btr_blob_dbg_t* b
+ = rbt_value(btr_blob_dbg_t, node);
+
+ if (b->ref_page_no != page_no && b->blob_page_no != page_no) {
+ continue;
+ }
+
+ fprintf(stderr,
+ "InnoDB: orphan BLOB ref%s%s%s %u:%u:%u->%u\n",
+ b->owner ? "" : "(disowned)",
+ b->always_owner ? "" : "(has disowned)",
+ b->del ? "(deleted)" : "",
+ b->ref_page_no, b->ref_heap_no, b->ref_field_no,
+ b->blob_page_no);
+
+ if (b->blob_page_no != page_no || b->owner || !b->del) {
+ success = FALSE;
+ }
+ }
+
+ mutex_exit(&index->blobs_mutex);
+ return(success);
+}
+
+/**************************************************************//**
+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 */
+{
+ ulint count = 0;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
+
+ ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
+ ut_a(!rec || page_align(rec) == page);
+
+ if (!index->blobs || !page_is_leaf(page)
+ || !dict_index_is_clust(index)) {
+ return(0);
+ }
+
+ if (rec == NULL) {
+ rec = page_get_infimum_rec(page);
+ }
+
+ do {
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ count += op(rec, index, offsets, ctx);
+ rec = page_rec_get_next_const(rec);
+ } while (!page_rec_is_supremum(rec));
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+ return(count);
+}
+
+/**************************************************************//**
+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) */
+{
+ btr_blob_dbg_assert_empty(index, page_get_page_no(page));
+
+ return(btr_blob_dbg_op(page, NULL, index, ctx, btr_blob_dbg_add_rec));
+}
+
+/**************************************************************//**
+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) */
+{
+ ulint count;
+
+ count = btr_blob_dbg_op(page, NULL, index, ctx,
+ btr_blob_dbg_remove_rec);
+
+ /* Check that no references exist. */
+ btr_blob_dbg_assert_empty(index, page_get_page_no(page));
+
+ return(count);
+}
+
+/**************************************************************//**
+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) */
+{
+ ulint removed;
+ ulint added;
+
+ ut_a(page_get_page_no(npage) == page_get_page_no(page));
+ ut_a(page_get_space_id(npage) == page_get_space_id(page));
+
+ removed = btr_blob_dbg_remove(npage, index, ctx);
+ added = btr_blob_dbg_add(page, index, ctx);
+ ut_a(added == removed);
+}
+
+/**************************************************************//**
+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 */
+{
+ const ib_rbt_node_t* node;
+ btr_blob_dbg_t b;
+ btr_blob_dbg_t* c;
+ ulint i;
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ ut_a(dict_index_is_clust(index));
+ ut_a(del == !!del);/* must be FALSE==0 or TRUE==1 */
+
+ if (!rec_offs_any_extern(offsets) || !index->blobs) {
+
+ return;
+ }
+
+ b.ref_page_no = page_get_page_no(page_align(rec));
+ b.ref_heap_no = page_rec_get_heap_no(rec);
+
+ for (i = 0; i < rec_offs_n_fields(offsets); i++) {
+ if (rec_offs_nth_extern(offsets, i)) {
+ ulint len;
+ const byte* 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_field_no = i;
+ b.blob_page_no = mach_read_from_4(
+ field_ref + BTR_EXTERN_PAGE_NO);
+
+ switch (b.blob_page_no) {
+ case 0:
+ ut_a(memcmp(field_ref, field_ref_zero,
+ BTR_EXTERN_FIELD_REF_SIZE));
+ /* page number 0 is for the
+ page allocation bitmap */
+ case FIL_NULL:
+ /* the column has been freed already */
+ ut_error;
+ }
+
+ mutex_enter(&index->blobs_mutex);
+ node = rbt_lookup(index->blobs, &b);
+ ut_a(node);
+
+ c = rbt_value(btr_blob_dbg_t, node);
+ /* The flag should be modified. */
+ c->del = del;
+ if (btr_blob_dbg_msg) {
+ b = *c;
+ mutex_exit(&index->blobs_mutex);
+ btr_blob_dbg_msg_issue("del_mk", &b, "");
+ } else {
+ mutex_exit(&index->blobs_mutex);
+ }
+ }
+ }
+}
+
+/**************************************************************//**
+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 */
+{
+ const ib_rbt_node_t* node;
+ btr_blob_dbg_t b;
+ const byte* field_ref;
+ ulint len;
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ ut_a(rec_offs_nth_extern(offsets, i));
+
+ 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.owner = !(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG);
+ b.blob_page_no = mach_read_from_4(field_ref + BTR_EXTERN_PAGE_NO);
+
+ ut_a(b.owner == own);
+
+ mutex_enter(&index->blobs_mutex);
+ node = rbt_lookup(index->blobs, &b);
+ /* row_ins_clust_index_entry_by_modify() invokes
+ btr_cur_unmark_extern_fields() also for the newly inserted
+ references, which are all zero bytes until the columns are stored.
+ The node lookup must fail if and only if that is the case. */
+ ut_a(!memcmp(field_ref, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE)
+ == !node);
+
+ if (node) {
+ btr_blob_dbg_t* c = rbt_value(btr_blob_dbg_t, node);
+ /* Some code sets ownership from TRUE to TRUE.
+ We do not allow changing ownership from FALSE to FALSE. */
+ ut_a(own || c->owner);
+
+ c->owner = own;
+ if (!own) {
+ c->always_owner = FALSE;
+ }
+ }
+
+ mutex_exit(&index->blobs_mutex);
+}
+#endif /* UNIV_BLOB_DEBUG */
+
/*
Latching strategy of the InnoDB B-tree
--------------------------------------
@@ -296,6 +850,7 @@ btr_page_create(
page_t* page = buf_block_get_frame(block);
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block));
if (UNIV_LIKELY_NULL(page_zip)) {
page_create_zip(block, index, level, mtr);
@@ -489,6 +1044,7 @@ btr_page_free_low(
modify clock */
buf_block_modify_clock_inc(block);
+ btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block));
if (dict_index_is_ibuf(index)) {
@@ -773,6 +1329,13 @@ btr_create(
block = buf_page_get(space, zip_size, page_no,
RW_X_LATCH, mtr);
} else {
+#ifdef UNIV_BLOB_DEBUG
+ if ((type & DICT_CLUSTERED) && !index->blobs) {
+ mutex_create(&index->blobs_mutex, SYNC_ANY_LATCH);
+ index->blobs = rbt_create(sizeof(btr_blob_dbg_t),
+ btr_blob_dbg_cmp);
+ }
+#endif /* UNIV_BLOB_DEBUG */
block = fseg_create(space, 0,
PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
}
@@ -996,6 +1559,7 @@ btr_page_reorganize_low(
block->check_index_page_at_flush = TRUE;
#endif /* !UNIV_HOTBACKUP */
+ btr_blob_dbg_remove(page, index, "btr_page_reorganize");
/* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */
@@ -1024,6 +1588,8 @@ btr_page_reorganize_low(
(!page_zip_compress(page_zip, page, index, NULL))) {
/* Restore the old page and exit. */
+ btr_blob_dbg_restore(page, temp_page, index,
+ "btr_page_reorganize_compress_fail");
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
/* Check that the bytes that we skip are identical. */
@@ -1157,6 +1723,7 @@ btr_page_empty(
#endif /* UNIV_ZIP_DEBUG */
btr_search_drop_page_hash_index(block);
+ btr_blob_dbg_remove(page, index, "btr_page_empty");
/* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */
@@ -2497,6 +3064,7 @@ btr_lift_page_up(
index);
}
+ btr_blob_dbg_remove(page, index, "btr_lift_page_up");
lock_update_copy_and_discard(father_block, block);
/* Go upward to root page, decrementing levels by one. */
@@ -2758,6 +3326,7 @@ err_exit:
lock_update_merge_right(merge_block, orig_succ, block);
}
+ btr_blob_dbg_remove(page, index, "btr_compress");
mem_heap_free(heap);
if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) {
@@ -2988,6 +3557,8 @@ btr_discard_page(
block);
}
+ btr_blob_dbg_remove(page, index, "btr_discard_page");
+
/* Free the file page */
btr_page_free(index, block, mtr);
diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c
index 704cc606a5f..86d77c79e7b 100644
--- a/storage/innodb_plugin/btr/btr0cur.c
+++ b/storage/innodb_plugin/btr/btr0cur.c
@@ -2572,6 +2572,7 @@ btr_cur_del_mark_set_clust_rec(
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);
trx = thr_get_trx(thr);
@@ -3595,6 +3596,8 @@ btr_cur_set_ownership_of_extern_field(
} else {
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(
}
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
+ BTR_EXTERN_SPACE_ID,
space_id);
@@ -4169,6 +4177,11 @@ next_zip_page:
MLOG_4BYTES, &mtr);
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
+ BTR_EXTERN_SPACE_ID,
space_id,
@@ -4337,6 +4350,37 @@ btr_free_externally_stored_field(
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 (;;) {
#ifdef UNIV_SYNC_DEBUG
buf_block_t* rec_block;
diff --git a/storage/innodb_plugin/dict/dict0mem.c b/storage/innodb_plugin/dict/dict0mem.c
index 3287247029f..aef815dd2f6 100644
--- a/storage/innodb_plugin/dict/dict0mem.c
+++ b/storage/innodb_plugin/dict/dict0mem.c
@@ -36,6 +36,9 @@ Created 1/8/1996 Heikki Tuuri
#ifndef UNIV_HOTBACKUP
# include "lock0lock.h"
#endif /* !UNIV_HOTBACKUP */
+#ifdef UNIV_BLOB_DEBUG
+# include "ut0rbt.h"
+#endif /* UNIV_BLOB_DEBUG */
#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
creating a table or index object */
@@ -316,6 +319,12 @@ dict_mem_index_free(
{
ut_ad(index);
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);
}
diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc
index 517445f7e69..dc1317d5c5a 100644
--- a/storage/innodb_plugin/handler/handler0alter.cc
+++ b/storage/innodb_plugin/handler/handler0alter.cc
@@ -782,10 +782,6 @@ err_exit:
ut_ad(error == DB_SUCCESS);
- /* We will need to rebuild index translation table. Set
- valid index entry count in the translation table to zero */
- share->idx_trans_tbl.index_count = 0;
-
/* Commit the data dictionary transaction in order to release
the table locks on the system tables. This means that if
MySQL crashes while creating a new primary key inside
@@ -911,6 +907,14 @@ error:
}
convert_error:
+ if (error == DB_SUCCESS) {
+ /* Build index is successful. We will need to
+ rebuild index translation table. Reset the
+ index entry count in the translation table
+ to zero, so that translation table will be rebuilt */
+ share->idx_trans_tbl.index_count = 0;
+ }
+
error = convert_error_code_to_mysql(error,
innodb_table->flags,
user_thd);
diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h
index dde3a0bab69..5aa02694e0e 100644
--- a/storage/innodb_plugin/include/btr0btr.h
+++ b/storage/innodb_plugin/include/btr0btr.h
@@ -81,6 +81,91 @@ UNIQUE definition on secondary indexes when we decide if we can use
the insert buffer to speed up inserts */
#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.
@return root page, x-latched */
diff --git a/storage/innodb_plugin/include/btr0types.h b/storage/innodb_plugin/include/btr0types.h
index ef4a6b04b34..07c06fb18d7 100644
--- a/storage/innodb_plugin/include/btr0types.h
+++ b/storage/innodb_plugin/include/btr0types.h
@@ -38,6 +38,131 @@ typedef struct btr_cur_struct btr_cur_t;
/** B-tree search information for the adaptive hash index */
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 reference is stored at the end of the prefix of the field
in the index record. */
diff --git a/storage/innodb_plugin/include/dict0mem.h b/storage/innodb_plugin/include/dict0mem.h
index 09a068ccb93..bd32a239cfd 100644
--- a/storage/innodb_plugin/include/dict0mem.h
+++ b/storage/innodb_plugin/include/dict0mem.h
@@ -340,6 +340,13 @@ struct dict_index_struct{
index, or 0 if the index existed
when InnoDB was started up */
#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
ulint magic_n;/*!< magic number */
/** Value of dict_index_struct::magic_n */
diff --git a/storage/innodb_plugin/include/page0zip.h b/storage/innodb_plugin/include/page0zip.h
index 574809e5227..00c1d0516e6 100644
--- a/storage/innodb_plugin/include/page0zip.h
+++ b/storage/innodb_plugin/include/page0zip.h
@@ -420,7 +420,7 @@ page_zip_copy_recs(
const page_t* src, /*!< in: page */
dict_index_t* index, /*!< in: index of the B-tree */
mtr_t* mtr) /*!< in: mini-transaction */
- __attribute__((nonnull(1,2,3,4)));
+ __attribute__((nonnull));
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i
index 9a719872c50..dc75879dbad 100644
--- a/storage/innodb_plugin/include/univ.i
+++ b/storage/innodb_plugin/include/univ.i
@@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 1
#define INNODB_VERSION_MINOR 0
-#define INNODB_VERSION_BUGFIX 15
+#define INNODB_VERSION_BUGFIX 16
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;
@@ -194,6 +194,8 @@ this will break redo log file compatibility, but it may be useful when
debugging redo log application problems. */
#define UNIV_MEM_DEBUG /* detect memory leaks etc */
#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;
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 */
diff --git a/storage/innodb_plugin/page/page0cur.c b/storage/innodb_plugin/page/page0cur.c
index f10f16a7dd9..936762b986a 100644
--- a/storage/innodb_plugin/page/page0cur.c
+++ b/storage/innodb_plugin/page/page0cur.c
@@ -1149,6 +1149,8 @@ use_heap:
current_rec, index, mtr);
}
+ btr_blob_dbg_add_rec(insert_rec, index, offsets, "insert");
+
return(insert_rec);
}
@@ -1195,10 +1197,12 @@ page_cur_insert_rec_zip_reorg(
}
/* Out of space: restore the page */
+ btr_blob_dbg_remove(page, index, "insert_zip_fail");
if (!page_zip_decompress(page_zip, page, FALSE)) {
ut_error; /* Memory corrupted? */
}
ut_ad(page_validate(page, index));
+ btr_blob_dbg_add(page, index, "insert_zip_fail");
return(NULL);
}
@@ -1490,6 +1494,8 @@ use_heap:
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 */
if (UNIV_LIKELY(mtr != NULL)) {
page_cur_insert_rec_write_log(insert_rec, rec_size,
@@ -1697,6 +1703,9 @@ page_copy_rec_list_end_to_created_page(
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,
index, mtr);
prev_rec = insert_rec;
@@ -1944,6 +1953,7 @@ page_cur_delete_rec(
page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1);
/* 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);
/* 7. Now we have decremented the number of owned records of the slot.
diff --git a/storage/innodb_plugin/page/page0page.c b/storage/innodb_plugin/page/page0page.c
index 10008f9ac25..6cae03e8829 100644
--- a/storage/innodb_plugin/page/page0page.c
+++ b/storage/innodb_plugin/page/page0page.c
@@ -685,12 +685,16 @@ page_copy_rec_list_end(
if (UNIV_UNLIKELY
(!page_zip_reorganize(new_block, index, mtr))) {
+ btr_blob_dbg_remove(new_page, index,
+ "copy_end_reorg_fail");
if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip,
new_page, FALSE))) {
ut_error;
}
ut_ad(page_validate(new_page, index));
+ btr_blob_dbg_add(new_page, index,
+ "copy_end_reorg_fail");
return(NULL);
} else {
/* The page was reorganized:
@@ -803,12 +807,16 @@ page_copy_rec_list_start(
if (UNIV_UNLIKELY
(!page_zip_reorganize(new_block, index, mtr))) {
+ btr_blob_dbg_remove(new_page, index,
+ "copy_start_reorg_fail");
if (UNIV_UNLIKELY
(!page_zip_decompress(new_page_zip,
new_page, FALSE))) {
ut_error;
}
ut_ad(page_validate(new_page, index));
+ btr_blob_dbg_add(new_page, index,
+ "copy_start_reorg_fail");
return(NULL);
} else {
/* The page was reorganized:
@@ -1080,6 +1088,9 @@ page_delete_rec_list_end(
/* Remove the record chain segment from the record chain */
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 */
page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE));
diff --git a/storage/innodb_plugin/page/page0zip.c b/storage/innodb_plugin/page/page0zip.c
index bb9b0995c72..a1dd4177ba8 100644
--- a/storage/innodb_plugin/page/page0zip.c
+++ b/storage/innodb_plugin/page/page0zip.c
@@ -4451,6 +4451,8 @@ page_zip_reorganize(
/* Copy the old page to temporary space */
buf_frame_copy(temp_page, page);
+ btr_blob_dbg_remove(page, index, "zip_reorg");
+
/* Recreate the page: note that global data on page (possible
segment headers, next page-field, etc.) is preserved intact */
@@ -4509,7 +4511,7 @@ page_zip_copy_recs(
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_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));
#ifdef UNIV_ZIP_DEBUG
/* The B-tree operations that call this function may set
@@ -4579,6 +4581,7 @@ page_zip_copy_recs(
#ifdef UNIV_ZIP_DEBUG
ut_a(page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
+ btr_blob_dbg_add(page, index, "page_zip_copy_recs");
page_zip_compress_write_log(page_zip, page, index, mtr);
}
diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c
index 9ded3d68018..3a6de4b94a7 100644
--- a/storage/innodb_plugin/row/row0upd.c
+++ b/storage/innodb_plugin/row/row0upd.c
@@ -498,14 +498,49 @@ row_upd_rec_in_place(
n_fields = upd_get_n_fields(update);
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);
new_val = &(upd_field->new_val);
ut_ad(!dfield_is_ext(new_val) ==
!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,
dfield_get_data(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)) {
diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c
index 73f8f319704..f8b5049ca65 100644
--- a/storage/innodb_plugin/srv/srv0start.c
+++ b/storage/innodb_plugin/srv/srv0start.c
@@ -1061,6 +1061,12 @@ innobase_start_or_create_for_mysql(void)
);
#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
fprintf(stderr,
"InnoDB: !!!!!!!! UNIV_SYNC_DEBUG switched on !!!!!!!!!\n");
diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c
index 00e0324becd..a5da606ad80 100644
--- a/storage/innodb_plugin/sync/sync0rw.c
+++ b/storage/innodb_plugin/sync/sync0rw.c
@@ -260,6 +260,9 @@ rw_lock_create_func(
contains garbage at initialization and cannot be used for
recursive x-locking. */
lock->recursive = FALSE;
+ /* Silence Valgrind when UNIV_DEBUG_VALGRIND is not enabled. */
+ memset((void*) &lock->writer_thread, 0, sizeof lock->writer_thread);
+ UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread);
#ifdef UNIV_SYNC_DEBUG
UT_LIST_INIT(lock->debug_list);