--- storage/innobase/os/os0file.c 2008-01-29 16:40:38.000000000 -0500 +++ storage/innobase/os/os0file.c 2008-02-25 11:46:45.855160084 -0500 @@ -1851,65 +1851,100 @@ return(FALSE); #else - int ret; + bool retry_loop = FALSE; + int retry_count = 0; + while (TRUE) + { + int ret; #if defined(HAVE_DARWIN_THREADS) # ifndef F_FULLFSYNC - /* The following definition is from the Mac OS X 10.3 */ + /* The following definition is from the Mac OS X 10.3 */ # define F_FULLFSYNC 51 /* fsync + ask the drive to flush to the media */ # elif F_FULLFSYNC != 51 # error "F_FULLFSYNC != 51: ABI incompatibility with Mac OS X 10.3" # endif - /* Apple has disabled fsync() for internal disk drives in OS X. That - caused corruption for a user when he tested a power outage. Let us in - OS X use a nonstandard flush method recommended by an Apple - engineer. */ - - if (!srv_have_fullfsync) { - /* If we are not on an operating system that supports this, - then fall back to a plain fsync. */ - - ret = fsync(file); - } else { - ret = fcntl(file, F_FULLFSYNC, NULL); - - if (ret) { - /* If we are not on a file system that supports this, + /* Apple has disabled fsync() for internal disk drives in OS X. That + caused corruption for a user when he tested a power outage. Let us in + OS X use a nonstandard flush method recommended by an Apple + engineer. */ + + if (!srv_have_fullfsync) { + /* If we are not on an operating system that supports this, then fall back to a plain fsync. */ + ret = fsync(file); + } else { + ret = fcntl(file, F_FULLFSYNC, NULL); + + if (ret) { + /* If we are not on a file system that supports this, + then fall back to a plain fsync. */ + ret = fsync(file); + } } - } #elif HAVE_FDATASYNC - ret = fdatasync(file); + ret = fdatasync(file); #else - /* fprintf(stderr, "Flushing to file %p\n", file); */ - ret = fsync(file); + /* fprintf(stderr, "Flushing to file %p\n", file); */ + ret = fsync(file); #endif - os_n_fsyncs++; + os_n_fsyncs++; - if (ret == 0) { - return(TRUE); - } - - /* Since Linux returns EINVAL if the 'file' is actually a raw device, - we choose to ignore that error if we are using raw disks */ - - if (srv_start_raw_disk_in_use && errno == EINVAL) { + if (ret == 0) { + if (retry_loop) + { + fprintf(stderr, + " InnoDB: File flush succeeded on retry #%d\n", retry_count); + } + return(TRUE); + } + + /* + * FreeBSD sometimes returns ENOLCK. The sages of the internet have said that code should just retry + * if this is the case. Thus, we lock ourselves in an infinite retry loop until it works. + * This is not a bug fix. Rather, it is a hack to avoid MySQL randomly shutting down from ENOLCK errors + * every couple days. + */ + if (errno == ENOLCK) + { + if (!retry_loop) + { + fprintf(stderr, + " InnoDB: Error: the OS said file flush did not succeed (ENOLCK), retrying...\n"); + retry_loop = TRUE; + } + if (retry_count % 100 == 0) + { + fprintf(stderr, + " InnoDB: File flush retry #%d and still nothing...\n", retry_count); + } + retry_count++; + errno = 0; + os_n_fsyncs--; + continue; + } + + /* Since Linux returns EINVAL if the 'file' is actually a raw device, + we choose to ignore that error if we are using raw disks */ - return(TRUE); + if (srv_start_raw_disk_in_use && errno == EINVAL) { + + return(TRUE); + } + + ut_print_timestamp(stderr); + + fprintf(stderr, + " InnoDB: Error: the OS said file flush did not succeed\n"); + + os_file_handle_error(NULL, "flush"); + + /* It is a fatal error if a file flush does not succeed, because then + the database can get corrupt on disk */ + ut_error; + return (FALSE); } - - ut_print_timestamp(stderr); - - fprintf(stderr, - " InnoDB: Error: the OS said file flush did not succeed\n"); - - os_file_handle_error(NULL, "flush"); - - /* It is a fatal error if a file flush does not succeed, because then - the database can get corrupt on disk */ - ut_error; - return(FALSE); #endif }