diff options
Diffstat (limited to 'storage/innobase/fil/fil0fil.cc')
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 159 |
1 files changed, 140 insertions, 19 deletions
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); } |