mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 22:12:30 +01:00
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);
This commit is contained in:
parent
e0e33cb44e
commit
64096ab555
3 changed files with 55 additions and 6 deletions
|
@ -1,3 +1,12 @@
|
|||
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";
|
||||
|
|
Loading…
Reference in a new issue