From cf1cf3a0d1fe277d18dae782b164f6c99f81be83 Mon Sep 17 00:00:00 2001 From: "tsmith@siva.hindu.god" <> Date: Wed, 18 Apr 2007 19:53:28 -0600 Subject: [PATCH] Applied innodb-5.1-ss1404 snapshot Fixes: - Bug #26662: mysqld assertion when creating temporary (InnoDB) table on a tmpfs filesystem Fix by not open(2)ing with O_DIRECT but rather calling fcntl(2) to set this flag immediately after open(2)ing. This way an error caused by O_DIRECT not being supported can easily be ignored. - Bug #23313: AUTO_INCREMENT=# not reported back for InnoDB tables - Bug #21404: AUTO_INCREMENT value reset when Adding FKEY (or ALTER?) Report the current value of the AUTO_INCREMENT counter to MySQL. --- mysql-test/r/innodb.result | 25 +++ mysql-test/t/innodb.test | 20 +++ storage/innobase/handler/ha_innodb.cc | 14 ++ storage/innobase/handler/ha_innodb.h | 1 + storage/innobase/os/os0file.c | 211 ++++++++++++++------------ storage/innobase/plug.in | 2 + 6 files changed, 177 insertions(+), 96 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 4d104c64fa9..34c845b8806 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -3159,6 +3159,31 @@ t2 CREATE TABLE `t2` ( CONSTRAINT `t2_t1` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t2, t1; +CREATE TABLE t1 (id int PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB +AUTO_INCREMENT=42; +INSERT INTO t1 VALUES (0),(347),(0); +SELECT * FROM t1; +id +42 +347 +348 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1 +CREATE TABLE t2 (id int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES(42),(347),(348); +ALTER TABLE t1 ADD CONSTRAINT t1_t2 FOREIGN KEY (id) REFERENCES t2(id); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`), + CONSTRAINT `t1_t2` FOREIGN KEY (`id`) REFERENCES `t2` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1 +DROP TABLE t1,t2; CREATE TABLE t1 (a INT, INDEX(a)) ENGINE=InnoDB; CREATE TABLE t2 (a INT, INDEX(a)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 75f2796abc6..439a7adc669 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2320,6 +2320,26 @@ INSERT INTO t1 VALUES ('DDD'); SELECT * FROM t1; DROP TABLE t1; +# +# Bug #23313 (AUTO_INCREMENT=# not reported back for InnoDB tables) +# Bug #21404 (AUTO_INCREMENT value reset when Adding FKEY (or ALTER?)) +# + +CREATE TABLE t1 (id int PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB +AUTO_INCREMENT=42; + +INSERT INTO t1 VALUES (0),(347),(0); +SELECT * FROM t1; + +SHOW CREATE TABLE t1; + +CREATE TABLE t2 (id int PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t2 VALUES(42),(347),(348); +ALTER TABLE t1 ADD CONSTRAINT t1_t2 FOREIGN KEY (id) REFERENCES t2(id); +SHOW CREATE TABLE t1; + +DROP TABLE t1,t2; + ####################################################################### # # # Please, DO NOT TOUCH this file as well as the innodb.result file. # diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 1932f775a3d..18f930bf7da 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4769,6 +4769,20 @@ create_clustered_index_when_no_primary( return(error); } +/********************************************************************* +Update create_info. Used in SHOW CREATE TABLE et al. */ + +void +ha_innobase::update_create_info( +/*============================*/ + HA_CREATE_INFO* create_info) /* in/out: create info */ +{ + if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) { + ha_innobase::info(HA_STATUS_AUTO); + create_info->auto_increment_value = stats.auto_increment_value; + } +} + /********************************************************************* Creates a new table to an InnoDB database. */ diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index f5df362b490..8b6c4d5a3d8 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -150,6 +150,7 @@ class ha_innobase: public handler *max_key); ha_rows estimate_rows_upper_bound(); + void update_create_info(HA_CREATE_INFO* create_info); int create(const char *name, register TABLE *form, HA_CREATE_INFO *create_info); int delete_all_rows(); diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index 60ba941dbbf..c18ba047d4e 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -318,7 +318,7 @@ os_file_get_last_error( fflush(stderr); - if (err == ENOSPC ) { + if (err == ENOSPC) { return(OS_FILE_DISK_FULL); #ifdef POSIX_ASYNC_IO } else if (err == EAGAIN) { @@ -337,15 +337,20 @@ os_file_get_last_error( } /******************************************************************** -Does error handling when a file operation fails. */ +Does error handling when a file operation fails. +Conditionally exits (calling exit(3)) based on should_exit value and the +error type */ + static ibool -os_file_handle_error( -/*=================*/ - /* out: TRUE if we should retry the - operation */ - const char* name, /* in: name of a file or NULL */ - const char* operation)/* in: operation */ +os_file_handle_error_cond_exit( +/*===========================*/ + /* out: TRUE if we should retry the + operation */ + const char* name, /* in: name of a file or NULL */ + const char* operation, /* in: operation */ + ibool should_exit) /* in: call exit(3) if unknown error + and this parameter is TRUE */ { ulint err; @@ -376,11 +381,9 @@ os_file_handle_error( fflush(stderr); return(FALSE); - } else if (err == OS_FILE_AIO_RESOURCES_RESERVED) { return(TRUE); - } else if (err == OS_FILE_ALREADY_EXISTS || err == OS_FILE_PATH_ERROR) { @@ -392,16 +395,49 @@ os_file_handle_error( fprintf(stderr, "InnoDB: File operation call: '%s'.\n", operation); - fprintf(stderr, "InnoDB: Cannot continue operation.\n"); - fflush(stderr); + if (should_exit) { + fprintf(stderr, "InnoDB: Cannot continue operation.\n"); - exit(1); + fflush(stderr); + + exit(1); + } } return(FALSE); } +/******************************************************************** +Does error handling when a file operation fails. */ +static +ibool +os_file_handle_error( +/*=================*/ + /* out: TRUE if we should retry the + operation */ + const char* name, /* in: name of a file or NULL */ + const char* operation)/* in: operation */ +{ + /* exit in case of unknown error */ + return(os_file_handle_error_cond_exit(name, operation, TRUE)); +} + +/******************************************************************** +Does error handling when a file operation fails. */ +static +ibool +os_file_handle_error_no_exit( +/*=========================*/ + /* out: TRUE if we should retry the + operation */ + const char* name, /* in: name of a file or NULL */ + const char* operation)/* in: operation */ +{ + /* don't exit in case of unknown error */ + return(os_file_handle_error_cond_exit(name, operation, FALSE)); +} + #undef USE_FILE_LOCK #define USE_FILE_LOCK #if defined(UNIV_HOTBACKUP) || defined(__WIN__) || defined(__FreeBSD__) || defined(__NETWARE__) @@ -445,68 +481,6 @@ os_file_lock( } #endif /* USE_FILE_LOCK */ -/******************************************************************** -Does error handling when a file operation fails. */ -static -ibool -os_file_handle_error_no_exit( -/*=========================*/ - /* out: TRUE if we should retry the - operation */ - const char* name, /* in: name of a file or NULL */ - const char* operation)/* in: operation */ -{ - ulint err; - - err = os_file_get_last_error(FALSE); - - if (err == OS_FILE_DISK_FULL) { - /* We only print a warning about disk full once */ - - if (os_has_said_disk_full) { - - return(FALSE); - } - - if (name) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Encountered a problem with" - " file %s\n", name); - } - - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Disk is full. Try to clean the disk" - " to free space.\n"); - - os_has_said_disk_full = TRUE; - - fflush(stderr); - - return(FALSE); - - } else if (err == OS_FILE_AIO_RESOURCES_RESERVED) { - - return(TRUE); - - } else if (err == OS_FILE_ALREADY_EXISTS - || err == OS_FILE_PATH_ERROR) { - - return(FALSE); - } else { - if (name) { - fprintf(stderr, "InnoDB: File name %s\n", name); - } - - fprintf(stderr, "InnoDB: File operation call: '%s'.\n", - operation); - return (FALSE); - } - - return(FALSE); /* not reached */ -} - /******************************************************************** Creates the seek mutexes used in positioned reads and writes. */ @@ -1124,6 +1098,51 @@ os_file_create_simple_no_error_handling( #endif /* __WIN__ */ } +/******************************************************************** +Tries to disable OS caching on an opened file descriptor. */ + +void +os_file_set_nocache( +/*================*/ + int fd, /* in: file descriptor to alter */ + const char* file_name, /* in: used in the diagnostic message */ + const char* operation_name) /* in: used in the diagnostic message, + we call os_file_set_nocache() + immediately after opening or creating + a file, so this is either "open" or + "create" */ +{ + /* some versions of Solaris may not have DIRECTIO_ON */ +#if defined(UNIV_SOLARIS) && defined(DIRECTIO_ON) + if (directio(fd, DIRECTIO_ON) == -1) { + int errno_save; + errno_save = (int)errno; + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Failed to set DIRECTIO_ON " + "on file %s: %s: %s, continuing anyway\n", + file_name, operation_name, strerror(errno_save)); + } +#elif defined(O_DIRECT) + if (fcntl(fd, F_SETFL, O_DIRECT) == -1) { + int errno_save; + errno_save = (int)errno; + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Failed to set O_DIRECT " + "on file %s: %s: %s, continuing anyway\n", + file_name, operation_name, strerror(errno_save)); + if (errno_save == EINVAL) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: O_DIRECT is known to result in " + "'Invalid argument' on Linux on tmpfs, " + "see MySQL Bug#26662\n"); + } + } +#endif +} + /******************************************************************** Opens an existing file or creates a new. */ @@ -1306,21 +1325,8 @@ try_again: create_flag = create_flag | O_SYNC; } #endif /* O_SYNC */ -#ifdef O_DIRECT - /* We let O_DIRECT only affect data files */ - if (type != OS_LOG_FILE - && srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) { -# if 0 - fprintf(stderr, "Using O_DIRECT for file %s\n", name); -# endif - create_flag = create_flag | O_DIRECT; - } -#endif /* O_DIRECT */ - if (create_mode == OS_FILE_CREATE) { - file = open(name, create_flag, os_innodb_umask); - } else { - file = open(name, create_flag); - } + + file = open(name, create_flag, os_innodb_umask); if (file == -1) { *success = FALSE; @@ -1330,11 +1336,24 @@ try_again: "create" : "open"); if (retry) { goto try_again; + } else { + return(file /* -1 */); } + } + /* else */ + + *success = TRUE; + + /* We disable OS caching (O_DIRECT) only on data files */ + if (type != OS_LOG_FILE + && srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) { + + os_file_set_nocache(file, name, mode_str); + } + #ifdef USE_FILE_LOCK - } else if (create_mode != OS_FILE_OPEN_RAW - && os_file_lock(file, name)) { - *success = FALSE; + if (create_mode != OS_FILE_OPEN_RAW && os_file_lock(file, name)) { + if (create_mode == OS_FILE_OPEN_RETRY) { int i; ut_print_timestamp(stderr); @@ -1352,12 +1371,12 @@ try_again: fputs(" InnoDB: Unable to open the first data file\n", stderr); } + + *success = FALSE; close(file); file = -1; -#endif - } else { - *success = TRUE; } +#endif /* USE_FILE_LOCK */ return(file); #endif /* __WIN__ */ diff --git a/storage/innobase/plug.in b/storage/innobase/plug.in index 9c21a491d9f..59634523399 100644 --- a/storage/innobase/plug.in +++ b/storage/innobase/plug.in @@ -30,6 +30,8 @@ MYSQL_PLUGIN_ACTIONS(innobase, [ CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; osf*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; + *solaris*|*SunOS*) + CFLAGS="$CFLAGS -DUNIV_SOLARIS";; sysv5uw7*) # Problem when linking on SCO CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;