summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <heikki@hundin.mysql.fi>2003-10-13 11:20:19 +0300
committerunknown <heikki@hundin.mysql.fi>2003-10-13 11:20:19 +0300
commit423747b570b5f01b4d2dd06da991f6a8ce15101f (patch)
tree5d5b7191e57ae4eafdff3f6a259ba37729217404
parent963d7baba7a1c37bd2154f04303df8e469f15049 (diff)
downloadmariadb-git-423747b570b5f01b4d2dd06da991f6a8ce15101f.tar.gz
Many files:
ALTER TABLE ... DISCARD/IMPORT TABLESPACE Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x sql/ha_innodb.cc: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/sql_class.cc: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/sql_parse.cc: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/sql_table.cc: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/ha_innodb.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/handler.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/lex.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/mysql_priv.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/sql_class.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/sql_lex.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE sql/sql_yacc.yy: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/ha/ha0ha.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/ha/hash0hash.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/buf/buf0buf.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/buf/buf0flu.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/buf/buf0lru.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/buf/buf0rea.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/btr/btr0btr.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/btr/btr0sea.c: Track crash in buf_LRU_block_remove_hashed_page + 1807 reported in MySQL-3.23.5x innobase/fil/fil0fil.c: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/include/buf0buf.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/include/ha0ha.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/include/hash0hash.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/include/row0mysql.h: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/include/buf0buf.ic: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/include/ha0ha.ic: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/include/ibuf0ibuf.ic: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/page/page0page.c: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/row/row0mysql.c: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/row/row0purge.c: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/row/row0uins.c: ALTER TABLE ... DISCARD/IMPORT TABLESPACE innobase/row/row0umod.c: ALTER TABLE ... DISCARD/IMPORT TABLESPACE
-rw-r--r--innobase/btr/btr0btr.c3
-rw-r--r--innobase/btr/btr0sea.c4
-rw-r--r--innobase/buf/buf0buf.c32
-rw-r--r--innobase/buf/buf0flu.c26
-rw-r--r--innobase/buf/buf0lru.c83
-rw-r--r--innobase/buf/buf0rea.c3
-rw-r--r--innobase/fil/fil0fil.c41
-rw-r--r--innobase/ha/ha0ha.c69
-rw-r--r--innobase/ha/hash0hash.c1
-rw-r--r--innobase/include/buf0buf.h7
-rw-r--r--innobase/include/buf0buf.ic11
-rw-r--r--innobase/include/ha0ha.h2
-rw-r--r--innobase/include/ha0ha.ic35
-rw-r--r--innobase/include/hash0hash.h4
-rw-r--r--innobase/include/ibuf0ibuf.ic2
-rw-r--r--innobase/include/row0mysql.h39
-rw-r--r--innobase/page/page0page.c3
-rw-r--r--innobase/row/row0mysql.c3
-rw-r--r--innobase/row/row0purge.c8
-rw-r--r--innobase/row/row0uins.c7
-rw-r--r--innobase/row/row0umod.c7
-rw-r--r--sql/ha_innodb.cc51
-rw-r--r--sql/ha_innodb.h1
-rw-r--r--sql/handler.h1
-rw-r--r--sql/lex.h3
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_lex.h6
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_table.cc77
-rw-r--r--sql/sql_yacc.yy6
32 files changed, 424 insertions, 118 deletions
diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c
index 1af9336ce72..3d11cbe1748 100644
--- a/innobase/btr/btr0btr.c
+++ b/innobase/btr/btr0btr.c
@@ -426,7 +426,8 @@ btr_page_free_for_ibuf(
flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
- ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr));
+ ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
+ mtr));
}
/******************************************************************
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c
index 8dbffd82a20..e49ee15f5ea 100644
--- a/innobase/btr/btr0sea.c
+++ b/innobase/btr/btr0sea.c
@@ -776,8 +776,8 @@ btr_search_guess_on_hash(
goto failure;
}
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
- ut_ad(page_rec_is_user_rec(rec));
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(page_rec_is_user_rec(rec));
btr_cur_position(index, rec, cursor);
diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c
index 1e1c6b25c1d..b403cc4df0d 100644
--- a/innobase/buf/buf0buf.c
+++ b/innobase/buf/buf0buf.c
@@ -468,6 +468,11 @@ buf_block_init(
block->check_index_page_at_flush = FALSE;
+ block->in_free_list = FALSE;
+ block->in_LRU_list = FALSE;
+
+ block->n_pointers = 0;
+
rw_lock_create(&(block->lock));
ut_ad(rw_lock_validate(&(block->lock)));
@@ -687,6 +692,7 @@ buf_pool_init(
}
UT_LIST_ADD_LAST(free, buf_pool->free, block);
+ block->in_free_list = TRUE;
}
mutex_exit(&(buf_pool->mutex));
@@ -830,7 +836,7 @@ buf_page_make_young(
block = buf_block_align(frame);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
buf_LRU_make_block_young(block);
@@ -845,7 +851,7 @@ buf_block_free(
/*===========*/
buf_block_t* block) /* in, own: block to be freed */
{
- ut_ad(block->state != BUF_BLOCK_FILE_PAGE);
+ ut_a(block->state != BUF_BLOCK_FILE_PAGE);
mutex_enter(&(buf_pool->mutex));
@@ -1109,6 +1115,8 @@ loop:
goto loop;
}
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
must_read = FALSE;
if (block->io_fix == BUF_IO_READ) {
@@ -1407,6 +1415,8 @@ buf_page_get_known_nowait(
return(FALSE);
}
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
#ifdef UNIV_SYNC_DEBUG
buf_block_buf_fix_inc_debug(block, file, line);
#else
@@ -1517,7 +1527,7 @@ buf_page_init(
buf_block_t* block) /* in: block to init */
{
ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(block->state == BUF_BLOCK_READY_FOR_USE);
+ ut_a(block->state != BUF_BLOCK_FILE_PAGE);
/* Set the state of the block */
block->magic_n = BUF_BLOCK_MAGIC_N;
@@ -1533,6 +1543,18 @@ buf_page_init(
/* Insert into the hash table of file pages */
+ if (buf_page_hash_get(space, offset)) {
+ fprintf(stderr,
+"InnoDB: Error: page %lu %lu already found from the hash table\n", space,
+ offset);
+ buf_print();
+ buf_LRU_print();
+ buf_validate();
+ buf_LRU_validate();
+
+ ut_a(0);
+ }
+
HASH_INSERT(buf_block_t, hash, buf_pool->page_hash,
buf_page_address_fold(space, offset), block);
@@ -1605,7 +1627,7 @@ buf_page_init_for_read(
block = buf_block_alloc();
- ut_ad(block);
+ ut_a(block);
mutex_enter(&(buf_pool->mutex));
@@ -1769,6 +1791,8 @@ buf_page_io_complete(
ut_ad(block);
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
io_type = block->io_fix;
if (io_type == BUF_IO_READ) {
diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c
index 3f8022f36bc..27a1829942d 100644
--- a/innobase/buf/buf0flu.c
+++ b/innobase/buf/buf0flu.c
@@ -50,6 +50,8 @@ buf_flush_insert_into_flush_list(
{
ut_ad(mutex_own(&(buf_pool->mutex)));
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
ut_ad((UT_LIST_GET_FIRST(buf_pool->flush_list) == NULL)
|| (ut_dulint_cmp(
(UT_LIST_GET_FIRST(buf_pool->flush_list))
@@ -131,7 +133,7 @@ buf_flush_ready_for_flush(
ulint flush_type)/* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */
{
ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
&& (block->io_fix == 0)) {
@@ -163,6 +165,8 @@ buf_flush_write_complete(
ut_ad(block);
ut_ad(mutex_own(&(buf_pool->mutex)));
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
block->oldest_modification = ut_dulint_zero;
UT_LIST_REMOVE(flush_list, buf_pool->flush_list, block);
@@ -282,6 +286,8 @@ buf_flush_buffered_writes(void)
for (i = 0; i < trx_doublewrite->first_free; i++) {
block = trx_doublewrite->buf_block_arr[i];
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
FALSE, block->space, block->offset, 0, UNIV_PAGE_SIZE,
(void*)block->frame, (void*)block);
@@ -321,6 +327,8 @@ buf_flush_post_to_doublewrite_buf(
try_again:
mutex_enter(&(trx_doublewrite->mutex));
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
if (trx_doublewrite->first_free
>= 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
mutex_exit(&(trx_doublewrite->mutex));
@@ -395,6 +403,8 @@ buf_flush_write_block_low(
/*======================*/
buf_block_t* block) /* in: buffer block to write */
{
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
#ifdef UNIV_IBUF_DEBUG
ut_a(ibuf_count_get(block->space, block->offset) == 0);
#endif
@@ -443,7 +453,7 @@ buf_flush_try_page(
block = buf_page_hash_get(space, offset);
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE);
if (flush_type == BUF_FLUSH_LIST
&& block && buf_flush_ready_for_flush(block, flush_type)) {
@@ -635,6 +645,7 @@ buf_flush_try_neighbors(
for (i = low; i < high; i++) {
block = buf_page_hash_get(space, i);
+ ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE);
if (block && flush_type == BUF_FLUSH_LRU && i != offset
&& !block->old) {
@@ -703,10 +714,10 @@ buf_flush_batch(
ulint offset;
ibool found;
- ut_ad((flush_type == BUF_FLUSH_LRU) || (flush_type == BUF_FLUSH_LIST));
- ut_ad((flush_type != BUF_FLUSH_LIST) ||
- sync_thread_levels_empty_gen(TRUE));
-
+ ut_ad((flush_type == BUF_FLUSH_LRU)
+ || (flush_type == BUF_FLUSH_LIST));
+ ut_ad((flush_type != BUF_FLUSH_LIST)
+ || sync_thread_levels_empty_gen(TRUE));
mutex_enter(&(buf_pool->mutex));
if ((buf_pool->n_flush[flush_type] > 0)
@@ -737,7 +748,6 @@ buf_flush_batch(
ut_ad(flush_type == BUF_FLUSH_LIST);
block = UT_LIST_GET_LAST(buf_pool->flush_list);
-
if (!block
|| (ut_dulint_cmp(block->oldest_modification,
lsn_limit) >= 0)) {
@@ -756,6 +766,7 @@ buf_flush_batch(
function a pointer to a block in the list! */
while ((block != NULL) && !found) {
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
if (buf_flush_ready_for_flush(block, flush_type)) {
@@ -781,7 +792,6 @@ buf_flush_batch(
} else if (flush_type == BUF_FLUSH_LRU) {
block = UT_LIST_GET_PREV(LRU, block);
-
} else {
ut_ad(flush_type == BUF_FLUSH_LIST);
diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c
index 5d48d460745..55a5ecbeba5 100644
--- a/innobase/buf/buf0lru.c
+++ b/innobase/buf/buf0lru.c
@@ -82,6 +82,8 @@ scan_again:
block = UT_LIST_GET_LAST(buf_pool->LRU);
while (block != NULL) {
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
if (block->space == id
&& (block->buf_fix_count > 0 || block->io_fix != 0)) {
@@ -199,19 +201,16 @@ buf_LRU_search_and_free_block(
mutex_enter(&(buf_pool->mutex));
freed = FALSE;
-
block = UT_LIST_GET_LAST(buf_pool->LRU);
while (block != NULL) {
-
+ ut_a(block->in_LRU_list);
if (buf_flush_ready_for_replace(block)) {
-
if (buf_debug_prints) {
printf(
"Putting space %lu page %lu to free list\n",
block->space, block->offset);
}
-
buf_LRU_block_remove_hashed_page(block);
mutex_exit(&(buf_pool->mutex));
@@ -223,25 +222,21 @@ buf_LRU_search_and_free_block(
if (block->frame) {
btr_search_drop_page_hash_index(block->frame);
}
-
mutex_enter(&(buf_pool->mutex));
ut_a(block->buf_fix_count == 0);
buf_LRU_block_free_hashed_page(block);
-
freed = TRUE;
break;
}
-
block = UT_LIST_GET_PREV(LRU, block);
distance++;
if (!freed && n_iterations <= 10
&& distance > 100 + (n_iterations * buf_pool->curr_size)
/ 10) {
-
buf_pool->LRU_flush_ended = 0;
mutex_exit(&(buf_pool->mutex));
@@ -249,15 +244,12 @@ buf_LRU_search_and_free_block(
return(FALSE);
}
}
-
if (buf_pool->LRU_flush_ended > 0) {
buf_pool->LRU_flush_ended--;
}
-
- if (!freed) {
+ if (!freed) {
buf_pool->LRU_flush_ended = 0;
}
-
mutex_exit(&(buf_pool->mutex));
return(freed);
@@ -355,7 +347,11 @@ loop:
if (UT_LIST_GET_LEN(buf_pool->free) > 0) {
block = UT_LIST_GET_FIRST(buf_pool->free);
+ ut_a(block->in_free_list);
UT_LIST_REMOVE(free, buf_pool->free, block);
+ block->in_free_list = FALSE;
+ ut_a(block->state != BUF_BLOCK_FILE_PAGE);
+ ut_a(!block->in_LRU_list);
if (srv_use_awe) {
if (block->frame) {
@@ -466,7 +462,7 @@ buf_LRU_old_adjust_len(void)
ulint old_len;
ulint new_len;
- ut_ad(buf_pool->LRU_old);
+ ut_a(buf_pool->LRU_old);
ut_ad(mutex_own(&(buf_pool->mutex)));
ut_ad(3 * (BUF_LRU_OLD_MIN_LEN / 8) > BUF_LRU_OLD_TOLERANCE + 5);
@@ -474,6 +470,8 @@ buf_LRU_old_adjust_len(void)
old_len = buf_pool->LRU_old_len;
new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
+ ut_a(buf_pool->LRU_old->in_LRU_list);
+
/* Update the LRU_old pointer if necessary */
if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) {
@@ -490,7 +488,7 @@ buf_LRU_old_adjust_len(void)
buf_pool->LRU_old);
buf_pool->LRU_old_len--;
} else {
- ut_ad(buf_pool->LRU_old); /* Check that we did not
+ ut_a(buf_pool->LRU_old); /* Check that we did not
fall out of the LRU list */
return;
}
@@ -498,9 +496,8 @@ buf_LRU_old_adjust_len(void)
}
/***********************************************************************
-Initializes the old blocks pointer in the LRU list.
-This function should be called when the LRU list grows to
-BUF_LRU_OLD_MIN_LEN length. */
+Initializes the old blocks pointer in the LRU list. This function should be
+called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */
static
void
buf_LRU_old_init(void)
@@ -508,7 +505,7 @@ buf_LRU_old_init(void)
{
buf_block_t* block;
- ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
+ ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
/* We first initialize all blocks in the LRU list as old and then use
the adjust function to move the LRU_old pointer to the right
@@ -517,6 +514,8 @@ buf_LRU_old_init(void)
block = UT_LIST_GET_FIRST(buf_pool->LRU);
while (block != NULL) {
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(block->in_LRU_list);
block->old = TRUE;
block = UT_LIST_GET_NEXT(LRU, block);
}
@@ -539,6 +538,9 @@ buf_LRU_remove_block(
ut_ad(block);
ut_ad(mutex_own(&(buf_pool->mutex)));
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(block->in_LRU_list);
+
/* If the LRU_old pointer is defined and points to just this block,
move it backward one step */
@@ -552,11 +554,12 @@ buf_LRU_remove_block(
(buf_pool->LRU_old)->old = TRUE;
buf_pool->LRU_old_len++;
- ut_ad(buf_pool->LRU_old);
+ ut_a(buf_pool->LRU_old);
}
/* Remove the block from the LRU list */
UT_LIST_REMOVE(LRU, buf_pool->LRU, block);
+ block->in_LRU_list = FALSE;
if (srv_use_awe && block->frame) {
/* Remove from the list of mapped pages */
@@ -599,6 +602,8 @@ buf_LRU_add_block_to_end_low(
ut_ad(block);
ut_ad(mutex_own(&(buf_pool->mutex)));
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
block->old = TRUE;
last_block = UT_LIST_GET_LAST(buf_pool->LRU);
@@ -609,7 +614,9 @@ buf_LRU_add_block_to_end_low(
block->LRU_position = buf_pool_clock_tic();
}
+ ut_a(!block->in_LRU_list);
UT_LIST_ADD_LAST(LRU, buf_pool->LRU, block);
+ block->in_LRU_list = TRUE;
if (srv_use_awe && block->frame) {
/* Add to the list of mapped pages */
@@ -658,6 +665,9 @@ buf_LRU_add_block_low(
ut_ad(block);
ut_ad(mutex_own(&(buf_pool->mutex)));
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(!block->in_LRU_list);
+
block->old = old;
cl = buf_pool_clock_tic();
@@ -687,6 +697,8 @@ buf_LRU_add_block_low(
block->LRU_position = (buf_pool->LRU_old)->LRU_position;
}
+ block->in_LRU_list = TRUE;
+
if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
ut_ad(buf_pool->LRU_old);
@@ -755,9 +767,12 @@ buf_LRU_block_free_non_file_page(
ut_ad(mutex_own(&(buf_pool->mutex)));
ut_ad(block);
- ut_ad((block->state == BUF_BLOCK_MEMORY)
+ ut_a((block->state == BUF_BLOCK_MEMORY)
|| (block->state == BUF_BLOCK_READY_FOR_USE));
+ ut_a(block->n_pointers == 0);
+ ut_a(!block->in_free_list);
+
block->state = BUF_BLOCK_NOT_USED;
#ifdef UNIV_DEBUG
@@ -765,6 +780,7 @@ buf_LRU_block_free_non_file_page(
memset(block->frame, '\0', UNIV_PAGE_SIZE);
#endif
UT_LIST_ADD_FIRST(free, buf_pool->free, block);
+ block->in_free_list = TRUE;
if (srv_use_awe && block->frame) {
/* Add to the list of mapped pages */
@@ -788,8 +804,7 @@ buf_LRU_block_remove_hashed_page(
ut_ad(mutex_own(&(buf_pool->mutex)));
ut_ad(block);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
-
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
ut_a(block->io_fix == 0);
ut_a(block->buf_fix_count == 0);
ut_a(ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) == 0);
@@ -802,6 +817,28 @@ buf_LRU_block_remove_hashed_page(
buf_block_modify_clock_inc(block);
+ if (block != buf_page_hash_get(block->space, block->offset)) {
+ fprintf(stderr,
+"InnoDB: Error: page %lu %lu not found from the hash table\n",
+ block->space,
+ block->offset);
+ if (buf_page_hash_get(block->space, block->offset)) {
+ fprintf(stderr,
+"InnoDB: From hash table we find block %lx of %lu %lu which is not %lx\n",
+ (ulint)buf_page_hash_get(block->space, block->offset),
+ buf_page_hash_get(block->space, block->offset)->space,
+ buf_page_hash_get(block->space, block->offset)->offset,
+ (ulint)block);
+ }
+
+ buf_print();
+ buf_LRU_print();
+ buf_validate();
+ buf_LRU_validate();
+
+ ut_a(0);
+ }
+
HASH_DELETE(buf_block_t, hash, buf_pool->page_hash,
buf_page_address_fold(block->space, block->offset),
block);
@@ -819,7 +856,7 @@ buf_LRU_block_free_hashed_page(
be in a state where it can be freed */
{
ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(block->state == BUF_BLOCK_REMOVE_HASH);
+ ut_a(block->state == BUF_BLOCK_REMOVE_HASH);
block->state = BUF_BLOCK_MEMORY;
diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c
index 8cc379e75d8..0fa6912ba1d 100644
--- a/innobase/buf/buf0rea.c
+++ b/innobase/buf/buf0rea.c
@@ -129,6 +129,8 @@ buf_read_page_low(
offset, sync);
}
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+
*err = fil_io(OS_FILE_READ | wake_later,
sync, space,
offset, 0, UNIV_PAGE_SIZE,
@@ -604,7 +606,6 @@ buf_read_ibuf_merge_pages(
}
for (i = 0; i < n_stored; i++) {
-
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE,
space_ids[i], space_versions[i], page_nos[i]);
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c
index 2b0138ccb5a..f96d98c7b2d 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -1517,8 +1517,8 @@ try_again:
if (space == NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
-" InnoDB: Error: cannot delete tablespace %lu because it is not found\n"
-"InnoDB: in the tablespace memory cache.\n", id);
+" InnoDB: Error: cannot delete tablespace %lu\n"
+"InnoDB: because it is not found in the tablespace memory cache.\n", id);
mutex_exit(&(system->mutex));
@@ -2426,19 +2426,24 @@ fil_space_for_table_exists_in_mem(
if (namespace == NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
-" InnoDB: Error: table %s in InnoDB data dictionary has tablespace\n"
-"InnoDB: id %lu, but tablespace with that id or name does not exist. Have\n"
-"InnoDB: you deleted or moved .ibd files? We cannot open table %s now.\n",
- name, id, name);
+" InnoDB: Error: table %s\n"
+"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
+"InnoDB: but tablespace with that id or name does not exist. Have\n"
+"InnoDB: you deleted or moved .ibd files?\n",
+ name, id);
} else {
ut_print_timestamp(stderr);
fprintf(stderr,
-" InnoDB: Error: table %s in InnoDB data dictionary has tablespace\n"
-"InnoDB: id %lu, but tablespace with that id does not exist. There is\n"
+" InnoDB: Error: table %s\n"
+"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
+"InnoDB: but tablespace with that id does not exist. There is\n"
"InnoDB: a tablespace of name %s and id %lu, though. Have\n"
-"InnoDB: you deleted or moved .ibd files? We cannot open table %s now.\n",
- name, id, namespace->name, namespace->id, name);
+"InnoDB: you deleted or moved .ibd files?\n",
+ name, id, namespace->name, namespace->id);
}
+ fprintf(stderr,
+"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
+"InnoDB: how to resolve the issue.\n");
mutex_exit(&(system->mutex));
@@ -2448,16 +2453,20 @@ fil_space_for_table_exists_in_mem(
if (0 != strcmp(space->name, path)) {
ut_print_timestamp(stderr);
fprintf(stderr,
-" InnoDB: Error: table %s in InnoDB data dictionary has tablespace\n"
-"InnoDB: id %lu, but tablespace with that id has name %s. Have you\n"
-"InnoDB: deleted or moved .ibd files? We cannot open table %s now.\n",
- name, id, space->name, name);
+" InnoDB: Error: table %s\n"
+"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
+"InnoDB: but tablespace with that id has name %s.\n"
+"InnoDB: Have you deleted or moved .ibd files?", name, id, space->name);
if (namespace != NULL) {
fprintf(stderr,
-"InnoDB: There is a tablespace with the right name %s, but its id is %lu.\n",
- namespace->name, namespace->id);
+"InnoDB: There is a tablespace with the right name\n"
+"InnoDB: %s, but its id is %lu.\n", namespace->name, namespace->id);
}
+ fprintf(stderr,
+"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
+"InnoDB: how to resolve the issue.\n");
+
mutex_exit(&(system->mutex));
return(FALSE);
diff --git a/innobase/ha/ha0ha.c b/innobase/ha/ha0ha.c
index c7e23d0be1e..87c32bf5dbd 100644
--- a/innobase/ha/ha0ha.c
+++ b/innobase/ha/ha0ha.c
@@ -34,6 +34,12 @@ ha_create(
table = hash_create(n);
+ if (in_btr_search) {
+ table->adaptive = TRUE;
+ } else {
+ table->adaptive = FALSE;
+ }
+
if (n_mutexes == 0) {
if (in_btr_search) {
table->heap = mem_heap_create_in_btr_search(4096);
@@ -106,6 +112,7 @@ ha_insert_for_fold(
hash_cell_t* cell;
ha_node_t* node;
ha_node_t* prev_node;
+ buf_block_t* prev_block;
ulint hash;
ut_ad(table && data);
@@ -119,6 +126,12 @@ ha_insert_for_fold(
while (prev_node != NULL) {
if (prev_node->fold == fold) {
+ if (table->adaptive) {
+ prev_block = buf_block_align(prev_node->data);
+ ut_a(prev_block->n_pointers > 0);
+ prev_block->n_pointers--;
+ buf_block_align(data)->n_pointers++;
+ }
prev_node->data = data;
@@ -142,6 +155,11 @@ ha_insert_for_fold(
}
ha_node_set_data(node, data);
+
+ if (table->adaptive) {
+ buf_block_align(data)->n_pointers++;
+ }
+
node->fold = fold;
node->next = NULL;
@@ -174,6 +192,11 @@ ha_delete_hash_node(
hash_table_t* table, /* in: hash table */
ha_node_t* del_node) /* in: node to be deleted */
{
+ if (table->adaptive) {
+ ut_a(buf_block_align(del_node->data)->n_pointers > 0);
+ buf_block_align(del_node->data)->n_pointers--;
+ }
+
HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
}
@@ -199,6 +222,35 @@ ha_delete(
ha_delete_hash_node(table, node);
}
+/*************************************************************
+Looks for an element when we know the pointer to the data, and updates
+the pointer to data, if found. */
+
+void
+ha_search_and_update_if_found(
+/*==========================*/
+ hash_table_t* table, /* in: hash table */
+ ulint fold, /* in: folded value of the searched data */
+ void* data, /* in: pointer to the data */
+ void* new_data)/* in: new pointer to the data */
+{
+ ha_node_t* node;
+
+ ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
+
+ node = ha_search_with_data(table, fold, data);
+
+ if (node) {
+ if (table->adaptive) {
+ ut_a(buf_block_align(node->data)->n_pointers > 0);
+ buf_block_align(node->data)->n_pointers--;
+ buf_block_align(new_data)->n_pointers++;
+ }
+
+ node->data = new_data;
+ }
+}
+
/*********************************************************************
Removes from the chain determined by fold all nodes whose data pointer
points to the page given. */
@@ -229,10 +281,10 @@ ha_remove_all_nodes_to_page(
node = ha_chain_get_first(table, fold);
} else {
- node = ha_chain_get_next(table, node);
+ node = ha_chain_get_next(node);
}
}
-
+#ifdef UNIV_DEBUG
/* Check that all nodes really got deleted */
node = ha_chain_get_first(table, fold);
@@ -240,8 +292,9 @@ ha_remove_all_nodes_to_page(
while (node) {
ut_a(buf_frame_align(ha_node_get_data(node)) != page);
- node = ha_chain_get_next(table, node);
+ node = ha_chain_get_next(node);
}
+#endif
}
/*****************************************************************
@@ -293,12 +346,10 @@ ha_print_info(
hash_table_t* table) /* in: hash table */
{
hash_cell_t* cell;
-/*
- ha_node_t* node;
- ulint len = 0;
- ulint max_len = 0;
- ulint nodes = 0;
-*/
+/* ha_node_t* node;
+ ulint nodes = 0;
+ ulint len = 0;
+ ulint max_len = 0; */
ulint cells = 0;
ulint n_bufs;
ulint i;
diff --git a/innobase/ha/hash0hash.c b/innobase/ha/hash0hash.c
index 1f7edf9d7d2..facdea66198 100644
--- a/innobase/ha/hash0hash.c
+++ b/innobase/ha/hash0hash.c
@@ -91,6 +91,7 @@ hash_create(
array = ut_malloc(sizeof(hash_cell_t) * prime);
+ table->adaptive = FALSE;
table->array = array;
table->n_cells = prime;
table->n_mutexes = 0;
diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h
index 0457da60534..3f2fd5bbbe0 100644
--- a/innobase/include/buf0buf.h
+++ b/innobase/include/buf0buf.h
@@ -755,12 +755,16 @@ struct buf_block_struct{
UT_LIST_NODE_T(buf_block_t) free;
/* node of the free block list */
+ ibool in_free_list; /* TRUE if in the free list; used in
+ debugging */
UT_LIST_NODE_T(buf_block_t) LRU;
/* node of the LRU list */
UT_LIST_NODE_T(buf_block_t) awe_LRU_free_mapped;
/* in the AWE version node in the
list of free and LRU blocks which are
mapped to a frame */
+ ibool in_LRU_list; /* TRUE of the page is in the LRU list;
+ used in debugging */
ulint LRU_position; /* value which monotonically
decreases (or may stay constant if
the block is in the old blocks) toward
@@ -821,6 +825,9 @@ struct buf_block_struct{
complete, though: there may have been
hash collisions, record deletions,
etc. */
+ ulint n_pointers; /* used in debugging: the number of
+ pointers in the adaptive hash index
+ pointing to this frame */
ulint curr_n_fields; /* prefix length for hash indexing:
number of full fields */
ulint curr_n_bytes; /* number of bytes in hash indexing */
diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic
index d4e7122f3f9..281bb1ea527 100644
--- a/innobase/include/buf0buf.ic
+++ b/innobase/include/buf0buf.ic
@@ -28,7 +28,6 @@ buf_block_peek_if_too_old(
{
if (buf_pool->freed_page_clock >= block->freed_page_clock
+ 1 + (buf_pool->curr_size / 1024)) {
-
return(TRUE);
}
@@ -169,7 +168,7 @@ buf_block_get_space(
ut_ad(block);
ut_ad(block >= buf_pool->blocks);
ut_ad(block < buf_pool->blocks + buf_pool->max_size);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
ut_ad(block->buf_fix_count > 0);
return(block->space);
@@ -187,7 +186,7 @@ buf_block_get_page_no(
ut_ad(block);
ut_ad(block >= buf_pool->blocks);
ut_ad(block < buf_pool->blocks + buf_pool->max_size);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
ut_ad(block->buf_fix_count > 0);
return(block->offset);
@@ -550,6 +549,8 @@ buf_page_hash_get(
HASH_SEARCH(hash, buf_pool->page_hash, fold, block,
(block->space == space) && (block->offset == offset));
+ ut_a(block == NULL || block->state == BUF_BLOCK_FILE_PAGE);
+
return(block);
}
@@ -617,8 +618,8 @@ buf_page_release(
mutex_enter_fast(&(buf_pool->mutex));
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
- ut_ad(block->buf_fix_count > 0);
+ ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_a(block->buf_fix_count > 0);
if (rw_latch == RW_X_LATCH && mtr->modifications) {
diff --git a/innobase/include/ha0ha.h b/innobase/include/ha0ha.h
index 0beac928b7e..c3fc04b47bb 100644
--- a/innobase/include/ha0ha.h
+++ b/innobase/include/ha0ha.h
@@ -28,7 +28,7 @@ ha_search_and_get_data(
/*************************************************************
Looks for an element when we know the pointer to the data and updates
the pointer to data if found. */
-UNIV_INLINE
+
void
ha_search_and_update_if_found(
/*==========================*/
diff --git a/innobase/include/ha0ha.ic b/innobase/include/ha0ha.ic
index 761bc3b20de..22da7107659 100644
--- a/innobase/include/ha0ha.ic
+++ b/innobase/include/ha0ha.ic
@@ -49,7 +49,6 @@ ha_node_t*
ha_chain_get_next(
/*==============*/
/* out: next node, NULL if none */
- hash_table_t* table __attribute__((unused)), /* in: hash table */
ha_node_t* node) /* in: hash chain node */
{
ut_ad(table);
@@ -94,7 +93,7 @@ ha_search(
return(node);
}
- node = ha_chain_get_next(table, node);
+ node = ha_chain_get_next(node);
}
return(NULL);
@@ -124,7 +123,7 @@ ha_search_and_get_data(
return(node->data);
}
- node = ha_chain_get_next(table, node);
+ node = ha_chain_get_next(node);
}
return(NULL);
@@ -139,7 +138,6 @@ ha_next(
/* out: pointer to the next hash table node
in chain with the fold value, NULL if not
found */
- hash_table_t* table, /* in: hash table */
ha_node_t* node) /* in: hash table node */
{
ulint fold;
@@ -148,7 +146,7 @@ ha_next(
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
- node = ha_chain_get_next(table, node);
+ node = ha_chain_get_next(node);
while (node) {
if (node->fold == fold) {
@@ -156,7 +154,7 @@ ha_next(
return(node);
}
- node = ha_chain_get_next(table, node);
+ node = ha_chain_get_next(node);
}
return(NULL);
@@ -186,36 +184,13 @@ ha_search_with_data(
return(node);
}
- node = ha_chain_get_next(table, node);
+ node = ha_chain_get_next(node);
}
return(NULL);
}
/*************************************************************
-Looks for an element when we know the pointer to the data, and updates
-the pointer to data, if found. */
-UNIV_INLINE
-void
-ha_search_and_update_if_found(
-/*==========================*/
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of the searched data */
- void* data, /* in: pointer to the data */
- void* new_data)/* in: new pointer to the data */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_search_with_data(table, fold, data);
-
- if (node) {
- node->data = new_data;
- }
-}
-
-/*************************************************************
Looks for an element when we know the pointer to the data, and deletes
it from the hash table, if found. */
UNIV_INLINE
diff --git a/innobase/include/hash0hash.h b/innobase/include/hash0hash.h
index 378925a5bea..2e9ab498116 100644
--- a/innobase/include/hash0hash.h
+++ b/innobase/include/hash0hash.h
@@ -100,7 +100,7 @@ Deletes a struct from a hash table. */
\
while (struct3333->NAME != DATA) {\
\
- ut_ad(struct3333)\
+ ut_a(struct3333)\
struct3333 = struct3333->NAME;\
}\
\
@@ -322,6 +322,8 @@ struct hash_cell_struct{
/* The hash table structure */
struct hash_table_struct {
+ ibool adaptive;/* TRUE if this is the hash table of the
+ adaptive hash index */
ulint n_cells;/* number of cells in the hash table */
hash_cell_t* array; /* pointer to cell array */
ulint n_mutexes;/* if mutexes != NULL, then the number of
diff --git a/innobase/include/ibuf0ibuf.ic b/innobase/include/ibuf0ibuf.ic
index 0886c8c02cc..68f7ce9c1d0 100644
--- a/innobase/include/ibuf0ibuf.ic
+++ b/innobase/include/ibuf0ibuf.ic
@@ -218,7 +218,7 @@ ibuf_update_free_bits_if_full(
}
if (after == 0) {
- /* We move the page to front of the buffer pool LRU list:
+ /* We move the page to the front of the buffer pool LRU list:
the purpose of this is to prevent those pages to which we
cannot make inserts using the insert buffer from slipping
out of the buffer pool */
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index 1964f53dabb..fade3709631 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -339,6 +339,45 @@ row_drop_table_for_mysql(
char* name, /* in: table name */
trx_t* trx); /* in: transaction handle */
/*************************************************************************
+Discards the tablespace of a table which stored in an .ibd file. Discarding
+means that this function deletes the .ibd file and assigns a new table id for
+the table. Also the flag table->ibd_file_missing is set TRUE.
+
+How do we prevent crashes caused by ongoing operations on the table? Old
+operations could try to access non-existent pages.
+
+1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock
+on the table before we can do DISCARD TABLESPACE. Then there are no running
+queries on the table.
+2) Purge and rollback: we assign a new table id for the table. Since purge and
+rollback look for the table based on the table id, they see the table as
+'dropped' and discard their operations.
+3) Insert buffer: we remove all entries for the tablespace in the insert
+buffer tree; as long as the tablespace mem object does not exist, ongoing
+insert buffer page merges are discarded in buf0rea.c. If we recreate the
+tablespace mem object with IMPORT TABLESPACE later, then the tablespace will
+have the same id, but the tablespace_version field in the mem object is
+different, and ongoing old insert buffer page merges get discarded.
+4) Linear readahead and random readahead: we use the same method as in 3) to
+discard ongoing operations. */
+
+int
+row_discard_tablespace_for_mysql(
+/*=============================*/
+ /* out: error code or DB_SUCCESS */
+ char* name, /* in: table name */
+ trx_t* trx); /* in: transaction handle */
+/*********************************************************************
+Imports a tablespace. The space id in the .ibd file must match the space id
+of the table in the data dictionary. */
+
+int
+row_import_tablespace_for_mysql(
+/*============================*/
+ /* out: error code or DB_SUCCESS */
+ char* name, /* in: table name */
+ trx_t* trx); /* in: transaction handle */
+/*************************************************************************
Drops a database for MySQL. */
int
diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c
index e087941a970..2422f0ff87e 100644
--- a/innobase/page/page0page.c
+++ b/innobase/page/page0page.c
@@ -582,7 +582,8 @@ byte*
page_parse_delete_rec_list(
/*=======================*/
/* out: end of log record or NULL */
- byte type, /* in: MLOG_LIST_END_DELETE or MLOG_LIST_START_DELETE */
+ byte type, /* in: MLOG_LIST_END_DELETE or
+ MLOG_LIST_START_DELETE */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
page_t* page, /* in: page or NULL */
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 497b74fd320..5d5985d16af 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -2007,9 +2007,6 @@ row_import_tablespace_for_mysql(
success = fil_open_single_table_tablespace(table->space, table->name);
- printf(
-"Remember to stop purge + undo if table->ibd_file_is_missing!!!\n");
-
if (success) {
table->ibd_file_missing = FALSE;
table->tablespace_discarded = FALSE;
diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c
index 104d71eda2d..99332dc275d 100644
--- a/innobase/row/row0purge.c
+++ b/innobase/row/row0purge.c
@@ -529,6 +529,14 @@ row_purge_parse_undo_rec(
return(FALSE);
}
+ if (node->table->ibd_file_missing) {
+ /* We skip purge of missing .ibd files */
+
+ node->table = NULL;
+
+ return;
+ }
+
clust_index = dict_table_get_first_index(node->table);
if (clust_index == NULL) {
diff --git a/innobase/row/row0uins.c b/innobase/row/row0uins.c
index fff67dcd627..08f0e29c839 100644
--- a/innobase/row/row0uins.c
+++ b/innobase/row/row0uins.c
@@ -258,6 +258,13 @@ row_undo_ins_parse_undo_rec(
return;
}
+ if (node->table->ibd_file_missing) {
+ /* We skip undo operations to missing .ibd files */
+ node->table = NULL;
+
+ return;
+ }
+
clust_index = dict_table_get_first_index(node->table);
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c
index b22e494f891..0a050e0a1b6 100644
--- a/innobase/row/row0umod.c
+++ b/innobase/row/row0umod.c
@@ -620,6 +620,13 @@ row_undo_mod_parse_undo_rec(
return;
}
+ if (node->table->ibd_file_missing) {
+ /* We skip undo operations to missing .ibd files */
+ node->table = NULL;
+
+ return;
+ }
+
clust_index = dict_table_get_first_index(node->table);
ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index f1072c3137a..d07b166d9e2 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1451,7 +1451,7 @@ ha_innobase::open(
DBUG_RETURN(1);
}
- if (ib_table->ibd_file_missing) {
+ if (ib_table->ibd_file_missing && !current_thd->tablespace_op) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB error:\n"
"MySQL is trying to open a table handle but the .ibd file for\n"
@@ -3629,6 +3629,42 @@ ha_innobase::create(
}
/*********************************************************************
+Discards or imports an InnoDB tablespace. */
+
+int
+ha_innobase::discard_or_import_tablespace(
+/*======================================*/
+ /* out: 0 == success, -1 == error */
+ my_bool discard) /* in: TRUE if discard, else import */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ dict_table_t* table;
+ trx_t* trx;
+ int err;
+
+ DBUG_ENTER("ha_innobase::discard_or_import_tablespace");
+
+ ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
+ ut_a(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
+
+ table = prebuilt->table;
+ trx = prebuilt->trx;
+
+ if (discard) {
+ err = row_discard_tablespace_for_mysql(table->name, trx);
+ } else {
+ err = row_import_tablespace_for_mysql(table->name, trx);
+ }
+
+ if (err == DB_SUCCESS) {
+ DBUG_RETURN(0);
+ }
+
+ DBUG_RETURN(-1);
+}
+
+/*********************************************************************
Drops a table from an InnoDB database. Before calling this function,
MySQL calls innobase_commit to commit the transaction of the current user.
Then the current user cannot have locks set on the table. Drop table
@@ -3647,7 +3683,7 @@ ha_innobase::delete_table(
trx_t* trx;
char norm_name[1000];
- DBUG_ENTER("ha_innobase::delete_table");
+ DBUG_ENTER("ha_innobase::delete_table");
/* Get the transaction associated with the current thd, or create one
if not yet created */
@@ -4536,7 +4572,8 @@ ha_innobase::external_lock(
update_thd(thd);
- if (lock_type != F_UNLCK && prebuilt->table->ibd_file_missing) {
+ if (lock_type != F_UNLCK && prebuilt->table->ibd_file_missing
+ && !current_thd->tablespace_op) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB error:\n"
"MySQL is trying to use a table handle but the .ibd file for\n"
@@ -4546,6 +4583,7 @@ ha_innobase::external_lock(
"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
"how you can resolve the problem.\n",
prebuilt->table->name);
+ DBUG_RETURN(HA_ERR_CRASHED);
}
trx = prebuilt->trx;
@@ -4793,11 +4831,12 @@ ha_innobase::store_lock(
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
- /* If we are not doing a LOCK TABLE, then allow multiple
- writers */
+ /* If we are not doing a LOCK TABLE or DISCARD/IMPORT
+ TABLESPACE, then allow multiple writers */
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
- lock_type <= TL_WRITE) && !thd->in_lock_tables) {
+ lock_type <= TL_WRITE) && !thd->in_lock_tables
+ && !thd->tablespace_op) {
lock_type = TL_WRITE_ALLOW_WRITE;
}
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index b17097b3c57..0c89a9d29ce 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -160,6 +160,7 @@ class ha_innobase: public handler
void info(uint);
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int optimize(THD* thd,HA_CHECK_OPT* check_opt);
+ int discard_or_import_tablespace(my_bool discard);
int extra(enum ha_extra_function operation);
int reset(void);
int external_lock(THD *thd, int lock_type);
diff --git a/sql/handler.h b/sql/handler.h
index b74e06c6edf..b756d9a09fb 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -317,6 +317,7 @@ public:
virtual int dump(THD* thd, int fd = -1) { return ER_DUMP_NOT_IMPLEMENTED; }
virtual void deactivate_non_unique_index(ha_rows rows) {}
virtual bool activate_all_index(THD *thd) {return 0;}
+ virtual int discard_or_import_tablespace(my_bool discard) {return -1;}
// not implemented by default
virtual int net_read_dump(NET* net)
{ return ER_DUMP_NOT_IMPLEMENTED; }
diff --git a/sql/lex.h b/sql/lex.h
index e11b50ed16d..859f92dd752 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -130,6 +130,7 @@ static SYMBOL symbols[] = {
{ "DESCRIBE", SYM(DESCRIBE),0,0},
{ "DIRECTORY", SYM(DIRECTORY_SYM),0,0},
{ "DISABLE", SYM(DISABLE_SYM),0,0},
+ { "DISCARD", SYM(DISCARD),0,0},
{ "DISTINCT", SYM(DISTINCT),0,0},
{ "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */
{ "DIV", SYM(DIV_SYM),0,0},
@@ -200,6 +201,7 @@ static SYMBOL symbols[] = {
{ "INNER", SYM(INNER_SYM),0,0},
{ "INNOBASE", SYM(INNOBASE_SYM),0,0},
{ "INNODB", SYM(INNOBASE_SYM),0,0},
+ { "IMPORT", SYM(IMPORT),0,0},
{ "INSERT", SYM(INSERT),0,0},
{ "INSERT_METHOD", SYM(INSERT_METHOD),0,0},
{ "INT", SYM(INT_SYM),0,0},
@@ -387,6 +389,7 @@ static SYMBOL symbols[] = {
{ "SUPER", SYM(SUPER_SYM),0,0},
{ "TABLE", SYM(TABLE_SYM),0,0},
{ "TABLES", SYM(TABLES),0,0},
+ { "TABLESPACE", SYM(TABLESPACE),0,0},
{ "TEMPORARY", SYM(TEMPORARY),0,0},
{ "TERMINATED", SYM(TERMINATED),0,0},
{ "TEXT", SYM(TEXT_SYM),0,0},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index afbda2b4ad1..a1919bf1a0e 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -486,6 +486,7 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name,
bool drop_primary,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
+ enum tablespace_op_type tablespace_op=NO_TABLESPACE_OP,
bool simple_alter=0);
int mysql_create_like_table(THD *thd, TABLE_LIST *table,
HA_CREATE_INFO *create_info,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index cdca7454698..c7d77c67236 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -173,6 +173,7 @@ THD::THD():user_time(0), is_fatal_error(0),
protocol_simple.init(this);
protocol_prep.init(this);
+ tablespace_op=FALSE;
#ifdef USING_TRANSACTIONS
bzero((char*) &transaction,sizeof(transaction));
if (opt_using_transactions)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 5e5d0335e9d..146ee18e3e2 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -502,6 +502,7 @@ public:
time_t connect_time,thr_create_time; // track down slow pthread_create
thr_lock_type update_lock_default;
delayed_insert *di;
+ my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
struct st_transactions {
IO_CACHE trans_log;
THD_TRANS all; // Trans since BEGIN WORK
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 8ce028020c2..0166951ab9d 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -110,6 +110,11 @@ enum olap_type
UNSPECIFIED_OLAP_TYPE, CUBE_TYPE, ROLLUP_TYPE
};
+enum tablespace_op_type
+{
+ NO_TABLESPACE_OP, DISCARD_TABLESPACE, IMPORT_TABLESPACE
+};
+
/*
The state of the lex parsing for selects
@@ -530,6 +535,7 @@ typedef struct st_lex
enum ha_rkey_function ha_rkey_mode;
enum enum_enable_or_disable alter_keys_onoff;
enum enum_var_type option_type;
+ enum tablespace_op_type tablespace_op;
uint uint_geom_type;
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e30fd0acfae..248dfc0e47a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2207,7 +2207,9 @@ mysql_execute_command(THD *thd)
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
lex->drop_primary, lex->duplicates,
- lex->alter_keys_onoff, lex->simple_alter);
+ lex->alter_keys_onoff,
+ lex->tablespace_op,
+ lex->simple_alter);
}
break;
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 16afd592e59..3840e29f04a 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1748,6 +1748,70 @@ int mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
&handler::check));
}
+/* table_list should contain just one table */
+int mysql_discard_or_import_tablespace(THD *thd,
+ TABLE_LIST *table_list,
+ enum tablespace_op_type tablespace_op)
+{
+ TABLE *table;
+ my_bool discard;
+ int error;
+ DBUG_ENTER("mysql_discard_or_import_tablespace");
+
+ /* Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
+ ALTER TABLE */
+
+ thd->proc_info="discard_or_import_tablespace";
+
+ if (tablespace_op == DISCARD_TABLESPACE)
+ discard = TRUE;
+ else
+ discard = FALSE;
+
+ thd->tablespace_op=TRUE; /* we set this flag so that ha_innobase::open
+ and ::external_lock() do not complain when we
+ lock the table */
+ mysql_ha_closeall(thd, table_list);
+
+ if (!(table=open_ltable(thd,table_list,TL_WRITE)))
+ {
+ thd->tablespace_op=FALSE;
+ DBUG_RETURN(-1);
+ }
+
+ thd->tablespace_op=FALSE;
+
+ error=table->file->discard_or_import_tablespace(discard);
+
+ thd->proc_info="end";
+
+ if (error)
+ goto err;
+
+ /* The 0 in the call below means 'not in a transaction', which means
+ immediate invalidation; that is probably what we wish here */
+ query_cache_invalidate3(thd, table_list, 0);
+
+ /* The ALTER TABLE is always in its own transaction */
+ error = ha_commit_stmt(thd);
+ if (ha_commit(thd))
+ error=1;
+ if (error)
+ goto err;
+ mysql_update_log.write(thd, thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
+ }
+err:
+ close_thread_tables(thd);
+ if (error == 0) {
+ send_ok(thd);
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(error);
+}
int mysql_alter_table(THD *thd,char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
@@ -1759,6 +1823,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
bool drop_primary,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff,
+ enum tablespace_op_type tablespace_op,
bool simple_alter)
{
TABLE *table,*new_table;
@@ -1771,6 +1836,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
ulonglong next_insert_id;
uint save_time_stamp,db_create_options, used_fields;
enum db_type old_db_type,new_db_type;
+ thr_lock_type lock_type;
DBUG_ENTER("mysql_alter_table");
thd->proc_info="init";
@@ -1781,6 +1847,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
used_fields=create_info->used_fields;
mysql_ha_closeall(thd, table_list);
+
+ if (tablespace_op != NO_TABLESPACE_OP)
+ DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list,
+ tablespace_op));
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
DBUG_RETURN(-1);
@@ -1834,8 +1904,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (create_info->row_type == ROW_TYPE_NOT_USED)
create_info->row_type=table->row_type;
- /* In some simple cases we need not to recreate the table */
-
thd->proc_info="setup";
if (simple_alter && !table->tmp_table)
{
@@ -1860,6 +1928,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
VOID(pthread_mutex_unlock(&LOCK_open));
}
+
if (!error)
{
switch (keys_onoff) {
@@ -2395,8 +2464,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
goto err;
}
}
-
- /* The ALTER TABLE is always in it's own transaction */
+ /* The ALTER TABLE is always in its own transaction */
error = ha_commit_stmt(thd);
if (ha_commit(thd))
error=1;
@@ -2695,4 +2763,3 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
table->table=0;
DBUG_RETURN(-1);
}
-
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 81a59196e3c..f917e4ec027 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -211,6 +211,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token DESCRIBE
%token DES_KEY_FILE
%token DISABLE_SYM
+%token DISCARD
%token DISTINCT
%token DUPLICATE_SYM
%token DYNAMIC_SYM
@@ -244,6 +245,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token HOSTS_SYM
%token IDENT
%token IGNORE_SYM
+%token IMPORT
%token INDEX
%token INDEXES
%token INFILE
@@ -360,6 +362,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SUBJECT_SYM
%token TABLES
%token TABLE_SYM
+%token TABLESPACE
%token TEMPORARY
%token TERMINATED
%token TEXT_STRING
@@ -1635,6 +1638,7 @@ alter:
lex->create_info.table_charset= thd->variables.collation_database;
lex->create_info.row_type= ROW_TYPE_NOT_USED;
lex->alter_keys_onoff=LEAVE_AS_IS;
+ lex->tablespace_op=NO_TABLESPACE_OP;
lex->simple_alter=1;
}
alter_list
@@ -1648,6 +1652,8 @@ alter:
alter_list:
+ | DISCARD TABLESPACE { Lex->tablespace_op=DISCARD_TABLESPACE; }
+ | IMPORT TABLESPACE { Lex->tablespace_op=IMPORT_TABLESPACE; }
| alter_list_item
| alter_list ',' alter_list_item;