|
35 | 35 | #include "util/posix_logger.h"
|
36 | 36 | #include "util/env_posix_test_helper.h"
|
37 | 37 |
|
38 |
| -// HAVE_FDATASYNC is defined in the auto-generated port_config.h, which is |
39 |
| -// included by port_stdcxx.h. |
40 |
| -#if !HAVE_FDATASYNC |
41 |
| -#define fdatasync fsync |
42 |
| -#endif // !HAVE_FDATASYNC |
43 |
| - |
44 | 38 | namespace leveldb {
|
45 | 39 |
|
46 | 40 | namespace {
|
@@ -314,10 +308,11 @@ class PosixWritableFile final : public WritableFile {
|
314 | 308 | }
|
315 | 309 |
|
316 | 310 | status = FlushBuffer();
|
317 |
| - if (status.ok() && ::fdatasync(fd_) != 0) { |
318 |
| - status = PosixError(filename_, errno); |
| 311 | + if (!status.ok()) { |
| 312 | + return status; |
319 | 313 | }
|
320 |
| - return status; |
| 314 | + |
| 315 | + return SyncFd(fd_, filename_); |
321 | 316 | }
|
322 | 317 |
|
323 | 318 | private:
|
@@ -352,14 +347,41 @@ class PosixWritableFile final : public WritableFile {
|
352 | 347 | if (fd < 0) {
|
353 | 348 | status = PosixError(dirname_, errno);
|
354 | 349 | } else {
|
355 |
| - if (::fsync(fd) < 0) { |
356 |
| - status = PosixError(dirname_, errno); |
357 |
| - } |
| 350 | + status = SyncFd(fd, dirname_); |
358 | 351 | ::close(fd);
|
359 | 352 | }
|
360 | 353 | return status;
|
361 | 354 | }
|
362 | 355 |
|
| 356 | + // Ensures that all the caches associated with the given file descriptor's |
| 357 | + // data are flushed all the way to durable media, and can withstand power |
| 358 | + // failures. |
| 359 | + // |
| 360 | + // The path argument is only used to populate the description string in the |
| 361 | + // returned Status if an error occurs. |
| 362 | + static Status SyncFd(int fd, const std::string& fd_path) { |
| 363 | +#if HAVE_FULLFSYNC |
| 364 | + // On macOS and iOS, fsync() doesn't guarantee durability past power |
| 365 | + // failures. fcntl(F_FULLFSYNC) is required for that purpose. Some |
| 366 | + // filesystems don't support fcntl(F_FULLFSYNC), and require a fallback to |
| 367 | + // fsync(). |
| 368 | + if (::fcntl(fd, F_FULLFSYNC) == 0) { |
| 369 | + return Status::OK(); |
| 370 | + } |
| 371 | +#endif // HAVE_FULLFSYNC |
| 372 | + |
| 373 | +#if HAVE_FDATASYNC |
| 374 | + bool sync_success = ::fdatasync(fd) == 0; |
| 375 | +#else |
| 376 | + bool sync_success = ::fsync(fd) == 0; |
| 377 | +#endif // HAVE_FDATASYNC |
| 378 | + |
| 379 | + if (sync_success) { |
| 380 | + return Status::OK(); |
| 381 | + } |
| 382 | + return PosixError(fd_path, errno); |
| 383 | + } |
| 384 | + |
363 | 385 | // Returns the directory name in a path pointing to a file.
|
364 | 386 | //
|
365 | 387 | // Returns "." if the path does not contain any directory separator.
|
|
0 commit comments