Skip to content

Commit 5534d81

Browse files
author
Jan Lindström
committed
Merged following change from MySQL 5.6 to MariaDB 10.1 XtraDB
including the test case: mysql/mysql-server@520aedfe INNODB: "DATA DIRECTORY" OPTION OF CREATE TABLE FAILS WITH PWRITE() OS ERROR 22 Fix for version mysql-5.6 PROBLEM ======== For version mysql-5.6.27 onwards InnoDB fails to create a table with explicit 'data directory' option when Innodb_flush_method is set to O_DIRECT.While creating link file we get a a pwrite error 22 due to the alignment restrictions imposed by O_DIRECT flag which is being set for the link file created. FIX === Fixed the above issue by making use of file IO functions while creating the link file that wouldn't let the O_DIRECT flag restrictions arise. Reviewed-by: Kevin Lewis <kevin.lewis@oracle.com> Reviewed-by: Shaohua Wang <shaohua.wang@oracle.com> RB: 11387
1 parent 1512078 commit 5534d81

File tree

4 files changed

+63
-16
lines changed

4 files changed

+63
-16
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
SHOW VARIABLES LIKE 'innodb_flush_method';
2+
Variable_name Value
3+
innodb_flush_method O_DIRECT
4+
CREATE TABLE t1 (x INT) ENGINE=INNODB, DATA DIRECTORY='MYSQL_TMP_DIR';
5+
# Contents of tmp/test directory containing .ibd file
6+
t1.ibd
7+
# Contents of the 'test' database directory containing .isl and .frm files
8+
t1.frm
9+
t1.isl
10+
DROP TABLE t1;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--innodb_flush_method=O_DIRECT
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--source include/not_embedded.inc
2+
--source include/have_innodb.inc
3+
--source include/not_windows.inc
4+
5+
--disable_query_log
6+
CALL mtr.add_suppression("\\[Warning\\] InnoDB: Failed to set O_DIRECT on file ./ibdata1: OPEN: Invalid argument, continuing anyway. O_DIRECT is known to result in 'Invalid argument' on Linux on tmpfs, see MySQL Bug#26662.");
7+
8+
# The below mtr suppression to avoid failure in solaris platform.
9+
CALL mtr.add_suppression("\\[ERROR\\] InnoDB: Failed to set DIRECTIO_ON on file.*");
10+
--enable_query_log
11+
12+
SHOW VARIABLES LIKE 'innodb_flush_method';
13+
14+
let MYSQLD_DATADIR=`SELECT @@datadir`;
15+
16+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
17+
18+
# Create a table with explicit data directory option.
19+
EVAL CREATE TABLE t1 (x INT) ENGINE=INNODB, DATA DIRECTORY='$MYSQL_TMP_DIR';
20+
21+
--echo # Contents of tmp/test directory containing .ibd file
22+
--list_files $MYSQL_TMP_DIR/test
23+
24+
--echo # Contents of the 'test' database directory containing .isl and .frm files
25+
--list_files $MYSQLD_DATADIR/test
26+
27+
DROP TABLE t1;
28+

storage/xtradb/fil/fil0fil.cc

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3225,8 +3225,6 @@ fil_create_link_file(
32253225
const char* tablename, /*!< in: tablename */
32263226
const char* filepath) /*!< in: pathname of tablespace */
32273227
{
3228-
os_file_t file;
3229-
ibool success;
32303228
dberr_t err = DB_SUCCESS;
32313229
char* link_filepath;
32323230
char* prev_filepath = fil_read_link_file(tablename);
@@ -3245,16 +3243,24 @@ fil_create_link_file(
32453243

32463244
link_filepath = fil_make_isl_name(tablename);
32473245

3248-
/* Note that OS_FILE_READ_WRITE_CACHED used here to avoid
3249-
unnecessary errors on O_DIRECT, link files are not really
3250-
a data files. */
3251-
file = os_file_create_simple_no_error_handling(
3252-
innodb_file_data_key, link_filepath,
3253-
OS_FILE_CREATE, OS_FILE_READ_WRITE_CACHED, &success, 0);
3246+
/** Check if the file already exists. */
3247+
FILE* file = NULL;
3248+
ibool exists;
3249+
os_file_type_t ftype;
32543250

3255-
if (!success) {
3256-
/* The following call will print an error message */
3257-
ulint error = os_file_get_last_error(true);
3251+
bool success = os_file_status(link_filepath, &exists, &ftype);
3252+
3253+
ulint error = 0;
3254+
if (success && !exists) {
3255+
file = fopen(link_filepath, "w");
3256+
if (file == NULL) {
3257+
/* This call will print its own error message */
3258+
error = os_file_get_last_error(true);
3259+
}
3260+
} else {
3261+
error = OS_FILE_ALREADY_EXISTS;
3262+
}
3263+
if (error != 0) {
32583264

32593265
ut_print_timestamp(stderr);
32603266
fputs(" InnoDB: Cannot create file ", stderr);
@@ -3266,10 +3272,8 @@ fil_create_link_file(
32663272
ut_print_filename(stderr, filepath);
32673273
fputs(" already exists.\n", stderr);
32683274
err = DB_TABLESPACE_EXISTS;
3269-
32703275
} else if (error == OS_FILE_DISK_FULL) {
32713276
err = DB_OUT_OF_FILE_SPACE;
3272-
32733277
} else if (error == OS_FILE_OPERATION_NOT_SUPPORTED) {
32743278
err = DB_UNSUPPORTED;
32753279
} else {
@@ -3281,13 +3285,17 @@ fil_create_link_file(
32813285
return(err);
32823286
}
32833287

3284-
if (!os_file_write(link_filepath, file, filepath, 0,
3285-
strlen(filepath))) {
3288+
ulint rbytes = fwrite(filepath, 1, strlen(filepath), file);
3289+
if (rbytes != strlen(filepath)) {
3290+
os_file_get_last_error(true);
3291+
ib_logf(IB_LOG_LEVEL_ERROR,
3292+
"cannot write link file "
3293+
"%s",filepath);
32863294
err = DB_ERROR;
32873295
}
32883296

32893297
/* Close the file, we only need it at startup */
3290-
os_file_close(file);
3298+
fclose(file);
32913299

32923300
mem_free(link_filepath);
32933301

0 commit comments

Comments
 (0)