Commit 64096ab5 authored by marko's avatar marko

branches/zip: Clean up after a crash during DROP INDEX.

When InnoDB crashes while dropping an index, ensure that
the index will be completely dropped during crash recovery.

row_merge_drop_index(): Before dropping an index, rename the index to
start with TEMP_INDEX_PREFIX_STR and commit the change, so that
row_merge_drop_temp_indexes() will drop the index after crash
recovery if the server crashes while dropping the index.

fseg_inode_try_get(): New function, forked from fseg_inode_get().
Return NULL if the file segment index node is free.

fseg_inode_get(): Assert that the file segment index node is not free.

fseg_free_step(): If the file segment index node is already free,
print a diagnostic message and return TRUE.

fsp_free_seg_inode(): Write a nonzero number to FSEG_MAGIC_N, so that
allocated-and-freed file segment index nodes can be better
distinguished from uninitialized ones.

This is rb://174, addressing Issue #348.

Tested by restarting mysqld upon the completion of the added
log_write_up_to() invocation below, during DROP INDEX.  The index was
dropped after crash recovery, and re-issuing the DROP INDEX did not
crash the server.

  Index: btr/btr0btr.c
  ===================================================================
  --- btr/btr0btr.c	(revision 6026)
  +++ btr/btr0btr.c	(working copy)
  @@ -42,6 +42,7 @@ Created 6/2/1994 Heikki Tuuri
   #include "ibuf0ibuf.h"
   #include "trx0trx.h"
  +#include "log0log.h"
   
   /*
   Latching strategy of the InnoDB B-tree
   --------------------------------------
  @@ -873,6 +874,8 @@ leaf_loop:
   
   		goto leaf_loop;
   	}
  +
  +	log_write_up_to(mtr.end_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
   top_loop:
   	mtr_start(&mtr);
parent e0e33cb4
2009-10-01 The InnoDB Team
* fsp/fsp0fsp.c, row/row0merge.c:
Clean up after a crash during DROP INDEX. When InnoDB crashes
while dropping an index, ensure that the index will be completely
dropped during crash recovery. The MySQL .frm file may still
contain the dropped index, but there is little that we can do
about it.
2009-09-28 The InnoDB Team
* handler/ha_innodb.cc:
......
......@@ -2041,7 +2041,7 @@ fsp_free_seg_inode(
}
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr);
mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
if (ULINT_UNDEFINED
== fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
......@@ -2057,11 +2057,11 @@ fsp_free_seg_inode(
/**********************************************************************//**
Returns the file segment inode, page x-latched.
@return segment inode, page x-latched */
@return segment inode, page x-latched; NULL if the inode is free */
static
fseg_inode_t*
fseg_inode_get(
/*===========*/
fseg_inode_try_get(
/*===============*/
fseg_header_t* header, /*!< in: segment header */
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes
......@@ -2077,8 +2077,34 @@ fseg_inode_get(
inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
if (UNIV_UNLIKELY
(ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)))) {
inode = NULL;
} else {
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
== FSEG_MAGIC_N_VALUE);
}
return(inode);
}
/**********************************************************************//**
Returns the file segment inode, page x-latched.
@return segment inode, page x-latched */
static
fseg_inode_t*
fseg_inode_get(
/*===========*/
fseg_header_t* header, /*!< in: segment header */
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
mtr_t* mtr) /*!< in: mtr handle */
{
fseg_inode_t* inode
= fseg_inode_try_get(header, space, zip_size, mtr);
ut_a(inode);
return(inode);
}
......@@ -3495,7 +3521,13 @@ fseg_free_step(
ut_a(descr);
ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
inode = fseg_inode_get(header, space, zip_size, mtr);
inode = fseg_inode_try_get(header, space, zip_size, mtr);
if (UNIV_UNLIKELY(inode == NULL)) {
fprintf(stderr, "double free of inode from %u:%u\n",
(unsigned) space, (unsigned) header_page);
return(TRUE);
}
descr = fseg_get_first_extent(inode, space, zip_size, mtr);
......
......@@ -1947,7 +1947,15 @@ row_merge_drop_index(
static const char str1[] =
"PROCEDURE DROP_INDEX_PROC () IS\n"
"BEGIN\n"
/* Rename the index, so that it will be dropped by
row_merge_drop_temp_indexes() at crash recovery
if the server crashes before this trx is committed. */
"UPDATE SYS_INDEXES SET NAME=CONCAT('"
TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n"
"COMMIT WORK;\n"
/* Drop the field definitions of the index. */
"DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n"
/* Drop the index definition and the B-tree. */
"DELETE FROM SYS_INDEXES WHERE ID = :indexid\n"
" AND TABLE_ID = :tableid;\n"
"END;\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