diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index ff89274..b54c405 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -306,7 +306,7 @@ dict_build_table_def_step( || dict_table_get_format(table) >= UNIV_FORMAT_B); error = fil_create_new_single_table_tablespace( - space, table->name, path, + space, 0, table->name, path, dict_tf_to_fsp_flags(table->flags), table->flags2, FIL_IBD_FILE_INITIAL_SIZE); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 088eeb9..5340ea6 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1449,7 +1449,7 @@ dict_table_rename_in_cache( filepath = fil_make_ibd_name(table->name, false); } - fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE); + fil_delete_tablespace(table->space, false, BUF_REMOVE_ALL_NO_WRITE); /* Delete any temp file hanging around. */ if (os_file_status(filepath, &exists, &type) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 16891c3..5dfce16 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2376,7 +2376,7 @@ fil_op_log_parse_or_replay( case MLOG_FILE_DELETE: if (fil_tablespace_exists_in_mem(space_id)) { dberr_t err = fil_delete_tablespace( - space_id, BUF_REMOVE_FLUSH_NO_WRITE); + space_id, false, BUF_REMOVE_FLUSH_NO_WRITE); ut_a(err == DB_SUCCESS); } @@ -2420,7 +2420,7 @@ fil_op_log_parse_or_replay( fil_create_directory_for_tablename(name); if (fil_create_new_single_table_tablespace( - space_id, name, path, flags, + space_id, 0, name, path, flags, DICT_TF2_USE_TABLESPACE, FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) { ut_error; @@ -2437,6 +2437,28 @@ fil_op_log_parse_or_replay( } /*******************************************************************//** +Allocates a file name for the TRUNCATE backup file name. The +string must be freed by caller with mem_free(). +@return own: file name */ +static +char* +fil_make_bak_name( +/*==============*/ + const char* filepath) /*!< in: .ibd file name */ +{ + char* bak_name; + + /* Create a temporary file path by replacing the .ibd suffix + with .tru. */ + + ut_ad(strlen(filepath) > 4); + + bak_name = mem_strdup(filepath); + ut_snprintf(bak_name + strlen(bak_name) - 3, 4, "tru"); + return(bak_name); +} + +/*******************************************************************//** Allocates a file name for the EXPORT/IMPORT config file name. The string must be freed by caller with mem_free(). @return own: file name */ @@ -2678,6 +2700,7 @@ dberr_t fil_delete_tablespace( /*==================*/ ulint id, /*!< in: space id */ + bool do_back_file, /*!< in: backup ibd file that delete later */ buf_remove_t buf_remove) /*!< in: specify the action to take on the tables pages in the buffer pool */ @@ -2772,13 +2795,24 @@ fil_delete_tablespace( if (err != DB_SUCCESS) { rw_lock_x_unlock(&space->latch); - } else if (!os_file_delete(innodb_file_data_key, path) - && !os_file_delete_if_exists(innodb_file_data_key, path)) { + } else if (do_back_file) { + /* backup ibd file, for example, like TRUNCATE */ + char *bak_path = fil_make_bak_name(path); + bool ret = os_file_rename(innodb_file_data_key, path, bak_path); + mem_free(bak_path); - /* Note: This is because we have removed the - tablespace instance from the cache. */ + if (ret == FALSE) + err = DB_IO_ERROR; - err = DB_IO_ERROR; + } else { + if (!os_file_delete(innodb_file_data_key, path) + && !os_file_delete_if_exists(innodb_file_data_key, path)) { + + /* Note: This is because we have removed the + tablespace instance from the cache. */ + + err = DB_IO_ERROR; + } } if (err == DB_SUCCESS) { @@ -2845,11 +2879,12 @@ UNIV_INTERN dberr_t fil_discard_tablespace( /*===================*/ - ulint id) /*!< in: space id */ + ulint id, /*!< in: space id */ + bool do_back_file) /*!< in: backup ibd file that delete later */ { dberr_t err; - switch (err = fil_delete_tablespace(id, BUF_REMOVE_ALL_NO_WRITE)) { + switch (err = fil_delete_tablespace(id, do_back_file, BUF_REMOVE_ALL_NO_WRITE)) { case DB_SUCCESS: break; @@ -3349,6 +3384,7 @@ dberr_t fil_create_new_single_table_tablespace( /*===================================*/ ulint space_id, /*!< in: space id */ + ulint old_space_id, /*!< in: old space id for truncate */ const char* tablename, /*!< in: the table name in the usual databasename/tablename format of InnoDB */ @@ -3365,6 +3401,7 @@ fil_create_new_single_table_tablespace( byte* buf2; byte* page; char* path; + char* bak_path; ibool success; /* TRUE if a table is created with CREATE TEMPORARY TABLE */ bool is_temp = !!(flags2 & DICT_TF2_TEMPORARY); @@ -3429,12 +3466,31 @@ fil_create_new_single_table_tablespace( } if (error == OS_FILE_DISK_FULL) { + if (old_space_id) { + /* restore bak file for truncate */ + bak_path = fil_make_bak_name(path); + ret = os_file_rename(innodb_file_data_key,bak_path, path); + mem_free(bak_path); + + /* restore space and node */ + if (ret) { + fil_space_create(tablename, old_space_id, flags, + FIL_TABLESPACE) + && fil_node_create(path, 0, old_space_id, FALSE); + } + } + err = DB_OUT_OF_FILE_SPACE; goto error_exit_3; } err = DB_ERROR; goto error_exit_3; + } else if (old_space_id) { + /* delete bak file for truncate */ + bak_path = fil_make_bak_name(path); + os_file_delete_if_exists(innodb_file_data_key,bak_path); + mem_free(bak_path); } ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE); @@ -4691,6 +4747,43 @@ fil_load_single_table_tablespaces(void) goto next_file_item; } + if (strlen(fileinfo.name) > 4 + && (0 == strcmp(fileinfo.name + + strlen(fileinfo.name) - 4, + ".tru"))) { + /* rename .tru to .ibd */ + char* ibd_name; + + ibd_name = mem_strdup(fileinfo.name); + ibd_name[strlen(ibd_name) - 4] = '\0'; + + int len= strlen(dbinfo.name) + strlen(fileinfo.name) + 4; + char *from = static_cast(mem_alloc(len)); + char *to = static_cast(mem_alloc(len)); + + ut_snprintf(from, len, "./%s/%s.tru", dbinfo.name, ibd_name); + ut_snprintf(to, len, "./%s/%s.ibd", dbinfo.name, ibd_name); + + ret = os_file_rename(innodb_file_data_key, from, to); + if (ret) { + ib_logf(IB_LOG_LEVEL_WARN, + "Successful restored truncate file due to half done by crash-recovery.\n" + "from %s to %s \n", + from, to); + } else { + ib_logf(IB_LOG_LEVEL_WARN, + "Failed to restore truncate file due to half done by crash-recovery\n" + "from %s to %s \n", + from, to); + } + + mem_free(ibd_name); + mem_free(from); + mem_free(to); + + goto next_file_item; + } + /* We found a symlink or a file */ if (strlen(fileinfo.name) > 4 && (0 == strcmp(fileinfo.name diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 8785bd0..7f53867 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -439,6 +439,7 @@ dberr_t fil_delete_tablespace( /*==================*/ ulint id, /*!< in: space id */ + bool do_back_file, /*!< in: backup ibd file deleted later */ buf_remove_t buf_remove); /*!< in: specify the action to take on the tables pages in the buffer pool */ @@ -471,7 +472,8 @@ UNIV_INTERN dberr_t fil_discard_tablespace( /*===================*/ - ulint id) /*!< in: space id */ + ulint id, /*!< in: space id */ + bool do_back_file) /*!< in: backup ibd file deleted later */ __attribute__((warn_unused_result)); #endif /* !UNIV_HOTBACKUP */ /*******************************************************************//** @@ -557,6 +559,7 @@ dberr_t fil_create_new_single_table_tablespace( /*===================================*/ ulint space_id, /*!< in: space id */ + ulint old_space_id, /*!< in: old space id for truncate */ const char* tablename, /*!< in: the table name in the usual databasename/tablename format of InnoDB */ diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 68c71fa..f740626 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2683,7 +2683,7 @@ err_exit: if (table->space && fil_delete_tablespace( - table->space, + table->space, false, BUF_REMOVE_FLUSH_NO_WRITE) != DB_SUCCESS) { @@ -3337,7 +3337,7 @@ row_discard_tablespace( /* Discard the physical file that is used for the tablespace. */ - err = fil_discard_tablespace(table->space); + err = fil_discard_tablespace(table->space, false); switch(err) { case DB_SUCCESS: @@ -3727,7 +3727,7 @@ row_truncate_table_for_mysql( dict_get_and_save_data_dir_path(table, true); if (flags != ULINT_UNDEFINED - && fil_discard_tablespace(space) == DB_SUCCESS) { + && fil_discard_tablespace(space, true) == DB_SUCCESS) { dict_index_t* index; @@ -3740,7 +3740,7 @@ row_truncate_table_for_mysql( if (space == ULINT_UNDEFINED || fil_create_new_single_table_tablespace( - space, table->name, + space, old_space, table->name, table->data_dir_path, flags, table->flags2, FIL_IBD_FILE_INITIAL_SIZE) @@ -3752,7 +3752,8 @@ row_truncate_table_for_mysql( "create a new tablespace", table->name); - table->ibd_file_missing = 1; + /* don't unregister ibd space as .ibd is renamed to .tru */ + //table->ibd_file_missing = 1; err = DB_ERROR; goto funct_exit; } @@ -4620,7 +4621,7 @@ check_next_foreign: fil_delete_file(filepath); } else if (fil_delete_tablespace( - space_id, + space_id, false, BUF_REMOVE_FLUSH_NO_WRITE) != DB_SUCCESS) { fprintf(stderr,