Commit 2f46e5b9 authored by Jan Lindström's avatar Jan Lindström

MDEV-6070: FusionIO: Failure to create a table with ATOMIC_WRITES

option leaves the database in inconsistent state,

Analysis: Problem was that atomic writes variable had incorrect
type on same places leading to fact that e.g. OFF option was
not regognized. Furthermore, some error check code was missing
from both InnoDB and XtraDB engines. Finally, when table is
created we have already created the .ibd file and if we can't
set atomic writes it stays there.

Fix: Fix atomic writes variable type to ulint as it should be.
Fix: Add proper error code checking on os errors on both InnoDB
and XtraDB
Fix: Remove the .idb file when atomic writes can't be enabled
to a new table.
parent 13c73c31
...@@ -745,7 +745,7 @@ fil_node_open_file( ...@@ -745,7 +745,7 @@ fil_node_open_file(
ulint space_id; ulint space_id;
ulint flags=0; ulint flags=0;
ulint page_size; ulint page_size;
ibool atomic_writes=FALSE; ulint atomic_writes=0;
ut_ad(mutex_own(&(system->mutex))); ut_ad(mutex_own(&(system->mutex)));
ut_a(node->n_pending == 0); ut_a(node->n_pending == 0);
...@@ -3425,7 +3425,7 @@ fil_create_new_single_table_tablespace( ...@@ -3425,7 +3425,7 @@ fil_create_new_single_table_tablespace(
/* TRUE if a table is created with CREATE TEMPORARY TABLE */ /* TRUE if a table is created with CREATE TEMPORARY TABLE */
bool is_temp = !!(flags2 & DICT_TF2_TEMPORARY); bool is_temp = !!(flags2 & DICT_TF2_TEMPORARY);
bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags); bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags);
bool atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags); ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
ut_a(space_id > 0); ut_a(space_id > 0);
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
...@@ -3720,7 +3720,7 @@ fil_open_single_table_tablespace( ...@@ -3720,7 +3720,7 @@ fil_open_single_table_tablespace(
fsp_open_info remote; fsp_open_info remote;
ulint tablespaces_found = 0; ulint tablespaces_found = 0;
ulint valid_tablespaces_found = 0; ulint valid_tablespaces_found = 0;
ibool atomic_writes = FALSE; ulint atomic_writes = 0;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_ad(!fix_dict || rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); ut_ad(!fix_dict || rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
......
...@@ -399,9 +399,8 @@ os_file_set_atomic_writes( ...@@ -399,9 +399,8 @@ os_file_set_atomic_writes(
if (ioctl(file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic_option)) { if (ioctl(file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic_option)) {
fprintf(stderr, "InnoDB: Error: trying to enable atomic writes on " fprintf(stderr, "InnoDB: Warning:Trying to enable atomic writes on "
"file %s on non-supported platform! Please restart with " "file %s on non-supported platform!\n", name);
"innodb_use_atomic_writes disabled.\n", name);
os_file_handle_error_no_exit(name, "ioctl", FALSE, __FILE__, __LINE__); os_file_handle_error_no_exit(name, "ioctl", FALSE, __FILE__, __LINE__);
return(FALSE); return(FALSE);
} }
...@@ -409,8 +408,7 @@ os_file_set_atomic_writes( ...@@ -409,8 +408,7 @@ os_file_set_atomic_writes(
return(TRUE); return(TRUE);
#else #else
fprintf(stderr, "InnoDB: Error: trying to enable atomic writes on " fprintf(stderr, "InnoDB: Error: trying to enable atomic writes on "
"non-supported platform! Please restart with " "file %s on non-supported platform!\n", name);
"innodb_use_atomic_writes disabled.\n");
return(FALSE); return(FALSE);
#endif #endif
} }
...@@ -561,6 +559,19 @@ os_file_get_last_error_low( ...@@ -561,6 +559,19 @@ os_file_get_last_error_low(
"InnoDB: because of either a thread exit" "InnoDB: because of either a thread exit"
" or an application request.\n" " or an application request.\n"
"InnoDB: Retry attempt is made.\n"); "InnoDB: Retry attempt is made.\n");
} else if (err == ECANCELED || err == ENOTTY) {
if (strerror(err) != NULL) {
fprintf(stderr,
"InnoDB: Error number %d"
" means '%s'.\n",
err, strerror(err));
}
if(srv_use_atomic_writes) {
fprintf(stderr,
"InnoDB: Error trying to enable atomic writes on "
"non-supported destination!\n");
}
} else { } else {
fprintf(stderr, fprintf(stderr,
"InnoDB: Some operating system error numbers" "InnoDB: Some operating system error numbers"
...@@ -620,11 +631,14 @@ os_file_get_last_error_low( ...@@ -620,11 +631,14 @@ os_file_get_last_error_low(
fprintf(stderr, fprintf(stderr,
"InnoDB: The error means mysqld does not have" "InnoDB: The error means mysqld does not have"
" the access rights to\n" " the access rights to\n"
"InnoDECANCELEDB: the directory.\n"); "InnoDB: the directory.\n");
} else if (err == ECANCELED) { } else if (err == ECANCELED || err == ENOTTY) {
fprintf(stderr, if (strerror(err) != NULL) {
"InnoDB: Operation canceled (%d):%s\n", fprintf(stderr,
err, strerror(err)); "InnoDB: Error number %d"
" means '%s'.\n",
err, strerror(err));
}
if(srv_use_atomic_writes) { if(srv_use_atomic_writes) {
fprintf(stderr, fprintf(stderr,
...@@ -663,6 +677,7 @@ os_file_get_last_error_low( ...@@ -663,6 +677,7 @@ os_file_get_last_error_low(
case EISDIR: case EISDIR:
return(OS_FILE_PATH_ERROR); return(OS_FILE_PATH_ERROR);
case ECANCELED: case ECANCELED:
case ENOTTY:
return(OS_FILE_OPERATION_NOT_SUPPORTED); return(OS_FILE_OPERATION_NOT_SUPPORTED);
case EAGAIN: case EAGAIN:
if (srv_use_native_aio) { if (srv_use_native_aio) {
...@@ -1521,13 +1536,21 @@ os_file_create_simple_no_error_handling_func( ...@@ -1521,13 +1536,21 @@ os_file_create_simple_no_error_handling_func(
attributes, attributes,
NULL); // No template file NULL); // No template file
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != INVALID_HANDLE_VALUE if (file != INVALID_HANDLE_VALUE
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
CloseHandle(file); if (create_mode == OS_FILE_CREATE) {
fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
CloseHandle(file);
os_file_delete_if_exists_func(name);
*success = FALSE; *success = FALSE;
file = INVALID_HANDLE_VALUE; file = INVALID_HANDLE_VALUE;
}
} }
*success = (file != INVALID_HANDLE_VALUE); *success = (file != INVALID_HANDLE_VALUE);
...@@ -1590,13 +1613,21 @@ os_file_create_simple_no_error_handling_func( ...@@ -1590,13 +1613,21 @@ os_file_create_simple_no_error_handling_func(
} }
#endif /* USE_FILE_LOCK */ #endif /* USE_FILE_LOCK */
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != -1 if (file != -1
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
*success = FALSE; if (create_mode == OS_FILE_CREATE) {
close(file); fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
file = -1; close(file);
os_file_delete_if_exists_func(name);
*success = FALSE;
file = -1;
}
} }
...@@ -1836,13 +1867,21 @@ os_file_create_func( ...@@ -1836,13 +1867,21 @@ os_file_create_func(
} while (retry); } while (retry);
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != INVALID_HANDLE_VALUE if (file != INVALID_HANDLE_VALUE
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
CloseHandle(file); if (create_mode == OS_FILE_CREATE) {
fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
CloseHandle(file);
os_file_delete_if_exists_func(name);
*success = FALSE; *success = FALSE;
file = INVALID_HANDLE_VALUE; file = INVALID_HANDLE_VALUE;
}
} }
#else /* __WIN__ */ #else /* __WIN__ */
int create_flag; int create_flag;
...@@ -1972,13 +2011,21 @@ os_file_create_func( ...@@ -1972,13 +2011,21 @@ os_file_create_func(
} }
#endif /* USE_FILE_LOCK */ #endif /* USE_FILE_LOCK */
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != -1 if (file != -1
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
*success = FALSE; if (create_mode == OS_FILE_CREATE) {
close(file); fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
file = -1; close(file);
os_file_delete_if_exists_func(name);
*success = FALSE;
file = -1;
}
} }
#endif /* __WIN__ */ #endif /* __WIN__ */
......
...@@ -746,7 +746,7 @@ fil_node_open_file( ...@@ -746,7 +746,7 @@ fil_node_open_file(
ulint space_id; ulint space_id;
ulint flags=0; ulint flags=0;
ulint page_size; ulint page_size;
ibool atomic_writes=FALSE; ulint atomic_writes=0;
ut_ad(mutex_own(&(system->mutex))); ut_ad(mutex_own(&(system->mutex)));
ut_a(node->n_pending == 0); ut_a(node->n_pending == 0);
...@@ -3288,6 +3288,8 @@ fil_create_link_file( ...@@ -3288,6 +3288,8 @@ fil_create_link_file(
} else if (error == OS_FILE_DISK_FULL) { } else if (error == OS_FILE_DISK_FULL) {
err = DB_OUT_OF_FILE_SPACE; err = DB_OUT_OF_FILE_SPACE;
} else if (error == OS_FILE_OPERATION_NOT_SUPPORTED) {
err = DB_UNSUPPORTED;
} else { } else {
err = DB_ERROR; err = DB_ERROR;
} }
...@@ -3448,7 +3450,7 @@ fil_create_new_single_table_tablespace( ...@@ -3448,7 +3450,7 @@ fil_create_new_single_table_tablespace(
/* TRUE if a table is created with CREATE TEMPORARY TABLE */ /* TRUE if a table is created with CREATE TEMPORARY TABLE */
bool is_temp = !!(flags2 & DICT_TF2_TEMPORARY); bool is_temp = !!(flags2 & DICT_TF2_TEMPORARY);
bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags); bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags);
bool atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags); ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
ut_a(space_id > 0); ut_a(space_id > 0);
ut_ad(!srv_read_only_mode); ut_ad(!srv_read_only_mode);
...@@ -3509,6 +3511,11 @@ fil_create_new_single_table_tablespace( ...@@ -3509,6 +3511,11 @@ fil_create_new_single_table_tablespace(
goto error_exit_3; goto error_exit_3;
} }
if (error == OS_FILE_OPERATION_NOT_SUPPORTED) {
err = DB_UNSUPPORTED;
goto error_exit_3;
}
if (error == OS_FILE_DISK_FULL) { if (error == OS_FILE_DISK_FULL) {
err = DB_OUT_OF_FILE_SPACE; err = DB_OUT_OF_FILE_SPACE;
goto error_exit_3; goto error_exit_3;
...@@ -3735,7 +3742,7 @@ fil_open_single_table_tablespace( ...@@ -3735,7 +3742,7 @@ fil_open_single_table_tablespace(
fsp_open_info remote; fsp_open_info remote;
ulint tablespaces_found = 0; ulint tablespaces_found = 0;
ulint valid_tablespaces_found = 0; ulint valid_tablespaces_found = 0;
ibool atomic_writes = FALSE; ulint atomic_writes = 0;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_ad(!fix_dict || rw_lock_own(&dict_operation_lock, RW_LOCK_EX)); ut_ad(!fix_dict || rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
...@@ -3746,6 +3753,8 @@ fil_open_single_table_tablespace( ...@@ -3746,6 +3753,8 @@ fil_open_single_table_tablespace(
return(DB_CORRUPTION); return(DB_CORRUPTION);
} }
atomic_writes = fsp_flags_get_atomic_writes(flags);
/* If the tablespace was relocated, we do not /* If the tablespace was relocated, we do not
compare the DATA_DIR flag */ compare the DATA_DIR flag */
ulint mod_flags = flags & ~FSP_FLAGS_MASK_DATA_DIR; ulint mod_flags = flags & ~FSP_FLAGS_MASK_DATA_DIR;
......
...@@ -628,10 +628,13 @@ os_file_get_last_error_low( ...@@ -628,10 +628,13 @@ os_file_get_last_error_low(
"InnoDB: because of either a thread exit" "InnoDB: because of either a thread exit"
" or an application request.\n" " or an application request.\n"
"InnoDB: Retry attempt is made.\n"); "InnoDB: Retry attempt is made.\n");
} else if (err == ECANCELED) { } else if (err == ECANCELED || err == ENOTTY) {
fprintf(stderr, if (strerror(err) != NULL) {
"InnoDB: Operation canceled (%d):%s\n", fprintf(stderr,
err, strerror(err)); "InnoDB: Error number %d"
" means '%s'.\n",
err, strerror(err));
}
if(srv_use_atomic_writes) { if(srv_use_atomic_writes) {
fprintf(stderr, fprintf(stderr,
...@@ -698,6 +701,20 @@ os_file_get_last_error_low( ...@@ -698,6 +701,20 @@ os_file_get_last_error_low(
"InnoDB: The error means mysqld does not have" "InnoDB: The error means mysqld does not have"
" the access rights to\n" " the access rights to\n"
"InnoDB: the directory.\n"); "InnoDB: the directory.\n");
} else if (err == ECANCELED || err == ENOTTY) {
if (strerror(err) != NULL) {
fprintf(stderr,
"InnoDB: Error number %d"
" means '%s'.\n",
err, strerror(err));
}
if(srv_use_atomic_writes) {
fprintf(stderr,
"InnoDB: Error trying to enable atomic writes on "
"non-supported destination!\n");
}
} else { } else {
if (strerror(err) != NULL) { if (strerror(err) != NULL) {
fprintf(stderr, fprintf(stderr,
...@@ -735,6 +752,7 @@ os_file_get_last_error_low( ...@@ -735,6 +752,7 @@ os_file_get_last_error_low(
} }
break; break;
case ECANCELED: case ECANCELED:
case ENOTTY:
return(OS_FILE_OPERATION_NOT_SUPPORTED); return(OS_FILE_OPERATION_NOT_SUPPORTED);
case EINTR: case EINTR:
if (srv_use_native_aio) { if (srv_use_native_aio) {
...@@ -1591,13 +1609,21 @@ os_file_create_simple_no_error_handling_func( ...@@ -1591,13 +1609,21 @@ os_file_create_simple_no_error_handling_func(
attributes, attributes,
NULL); // No template file NULL); // No template file
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != INVALID_HANDLE_VALUE if (file != INVALID_HANDLE_VALUE
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
CloseHandle(file); if (create_mode == OS_FILE_CREATE) {
fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
CloseHandle(file);
os_file_delete_if_exists_func(name);
*success = FALSE; *success = FALSE;
file = INVALID_HANDLE_VALUE; file = INVALID_HANDLE_VALUE;
}
} }
*success = (file != INVALID_HANDLE_VALUE); *success = (file != INVALID_HANDLE_VALUE);
...@@ -1660,13 +1686,21 @@ os_file_create_simple_no_error_handling_func( ...@@ -1660,13 +1686,21 @@ os_file_create_simple_no_error_handling_func(
} }
#endif /* USE_FILE_LOCK */ #endif /* USE_FILE_LOCK */
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != -1 if (file != -1
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
*success = FALSE; if (create_mode == OS_FILE_CREATE) {
close(file); fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
file = -1; close(file);
os_file_delete_if_exists_func(name);
*success = FALSE;
file = -1;
}
} }
#endif /* __WIN__ */ #endif /* __WIN__ */
...@@ -1752,15 +1786,16 @@ os_file_set_atomic_writes( ...@@ -1752,15 +1786,16 @@ os_file_set_atomic_writes(
if (ioctl(file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic_option)) { if (ioctl(file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic_option)) {
fprintf(stderr, "InnoDB: Warning:Trying to enable atomic writes on "
"file %s on non-supported platform!\n", name);
os_file_handle_error_no_exit(name, "ioctl(DFS_IOCTL_ATOMIC_WRITE_SET)", FALSE, __FILE__, __LINE__); os_file_handle_error_no_exit(name, "ioctl(DFS_IOCTL_ATOMIC_WRITE_SET)", FALSE, __FILE__, __LINE__);
return(FALSE); return(FALSE);
} }
return(TRUE); return(TRUE);
#else #else
ib_logf(IB_LOG_LEVEL_ERROR, fprintf(stderr, "InnoDB: Error: trying to enable atomic writes on "
"trying to enable atomic writes on non-supported platform! " "file %s on non-supported platform!\n", name);
"Please restart with innodb_use_atomic_writes disabled.\n");
return(FALSE); return(FALSE);
#endif #endif
} }
...@@ -1951,13 +1986,21 @@ os_file_create_func( ...@@ -1951,13 +1986,21 @@ os_file_create_func(
} while (retry); } while (retry);
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != INVALID_HANDLE_VALUE if (file != INVALID_HANDLE_VALUE
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
CloseHandle(file); if (create_mode == OS_FILE_CREATE) {
fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
CloseHandle(file);
os_file_delete_if_exists_func(name);
*success = FALSE; *success = FALSE;
file = INVALID_HANDLE_VALUE; file = INVALID_HANDLE_VALUE;
}
} }
#else /* __WIN__ */ #else /* __WIN__ */
...@@ -2090,13 +2133,21 @@ os_file_create_func( ...@@ -2090,13 +2133,21 @@ os_file_create_func(
} }
#endif /* USE_FILE_LOCK */ #endif /* USE_FILE_LOCK */
/* If we have proper file handle and atomic writes should be used,
try to set atomic writes and if that fails when creating a new
table, produce a error. If atomic writes are used on existing
file, ignore error and use traditional writes for that file */
if (file != -1 if (file != -1
&& (awrites == ATOMIC_WRITES_ON || && (awrites == ATOMIC_WRITES_ON ||
(srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT)) (srv_use_atomic_writes && awrites == ATOMIC_WRITES_DEFAULT))
&& !os_file_set_atomic_writes(name, file)) { && !os_file_set_atomic_writes(name, file)) {
*success = FALSE; if (create_mode == OS_FILE_CREATE) {
close(file); fprintf(stderr, "InnoDB: Error: Can't create file using atomic writes\n");
file = -1; close(file);
os_file_delete_if_exists_func(name);
*success = FALSE;
file = -1;
}
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment