diff options
Diffstat (limited to 'storage/maria/ma_rename.c')
-rw-r--r-- | storage/maria/ma_rename.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/storage/maria/ma_rename.c b/storage/maria/ma_rename.c new file mode 100644 index 00000000..ade6e52f --- /dev/null +++ b/storage/maria/ma_rename.c @@ -0,0 +1,165 @@ +/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +/* + Rename a table +*/ + +#include "ma_fulltext.h" +#include "trnman_public.h" + +/** + @brief renames a table + + @param old_name current name of table + @param new_name table should be renamed to this name + + @return Operation status + @retval 0 OK + @retval !=0 Error +*/ + +int maria_rename(const char *old_name, const char *new_name) +{ + char from[FN_REFLEN],to[FN_REFLEN]; + int data_file_rename_error= 0, index_file_rename_error= 0; +#ifdef USE_RAID + uint raid_type=0,raid_chunks=0; +#endif + MARIA_HA *info; + MARIA_SHARE *share; + myf sync_dir= 0; + my_bool ddl_recovery= 0; + DBUG_ENTER("maria_rename"); + +#ifdef EXTRA_DEBUG + _ma_check_table_is_closed(old_name,"rename old_table"); + _ma_check_table_is_closed(new_name,"rename new table2"); +#endif + /** @todo LOCK take X-lock on table */ + if (!(info= maria_open(old_name, O_RDWR, HA_OPEN_FOR_REPAIR, 0))) + { + int error= my_errno; + /* + Check if we are in recovery from a rename that failed in the middle + and we are now renaming things back. + */ + if (error == ENOENT) + { + char *index_file= from; + char *data_file= to; + fn_format(index_file, old_name, "", MARIA_NAME_IEXT, + MY_UNPACK_FILENAME | MY_APPEND_EXT); + fn_format(data_file, old_name, "", MARIA_NAME_DEXT, + MY_UNPACK_FILENAME | MY_APPEND_EXT); + if (!access(data_file, F_OK) && access(index_file, F_OK)) + { + ddl_recovery= 1; + goto forced_rename; + } + } + DBUG_RETURN(error); + } + share= info->s; +#ifdef USE_RAID + raid_type = share->base.raid_type; + raid_chunks = share->base.raid_chunks; +#endif + + /* + the renaming of an internal table to the final table (like in ALTER TABLE) + is the moment when this table receives its correct create_rename_lsn and + this is important; make sure transactionality has been re-enabled. + */ + DBUG_ASSERT(share->now_transactional == share->base.born_transactional); + if (share->now_transactional && !share->temporary && !maria_in_recovery) + { + LSN lsn; + LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2]; + size_t old_name_len= strlen(old_name)+1, new_name_len= strlen(new_name)+1; + sync_dir= MY_SYNC_DIR; + log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (uchar*)old_name; + log_array[TRANSLOG_INTERNAL_PARTS + 0].length= old_name_len; + log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (uchar*)new_name; + log_array[TRANSLOG_INTERNAL_PARTS + 1].length= new_name_len; + /* + For this record to be of any use for Recovery, we need the upper + MySQL layer to be crash-safe, which it is not now (that would require + work using the ddl_log of sql/sql_table.cc); when it is, we should + reconsider the moment of writing this log record (before or after op, + under THR_LOCK_maria or not...), how to use it in Recovery. + For now it can serve to apply logs to a backup so we sync it. + */ + if (unlikely(translog_write_record(&lsn, LOGREC_REDO_RENAME_TABLE, + &dummy_transaction_object, NULL, + (translog_size_t)(old_name_len + new_name_len), + sizeof(log_array)/sizeof(log_array[0]), + log_array, NULL, NULL) || + translog_flush(lsn))) + { + maria_close(info); + DBUG_RETURN(1); + } + /* + store LSN into file, needed for Recovery to not be confused if a + RENAME happened (applying REDOs to the wrong table). + */ + if (_ma_update_state_lsns(share, lsn, share->state.create_trid, TRUE, + TRUE)) + { + maria_close(info); + DBUG_RETURN(1); + } + } + + _ma_reset_state(info); + maria_close(info); + +forced_rename: + /* + This code is written so that it should be possible to re-run a + failed rename (even if there is a server crash in between the + renames) and complete it. + */ + fn_format(from,old_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT); + fn_format(to,new_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT); + if (mysql_file_rename_with_symlink(key_file_kfile, from, to, + MYF(MY_WME | sync_dir))) + index_file_rename_error= my_errno; + fn_format(from,old_name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT); + fn_format(to,new_name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT); + if (mysql_file_rename_with_symlink(key_file_dfile, from, to, + MYF(MY_WME | sync_dir))) + data_file_rename_error= my_errno; + if (data_file_rename_error && data_file_rename_error != ENOENT && + !ddl_recovery) + { + /* + Now we have a renamed index file and a non-renamed data file, try to + undo a successful rename of the index file. + */ + if (!index_file_rename_error) + { + fn_format(from, old_name, "", MARIA_NAME_IEXT, + MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT)); + fn_format(to, new_name, "", MARIA_NAME_IEXT, + MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT)); + mysql_file_rename_with_symlink(key_file_kfile, to, from, + MYF(MY_WME | sync_dir)); + } + } + DBUG_RETURN(data_file_rename_error ? data_file_rename_error: + index_file_rename_error); +} |