summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--port/port_config.h.in5
-rw-r--r--util/env_posix.cc46
3 files changed, 40 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 57a0c74..f6a7c0a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,6 +37,7 @@ include(CheckCXXSymbolExists)
# versions of do not expose fdatasync() in <unistd.h> in standard C mode
# (-std=c11), but do expose the function in standard C++ mode (-std=c++11).
check_cxx_symbol_exists(fdatasync "unistd.h" HAVE_FDATASYNC)
+check_cxx_symbol_exists(F_FULLFSYNC "fcntl.h" HAVE_FULLFSYNC)
include(CheckCXXSourceCompiles)
diff --git a/port/port_config.h.in b/port/port_config.h.in
index 645c78c..d6a6d01 100644
--- a/port/port_config.h.in
+++ b/port/port_config.h.in
@@ -10,6 +10,11 @@
#cmakedefine01 HAVE_FDATASYNC
#endif // !defined(HAVE_FDATASYNC)
+// Define to 1 if you have a definition for F_FULLFSYNC in <fcntl.h>.
+#if !defined(HAVE_FULLFSYNC)
+#cmakedefine01 HAVE_FULLFSYNC
+#endif // !defined(HAVE_FULLFSYNC)
+
// Define to 1 if you have Google CRC32C.
#if !defined(HAVE_CRC32C)
#cmakedefine01 HAVE_CRC32C
diff --git a/util/env_posix.cc b/util/env_posix.cc
index 76bb648..362adb3 100644
--- a/util/env_posix.cc
+++ b/util/env_posix.cc
@@ -35,12 +35,6 @@
#include "util/posix_logger.h"
#include "util/env_posix_test_helper.h"
-// HAVE_FDATASYNC is defined in the auto-generated port_config.h, which is
-// included by port_stdcxx.h.
-#if !HAVE_FDATASYNC
-#define fdatasync fsync
-#endif // !HAVE_FDATASYNC
-
namespace leveldb {
namespace {
@@ -314,10 +308,11 @@ class PosixWritableFile final : public WritableFile {
}
status = FlushBuffer();
- if (status.ok() && ::fdatasync(fd_) != 0) {
- status = PosixError(filename_, errno);
+ if (!status.ok()) {
+ return status;
}
- return status;
+
+ return SyncFd(fd_, filename_);
}
private:
@@ -352,14 +347,41 @@ class PosixWritableFile final : public WritableFile {
if (fd < 0) {
status = PosixError(dirname_, errno);
} else {
- if (::fsync(fd) < 0) {
- status = PosixError(dirname_, errno);
- }
+ status = SyncFd(fd, dirname_);
::close(fd);
}
return status;
}
+ // Ensures that all the caches associated with the given file descriptor's
+ // data are flushed all the way to durable media, and can withstand power
+ // failures.
+ //
+ // The path argument is only used to populate the description string in the
+ // returned Status if an error occurs.
+ static Status SyncFd(int fd, const std::string& fd_path) {
+#if HAVE_FULLFSYNC
+ // On macOS and iOS, fsync() doesn't guarantee durability past power
+ // failures. fcntl(F_FULLFSYNC) is required for that purpose. Some
+ // filesystems don't support fcntl(F_FULLFSYNC), and require a fallback to
+ // fsync().
+ if (::fcntl(fd, F_FULLFSYNC) == 0) {
+ return Status::OK();
+ }
+#endif // HAVE_FULLFSYNC
+
+#if HAVE_FDATASYNC
+ bool sync_success = ::fdatasync(fd) == 0;
+#else
+ bool sync_success = ::fsync(fd) == 0;
+#endif // HAVE_FDATASYNC
+
+ if (sync_success) {
+ return Status::OK();
+ }
+ return PosixError(fd_path, errno);
+ }
+
// Returns the directory name in a path pointing to a file.
//
// Returns "." if the path does not contain any directory separator.