summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase')
-rw-r--r--storage/innobase/btr/btr0btr.cc32
-rw-r--r--storage/innobase/btr/btr0cur.cc26
-rw-r--r--storage/innobase/buf/buf0buf.cc7
-rw-r--r--storage/innobase/buf/buf0lru.cc4
-rw-r--r--storage/innobase/dict/dict0dict.cc18
-rw-r--r--storage/innobase/fil/fil0fil.cc127
-rw-r--r--storage/innobase/handler/ha_innodb.cc65
-rw-r--r--storage/innobase/handler/ha_innodb.h9
-rw-r--r--storage/innobase/handler/handler0alter.cc8
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc44
-rw-r--r--storage/innobase/include/btr0cur.h2
-rw-r--r--storage/innobase/include/dict0mem.h7
-rw-r--r--storage/innobase/include/fil0fil.h15
-rw-r--r--storage/innobase/include/lock0lock.h25
-rw-r--r--storage/innobase/include/page0zip.h8
-rw-r--r--storage/innobase/include/row0undo.h7
-rw-r--r--storage/innobase/include/row0upd.ic3
-rw-r--r--storage/innobase/lock/lock0lock.cc10
-rw-r--r--storage/innobase/log/log0recv.cc5
-rw-r--r--storage/innobase/mysql-test/storage_engine/alter_tablespace.rdiff11
-rw-r--r--storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff2
-rw-r--r--storage/innobase/os/os0file.cc13
-rw-r--r--storage/innobase/page/page0cur.cc6
-rw-r--r--storage/innobase/page/page0page.cc14
-rw-r--r--storage/innobase/page/page0zip.cc158
-rw-r--r--storage/innobase/row/row0mysql.cc6
-rw-r--r--storage/innobase/row/row0sel.cc25
-rw-r--r--storage/innobase/row/row0umod.cc52
-rw-r--r--storage/innobase/row/row0undo.cc19
29 files changed, 459 insertions, 269 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 3f29f403622..8b7a19777ab 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -1605,7 +1605,7 @@ btr_page_reorganize_low(
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
btr_assert_not_corrupted(block, index);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
data_size1 = page_get_data_size(page);
max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
@@ -1722,7 +1722,7 @@ btr_page_reorganize_low(
func_exit:
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
#ifndef UNIV_HOTBACKUP
buf_block_free(temp_block);
@@ -1797,7 +1797,7 @@ btr_page_empty(
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
ut_ad(page_zip == buf_block_get_page_zip(block));
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
btr_search_drop_page_hash_index(block);
@@ -1854,10 +1854,10 @@ btr_root_raise_and_insert(
root_block = btr_cur_get_block(cursor);
root_page_zip = buf_block_get_page_zip(root_block);
ut_ad(page_get_n_recs(root) > 0);
+ index = btr_cur_get_index(cursor);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!root_page_zip || page_zip_validate(root_page_zip, root));
+ ut_a(!root_page_zip || page_zip_validate(root_page_zip, root, index));
#endif /* UNIV_ZIP_DEBUG */
- index = btr_cur_get_index(cursor);
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
ulint space = dict_index_get_space(index);
@@ -2782,8 +2782,8 @@ insert_empty:
#ifdef UNIV_ZIP_DEBUG
if (page_zip) {
- ut_a(page_zip_validate(page_zip, page));
- ut_a(page_zip_validate(new_page_zip, new_page));
+ ut_a(page_zip_validate(page_zip, page, cursor->index));
+ ut_a(page_zip_validate(new_page_zip, new_page, cursor->index));
}
#endif /* UNIV_ZIP_DEBUG */
@@ -2817,7 +2817,8 @@ insert_empty:
= buf_block_get_page_zip(insert_block);
ut_a(!insert_page_zip
- || page_zip_validate(insert_page_zip, insert_page));
+ || page_zip_validate(insert_page_zip, insert_page,
+ cursor->index));
}
#endif /* UNIV_ZIP_DEBUG */
@@ -3181,7 +3182,7 @@ btr_lift_page_up(
btr_page_set_level(page, page_zip, page_level, mtr);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -3355,8 +3356,8 @@ err_exit:
const page_zip_des_t* page_zip
= buf_block_get_page_zip(block);
ut_a(page_zip);
- ut_a(page_zip_validate(merge_page_zip, merge_page));
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(merge_page_zip, merge_page, index));
+ ut_a(page_zip_validate(page_zip, page, index));
}
#endif /* UNIV_ZIP_DEBUG */
@@ -3489,7 +3490,8 @@ err_exit:
ut_ad(page_validate(merge_page, index));
#ifdef UNIV_ZIP_DEBUG
- ut_a(!merge_page_zip || page_zip_validate(merge_page_zip, merge_page));
+ ut_a(!merge_page_zip || page_zip_validate(merge_page_zip, merge_page,
+ index));
#endif /* UNIV_ZIP_DEBUG */
/* Free the file page */
@@ -3671,7 +3673,7 @@ btr_discard_page(
page_zip_des_t* merge_page_zip
= buf_block_get_page_zip(merge_block);
ut_a(!merge_page_zip
- || page_zip_validate(merge_page_zip, merge_page));
+ || page_zip_validate(merge_page_zip, merge_page, index));
}
#endif /* UNIV_ZIP_DEBUG */
@@ -4123,7 +4125,7 @@ btr_validate_level(
ut_a(space == page_get_space_id(page));
#ifdef UNIV_ZIP_DEBUG
page_zip = buf_block_get_page_zip(block);
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
ut_a(!page_is_leaf(page));
@@ -4151,7 +4153,7 @@ loop:
#ifdef UNIV_ZIP_DEBUG
page_zip = buf_block_get_page_zip(block);
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
/* Check ordering etc. of records */
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 95193546115..aeb16200f80 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -679,7 +679,7 @@ retry_page_get:
#ifdef UNIV_ZIP_DEBUG
const page_zip_des_t* page_zip
= buf_block_get_page_zip(block);
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
buf_block_dbg_add_level(
@@ -2045,7 +2045,7 @@ any_extern:
page_zip = buf_block_get_page_zip(block);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
if (page_zip
@@ -2254,7 +2254,7 @@ btr_cur_pessimistic_update(
MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
/* The insert buffer tree should never be updated in place. */
ut_ad(!dict_index_is_ibuf(index));
@@ -2392,7 +2392,7 @@ make_external:
btr_search_update_hash_on_delete(cursor);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
page_cursor = btr_cur_get_page_cur(cursor);
@@ -2499,7 +2499,7 @@ make_external:
buf_block_t* rec_block = btr_cur_get_block(cursor);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
page = buf_block_get_frame(rec_block);
#endif /* UNIV_ZIP_DEBUG */
page_zip = buf_block_get_page_zip(rec_block);
@@ -2525,7 +2525,7 @@ make_external:
return_after_reservations:
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
if (n_extents > 0) {
@@ -2887,7 +2887,7 @@ btr_cur_set_deleted_flag_for_ibuf(
when the tablespace is
uncompressed */
ibool val, /*!< in: value to set */
- mtr_t* mtr) /*!< in: mtr */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
/* We do not need to reserve btr_search_latch, as the page
has just been read to the buffer pool and there cannot be
@@ -2987,12 +2987,14 @@ btr_cur_optimistic_delete(
page, 1);
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip
+ || page_zip_validate(page_zip, page, cursor->index));
#endif /* UNIV_ZIP_DEBUG */
page_cur_delete_rec(btr_cur_get_page_cur(cursor),
cursor->index, offsets, mtr);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip
+ || page_zip_validate(page_zip, page, cursor->index));
#endif /* UNIV_ZIP_DEBUG */
if (dict_index_is_clust(cursor->index)
@@ -3087,7 +3089,7 @@ btr_cur_pessimistic_delete(
rec = btr_cur_get_rec(cursor);
page_zip = buf_block_get_page_zip(block);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
@@ -3097,7 +3099,7 @@ btr_cur_pessimistic_delete(
rec, offsets, page_zip,
rb_ctx, mtr);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -3158,7 +3160,7 @@ btr_cur_pessimistic_delete(
page_cur_delete_rec(btr_cur_get_page_cur(cursor), index, offsets, mtr);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
ut_ad(btr_check_node_ptr(index, block, mtr));
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 2b543d8d1cf..96821478e60 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -245,7 +245,7 @@ the read requests for the whole area.
#ifndef UNIV_HOTBACKUP
/** Value in microseconds */
-static const int WAIT_FOR_READ = 5000;
+static const int WAIT_FOR_READ = 100;
/** Number of attemtps made to read in a page in the buffer pool */
static const ulint BUF_PAGE_READ_MAX_RETRIES = 100;
@@ -2829,8 +2829,9 @@ wait_until_unfixed:
mutex_exit(&block->mutex);
if (io_fix == BUF_IO_READ) {
-
- os_thread_sleep(WAIT_FOR_READ);
+ /* wait by temporaly s-latch */
+ rw_lock_s_lock(&(block->lock));
+ rw_lock_s_unlock(&(block->lock));
} else {
break;
}
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 1e2c15f969f..c35d84cb985 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -1805,7 +1805,9 @@ buf_LRU_block_remove_hashed_page(
break;
case FIL_PAGE_INDEX:
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(&bpage->zip, page));
+ ut_a(page_zip_validate(
+ &bpage->zip, page,
+ ((buf_block_t*) bpage)->index));
#endif /* UNIV_ZIP_DEBUG */
break;
default:
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 5871281e1b9..8282dafda0c 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -2528,7 +2528,6 @@ dict_index_build_internal_clust(
{
dict_index_t* new_index;
dict_field_t* field;
- ulint fixed_size;
ulint trx_id_pos;
ulint i;
ibool* indexed;
@@ -2605,7 +2604,7 @@ dict_index_build_internal_clust(
for (i = 0; i < trx_id_pos; i++) {
- fixed_size = dict_col_get_fixed_size(
+ ulint fixed_size = dict_col_get_fixed_size(
dict_index_get_nth_col(new_index, i),
dict_table_is_comp(table));
@@ -2622,7 +2621,20 @@ dict_index_build_internal_clust(
break;
}
- new_index->trx_id_offset += (unsigned int) fixed_size;
+ /* Add fixed_size to new_index->trx_id_offset.
+ Because the latter is a bit-field, an overflow
+ can theoretically occur. Check for it. */
+ fixed_size += new_index->trx_id_offset;
+
+ new_index->trx_id_offset = fixed_size;
+
+ if (new_index->trx_id_offset != fixed_size) {
+ /* Overflow. Pretend that this is a
+ variable-length PRIMARY KEY. */
+ ut_ad(0);
+ new_index->trx_id_offset = 0;
+ break;
+ }
}
}
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 4c6ed9807f6..2e6835fe0c0 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -194,16 +194,18 @@ struct fil_space_struct {
.ibd file of tablespace and want to
stop temporarily posting of new i/o
requests on the file */
- ibool stop_ibuf_merges;
+ ibool stop_new_ops;
/*!< we set this TRUE when we start
- deleting a single-table tablespace */
- ibool is_being_deleted;
- /*!< this is set to TRUE when we start
- deleting a single-table tablespace and its
- file; when this flag is set no further i/o
- or flush requests can be placed on this space,
- though there may be such requests still being
- processed on this space */
+ deleting a single-table tablespace.
+ When this is set following new ops
+ are not allowed:
+ * read IO request
+ * ibuf merge
+ * file flush
+ Note that we can still possibly have
+ new write operations because we don't
+ check this flag when doing flush
+ batches. */
ulint purpose;/*!< FIL_TABLESPACE, FIL_LOG, or
FIL_ARCH_LOG */
UT_LIST_BASE_NODE_T(fil_node_t) chain;
@@ -220,12 +222,13 @@ struct fil_space_struct {
ulint n_pending_flushes; /*!< this is positive when flushing
the tablespace to disk; dropping of the
tablespace is forbidden if this is positive */
- ulint n_pending_ibuf_merges;/*!< this is positive
- when merging insert buffer entries to
- a page so that we may need to access
- the ibuf bitmap page in the
- tablespade: dropping of the tablespace
- is forbidden if this is positive */
+ ulint n_pending_ops;/*!< this is positive when we
+ have pending operations against this
+ tablespace. The pending operations can
+ be ibuf merges or lock validation code
+ trying to read a block.
+ Dropping of the tablespace is forbidden
+ if this is positive */
hash_node_t hash; /*!< hash chain node */
hash_node_t name_hash;/*!< hash chain the name_hash table */
#ifndef UNIV_HOTBACKUP
@@ -1928,13 +1931,12 @@ fil_read_first_page(
#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
-Increments the count of pending insert buffer page merges, if space is not
-being deleted.
-@return TRUE if being deleted, and ibuf merges should be skipped */
+Increments the count of pending operation, if space is not being deleted.
+@return TRUE if being deleted, and operation should be skipped */
UNIV_INTERN
ibool
-fil_inc_pending_ibuf_merges(
-/*========================*/
+fil_inc_pending_ops(
+/*================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
@@ -1945,18 +1947,18 @@ fil_inc_pending_ibuf_merges(
if (space == NULL) {
fprintf(stderr,
- "InnoDB: Error: trying to do ibuf merge to a"
+ "InnoDB: Error: trying to do an operation on a"
" dropped tablespace %lu\n",
(ulong) id);
}
- if (space == NULL || space->stop_ibuf_merges) {
+ if (space == NULL || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return(TRUE);
}
- space->n_pending_ibuf_merges++;
+ space->n_pending_ops++;
mutex_exit(&fil_system->mutex);
@@ -1964,11 +1966,11 @@ fil_inc_pending_ibuf_merges(
}
/*******************************************************************//**
-Decrements the count of pending insert buffer page merges. */
+Decrements the count of pending operations. */
UNIV_INTERN
void
-fil_decr_pending_ibuf_merges(
-/*=========================*/
+fil_decr_pending_ops(
+/*=================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
@@ -1979,13 +1981,13 @@ fil_decr_pending_ibuf_merges(
if (space == NULL) {
fprintf(stderr,
- "InnoDB: Error: decrementing ibuf merge of a"
- " dropped tablespace %lu\n",
+ "InnoDB: Error: decrementing pending operation"
+ " of a dropped tablespace %lu\n",
(ulong) id);
}
if (space != NULL) {
- space->n_pending_ibuf_merges--;
+ space->n_pending_ops--;
}
mutex_exit(&fil_system->mutex);
@@ -2181,7 +2183,6 @@ fil_op_log_parse_or_replay(
}
*/
if (!space_id) {
-
return(ptr);
}
@@ -2276,15 +2277,15 @@ fil_delete_tablespace(
char* path;
ut_a(id != 0);
-stop_ibuf_merges:
+stop_new_ops:
mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(id);
if (space != NULL) {
- space->stop_ibuf_merges = TRUE;
+ space->stop_new_ops = TRUE;
- if (space->n_pending_ibuf_merges == 0) {
+ if (space->n_pending_ops == 0) {
mutex_exit(&fil_system->mutex);
count = 0;
@@ -2298,9 +2299,10 @@ stop_ibuf_merges:
ut_print_filename(stderr, space->name);
fprintf(stderr, ",\n"
"InnoDB: but there are %lu pending"
- " ibuf merges on it.\n"
+ " operations (most likely ibuf merges)"
+ " on it.\n"
"InnoDB: Loop %lu.\n",
- (ulong) space->n_pending_ibuf_merges,
+ (ulong) space->n_pending_ops,
(ulong) count);
}
@@ -2309,7 +2311,7 @@ stop_ibuf_merges:
os_thread_sleep(20000);
count++;
- goto stop_ibuf_merges;
+ goto stop_new_ops;
}
}
@@ -2334,10 +2336,8 @@ try_again:
return(FALSE);
}
- ut_a(space);
- ut_a(space->n_pending_ibuf_merges == 0);
-
- space->is_being_deleted = TRUE;
+ ut_a(space->stop_new_ops);
+ ut_a(space->n_pending_ops == 0);
/* TODO: The following code must change when InnoDB supports
multiple datafiles per tablespace. */
@@ -2386,12 +2386,26 @@ try_again:
rw_lock_x_lock(&space->latch);
#ifndef UNIV_HOTBACKUP
- /* Invalidate in the buffer pool all pages belonging to the
- tablespace. Since we have set space->is_being_deleted = TRUE, readahead
- or ibuf merge can no longer read more pages of this tablespace to the
- buffer pool. Thus we can clean the tablespace out of the buffer pool
- completely and permanently. The flag is_being_deleted also prevents
- fil_flush() from being applied to this tablespace. */
+ /* IMPORTANT: Because we have set space::stop_new_ops there
+ can't be any new ibuf merges, reads or flushes. We are here
+ because node::n_pending was zero above. However, it is still
+ possible to have pending read and write requests:
+
+ A read request can happen because the reader thread has
+ gone through the ::stop_new_ops check in buf_page_init_for_read()
+ before the flag was set and has not yet incremented ::n_pending
+ when we checked it above.
+
+ A write request can be issued any time because we don't check
+ the ::stop_new_ops flag when queueing a block for write.
+
+ We deal with pending write requests in the following function
+ where we'd minimally evict all dirty pages belonging to this
+ space from the flush_list. Not that if a block is IO-fixed
+ we'll wait for IO to complete.
+
+ To deal with potential read requests by checking the
+ ::stop_new_ops flag in fil_io() */
buf_LRU_invalidate_tablespace(id);
#endif
@@ -2399,6 +2413,15 @@ try_again:
mutex_enter(&fil_system->mutex);
+ /* Double check the sanity of pending ops after reacquiring
+ the fil_system::mutex. */
+ if (fil_space_get_by_id(id)) {
+ ut_a(space->n_pending_ops == 0);
+ ut_a(UT_LIST_GET_LEN(space->chain) == 1);
+ node = UT_LIST_GET_FIRST(space->chain);
+ ut_a(node->n_pending == 0);
+ }
+
success = fil_space_free(id, TRUE);
mutex_exit(&fil_system->mutex);
@@ -2456,7 +2479,7 @@ fil_tablespace_is_being_deleted(
ut_a(space != NULL);
- is_being_deleted = space->is_being_deleted;
+ is_being_deleted = space->stop_new_ops;
mutex_exit(&fil_system->mutex);
@@ -3744,7 +3767,7 @@ fil_tablespace_deleted_or_being_deleted_in_mem(
space = fil_space_get_by_id(id);
- if (space == NULL || space->is_being_deleted) {
+ if (space == NULL || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return(TRUE);
@@ -4472,7 +4495,9 @@ fil_io(
space = fil_space_get_by_id(space_id);
- if (!space) {
+ /* If we are deleting a tablespace we don't allow any read
+ operations on that. However, we do allow write operations. */
+ if (!space || (type == OS_FILE_READ && space->stop_new_ops)) {
mutex_exit(&fil_system->mutex);
ut_print_timestamp(stderr);
@@ -4691,7 +4716,7 @@ fil_flush(
space = fil_space_get_by_id(space_id);
- if (!space || space->is_being_deleted) {
+ if (!space || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return;
@@ -4823,7 +4848,7 @@ fil_flush_file_spaces(
space;
space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
- if (space->purpose == purpose && !space->is_being_deleted) {
+ if (space->purpose == purpose && !space->stop_new_ops) {
space_ids[n_space_ids++] = space->id;
}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index b1215e6bdef..e19fe47e81a 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -607,6 +607,9 @@ innobase_commit_ordered(
bool all); /*!< in: TRUE - commit transaction
FALSE - the current SQL statement
ended */
+static
+void
+innobase_kill_query(handlerton *hton, THD* thd, enum thd_kill_levels level);
/*****************************************************************//**
Commits a transaction in an InnoDB database or marks an SQL statement
@@ -1255,8 +1258,7 @@ convert_error_code_to_mysql(
return(0);
case DB_INTERRUPTED:
- my_error(ER_QUERY_INTERRUPTED, MYF(0));
- /* fall through */
+ return(HA_ERR_ABORTED_BY_USER);
case DB_FOREIGN_EXCEED_MAX_CASCADE:
ut_ad(thd);
@@ -1348,11 +1350,22 @@ convert_error_code_to_mysql(
case DB_TABLE_NOT_FOUND:
return(HA_ERR_NO_SUCH_TABLE);
- case DB_TOO_BIG_RECORD:
- my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
- page_get_free_space_of_empty(flags
- & DICT_TF_COMPACT) / 2);
+ case DB_TOO_BIG_RECORD: {
+ /* If prefix is true then a 768-byte prefix is stored
+ locally for BLOB fields. Refer to dict_table_get_format() */
+ bool prefix = (dict_tf_get_format(flags) == UNIV_FORMAT_A);
+ my_printf_error(ER_TOO_BIG_ROWSIZE,
+ "Row size too large (> %lu). Changing some columns "
+ "to TEXT or BLOB %smay help. In current row "
+ "format, BLOB prefix of %d bytes is stored inline.",
+ MYF(0),
+ page_get_free_space_of_empty(flags &
+ DICT_TF_COMPACT) / 2,
+ prefix ? "or using ROW_FORMAT=DYNAMIC "
+ "or ROW_FORMAT=COMPRESSED ": "",
+ prefix ? DICT_MAX_FIXED_COL_LEN : 0);
return(HA_ERR_TO_BIG_ROW);
+ }
case DB_TOO_BIG_INDEX_COL:
my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0),
@@ -1869,7 +1882,10 @@ innobase_next_autoinc(
offset = 0;
}
- /* Check for overflow. */
+ /* Check for overflow. Current can be > max_value if the value is
+ in reality a negative value.The visual studio compilers converts
+ large double values automatically into unsigned long long datatype
+ maximum value */
if (block >= max_value
|| offset > max_value
|| current >= max_value
@@ -2523,7 +2539,7 @@ trx_is_interrupted(
/*===============*/
trx_t* trx) /*!< in: transaction */
{
- return(trx && trx->mysql_thd && thd_killed((THD*) trx->mysql_thd));
+ return(trx && trx->mysql_thd && thd_kill_level((THD*) trx->mysql_thd));
}
/**********************************************************************//**
@@ -2673,6 +2689,7 @@ innobase_init(
innobase_release_temporary_latches;
innobase_hton->alter_table_flags = innobase_alter_table_flags;
+ innobase_hton->kill_query = innobase_kill_query;
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -3830,6 +3847,30 @@ innobase_close_connection(
DBUG_RETURN(0);
}
+/*****************************************************************//**
+Cancel any pending lock request associated with the current THD. */
+static
+void
+innobase_kill_query(
+/*======================*/
+ handlerton* hton, /*!< in: innobase handlerton */
+ THD* thd, /*!< in: MySQL thread being killed */
+ enum thd_kill_levels level) /*!< in: kill level */
+{
+ trx_t* trx;
+ DBUG_ENTER("innobase_kill_query");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
+ trx = thd_to_trx(thd);
+ /* Cancel a pending lock request. */
+ if (trx) {
+ lock_trx_handle_wait(trx);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
/*************************************************************************//**
** InnoDB database tables
*****************************************************************************/
@@ -10732,7 +10773,7 @@ ha_innobase::check(
row_mysql_unlock_data_dictionary(prebuilt->trx);
}
- if (thd_killed(user_thd)) {
+ if (thd_kill_level(user_thd)) {
break;
}
@@ -10790,7 +10831,7 @@ ha_innobase::check(
srv_fatal_semaphore_wait_threshold, 7200/*2 hours*/);
prebuilt->trx->op_info = "";
- if (thd_killed(user_thd)) {
+ if (thd_kill_level(user_thd)) {
my_error(ER_QUERY_INTERRUPTED, MYF(0));
}
@@ -15094,8 +15135,8 @@ static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method,
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
PLUGIN_VAR_RQCMDARG,
- "Debug flags for InnoDB change buffering (0=none)",
- NULL, NULL, 0, 0, 1, 0);
+ "Debug flags for InnoDB change buffering (0=none, 2=crash at merge)",
+ NULL, NULL, 0, 0, 2, 0);
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
static MYSQL_SYSVAR_BOOL(random_read_ahead, srv_random_read_ahead,
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 9039a91d56f..e56a1ec52e3 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -78,12 +78,13 @@ class ha_innobase: public handler
uchar* upd_buf; /*!< buffer used in updates */
ulint upd_buf_size; /*!< the size of upd_buf in bytes */
- uchar srch_key_val1[REC_VERSION_56_MAX_INDEX_COL_LEN + 2];
- uchar srch_key_val2[REC_VERSION_56_MAX_INDEX_COL_LEN + 2];
+ uchar srch_key_val1[MAX_KEY_LENGTH + MAX_REF_PARTS*2];
+ uchar srch_key_val2[MAX_KEY_LENGTH + MAX_REF_PARTS*2];
/*!< buffers used in converting
search key values from MySQL format
- to InnoDB format. "+ 2" for the two
- bytes where the length is stored */
+ to InnoDB format. For each column
+ 2 bytes are used to store length,
+ hence MAX_REF_PARTS*2. */
Table_flags int_table_flags;
uint primary_key;
ulong start_of_scan; /*!< this is set to 1 when we are
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 9de45527ec7..1468bc79c04 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -113,13 +113,17 @@ innobase_col_to_mysql(
/* These column types should never be shipped to MySQL. */
ut_ad(0);
- case DATA_CHAR:
case DATA_FIXBINARY:
case DATA_FLOAT:
case DATA_DOUBLE:
case DATA_DECIMAL:
/* Above are the valid column types for MySQL data. */
ut_ad(flen == len);
+ /* fall through */
+ case DATA_CHAR:
+ /* We may have flen > len when there is a shorter
+ prefix on a CHAR column. */
+ ut_ad(flen >= len);
#else /* UNIV_DEBUG */
default:
#endif /* UNIV_DEBUG */
@@ -154,7 +158,7 @@ innobase_rec_to_mysql(
field->reset();
- ipos = dict_index_get_nth_col_pos(index, i);
+ ipos = dict_index_get_nth_col_or_prefix_pos(index, i, TRUE);
if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
null_field:
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index 1d0abbc2981..cd9de39f3c6 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -2756,6 +2756,14 @@ ibuf_get_volume_buffered_count_func(
when the database was started up. */
ut_a(len == 1);
+ if (rec_get_deleted_flag(rec, 0)) {
+ /* This record has been merged already,
+ but apparently the system crashed before
+ the change was discarded from the buffer.
+ Pretend that the record does not exist. */
+ return(0);
+ }
+
types = rec_get_nth_field_old(rec, IBUF_REC_FIELD_METADATA, &len);
switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE,
@@ -4050,11 +4058,11 @@ ibuf_delete(
page, 1);
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
page_cur_delete_rec(&page_cur, index, offsets, mtr);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
if (page_zip) {
@@ -4159,6 +4167,22 @@ ibuf_delete_rec(
ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no);
ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space);
+#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
+ if (ibuf_debug == 2) {
+ /* Inject a fault (crash). We do this before trying
+ optimistic delete, because a pessimistic delete in the
+ change buffer would require a larger test case. */
+
+ /* Flag the buffered record as processed, to avoid
+ an assertion failure after crash recovery. */
+ btr_cur_set_deleted_flag_for_ibuf(
+ btr_pcur_get_rec(pcur), NULL, TRUE, mtr);
+ ibuf_mtr_commit(mtr);
+ log_write_up_to(IB_ULONGLONG_MAX, LOG_WAIT_ALL_GROUPS, TRUE);
+ DBUG_SUICIDE();
+ }
+#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
+
success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
if (success) {
@@ -4193,7 +4217,13 @@ ibuf_delete_rec(
ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no);
ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space);
- /* We have to resort to a pessimistic delete from ibuf */
+ /* We have to resort to a pessimistic delete from ibuf.
+ Delete-mark the record so that it will not be applied again,
+ in case the server crashes before the pessimistic delete is
+ made persistent. */
+ btr_cur_set_deleted_flag_for_ibuf(
+ btr_pcur_get_rec(pcur), NULL, TRUE, mtr);
+
btr_pcur_store_position(pcur, mtr);
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
@@ -4309,7 +4339,7 @@ ibuf_merge_or_delete_for_page(
function. When the counter is > 0, that prevents tablespace
from being dropped. */
- tablespace_being_deleted = fil_inc_pending_ibuf_merges(space);
+ tablespace_being_deleted = fil_inc_pending_ops(space);
if (UNIV_UNLIKELY(tablespace_being_deleted)) {
/* Do not try to read the bitmap page from space;
@@ -4335,7 +4365,7 @@ ibuf_merge_or_delete_for_page(
/* No inserts buffered for this page */
if (!tablespace_being_deleted) {
- fil_decr_pending_ibuf_merges(space);
+ fil_decr_pending_ops(space);
}
return;
@@ -4468,7 +4498,7 @@ loop:
fputs("InnoDB: Discarding record\n ", stderr);
rec_print_old(stderr, rec);
fputs("\nInnoDB: from the insert buffer!\n\n", stderr);
- } else if (block) {
+ } else if (block && !rec_get_deleted_flag(rec, 0)) {
/* Now we have at pcur a record which should be
applied on the index page; NOTE that the call below
copies pointers to fields in rec, and we must
@@ -4628,7 +4658,7 @@ reset_bit:
if (update_ibuf_bitmap && !tablespace_being_deleted) {
- fil_decr_pending_ibuf_merges(space);
+ fil_decr_pending_ops(space);
}
#ifdef UNIV_IBUF_COUNT_DEBUG
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index 354b6982a13..f437575579e 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -652,7 +652,7 @@ btr_cur_set_deleted_flag_for_ibuf(
when the tablespace is
uncompressed */
ibool val, /*!< in: value to set */
- mtr_t* mtr); /*!< in: mtr */
+ mtr_t* mtr); /*!< in/out: mini-transaction */
/*######################################################################*/
/** In the pessimistic delete, if the page data size drops below this
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index b770f7e3ca7..ea7e996dfa8 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -456,10 +456,15 @@ struct dict_index_struct{
unsigned type:DICT_IT_BITS;
/*!< index type (DICT_CLUSTERED, DICT_UNIQUE,
DICT_UNIVERSAL, DICT_IBUF, DICT_CORRUPT) */
- unsigned trx_id_offset:10;/*!< position of the trx id column
+#define MAX_KEY_LENGTH_BITS 12
+ unsigned trx_id_offset:MAX_KEY_LENGTH_BITS;
+ /*!< position of the trx id column
in a clustered index record, if the fields
before it are known to be of a fixed size,
0 otherwise */
+#if (1<<MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
+# error (1<<MAX_KEY_LENGTH_BITS) < MAX_KEY_LENGTH
+#endif
unsigned n_user_defined_cols:10;
/*!< number of columns the user defined to
be in the index: in the internal
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index fa632ea3c6b..1e2b8049860 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -357,20 +357,19 @@ fil_read_first_page(
lsn_t* max_flushed_lsn); /*!< out: max of flushed
lsn values in data files */
/*******************************************************************//**
-Increments the count of pending insert buffer page merges, if space is not
-being deleted.
-@return TRUE if being deleted, and ibuf merges should be skipped */
+Increments the count of pending operation, if space is not being deleted.
+@return TRUE if being deleted, and operation should be skipped */
UNIV_INTERN
ibool
-fil_inc_pending_ibuf_merges(
-/*========================*/
+fil_inc_pending_ops(
+/*================*/
ulint id); /*!< in: space id */
/*******************************************************************//**
-Decrements the count of pending insert buffer page merges. */
+Decrements the count of pending operations. */
UNIV_INTERN
void
-fil_decr_pending_ibuf_merges(
-/*=========================*/
+fil_decr_pending_ops(
+/*=================*/
ulint id); /*!< in: space id */
#endif /* !UNIV_HOTBACKUP */
/*******************************************************************//**
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index fa1e6d50224..a1ffe87d5bd 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -794,6 +794,31 @@ lock_table_get_n_locks(
/*===================*/
const dict_table_t* table) /*!< in: table */
__attribute__((nonnull));
+#ifdef UNIV_DEBUG
+/*********************************************************************//**
+Checks that a transaction id is sensible, i.e., not in the future.
+@return true if ok */
+UNIV_INTERN
+bool
+lock_check_trx_id_sanity(
+/*=====================*/
+ trx_id_t trx_id, /*!< in: trx id */
+ const rec_t* rec, /*!< in: user record */
+ dict_index_t* index, /*!< in: index */
+ const ulint* offsets) /*!< in: rec_get_offsets(rec, index) */
+ __attribute__((nonnull, warn_unused_result));
+/*******************************************************************//**
+Check if the transaction holds any locks on the sys tables
+or its records.
+@return the strongest lock found on any sys table or 0 for none */
+UNIV_INTERN
+const lock_t*
+lock_trx_has_sys_table_locks(
+/*=========================*/
+ const trx_t* trx) /*!< in: transaction to check */
+ __attribute__((warn_unused_result));
+#endif /* UNIV_DEBUG */
+
/** Lock modes and types */
/* @{ */
#define LOCK_MODE_MASK 0xFUL /*!< mask used to extract mode from the
diff --git a/storage/innobase/include/page0zip.h b/storage/innobase/include/page0zip.h
index f127fad2260..2c84f75b2ab 100644
--- a/storage/innobase/include/page0zip.h
+++ b/storage/innobase/include/page0zip.h
@@ -157,9 +157,10 @@ page_zip_validate_low(
/*==================*/
const page_zip_des_t* page_zip,/*!< in: compressed page */
const page_t* page, /*!< in: uncompressed page */
+ const dict_index_t* index, /*!< in: index of the page, if known */
ibool sloppy) /*!< in: FALSE=strict,
TRUE=ignore the MIN_REC_FLAG */
- __attribute__((nonnull));
+ __attribute__((nonnull(1,2)));
/**********************************************************************//**
Check that the compressed and decompressed pages match. */
UNIV_INTERN
@@ -167,8 +168,9 @@ ibool
page_zip_validate(
/*==============*/
const page_zip_des_t* page_zip,/*!< in: compressed page */
- const page_t* page) /*!< in: uncompressed page */
- __attribute__((nonnull));
+ const page_t* page, /*!< in: uncompressed page */
+ const dict_index_t* index) /*!< in: index of the page, if known */
+ __attribute__((nonnull(1,2)));
#endif /* UNIV_ZIP_DEBUG */
/**********************************************************************//**
diff --git a/storage/innobase/include/row0undo.h b/storage/innobase/include/row0undo.h
index 90a15172ae0..47f9afdc74a 100644
--- a/storage/innobase/include/row0undo.h
+++ b/storage/innobase/include/row0undo.h
@@ -87,10 +87,6 @@ that index record. */
enum undo_exec {
UNDO_NODE_FETCH_NEXT = 1, /*!< we should fetch the next
undo log record */
- UNDO_NODE_PREV_VERS, /*!< the roll ptr to previous
- version of a row is stored in
- node, and undo should be done
- based on it */
UNDO_NODE_INSERT, /*!< undo a fresh insert of a
row to a table */
UNDO_NODE_MODIFY /*!< undo a modify operation
@@ -108,9 +104,6 @@ struct undo_node_struct{
undo_no_t undo_no;/*!< undo number of the record */
ulint rec_type;/*!< undo log record type: TRX_UNDO_INSERT_REC,
... */
- roll_ptr_t new_roll_ptr;
- /*!< roll ptr to restore to clustered index
- record */
trx_id_t new_trx_id; /*!< trx id to restore to clustered index
record */
btr_pcur_t pcur; /*!< persistent cursor used in searching the
diff --git a/storage/innobase/include/row0upd.ic b/storage/innobase/include/row0upd.ic
index 8a2543eaac9..d054662c080 100644
--- a/storage/innobase/include/row0upd.ic
+++ b/storage/innobase/include/row0upd.ic
@@ -28,6 +28,7 @@ Created 12/27/1996 Heikki Tuuri
# include "trx0trx.h"
# include "trx0undo.h"
# include "row0row.h"
+# include "lock0lock.h"
#endif /* !UNIV_HOTBACKUP */
#include "page0zip.h"
@@ -171,6 +172,8 @@ row_upd_rec_sys_fields(
#if DATA_TRX_ID + 1 != DATA_ROLL_PTR
# error "DATA_TRX_ID + 1 != DATA_ROLL_PTR"
#endif
+ ut_ad(lock_check_trx_id_sanity(trx_read_trx_id(rec + offset),
+ rec, index, offsets));
trx_write_trx_id(rec + offset, trx->id);
trx_write_roll_ptr(rec + offset + DATA_TRX_ID_LEN, roll_ptr);
}
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index 18fbfbee91b..476b305ca70 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -488,9 +488,13 @@ lock_report_trx_id_insanity(
/*********************************************************************//**
Checks that a transaction id is sensible, i.e., not in the future.
-@return TRUE if ok */
-static
-ibool
+@return true if ok */
+#ifdef UNIV_DEBUG
+UNIV_INTERN
+#else
+static __attribute__((nonnull, warn_unused_result))
+#endif
+bool
lock_check_trx_id_sanity(
/*=====================*/
trx_id_t trx_id, /*!< in: trx id */
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index a360d05f056..f914fc2676c 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -1636,9 +1636,8 @@ recv_recover_page_func(
if (fil_page_get_type(page) == FIL_PAGE_INDEX) {
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
- if (page_zip) {
- ut_a(page_zip_validate_low(page_zip, page, FALSE));
- }
+ ut_a(!page_zip
+ || page_zip_validate_low(page_zip, page, NULL, FALSE));
}
#endif /* UNIV_ZIP_DEBUG */
diff --git a/storage/innobase/mysql-test/storage_engine/alter_tablespace.rdiff b/storage/innobase/mysql-test/storage_engine/alter_tablespace.rdiff
new file mode 100644
index 00000000000..0cbe1fa48ae
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/alter_tablespace.rdiff
@@ -0,0 +1,11 @@
+--- suite/storage_engine/alter_tablespace.result 2013-01-13 01:03:49.133994000 +0400
++++ suite/storage_engine/alter_tablespace.reject 2013-01-13 01:04:04.398937286 +0400
+@@ -10,7 +10,7 @@
+ 2
+ ALTER TABLE t1 DISCARD TABLESPACE;
+ SELECT * FROM t1;
+-ERROR HY000: Got error -1 from storage engine
++ERROR HY000: Got error -1 "Internal error < 0 (Not system error)" from storage engine
+ ALTER TABLE t1 IMPORT TABLESPACE;
+ SELECT * FROM t1;
+ a
diff --git a/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff b/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff
index 4c0e0c375f5..8bf84115a52 100644
--- a/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff
+++ b/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff
@@ -4,7 +4,7 @@
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> ROW_FORMAT=FIXED;
+Warnings:
-+Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
++Warning 140 InnoDB: assuming ROW_FORMAT=COMPACT.
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index ec9e234229a..62cde1cf728 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -1443,6 +1443,13 @@ os_file_create_func(
create_mode &= ~OS_FILE_ON_ERROR_NO_EXIT;
create_mode &= ~OS_FILE_ON_ERROR_SILENT;
+
+ DBUG_EXECUTE_IF(
+ "ib_create_table_fail_disk_full",
+ *success = FALSE;
+ SetLastError(ERROR_DISK_FULL);
+ return((os_file_t) -1);
+ );
try_again:
ut_a(name);
@@ -1560,6 +1567,12 @@ try_again:
create_mode &= ~OS_FILE_ON_ERROR_NO_EXIT;
create_mode &= ~OS_FILE_ON_ERROR_SILENT;
+ DBUG_EXECUTE_IF(
+ "ib_create_table_fail_disk_full",
+ *success = FALSE;
+ errno = ENOSPC;
+ return((os_file_t) -1);
+ );
try_again:
ut_a(name);
diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc
index 3ae063dedec..9046338f377 100644
--- a/storage/innobase/page/page0cur.cc
+++ b/storage/innobase/page/page0cur.cc
@@ -310,7 +310,7 @@ page_cur_search_with_match(
#endif /* UNIV_DEBUG */
page = buf_block_get_frame(block);
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
page_check_dir(page);
@@ -1249,7 +1249,7 @@ page_cur_insert_rec_zip(
ut_ad(!page_rec_is_supremum(*current_rec));
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
/* 1. Get the size of the physical record in the page */
@@ -1973,7 +1973,7 @@ page_cur_delete_rec(
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
}
diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc
index fb3e21b8b26..deef6935f08 100644
--- a/storage/innobase/page/page0page.cc
+++ b/storage/innobase/page/page0page.cc
@@ -626,7 +626,7 @@ page_copy_rec_list_end(
Furthermore, btr_compress() may set FIL_PAGE_PREV to
FIL_NULL on new_page while leaving it intact on
new_page_zip. So, we cannot validate new_page_zip. */
- ut_a(page_zip_validate_low(page_zip, page, TRUE));
+ ut_a(page_zip_validate_low(page_zip, page, index, TRUE));
}
#endif /* UNIV_ZIP_DEBUG */
ut_ad(buf_block_get_frame(block) == page);
@@ -943,7 +943,7 @@ page_delete_rec_list_end(
ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
ut_ad(!page_zip || page_rec_is_comp(rec));
#ifdef UNIV_ZIP_DEBUG
- ut_a(!page_zip || page_zip_validate(page_zip, page));
+ ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
if (page_rec_is_infimum(rec)) {
@@ -985,7 +985,7 @@ page_delete_rec_list_end(
ULINT_UNDEFINED, &heap);
rec = rec_get_next_ptr(rec, TRUE);
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
page_cur_delete_rec(&cur, index, offsets, mtr);
} while (page_offset(rec) != PAGE_NEW_SUPREMUM);
@@ -1123,7 +1123,8 @@ page_delete_rec_list_start(
between btr_attach_half_pages() and insert_page = ...
when btr_page_get_split_rec_to_left() holds
(direction == FSP_DOWN). */
- ut_a(!page_zip || page_zip_validate_low(page_zip, page, TRUE));
+ ut_a(!page_zip
+ || page_zip_validate_low(page_zip, page, index, TRUE));
}
#endif /* UNIV_ZIP_DEBUG */
@@ -1194,9 +1195,10 @@ page_move_rec_list_end(
= buf_block_get_page_zip(block);
ut_a(!new_page_zip == !page_zip);
ut_a(!new_page_zip
- || page_zip_validate(new_page_zip, new_page));
+ || page_zip_validate(new_page_zip, new_page, index));
ut_a(!page_zip
- || page_zip_validate(page_zip, page_align(split_rec)));
+ || page_zip_validate(page_zip, page_align(split_rec),
+ index));
}
#endif /* UNIV_ZIP_DEBUG */
diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc
index ce75d4e15fc..35a8f458fb2 100644
--- a/storage/innobase/page/page0zip.cc
+++ b/storage/innobase/page/page0zip.cc
@@ -1447,7 +1447,7 @@ err_exit:
page_zip_get_size(page_zip) - PAGE_DATA);
mem_heap_free(heap);
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
if (mtr) {
@@ -3140,6 +3140,7 @@ page_zip_validate_low(
/*==================*/
const page_zip_des_t* page_zip,/*!< in: compressed page */
const page_t* page, /*!< in: uncompressed page */
+ const dict_index_t* index, /*!< in: index of the page, if known */
ibool sloppy) /*!< in: FALSE=strict,
TRUE=ignore the MIN_REC_FLAG */
{
@@ -3227,39 +3228,102 @@ page_zip_validate_low(
committed. Let us tolerate that difference when we
are performing a sloppy validation. */
- if (sloppy) {
- byte info_bits_diff;
- ulint offset
- = rec_get_next_offs(page + PAGE_NEW_INFIMUM,
- TRUE);
- ut_a(offset >= PAGE_NEW_SUPREMUM);
- offset -= 5 /* REC_NEW_INFO_BITS */;
-
- info_bits_diff = page[offset] ^ temp_page[offset];
-
- if (info_bits_diff == REC_INFO_MIN_REC_FLAG) {
- temp_page[offset] = page[offset];
-
- if (!memcmp(page + PAGE_HEADER,
- temp_page + PAGE_HEADER,
- UNIV_PAGE_SIZE - PAGE_HEADER
- - FIL_PAGE_DATA_END)) {
-
- /* Only the minimum record flag
- differed. Let us ignore it. */
- page_zip_fail(("page_zip_validate: "
- "min_rec_flag "
- "(ignored, "
- "%lu,%lu,0x%02lx)\n",
- page_get_space_id(page),
- page_get_page_no(page),
- (ulong) page[offset]));
- goto func_exit;
- }
+ ulint* offsets;
+ mem_heap_t* heap;
+ const rec_t* rec;
+ const rec_t* trec;
+ byte info_bits_diff;
+ ulint offset
+ = rec_get_next_offs(page + PAGE_NEW_INFIMUM, TRUE);
+ ut_a(offset >= PAGE_NEW_SUPREMUM);
+ offset -= 5/*REC_NEW_INFO_BITS*/;
+
+ info_bits_diff = page[offset] ^ temp_page[offset];
+
+ if (info_bits_diff == REC_INFO_MIN_REC_FLAG) {
+ temp_page[offset] = page[offset];
+
+ if (!memcmp(page + PAGE_HEADER,
+ temp_page + PAGE_HEADER,
+ UNIV_PAGE_SIZE - PAGE_HEADER
+ - FIL_PAGE_DATA_END)) {
+
+ /* Only the minimum record flag
+ differed. Let us ignore it. */
+ page_zip_fail(("page_zip_validate: "
+ "min_rec_flag "
+ "(%s"
+ "%lu,%lu,0x%02lx)\n",
+ sloppy ? "ignored, " : "",
+ page_get_space_id(page),
+ page_get_page_no(page),
+ (ulong) page[offset]));
+ valid = sloppy;
+ goto func_exit;
+ }
+ }
+
+ /* Compare the pointers in the PAGE_FREE list. */
+ rec = page_header_get_ptr(page, PAGE_FREE);
+ trec = page_header_get_ptr(temp_page, PAGE_FREE);
+
+ while (rec || trec) {
+ if (page_offset(rec) != page_offset(trec)) {
+ page_zip_fail(("page_zip_validate: "
+ "PAGE_FREE list: %u!=%u\n",
+ (unsigned) page_offset(rec),
+ (unsigned) page_offset(trec)));
+ valid = FALSE;
+ goto func_exit;
}
+
+ rec = page_rec_get_next_low(rec, TRUE);
+ trec = page_rec_get_next_low(trec, TRUE);
}
- page_zip_fail(("page_zip_validate: content\n"));
+
+ /* Compare the records. */
+ heap = NULL;
+ offsets = NULL;
+ rec = page_rec_get_next_low(
+ page + PAGE_NEW_INFIMUM, TRUE);
+ trec = page_rec_get_next_low(
+ temp_page + PAGE_NEW_INFIMUM, TRUE);
+
+ do {
+ if (page_offset(rec) != page_offset(trec)) {
+ page_zip_fail(("page_zip_validate: "
+ "record list: 0x%02x!=0x%02x\n",
+ (unsigned) page_offset(rec),
+ (unsigned) page_offset(trec)));
valid = FALSE;
+ break;
+ }
+
+ if (index) {
+ /* Compare the data. */
+ offsets = rec_get_offsets(
+ rec, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
+ if (memcmp(rec - rec_offs_extra_size(offsets),
+ trec - rec_offs_extra_size(offsets),
+ rec_offs_size(offsets))) {
+ page_zip_fail(
+ ("page_zip_validate: "
+ "record content: 0x%02x",
+ (unsigned) page_offset(rec)));
+ valid = FALSE;
+ break;
+ }
+ }
+
+ rec = page_rec_get_next_low(rec, TRUE);
+ trec = page_rec_get_next_low(trec, TRUE);
+ } while (rec || trec);
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
}
func_exit:
@@ -3281,9 +3345,10 @@ ibool
page_zip_validate(
/*==============*/
const page_zip_des_t* page_zip,/*!< in: compressed page */
- const page_t* page) /*!< in: uncompressed page */
+ const page_t* page, /*!< in: uncompressed page */
+ const dict_index_t* index) /*!< in: index of the page, if known */
{
- return(page_zip_validate_low(page_zip, page,
+ return(page_zip_validate_low(page_zip, page, index,
recv_recovery_is_on()));
}
#endif /* UNIV_ZIP_DEBUG */
@@ -3614,7 +3679,7 @@ page_zip_write_rec(
page_zip->m_nonempty = TRUE;
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page_align(rec)));
+ ut_a(page_zip_validate(page_zip, page_align(rec), index));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -3661,7 +3726,7 @@ corrupt:
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, NULL));
#endif /* UNIV_ZIP_DEBUG */
memcpy(page + offset,
@@ -3670,7 +3735,7 @@ corrupt:
ptr + 4, BTR_EXTERN_FIELD_REF_SIZE);
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, NULL));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -3737,7 +3802,7 @@ page_zip_write_blob_ptr(
memcpy(externs, field, BTR_EXTERN_FIELD_REF_SIZE);
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
if (mtr) {
@@ -3808,7 +3873,7 @@ corrupt:
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, NULL));
#endif /* UNIV_ZIP_DEBUG */
field = page + offset;
@@ -3829,7 +3894,7 @@ corrupt:
memcpy(storage, ptr + 4, REC_NODE_PTR_SIZE);
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, NULL));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -3924,6 +3989,7 @@ page_zip_write_trx_id_and_roll_ptr(
ulint len;
ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
+
ut_ad(page_simple_validate_new(page));
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip_get_size(page_zip)
@@ -4056,7 +4122,7 @@ page_zip_clear_rec(
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -4080,7 +4146,7 @@ page_zip_rec_set_deleted(
*slot &= ~(PAGE_ZIP_DIR_SLOT_DEL >> 8);
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page_align(rec)));
+ ut_a(page_zip_validate(page_zip, page_align(rec), NULL));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -4381,14 +4447,14 @@ corrupt:
goto corrupt;
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, NULL));
#endif /* UNIV_ZIP_DEBUG */
memcpy(page + offset, ptr, len);
memcpy(page_zip->data + offset, ptr, len);
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, NULL));
#endif /* UNIV_ZIP_DEBUG */
}
@@ -4466,7 +4532,7 @@ page_zip_reorganize(
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
ut_ad(page_is_comp(page));
ut_ad(!dict_index_is_ibuf(index));
- /* Note that page_zip_validate(page_zip, page) may fail here. */
+ /* Note that page_zip_validate(page_zip, page, index) may fail here. */
UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
@@ -4553,7 +4619,7 @@ page_zip_copy_recs(
FIL_PAGE_PREV or PAGE_LEVEL, causing a temporary min_rec_flag
mismatch. A strict page_zip_validate() will be executed later
during the B-tree operations. */
- ut_a(page_zip_validate_low(src_zip, src, TRUE));
+ ut_a(page_zip_validate_low(src_zip, src, index, TRUE));
#endif /* UNIV_ZIP_DEBUG */
ut_a(page_zip_get_size(page_zip) == page_zip_get_size(src_zip));
if (UNIV_UNLIKELY(src_zip->n_blobs)) {
@@ -4614,7 +4680,7 @@ page_zip_copy_recs(
}
#ifdef UNIV_ZIP_DEBUG
- ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
btr_blob_dbg_add(page, index, "page_zip_copy_recs");
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index b4827782be6..f1811a664c2 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -2048,7 +2048,8 @@ Creates a table for MySQL. If the name of the table ends in
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
"innodb_table_monitor", then this will also start the printing of monitor
output by the master thread. If the table name ends in "innodb_mem_validate",
-InnoDB will try to invoke mem_validate().
+InnoDB will try to invoke mem_validate(). On failure the transaction will
+be rolled back and the 'table' object will be freed.
@return error code or DB_SUCCESS */
UNIV_INTERN
int
@@ -2193,7 +2194,10 @@ err_exit:
row_drop_table_for_mysql(table->name, trx, FALSE);
trx_commit_for_mysql(trx);
+ } else {
+ dict_mem_table_free(table);
}
+
break;
case DB_TOO_MANY_CONCURRENT_TRXS:
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 8f3f5711a61..96884e89511 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -2543,6 +2543,9 @@ row_sel_convert_mysql_key_to_innobase(
dfield++;
}
+ DBUG_EXECUTE_IF("innodb_srch_key_buffer_full",
+ ut_a(buf == (original_buf + buf_len)););
+
ut_a(buf <= original_buf + buf_len);
/* We set the length of tuple to n_fields: we assume that the memory
@@ -4207,6 +4210,11 @@ wait_table_again:
}
rec_loop:
+ if (trx_is_interrupted(trx)) {
+ err = DB_INTERRUPTED;
+ goto normal_return;
+ }
+
/*-------------------------------------------------------------*/
/* PHASE 4: Look for matching records in a loop */
@@ -5211,7 +5219,13 @@ row_search_autoinc_read_column(
rec_offs_init(offsets_);
- offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+ offsets = rec_get_offsets(rec, index, offsets, col_no + 1, &heap);
+
+ if (rec_offs_nth_sql_null(offsets, col_no)) {
+ /* There is no non-NULL value in the auto-increment column. */
+ value = 0;
+ goto func_exit;
+ }
data = rec_get_nth_field(rec, offsets, col_no, &len);
@@ -5237,14 +5251,15 @@ row_search_autoinc_read_column(
ut_error;
}
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
if (!unsigned_type && (ib_int64_t) value < 0) {
value = 0;
}
+func_exit:
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
return(value);
}
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index c9b42265553..4869909f5a6 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -69,36 +69,6 @@ If you make a change in this module make sure that no codepath is
introduced where a call to log_free_check() is bypassed. */
/***********************************************************//**
-Checks if also the previous version of the clustered index record was
-modified or inserted by the same transaction, and its undo number is such
-that it should be undone in the same rollback.
-@return TRUE if also previous modify or insert of this row should be undone */
-static
-ibool
-row_undo_mod_undo_also_prev_vers(
-/*=============================*/
- undo_node_t* node, /*!< in: row undo node */
- undo_no_t* undo_no)/*!< out: the undo number */
-{
- trx_undo_rec_t* undo_rec;
- trx_t* trx;
-
- trx = node->trx;
-
- if (node->new_trx_id != trx->id) {
-
- *undo_no = 0;
- return(FALSE);
- }
-
- undo_rec = trx_undo_get_undo_rec_low(node->new_roll_ptr, node->heap);
-
- *undo_no = trx_undo_rec_get_undo_no(undo_rec);
-
- return(trx->roll_limit <= *undo_no);
-}
-
-/***********************************************************//**
Undoes a modify in a clustered index record.
@return DB_SUCCESS, DB_FAIL, or error code: we may run out of file space */
static
@@ -226,18 +196,11 @@ row_undo_mod_clust(
btr_pcur_t* pcur;
mtr_t mtr;
ulint err;
- ibool success;
- ibool more_vers;
- undo_no_t new_undo_no;
ut_ad(node && thr);
log_free_check();
- /* Check if also the previous version of the clustered index record
- should be undone in this same rollback operation */
-
- more_vers = row_undo_mod_undo_also_prev_vers(node, &new_undo_no);
pcur = &(node->pcur);
@@ -286,20 +249,6 @@ row_undo_mod_clust(
trx_undo_rec_release(node->trx, node->undo_no);
- if (more_vers && err == DB_SUCCESS) {
-
- /* Reserve the undo log record to the prior version after
- committing &mtr: this is necessary to comply with the latching
- order, as &mtr may contain the fsp latch which is lower in
- the latch hierarchy than trx->undo_mutex. */
-
- success = trx_undo_rec_reserve(node->trx, new_undo_no);
-
- if (success) {
- node->state = UNDO_NODE_PREV_VERS;
- }
- }
-
return(err);
}
@@ -835,7 +784,6 @@ row_undo_mod_parse_undo_rec(
trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
roll_ptr, info_bits, trx,
node->heap, &(node->update));
- node->new_roll_ptr = roll_ptr;
node->new_trx_id = trx_id;
node->cmpl_info = cmpl_info;
diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc
index 6519e10334d..757d3544ba4 100644
--- a/storage/innobase/row/row0undo.cc
+++ b/storage/innobase/row/row0undo.cc
@@ -283,25 +283,6 @@ row_undo(
} else {
node->state = UNDO_NODE_MODIFY;
}
-
- } else if (node->state == UNDO_NODE_PREV_VERS) {
-
- /* Undo should be done to the same clustered index record
- again in this same rollback, restoring the previous version */
-
- roll_ptr = node->new_roll_ptr;
-
- node->undo_rec = trx_undo_get_undo_rec_low(roll_ptr,
- node->heap);
- node->roll_ptr = roll_ptr;
- node->undo_no = trx_undo_rec_get_undo_no(node->undo_rec);
-
- if (trx_undo_roll_ptr_is_insert(roll_ptr)) {
-
- node->state = UNDO_NODE_INSERT;
- } else {
- node->state = UNDO_NODE_MODIFY;
- }
}
/* Prevent DROP TABLE etc. while we are rolling back this row.