mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Use F_FULLFSYNC on macOS with fallback to fsync for full barrier durability
This commit is contained in:
parent
b5a8ef7c33
commit
8ed0224e41
3 changed files with 49 additions and 2 deletions
|
|
@ -893,8 +893,27 @@ int parity_sync(struct snapraid_parity_handle* handle)
|
|||
* Ensure that data changes are written to disk.
|
||||
* This is required to ensure that parity is more updated than content
|
||||
* in case of a system crash.
|
||||
*
|
||||
* On macOS, standard fsync() only pushes data from kernel buffers to the
|
||||
* drive's volatile cache without requesting a physical media flush. F_FULLFSYNC
|
||||
* forces the drive controller to commit all cached data to permanent storage.
|
||||
* Because F_FULLFSYNC is not supported on directory descriptors, the subsequent
|
||||
* directory fsync() only flushes to the drive cache and is not guaranteed to be
|
||||
* instantly persistent across power loss. However, major database engines such
|
||||
* as SQLite and PostgreSQL follow this exact same pattern on Darwin, making it
|
||||
* the standard industry practice.
|
||||
*
|
||||
* See:
|
||||
* https://github.com/sqlite/sqlite/blob/f3b9f74d81132426dee1ccc07a67fdad2ccfeaa9/src/os_unix.c#L3928-L3953
|
||||
* https://github.com/postgres/postgres/blob/74c77052bc20017076100f0649ca0f44b1b98c29/src/backend/storage/file/fd.c#L835-L852
|
||||
*/
|
||||
#if defined(__APPLE__) && defined(F_FULLFSYNC)
|
||||
ret = fcntl(split->f, F_FULLFSYNC);
|
||||
if (ret != 0 && (errno == ENOTSUP || errno == EINVAL))
|
||||
ret = fsync(split->f);
|
||||
#else
|
||||
ret = fsync(split->f);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(errno, "Error syncing parity file '%s'. %s.\n", split->path, strerror(errno));
|
||||
|
|
|
|||
|
|
@ -5108,7 +5108,8 @@ static void state_rename_content(struct snapraid_state* state)
|
|||
/*
|
||||
* This sequence relies on POSIX file-system semantics.
|
||||
*
|
||||
* The temporary content file has already been flushed and fsync'ed.
|
||||
* The temporary content file has already been flushed and fsync'ed in
|
||||
* ssync() (using F_FULLFSYNC on macOS to force a physical media flush).
|
||||
* rename()/renameat() atomically replaces the old content file, but the
|
||||
* directory entry update is not necessarily durable when the rename
|
||||
* returns.
|
||||
|
|
@ -5119,6 +5120,19 @@ static void state_rename_content(struct snapraid_state* state)
|
|||
* may start only after the pre-sync content state has been durably
|
||||
* published.
|
||||
*
|
||||
* On macOS, standard fsync() only pushes data from kernel buffers to the
|
||||
* drive's volatile cache without requesting a physical media flush. F_FULLFSYNC
|
||||
* forces the drive controller to commit all cached data to permanent storage.
|
||||
* Because F_FULLFSYNC is not supported on directory descriptors, the subsequent
|
||||
* directory fsync() only flushes to the drive cache and is not guaranteed to be
|
||||
* instantly persistent across power loss. However, major database engines such
|
||||
* as SQLite and PostgreSQL follow this exact same pattern on Darwin, making it
|
||||
* the standard industry practice.
|
||||
*
|
||||
* See:
|
||||
* https://github.com/sqlite/sqlite/blob/f3b9f74d81132426dee1ccc07a67fdad2ccfeaa9/src/os_unix.c#L3928-L3953
|
||||
* https://github.com/postgres/postgres/blob/74c77052bc20017076100f0649ca0f44b1b98c29/src/backend/storage/file/fd.c#L835-L852
|
||||
*
|
||||
* When renameat() is available, perform the rename relative to the same
|
||||
* directory descriptor that is subsequently fsync'ed. Use O_DIRECTORY
|
||||
* when available, while retaining compatibility with POSIX systems where
|
||||
|
|
|
|||
|
|
@ -835,7 +835,21 @@ int ssync(STREAM* s)
|
|||
unsigned i;
|
||||
|
||||
for (i = 0; i < s->handle_size; ++i) {
|
||||
if (fsync(s->handle[i].f) != 0) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* On macOS, standard fsync() only pushes data from kernel buffers to the
|
||||
* drive's volatile cache without requesting a physical media flush. F_FULLFSYNC
|
||||
* forces the drive controller to commit all cached data to permanent storage.
|
||||
*/
|
||||
#if defined(__APPLE__) && defined(F_FULLFSYNC)
|
||||
ret = fcntl(s->handle[i].f, F_FULLFSYNC);
|
||||
if (ret != 0 && (errno == ENOTSUP || errno == EINVAL))
|
||||
ret = fsync(s->handle[i].f);
|
||||
#else
|
||||
ret = fsync(s->handle[i].f);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
s->state = STREAM_STATE_ERROR;
|
||||
s->state_index = i;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue