Skip to content

Commit 55abcfa

Browse files
committed
MDEV-16124 fil_rename_tablespace() times out and crashes server during table-rebuilding ALTER TABLE
InnoDB insisted on closing the file handle before renaming a file. Renaming a file should never be a problem on POSIX systems. Also on Windows it should work if the file was opened in FILE_SHARE_DELETE mode. fil_space_t::stop_ios: Remove. We no longer need to stop file access during rename operations. fil_mutex_enter_and_prepare_for_io(): Remove the wait for stop_ios. fil_rename_tablespace(): Remove the retry logic; do not close the file handle. Remove the unused fault injection that was added along with the DATA DIRECTORY functionality (MySQL WL#5980). os_file_create_simple_func(), os_file_create_func(), os_file_create_simple_no_error_handling_func(): Include FILE_SHARE_DELETE in the share_mode. (We will still prevent multiple InnoDB instances from using the same files by not setting FILE_SHARE_WRITE.)
1 parent a61724a commit 55abcfa

File tree

6 files changed

+10
-236
lines changed

6 files changed

+10
-236
lines changed

storage/innobase/fil/fil0fil.cc

Lines changed: 0 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,6 @@ fil_mutex_enter_and_prepare_for_io(
845845
ibool success;
846846
ibool print_info = FALSE;
847847
ulint count = 0;
848-
ulint count2 = 0;
849848

850849
retry:
851850
mutex_enter(&fil_system->mutex);
@@ -862,46 +861,6 @@ fil_mutex_enter_and_prepare_for_io(
862861

863862
space = fil_space_get_by_id(space_id);
864863

865-
if (space != NULL && space->stop_ios) {
866-
/* We are going to do a rename file and want to stop new i/o's
867-
for a while */
868-
869-
if (count2 > 20000) {
870-
fputs("InnoDB: Warning: tablespace ", stderr);
871-
ut_print_filename(stderr, space->name);
872-
fprintf(stderr,
873-
" has i/o ops stopped for a long time %lu\n",
874-
(ulong) count2);
875-
}
876-
877-
mutex_exit(&fil_system->mutex);
878-
879-
#ifndef UNIV_HOTBACKUP
880-
881-
/* Wake the i/o-handler threads to make sure pending
882-
i/o's are performed */
883-
os_aio_simulated_wake_handler_threads();
884-
885-
/* The sleep here is just to give IO helper threads a
886-
bit of time to do some work. It is not required that
887-
all IO related to the tablespace being renamed must
888-
be flushed here as we do fil_flush() in
889-
fil_rename_tablespace() as well. */
890-
os_thread_sleep(20000);
891-
892-
#endif /* UNIV_HOTBACKUP */
893-
894-
/* Flush tablespaces so that we can close modified
895-
files in the LRU list */
896-
fil_flush_file_spaces(FIL_TABLESPACE);
897-
898-
os_thread_sleep(20000);
899-
900-
count2++;
901-
902-
goto retry;
903-
}
904-
905864
if (fil_system->n_open < fil_system->max_n_open) {
906865

907866
return;
@@ -2898,33 +2857,17 @@ fil_rename_tablespace(
28982857
ibool success;
28992858
fil_space_t* space;
29002859
fil_node_t* node;
2901-
ulint count = 0;
29022860
char* new_path;
29032861
char* old_name;
29042862
char* old_path;
29052863
const char* not_given = "(name not specified)";
29062864

29072865
ut_a(id != 0);
29082866

2909-
retry:
2910-
count++;
2911-
2912-
if (!(count % 1000)) {
2913-
ut_print_timestamp(stderr);
2914-
fputs(" InnoDB: Warning: problems renaming ", stderr);
2915-
ut_print_filename(stderr,
2916-
old_name_in ? old_name_in : not_given);
2917-
fputs(" to ", stderr);
2918-
ut_print_filename(stderr, new_name);
2919-
fprintf(stderr, ", %lu iterations\n", (ulong) count);
2920-
}
2921-
29222867
mutex_enter(&fil_system->mutex);
29232868

29242869
space = fil_space_get_by_id(id);
29252870

2926-
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_1", space = NULL; );
2927-
29282871
if (space == NULL) {
29292872
ib_logf(IB_LOG_LEVEL_ERROR,
29302873
"Cannot find space id %lu in the tablespace "
@@ -2936,54 +2879,11 @@ fil_rename_tablespace(
29362879
return(FALSE);
29372880
}
29382881

2939-
if (count > 25000) {
2940-
space->stop_ios = FALSE;
2941-
mutex_exit(&fil_system->mutex);
2942-
2943-
return(FALSE);
2944-
}
2945-
2946-
/* We temporarily close the .ibd file because we do not trust that
2947-
operating systems can rename an open file. For the closing we have to
2948-
wait until there are no pending i/o's or flushes on the file. */
2949-
2950-
space->stop_ios = TRUE;
2951-
29522882
/* The following code must change when InnoDB supports
29532883
multiple datafiles per tablespace. */
29542884
ut_a(UT_LIST_GET_LEN(space->chain) == 1);
29552885
node = UT_LIST_GET_FIRST(space->chain);
29562886

2957-
if (node->n_pending > 0
2958-
|| node->n_pending_flushes > 0
2959-
|| node->being_extended) {
2960-
/* There are pending i/o's or flushes or the file is
2961-
currently being extended, sleep for a while and
2962-
retry */
2963-
2964-
mutex_exit(&fil_system->mutex);
2965-
2966-
os_thread_sleep(20000);
2967-
2968-
goto retry;
2969-
2970-
} else if (node->modification_counter > node->flush_counter) {
2971-
/* Flush the space */
2972-
2973-
mutex_exit(&fil_system->mutex);
2974-
2975-
os_thread_sleep(20000);
2976-
2977-
fil_flush(id);
2978-
2979-
goto retry;
2980-
2981-
} else if (node->open) {
2982-
/* Close the file */
2983-
2984-
fil_node_close_file(node, fil_system);
2985-
}
2986-
29872887
/* Check that the old name in the space is right */
29882888

29892889
if (old_name_in) {
@@ -3002,17 +2902,9 @@ fil_rename_tablespace(
30022902
space, node, new_name, new_path);
30032903

30042904
if (success) {
3005-
3006-
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
3007-
goto skip_second_rename; );
3008-
30092905
success = os_file_rename(
30102906
innodb_file_data_key, old_path, new_path);
30112907

3012-
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
3013-
skip_second_rename:
3014-
success = FALSE; );
3015-
30162908
if (!success) {
30172909
/* We have to revert the changes we made
30182910
to the tablespace memory cache */
@@ -3022,8 +2914,6 @@ fil_rename_tablespace(
30222914
}
30232915
}
30242916

3025-
space->stop_ios = FALSE;
3026-
30272917
mutex_exit(&fil_system->mutex);
30282918

30292919
#ifndef UNIV_HOTBACKUP

storage/innobase/include/fil0fil.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,10 +256,6 @@ struct fil_space_t {
256256
the space corresponds to a table in the InnoDB
257257
data dictionary; so we can print a warning of
258258
orphaned tablespaces */
259-
ibool stop_ios;/*!< TRUE if we want to rename the
260-
.ibd file of tablespace and want to
261-
stop temporarily posting of new i/o
262-
requests on the file */
263259
ibool stop_new_ops;
264260
/*!< we set this TRUE when we start
265261
deleting a single-table tablespace.

storage/innobase/os/os0file.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
44
Copyright (c) 2009, Percona Inc.
5-
Copyright (c) 2013, 2017, MariaDB Corporation.
5+
Copyright (c) 2013, 2018, MariaDB Corporation.
66
77
Portions of this file contain modifications contributed and copyrighted
88
by Percona Inc.. Those modifications are
@@ -1186,7 +1186,8 @@ os_file_create_simple_func(
11861186
/* Use default security attributes and no template file. */
11871187

11881188
file = CreateFile(
1189-
(LPCTSTR) name, access, FILE_SHARE_READ, NULL,
1189+
(LPCTSTR) name, access,
1190+
FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
11901191
create_flag, attributes, NULL);
11911192

11921193
if (file == INVALID_HANDLE_VALUE) {
@@ -1314,7 +1315,7 @@ os_file_create_simple_no_error_handling_func(
13141315
DWORD access;
13151316
DWORD create_flag;
13161317
DWORD attributes = 0;
1317-
DWORD share_mode = FILE_SHARE_READ;
1318+
DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_DELETE;
13181319
ut_a(name);
13191320

13201321
ut_a(!(create_mode & OS_FILE_ON_ERROR_SILENT));
@@ -1554,7 +1555,7 @@ os_file_create_func(
15541555

15551556
#ifdef __WIN__
15561557
DWORD create_flag;
1557-
DWORD share_mode = FILE_SHARE_READ;
1558+
DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_DELETE;
15581559

15591560
on_error_no_exit = create_mode & OS_FILE_ON_ERROR_NO_EXIT
15601561
? TRUE : FALSE;

storage/xtradb/fil/fil0fil.cc

Lines changed: 0 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,6 @@ fil_mutex_enter_and_prepare_for_io(
862862
ibool success;
863863
ibool print_info = FALSE;
864864
ulint count = 0;
865-
ulint count2 = 0;
866865

867866
retry:
868867
mutex_enter(&fil_system->mutex);
@@ -879,46 +878,6 @@ fil_mutex_enter_and_prepare_for_io(
879878

880879
space = fil_space_get_by_id(space_id);
881880

882-
if (space != NULL && space->stop_ios) {
883-
/* We are going to do a rename file and want to stop new i/o's
884-
for a while */
885-
886-
if (count2 > 20000) {
887-
fputs("InnoDB: Warning: tablespace ", stderr);
888-
ut_print_filename(stderr, space->name);
889-
fprintf(stderr,
890-
" has i/o ops stopped for a long time %lu\n",
891-
(ulong) count2);
892-
}
893-
894-
mutex_exit(&fil_system->mutex);
895-
896-
#ifndef UNIV_HOTBACKUP
897-
898-
/* Wake the i/o-handler threads to make sure pending
899-
i/o's are performed */
900-
os_aio_simulated_wake_handler_threads();
901-
902-
/* The sleep here is just to give IO helper threads a
903-
bit of time to do some work. It is not required that
904-
all IO related to the tablespace being renamed must
905-
be flushed here as we do fil_flush() in
906-
fil_rename_tablespace() as well. */
907-
os_thread_sleep(20000);
908-
909-
#endif /* UNIV_HOTBACKUP */
910-
911-
/* Flush tablespaces so that we can close modified
912-
files in the LRU list */
913-
fil_flush_file_spaces(FIL_TABLESPACE);
914-
915-
os_thread_sleep(20000);
916-
917-
count2++;
918-
919-
goto retry;
920-
}
921-
922881
if (fil_system->n_open < fil_system->max_n_open) {
923882

924883
return;
@@ -2950,33 +2909,17 @@ fil_rename_tablespace(
29502909
ibool success;
29512910
fil_space_t* space;
29522911
fil_node_t* node;
2953-
ulint count = 0;
29542912
char* new_path;
29552913
char* old_name;
29562914
char* old_path;
29572915
const char* not_given = "(name not specified)";
29582916

29592917
ut_a(id != 0);
29602918

2961-
retry:
2962-
count++;
2963-
2964-
if (!(count % 1000)) {
2965-
ut_print_timestamp(stderr);
2966-
fputs(" InnoDB: Warning: problems renaming ", stderr);
2967-
ut_print_filename(stderr,
2968-
old_name_in ? old_name_in : not_given);
2969-
fputs(" to ", stderr);
2970-
ut_print_filename(stderr, new_name);
2971-
fprintf(stderr, ", %lu iterations\n", (ulong) count);
2972-
}
2973-
29742919
mutex_enter(&fil_system->mutex);
29752920

29762921
space = fil_space_get_by_id(id);
29772922

2978-
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_1", space = NULL; );
2979-
29802923
if (space == NULL) {
29812924
ib_logf(IB_LOG_LEVEL_ERROR,
29822925
"Cannot find space id %lu in the tablespace "
@@ -2988,54 +2931,11 @@ fil_rename_tablespace(
29882931
return(FALSE);
29892932
}
29902933

2991-
if (count > 25000) {
2992-
space->stop_ios = FALSE;
2993-
mutex_exit(&fil_system->mutex);
2994-
2995-
return(FALSE);
2996-
}
2997-
2998-
/* We temporarily close the .ibd file because we do not trust that
2999-
operating systems can rename an open file. For the closing we have to
3000-
wait until there are no pending i/o's or flushes on the file. */
3001-
3002-
space->stop_ios = TRUE;
3003-
30042934
/* The following code must change when InnoDB supports
30052935
multiple datafiles per tablespace. */
30062936
ut_a(UT_LIST_GET_LEN(space->chain) == 1);
30072937
node = UT_LIST_GET_FIRST(space->chain);
30082938

3009-
if (node->n_pending > 0
3010-
|| node->n_pending_flushes > 0
3011-
|| node->being_extended) {
3012-
/* There are pending i/o's or flushes or the file is
3013-
currently being extended, sleep for a while and
3014-
retry */
3015-
3016-
mutex_exit(&fil_system->mutex);
3017-
3018-
os_thread_sleep(20000);
3019-
3020-
goto retry;
3021-
3022-
} else if (node->modification_counter > node->flush_counter) {
3023-
/* Flush the space */
3024-
3025-
mutex_exit(&fil_system->mutex);
3026-
3027-
os_thread_sleep(20000);
3028-
3029-
fil_flush(id);
3030-
3031-
goto retry;
3032-
3033-
} else if (node->open) {
3034-
/* Close the file */
3035-
3036-
fil_node_close_file(node, fil_system);
3037-
}
3038-
30392939
/* Check that the old name in the space is right */
30402940

30412941
if (old_name_in) {
@@ -3054,17 +2954,9 @@ fil_rename_tablespace(
30542954
space, node, new_name, new_path);
30552955

30562956
if (success) {
3057-
3058-
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
3059-
goto skip_second_rename; );
3060-
30612957
success = os_file_rename(
30622958
innodb_file_data_key, old_path, new_path);
30632959

3064-
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
3065-
skip_second_rename:
3066-
success = FALSE; );
3067-
30682960
if (!success) {
30692961
/* We have to revert the changes we made
30702962
to the tablespace memory cache */
@@ -3074,8 +2966,6 @@ fil_rename_tablespace(
30742966
}
30752967
}
30762968

3077-
space->stop_ios = FALSE;
3078-
30792969
mutex_exit(&fil_system->mutex);
30802970

30812971
#ifndef UNIV_HOTBACKUP

0 commit comments

Comments
 (0)