diff options
-rw-r--r-- | storage/innobase/btr/btr0btr.cc | 20 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 4 | ||||
-rw-r--r-- | storage/innobase/dict/dict0dict.cc | 42 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 159 | ||||
-rw-r--r-- | storage/innobase/fsp/fsp0fsp.cc | 26 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 127 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.h | 41 | ||||
-rw-r--r-- | storage/innobase/log/log0recv.cc | 4 | ||||
-rw-r--r-- | storage/innobase/row/row0import.cc | 16 | ||||
-rw-r--r-- | storage/innobase/row/row0log.cc | 17 | ||||
-rw-r--r-- | storage/innobase/srv/srv0start.cc | 15 |
11 files changed, 388 insertions, 83 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 79b533481b7..99bb42466d0 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. This program is free software; you can redistribute it and/or modify it under @@ -2101,7 +2101,7 @@ the tuple. It is assumed that mtr contains an x-latch on the tree. NOTE that the operation of this function must always succeed, we cannot reverse it: therefore enough free disk space must be guaranteed to be available before this function is called. -@return inserted record */ +@return inserted record or NULL if run out of space */ UNIV_INTERN rec_t* btr_root_raise_and_insert( @@ -2162,6 +2162,11 @@ btr_root_raise_and_insert( level = btr_page_get_level(root, mtr); new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr); + + if (new_block == NULL && os_has_said_disk_full) { + return(NULL); + } + new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); ut_a(!new_page_zip == !root_page_zip); @@ -2938,7 +2943,7 @@ function must always succeed, we cannot reverse it: therefore enough free disk space (2 pages) must be guaranteed to be available before this function is called. -@return inserted record */ +@return inserted record or NULL if run out of space */ UNIV_INTERN rec_t* btr_page_split_and_insert( @@ -3052,9 +3057,18 @@ func_start: } } + DBUG_EXECUTE_IF("disk_is_full", + os_has_said_disk_full = true; + return(NULL);); + /* 2. Allocate a new page to the index */ new_block = btr_page_alloc(cursor->index, hint_page_no, direction, btr_page_get_level(page, mtr), mtr, mtr); + + if (new_block == NULL && os_has_said_disk_full) { + return(NULL); + } + new_page = buf_block_get_frame(new_block); new_page_zip = buf_block_get_page_zip(new_block); btr_page_create(new_block, new_page_zip, cursor->index, diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index ad323531da6..1e4c31723db 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1604,6 +1604,10 @@ btr_cur_pessimistic_insert( flags, cursor, offsets, heap, entry, n_ext, mtr); } + if (*rec == NULL && os_has_said_disk_full) { + return(DB_OUT_OF_FILE_SPACE); + } + ut_ad(page_rec_get_next(btr_cur_get_rec(cursor)) == *rec); if (!(flags & BTR_NO_LOCKING_FLAG)) { diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index e530ec9e97a..03a117e0043 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1590,10 +1590,13 @@ dict_table_rename_in_cache( to preserve the original table name in constraints which reference it */ { + dberr_t err; dict_foreign_t* foreign; dict_index_t* index; ulint fold; char old_name[MAX_FULL_NAME_LEN + 1]; + os_file_type_t ftype; + ibool exists; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1631,8 +1634,6 @@ dict_table_rename_in_cache( .ibd file and rebuild the .isl file if needed. */ if (dict_table_is_discarded(table)) { - os_file_type_t type; - ibool exists; char* filepath; ut_ad(table->space != TRX_SYS_SPACE); @@ -1651,7 +1652,7 @@ dict_table_rename_in_cache( fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE); /* Delete any temp file hanging around. */ - if (os_file_status(filepath, &exists, &type) + if (os_file_status(filepath, &exists, &ftype) && exists && !os_file_delete_if_exists(innodb_file_temp_key, filepath)) { @@ -1663,8 +1664,6 @@ dict_table_rename_in_cache( mem_free(filepath); } else if (table->space != TRX_SYS_SPACE) { - char* new_path = NULL; - if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: trying to rename a" @@ -1678,34 +1677,43 @@ dict_table_rename_in_cache( } return(DB_ERROR); + } - } else if (DICT_TF_HAS_DATA_DIR(table->flags)) { - char* old_path; - - old_path = fil_space_get_first_path(table->space); + char* new_path = NULL; + char* old_path = fil_space_get_first_path(table->space); + if (DICT_TF_HAS_DATA_DIR(table->flags)) { new_path = os_file_make_new_pathname( old_path, new_name); - mem_free(old_path); - - dberr_t err = fil_create_link_file( - new_name, new_path); - + err = fil_create_link_file(new_name, new_path); if (err != DB_SUCCESS) { mem_free(new_path); + mem_free(old_path); return(DB_TABLESPACE_EXISTS); } + } else { + new_path = fil_make_ibd_name(new_name, false); + } + + /* New filepath must not exist. */ + err = fil_rename_tablespace_check( + table->space, old_path, new_path, false); + if (err != DB_SUCCESS) { + mem_free(old_path); + mem_free(new_path); + return(err); } ibool success = fil_rename_tablespace( old_name, table->space, new_name, new_path); + mem_free(old_path); + mem_free(new_path); + /* If the tablespace is remote, a new .isl file was created If success, delete the old one. If not, delete the new one. */ - if (new_path) { - - mem_free(new_path); + if (DICT_TF_HAS_DATA_DIR(table->flags)) { fil_delete_link_file(success ? old_name : new_name); } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index af6ddf5f837..a4e7c6f2ef2 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2990,6 +2990,48 @@ fil_make_isl_name( return(filename); } +/** Test if a tablespace file can be renamed to a new filepath by checking +if that the old filepath exists and the new filepath does not exist. +@param[in] space_id tablespace id +@param[in] old_path old filepath +@param[in] new_path new filepath +@param[in] is_discarded whether the tablespace is discarded +@return innodb error code */ +dberr_t +fil_rename_tablespace_check( + ulint space_id, + const char* old_path, + const char* new_path, + bool is_discarded) +{ + ulint exists = false; + os_file_type_t ftype; + + if (!is_discarded + && os_file_status(old_path, &exists, &ftype) + && !exists) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot rename '%s' to '%s' for space ID %lu" + " because the source file does not exist.", + old_path, new_path, space_id); + + return(DB_TABLESPACE_NOT_FOUND); + } + + exists = false; + if (!os_file_status(new_path, &exists, &ftype) || exists) { + ib_logf(IB_LOG_LEVEL_ERROR, + "Cannot rename '%s' to '%s' for space ID %lu" + " because the target file exists." + " Remove the target file and try again.", + old_path, new_path, space_id); + + return(DB_TABLESPACE_EXISTS); + } + + return(DB_SUCCESS); +} + /*******************************************************************//** Renames a single-table tablespace. The tablespace must be cached in the tablespace memory cache. @@ -6520,29 +6562,108 @@ fil_get_space_names( return(err); } -/****************************************************************//** -Generate redo logs for swapping two .ibd files */ +/** Generate redo log for swapping two .ibd files +@param[in] old_table old table +@param[in] new_table new table +@param[in] tmp_name temporary table name +@param[in,out] mtr mini-transaction +@return innodb error code */ UNIV_INTERN -void +dberr_t fil_mtr_rename_log( -/*===============*/ - ulint old_space_id, /*!< in: tablespace id of the old - table. */ - const char* old_name, /*!< in: old table name */ - ulint new_space_id, /*!< in: tablespace id of the new - table */ - const char* new_name, /*!< in: new table name */ - const char* tmp_name, /*!< in: temp table name used while - swapping */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + const dict_table_t* old_table, + const dict_table_t* new_table, + const char* tmp_name, + mtr_t* mtr) { - if (old_space_id != TRX_SYS_SPACE) { - fil_op_write_log(MLOG_FILE_RENAME, old_space_id, - 0, 0, old_name, tmp_name, mtr); + dberr_t err = DB_SUCCESS; + char* old_path; + + /* If neither table is file-per-table, + there will be no renaming of files. */ + if (old_table->space == TRX_SYS_SPACE + && new_table->space == TRX_SYS_SPACE) { + return(DB_SUCCESS); + } + + if (DICT_TF_HAS_DATA_DIR(old_table->flags)) { + old_path = os_file_make_remote_pathname( + old_table->data_dir_path, old_table->name, "ibd"); + } else { + old_path = fil_make_ibd_name(old_table->name, false); + } + if (old_path == NULL) { + return(DB_OUT_OF_MEMORY); + } + + if (old_table->space != TRX_SYS_SPACE) { + char* tmp_path; + + if (DICT_TF_HAS_DATA_DIR(old_table->flags)) { + tmp_path = os_file_make_remote_pathname( + old_table->data_dir_path, tmp_name, "ibd"); + } + else { + tmp_path = fil_make_ibd_name(tmp_name, false); + } + + if (tmp_path == NULL) { + mem_free(old_path); + return(DB_OUT_OF_MEMORY); + } + + /* Temp filepath must not exist. */ + err = fil_rename_tablespace_check( + old_table->space, old_path, tmp_path, + dict_table_is_discarded(old_table)); + mem_free(tmp_path); + if (err != DB_SUCCESS) { + mem_free(old_path); + return(err); + } + + fil_op_write_log(MLOG_FILE_RENAME, old_table->space, + 0, 0, old_table->name, tmp_name, mtr); } - if (new_space_id != TRX_SYS_SPACE) { - fil_op_write_log(MLOG_FILE_RENAME, new_space_id, - 0, 0, new_name, old_name, mtr); + if (new_table->space != TRX_SYS_SPACE) { + + /* Destination filepath must not exist unless this ALTER + TABLE starts and ends with a file_per-table tablespace. */ + if (old_table->space == TRX_SYS_SPACE) { + char* new_path = NULL; + + if (DICT_TF_HAS_DATA_DIR(new_table->flags)) { + new_path = os_file_make_remote_pathname( + new_table->data_dir_path, + new_table->name, "ibd"); + } + else { + new_path = fil_make_ibd_name( + new_table->name, false); + } + + if (new_path == NULL) { + mem_free(old_path); + return(DB_OUT_OF_MEMORY); + } + + err = fil_rename_tablespace_check( + new_table->space, new_path, old_path, + dict_table_is_discarded(new_table)); + mem_free(new_path); + if (err != DB_SUCCESS) { + mem_free(old_path); + return(err); + } + } + + fil_op_write_log(MLOG_FILE_RENAME, new_table->space, + 0, 0, new_table->name, old_table->name, mtr); + } + + mem_free(old_path); + + return(err); } diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 6ecf97aaeb6..0f8d6bcc4f0 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -952,10 +952,20 @@ fsp_try_extend_data_file( } } else { /* We extend single-table tablespaces first one extent - at a time, but for bigger tablespaces more. It is not - enough to extend always by one extent, because some - extents are frag page extents. */ + at a time, but 4 at a time for bigger tablespaces. It is + not enough to extend always by one extent, because we need + to add at least one extent to FSP_FREE. + A single extent descriptor page will track many extents. + And the extent that uses its extent descriptor page is + put onto the FSP_FREE_FRAG list. Extents that do not + use their extent descriptor page are added to FSP_FREE. + The physical page size is used to determine how many + extents are tracked on one extent descriptor page. */ ulint extent_size; /*!< one megabyte, in pages */ + ulint threshold; /*!< The size of the tablespace + (in number of pages) where we + start allocating more than one + extent at a time. */ if (!zip_size) { extent_size = FSP_EXTENT_SIZE; @@ -964,6 +974,14 @@ fsp_try_extend_data_file( * UNIV_PAGE_SIZE / zip_size; } + /* Threshold is set at 32mb except when the page + size is small enough that it must be done sooner. + For page size less than 4k, we may reach the + extent contains extent descriptor page before + 32 mb. */ + threshold = ut_min((32 * extent_size), + (zip_size ? zip_size : UNIV_PAGE_SIZE)); + if (size < extent_size) { /* Let us first extend the file to extent_size */ success = fsp_try_extend_data_file_with_pages( @@ -980,7 +998,7 @@ fsp_try_extend_data_file( size = extent_size; } - if (size < 32 * extent_size) { + if (size < threshold) { size_increase = extent_size; } else { /* Below in fsp_fill_free_list() we assume diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 2354f5537cb..e48ae04ed6a 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -156,10 +156,13 @@ my_error_innodb( /* TODO: report the row, as we do for DB_DUPLICATE_KEY */ my_error(ER_INVALID_USE_OF_NULL, MYF(0)); break; + case DB_TABLESPACE_EXISTS: + my_error(ER_TABLESPACE_EXISTS, MYF(0), table); + break; + #ifdef UNIV_DEBUG case DB_SUCCESS: case DB_DUPLICATE_KEY: - case DB_TABLESPACE_EXISTS: case DB_ONLINE_LOG_TOO_BIG: /* These codes should not be passed here. */ ut_error; @@ -5026,6 +5029,61 @@ commit_cache_rebuild( DBUG_VOID_RETURN; } +/** Store the column number of the columns in a list belonging +to indexes which are not being dropped. +@param[in] ctx In-place ALTER TABLE context +@param[out] drop_col_list list which will be set, containing columns + which is part of index being dropped */ +static +void +get_col_list_to_be_dropped( + ha_innobase_inplace_ctx* ctx, + std::set<ulint>& drop_col_list) +{ + for (ulint index_count = 0; index_count < ctx->num_to_drop_index; + index_count++) { + dict_index_t* index = ctx->drop_index[index_count]; + + for (ulint col = 0; col < index->n_user_defined_cols; col++) { + ulint col_no = dict_index_get_nth_col_no(index, col); + drop_col_list.insert(col_no); + } + } +} + +/** For each column, which is part of an index which is not going to be +dropped, it checks if the column number of the column is same as col_no +argument passed. +@param[in] table table object +@param[in] col_no column number of the column which is to be checked +@retval true column exists +@retval false column does not exist. */ +static +bool +check_col_exists_in_indexes( + const dict_table_t* table, + ulint col_no) +{ + for (dict_index_t* index = dict_table_get_first_index(table); index; + index = dict_table_get_next_index(index)) { + + if (index->to_be_dropped) { + continue; + } + + for (ulint col = 0; col < index->n_user_defined_cols; col++) { + + ulint index_col_no = dict_index_get_nth_col_no( + index, col); + if (col_no == index_col_no) { + return(true); + } + } + } + + return(false); +} + /** Commit the changes made during prepare_inplace_alter_table() and inplace_alter_table() inside the data dictionary tables, when not rebuilding the table. @@ -5161,6 +5219,20 @@ commit_cache_norebuild( DBUG_ASSERT(!ctx->need_rebuild()); + std::set<ulint> drop_list; + std::set<ulint>::const_iterator col_it; + + /* Check if the column, part of an index to be dropped is part of any + other index which is not being dropped. If it so, then set the ord_part + of the column to 0. */ + get_col_list_to_be_dropped(ctx, drop_list); + + for(col_it = drop_list.begin(); col_it != drop_list.end(); ++col_it) { + if (!check_col_exists_in_indexes(ctx->new_table, *col_it)) { + ctx->new_table->cols[*col_it].ord_part = 0; + } + } + for (ulint i = 0; i < ctx->num_to_add_index; i++) { dict_index_t* index = ctx->add_index[i]; DBUG_ASSERT(dict_index_get_online_status(index) @@ -5361,6 +5433,7 @@ ha_innobase::commit_inplace_alter_table( Alter_inplace_info* ha_alter_info, bool commit) { + dberr_t error; ha_innobase_inplace_ctx* ctx0 = static_cast<ha_innobase_inplace_ctx*> (ha_alter_info->handler_ctx); @@ -5442,7 +5515,7 @@ ha_innobase::commit_inplace_alter_table( transactions collected during crash recovery could be holding InnoDB locks only, not MySQL locks. */ - dberr_t error = row_merge_lock_table( + error = row_merge_lock_table( prebuilt->trx, ctx->old_table, LOCK_X); if (error != DB_SUCCESS) { @@ -5577,14 +5650,20 @@ ha_innobase::commit_inplace_alter_table( = static_cast<ha_innobase_inplace_ctx*>(*pctx); DBUG_ASSERT(ctx->need_rebuild()); - /* Generate the redo log for the file - operations that will be performed in - commit_cache_rebuild(). */ - fil_mtr_rename_log(ctx->old_table->space, - ctx->old_table->name, - ctx->new_table->space, - ctx->new_table->name, - ctx->tmp_name, &mtr); + /* Check for any possible problems for any + file operations that will be performed in + commit_cache_rebuild(), and if none, generate + the redo log for these operations. */ + error = fil_mtr_rename_log(ctx->old_table, + ctx->new_table, + ctx->tmp_name, &mtr); + if (error != DB_SUCCESS) { + /* Out of memory or a problem will occur + when renaming files. */ + fail = true; + my_error_innodb(error, ctx->old_table->name, + ctx->old_table->flags); + } DBUG_INJECT_CRASH("ib_commit_inplace_crash", crash_inject_count++); } @@ -5597,18 +5676,25 @@ ha_innobase::commit_inplace_alter_table( DBUG_EXECUTE_IF("innodb_alter_commit_crash_before_commit", log_buffer_flush_to_disk(); DBUG_SUICIDE();); - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); ut_ad(!trx->fts_trx); - ut_ad(trx->insert_undo || trx->update_undo); - /* The following call commits the - mini-transaction, making the data dictionary - transaction committed at mtr.end_lsn. The - transaction becomes 'durable' by the time when - log_buffer_flush_to_disk() returns. In the - logical sense the commit in the file-based - data structures happens here. */ - trx_commit_low(trx, &mtr); + if (fail) { + mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); + mtr_commit(&mtr); + trx_rollback_for_mysql(trx); + } else { + /* The following call commits the + mini-transaction, making the data dictionary + transaction committed at mtr.end_lsn. The + transaction becomes 'durable' by the time when + log_buffer_flush_to_disk() returns. In the + logical sense the commit in the file-based + data structures happens here. */ + ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); + ut_ad(trx->insert_undo || trx->update_undo); + + trx_commit_low(trx, &mtr); + } /* If server crashes here, the dictionary in InnoDB and MySQL will differ. The .ibd files @@ -5630,7 +5716,6 @@ ha_innobase::commit_inplace_alter_table( update the in-memory structures, close some handles, release temporary files, and (unless we rolled back) update persistent statistics. */ - dberr_t error = DB_SUCCESS; for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) { diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 168f2f5b594..43c9162914f 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -490,6 +490,21 @@ fil_discard_tablespace( ulint id) /*!< in: space id */ __attribute__((warn_unused_result)); #endif /* !UNIV_HOTBACKUP */ + +/** Test if a tablespace file can be renamed to a new filepath by checking +if that the old filepath exists and the new filepath does not exist. +@param[in] space_id tablespace id +@param[in] old_path old filepath +@param[in] new_path new filepath +@param[in] is_discarded whether the tablespace is discarded +@return innodb error code */ +dberr_t +fil_rename_tablespace_check( + ulint space_id, + const char* old_path, + const char* new_path, + bool is_discarded); + /*******************************************************************//** Renames a single-table tablespace. The tablespace must be cached in the tablespace memory cache. @@ -986,21 +1001,19 @@ fil_get_space_names( /*!< in/out: Vector for collecting the names. */ __attribute__((warn_unused_result)); -/****************************************************************//** -Generate redo logs for swapping two .ibd files */ +/** Generate redo log for swapping two .ibd files +@param[in] old_table old table +@param[in] new_table new table +@param[in] tmp_name temporary table name +@param[in,out] mtr mini-transaction +@return innodb error code */ UNIV_INTERN -void +dberr_t fil_mtr_rename_log( -/*===============*/ - ulint old_space_id, /*!< in: tablespace id of the old - table. */ - const char* old_name, /*!< in: old table name */ - ulint new_space_id, /*!< in: tablespace id of the new - table */ - const char* new_name, /*!< in: new table name */ - const char* tmp_name, /*!< in: temp table name used while - swapping */ - mtr_t* mtr) /*!< in/out: mini-transaction */ + const dict_table_t* old_table, + const dict_table_t* new_table, + const char* tmp_name, + mtr_t* mtr) __attribute__((nonnull)); /*******************************************************************//** diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 9affec63252..ca07f89890f 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -827,6 +827,10 @@ not_consistent: fprintf(stderr, "InnoDB: No valid checkpoint found.\n" + "InnoDB: If you are attempting downgrade" + " from MySQL 5.7.9 or later,\n" + "InnoDB: please refer to " REFMAN + "upgrading-downgrading.html\n" "InnoDB: If this error appears when you are" " creating an InnoDB database,\n" "InnoDB: the problem may be that during" diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index acf6be7d8d8..89496b4176b 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -2068,8 +2068,20 @@ PageConverter::validate( return(IMPORT_PAGE_STATUS_CORRUPTED); } else if (offset > 0 && page_get_page_no(page) == 0) { - const byte* b = page; - const byte* e = b + m_page_size; + ulint checksum; + + checksum = mach_read_from_4(page + FIL_PAGE_SPACE_OR_CHKSUM); + if (checksum != 0) { + /* Checksum check passed in buf_page_is_corrupted(). */ + ib_logf(IB_LOG_LEVEL_WARN, + "%s: Page %lu checksum %lu should be zero.", + m_filepath, (ulong) (offset / m_page_size), + checksum); + } + + const byte* b = page + FIL_PAGE_OFFSET; + const byte* e = page + m_page_size + - FIL_PAGE_END_LSN_OLD_CHKSUM; /* If the page number is zero and offset > 0 then the entire page MUST consist of zeroes. If not then diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index f88baa42d58..3989b669c28 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -1454,6 +1454,7 @@ row_log_table_apply_insert_low( dtuple_t* entry; const row_log_t*log = dup->index->online_log; dict_index_t* index = dict_table_get_first_index(log->table); + ulint n_index = 0; ut_ad(dtuple_validate(row)); ut_ad(trx_id); @@ -1489,6 +1490,8 @@ row_log_table_apply_insert_low( } do { + n_index++; + if (!(index = dict_table_get_next_index(index))) { break; } @@ -1501,6 +1504,12 @@ row_log_table_apply_insert_low( error = row_ins_sec_index_entry_low( flags, BTR_MODIFY_TREE, index, offsets_heap, heap, entry, trx_id, thr); + + /* Report correct index name for duplicate key error. */ + if (error == DB_DUPLICATE_KEY) { + thr_get_trx(thr)->error_key_num = n_index; + } + } while (error == DB_SUCCESS); return(error); @@ -1808,6 +1817,7 @@ row_log_table_apply_update( mtr_t mtr; btr_pcur_t pcur; dberr_t error; + ulint n_index = 0; ut_ad(dtuple_get_n_fields_cmp(old_pk) == dict_index_get_n_unique(index)); @@ -2083,6 +2093,8 @@ func_exit_committed: break; } + n_index++; + if (index->type & DICT_FTS) { continue; } @@ -2126,6 +2138,11 @@ func_exit_committed: BTR_MODIFY_TREE, index, offsets_heap, heap, entry, trx_id, thr); + /* Report correct index name for duplicate key error. */ + if (error == DB_DUPLICATE_KEY) { + thr_get_trx(thr)->error_key_num = n_index; + } + mtr_start(&mtr); } diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 8a9afd561a9..ca9d414156e 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -147,6 +147,9 @@ static const ulint SRV_UNDO_TABLESPACE_SIZE_IN_PAGES = #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 +/** The round off to MB is similar as done in srv_parse_megabytes() */ +#define CALC_NUMBER_OF_PAGES(size) ((size) / (1024 * 1024)) * \ + ((1024 * 1024) / (UNIV_PAGE_SIZE)) #ifdef UNIV_PFS_THREAD /* Keys to register InnoDB threads with performance schema */ UNIV_INTERN mysql_pfs_key_t io_handler_thread_key; @@ -958,10 +961,16 @@ open_or_create_data_files( size_check: size = os_file_get_size(files[i]); ut_a(size != (os_offset_t) -1); - /* Round size downward to megabytes */ - rounded_size_pages = (ulint) - (size >> UNIV_PAGE_SIZE_SHIFT); + /* Under some error conditions like disk full + narios or file size reaching filesystem + limit the data file could contain an incomplete + extent at the end. When we extend a data file + and if some failure happens, then also the data + file could contain an incomplete extent. So we + need to round the size downward to a megabyte.*/ + + rounded_size_pages = (ulint) CALC_NUMBER_OF_PAGES(size); if (i == srv_n_data_files - 1 && srv_auto_extend_last_data_file) { |