diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-01-29 15:10:47 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-01-29 15:10:47 +0100 |
commit | 0af4b6c6ee2b8a61823478c0a56ebdfa52cae3cc (patch) | |
tree | 7b24eb150b9cca718c88edaabbfc6c8bb16fd015 /storage/innobase | |
parent | cf20de000bdff07a34a373079991d24837423896 (diff) | |
parent | 52fbe44fbbe60ecaba6453884ec1ad32755d7a04 (diff) | |
download | mariadb-git-0af4b6c6ee2b8a61823478c0a56ebdfa52cae3cc.tar.gz |
5.5 merge
Diffstat (limited to 'storage/innobase')
26 files changed, 431 insertions, 239 deletions
diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index a6fdff72f50..1f4d8126be6 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -1594,7 +1594,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); @@ -1713,7 +1713,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); @@ -1788,7 +1788,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); @@ -1845,10 +1845,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); @@ -2778,8 +2778,8 @@ insert_empty: #ifdef UNIV_ZIP_DEBUG if (UNIV_LIKELY_NULL(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 */ @@ -2813,7 +2813,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 */ @@ -3178,7 +3179,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 */ } @@ -3354,8 +3355,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 */ @@ -3488,7 +3489,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 */ @@ -4149,7 +4151,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)); @@ -4177,7 +4179,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.c b/storage/innobase/btr/btr0cur.c index ce43cba8525..1f92de245b1 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -673,7 +673,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( @@ -2042,7 +2042,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 @@ -2253,7 +2253,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)); @@ -2391,7 +2391,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); @@ -2498,7 +2498,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); @@ -2524,7 +2524,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) { @@ -2886,7 +2886,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 @@ -2986,12 +2986,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) @@ -3086,7 +3088,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); @@ -3096,7 +3098,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 */ } @@ -3157,7 +3159,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.c b/storage/innobase/buf/buf0buf.c index 70841a168ab..1af019dfc45 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -242,7 +242,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; @@ -2582,8 +2582,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.c b/storage/innobase/buf/buf0lru.c index 7c8100df58e..60894cae6ad 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -1998,7 +1998,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.c b/storage/innobase/dict/dict0dict.c index 6f2c2caffaf..d5b16d419f1 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -487,10 +487,12 @@ Looks for column n in an index. ULINT_UNDEFINED if not contained */ UNIV_INTERN ulint -dict_index_get_nth_col_pos( -/*=======================*/ - const dict_index_t* index, /*!< in: index */ - ulint n) /*!< in: column number */ +dict_index_get_nth_col_or_prefix_pos( +/*=================================*/ + const dict_index_t* index, /*!< in: index */ + ulint n, /*!< in: column number */ + ibool inc_prefix) /*!< in: TRUE=consider + column prefixes too */ { const dict_field_t* field; const dict_col_t* col; @@ -512,7 +514,8 @@ dict_index_get_nth_col_pos( for (pos = 0; pos < n_fields; pos++) { field = dict_index_get_nth_field(index, pos); - if (col == field->col && field->prefix_len == 0) { + if (col == field->col + && (inc_prefix || field->prefix_len == 0)) { return(pos); } @@ -521,6 +524,20 @@ dict_index_get_nth_col_pos( return(ULINT_UNDEFINED); } +/********************************************************************//** +Looks for column n in an index. +@return position in internal representation of the index; +ULINT_UNDEFINED if not contained */ +UNIV_INTERN +ulint +dict_index_get_nth_col_pos( +/*=======================*/ + const dict_index_t* index, /*!< in: index */ + ulint n) /*!< in: column number */ +{ + return(dict_index_get_nth_col_or_prefix_pos(index, n, FALSE)); +} + #ifndef UNIV_HOTBACKUP /********************************************************************//** Returns TRUE if the index contains a column or a prefix of that column. @@ -2017,7 +2034,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; @@ -2094,7 +2110,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)); @@ -2111,7 +2127,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.c b/storage/innobase/fil/fil0fil.c index 23fe76f2281..8fe33459994 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -187,14 +187,16 @@ struct fil_space_struct { requests on the file */ 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; @@ -1286,7 +1288,6 @@ try_again: space->stop_ios = FALSE; space->stop_new_ops = FALSE; - space->is_being_deleted = FALSE; space->purpose = purpose; space->size = 0; space->flags = flags; @@ -2301,11 +2302,9 @@ try_again: return(FALSE); } - ut_a(space); + ut_a(space->stop_new_ops); ut_a(space->n_pending_ops == 0); - space->is_being_deleted = TRUE; - ut_a(UT_LIST_GET_LEN(space->chain) == 1); node = UT_LIST_GET_FIRST(space->chain); @@ -2348,13 +2347,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_flush_or_remove_pages( id, evict_all ? BUF_REMOVE_ALL_NO_WRITE @@ -2364,6 +2376,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); @@ -2421,7 +2442,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); @@ -3695,7 +3716,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); @@ -4408,7 +4429,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); @@ -4624,7 +4647,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; @@ -4755,7 +4778,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 42b0fe2b65f..bf7bfce6b5c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -342,6 +342,7 @@ static PSI_file_info all_innodb_files[] = { static INNOBASE_SHARE *get_share(const char *table_name); static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); +static void innobase_kill_query(handlerton *hton, THD* thd, enum thd_kill_levels level); static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all); static int innobase_commit(handlerton *hton, THD* thd, bool all); static int innobase_rollback(handlerton *hton, THD* thd, bool all); @@ -921,8 +922,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: push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, @@ -1013,11 +1013,23 @@ 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 = ((flags & DICT_TF_FORMAT_MASK) + >> DICT_TF_FORMAT_SHIFT) < UNIV_FORMAT_B; + 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), @@ -1487,19 +1499,19 @@ innobase_next_autoinc( */ max_value= (~(ulonglong) 0); - /* Current value should never be greater than the maximum. */ - ut_a(current <= max_value); - /* According to MySQL documentation, if the offset is greater than the step then the offset is ignored. */ if (offset > block) { 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 + || current >= max_value || max_value - offset <= offset) { next_value = max_value; @@ -2145,7 +2157,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)); } /**********************************************************************//** @@ -2276,6 +2288,7 @@ innobase_init( innobase_hton->flags=HTON_NO_FLAGS; innobase_hton->release_temporary_latches=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); @@ -3324,6 +3337,35 @@ innobase_close_connection( } +/*****************************************************************//** +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); + + mutex_enter(&kernel_mutex); + + trx = thd_to_trx(thd); + + /* Cancel a pending lock request. */ + if (trx && trx->wait_lock) { + lock_cancel_waiting_and_release(trx->wait_lock); + } + + mutex_exit(&kernel_mutex); + + DBUG_VOID_RETURN; +} + + /*************************************************************************//** ** InnoDB database tables *****************************************************************************/ @@ -8825,7 +8867,7 @@ ha_innobase::check( row_mysql_unlock_data_dictionary(prebuilt->trx); } - if (thd_killed(user_thd)) { + if (thd_kill_level(user_thd)) { break; } @@ -8882,7 +8924,7 @@ ha_innobase::check( mutex_exit(&kernel_mutex); prebuilt->trx->op_info = ""; - if (thd_killed(user_thd)) { + if (thd_kill_level(user_thd)) { my_error(ER_QUERY_INTERRUPTED, MYF(0)); } @@ -11867,8 +11909,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 7ef3e954636..a33af4db2fe 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -80,12 +80,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 dc65fb3ff1a..451e37f2136 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -112,13 +112,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 */ @@ -151,7 +155,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.c b/storage/innobase/ibuf/ibuf0ibuf.c index c7887afef92..70af56b99f2 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -2868,6 +2868,14 @@ ibuf_get_volume_buffered_count_func( ut_a(len == 1); ut_ad(trx_sys_multiple_tablespace_format); + 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, @@ -4176,11 +4184,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) { @@ -4285,6 +4293,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_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE); + DBUG_SUICIDE(); + } +#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ + success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr); if (success) { @@ -4319,7 +4343,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); @@ -4600,7 +4630,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 diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index cbc6103c2ee..6819f2bc2c5 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -635,7 +635,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/dict0dict.h b/storage/innobase/include/dict0dict.h index b609bce9d41..54af14313c4 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -910,6 +910,18 @@ dict_index_get_nth_col_pos( const dict_index_t* index, /*!< in: index */ ulint n); /*!< in: column number */ /********************************************************************//** +Looks for column n in an index. +@return position in internal representation of the index; +ULINT_UNDEFINED if not contained */ +UNIV_INTERN +ulint +dict_index_get_nth_col_or_prefix_pos( +/*=================================*/ + const dict_index_t* index, /*!< in: index */ + ulint n, /*!< in: column number */ + ibool inc_prefix); /*!< in: TRUE=consider + column prefixes too */ +/********************************************************************//** Returns TRUE if the index contains a column or a prefix of that column. @return TRUE if contains the column or its prefix */ UNIV_INTERN diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 4c371c8d5cf..980417715b3 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -377,10 +377,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/page0zip.h b/storage/innobase/include/page0zip.h index 00c1d0516e6..9cf3b9805bc 100644 --- a/storage/innobase/include/page0zip.h +++ b/storage/innobase/include/page0zip.h @@ -156,9 +156,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 @@ -166,8 +167,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 6eb4ca448b3..9420d022e3b 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 10646241125..6706c9f8c69 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, FALSE)); 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/include/univ.i b/storage/innobase/include/univ.i index ce7181e7bd5..0b0b4b8d04c 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -295,6 +295,24 @@ management to ensure correct alignment for doubles etc. */ ======================== */ +/** There are currently two InnoDB file formats which are used to group +features with similar restrictions and dependencies. Using an enum allows +switch statements to give a compiler warning when a new one is introduced. */ +enum innodb_file_formats_enum { + /** Antelope File Format: InnoDB/MySQL up to 5.1. + This format includes REDUNDANT and COMPACT row formats */ + UNIV_FORMAT_A = 0, + + /** Barracuda File Format: Introduced in InnoDB plugin for 5.1: + This format includes COMPRESSED and DYNAMIC row formats. It + includes the ability to create secondary indexes from data that + is not on the clustered index page and the ability to store more + data off the clustered index page. */ + UNIV_FORMAT_B = 1 +}; + +typedef enum innodb_file_formats_enum innodb_file_formats_t; + /* The 2-logarithm of UNIV_PAGE_SIZE: */ #define UNIV_PAGE_SIZE_SHIFT 14 /* The universal page size of the database */ diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index 6c55a1badc5..03ba4d12cd0 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -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/os/os0file.c b/storage/innobase/os/os0file.c index 1068c033871..46eb9c4a935 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -1397,6 +1397,13 @@ os_file_create_func( DWORD create_flag; DWORD attributes; ibool retry; + + 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); @@ -1512,6 +1519,12 @@ try_again: ibool retry; const char* mode_str = NULL; + 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.c b/storage/innobase/page/page0cur.c index 55ba72b4fe9..a722f5b188d 100644 --- a/storage/innobase/page/page0cur.c +++ b/storage/innobase/page/page0cur.c @@ -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); @@ -1248,7 +1248,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.c b/storage/innobase/page/page0page.c index 78135b0aff2..81051f8f4fe 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -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); @@ -946,7 +946,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)) { @@ -988,7 +988,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); @@ -1128,7 +1128,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 */ @@ -1199,9 +1200,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.c b/storage/innobase/page/page0zip.c index ca3836689d3..9f895e60803 100644 --- a/storage/innobase/page/page0zip.c +++ b/storage/innobase/page/page0zip.c @@ -1433,7 +1433,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) { @@ -3119,6 +3119,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 */ { @@ -3206,39 +3207,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); + } + + /* 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); } - page_zip_fail(("page_zip_validate: content\n")); - valid = FALSE; } func_exit: @@ -3260,9 +3324,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 */ @@ -3593,7 +3658,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 */ } @@ -3640,7 +3705,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, @@ -3649,7 +3714,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 */ } @@ -3716,7 +3781,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) { @@ -3787,7 +3852,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; @@ -3808,7 +3873,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 */ } @@ -4035,7 +4100,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 */ } @@ -4059,7 +4124,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 */ } @@ -4360,14 +4425,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 */ } @@ -4445,7 +4510,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)); @@ -4532,7 +4597,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)) { @@ -4593,7 +4658,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.c b/storage/innobase/row/row0mysql.c index 20e8c13ea70..7e1d18d41b6 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1855,7 +1855,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 @@ -1993,6 +1994,8 @@ err_exit: row_drop_table_for_mysql(table->name, trx, FALSE); trx_commit_for_mysql(trx); + } else { + dict_mem_table_free(table); } break; diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 7bec0a26225..b46b2eacd9d 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -2487,6 +2487,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 @@ -3915,6 +3918,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 */ @@ -4839,11 +4847,15 @@ 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); - data = rec_get_nth_field(rec, offsets, col_no, &len); + 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; + } - ut_a(len != UNIV_SQL_NULL); + data = rec_get_nth_field(rec, offsets, col_no, &len); switch (mtype) { case DATA_INT: @@ -4865,14 +4877,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.c b/storage/innobase/row/row0umod.c index 9597c476125..9e5fb8686c6 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -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,19 +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); mtr_start(&mtr); @@ -286,20 +248,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); } @@ -847,7 +795,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.c b/storage/innobase/row/row0undo.c index 09970b7fe21..a1c1d72f8c6 100644 --- a/storage/innobase/row/row0undo.c +++ b/storage/innobase/row/row0undo.c @@ -282,25 +282,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. |