diff options
author | unknown <heikki@hundin.mysql.fi> | 2003-10-13 11:20:19 +0300 |
---|---|---|
committer | unknown <heikki@hundin.mysql.fi> | 2003-10-13 11:20:19 +0300 |
commit | 423747b570b5f01b4d2dd06da991f6a8ce15101f (patch) | |
tree | 5d5b7191e57ae4eafdff3f6a259ba37729217404 | |
parent | 963d7baba7a1c37bd2154f04303df8e469f15049 (diff) | |
download | mariadb-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
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; |