This PR attempts to close (or at least help) #26455 (and closed duplicates #26400 #26530).
Context
macOS’s fsync
only flushes writes to the drive, but doesn’t ask the drive to immediately commit the data to permanent storage (ie - physically write it) (manpage). The data will eventually be physically written, but there are no guarantees when it will happen – it could be several seconds or more. For a stronger ‘immediate-write’ guarantee, they offer an F_FULLFSYNC
option to fcntl
(manpage) to accomplish that. This fsync
-on-macOS behavior has caused historical problems in this project for macOS builds, so, since then, the F_FULLSYNC
approach has been used for writing (see #3000).
However, certain external drives or filesystems do not support fcntl
with F_FULLFSYNC
option. (And some that do supposedly support the option do not actually do it.) These drives/filesystems will typically report errno
ENOTSUP
or ENOTTY
, which is what was reported in the referenced issues. However, there is no reliable way to determine lack of support, so relying on specific error codes is insufficient.
This bug seems to only be affecting macOS 13 (Ventura) systems, but in theory, any macOS version could be affected.
What other projects have done
Other projects, including LevelDB, SQLite, and MariaDB have experienced similar issues, and have taken the strategy of falling back on the (less reliable) fsync
when F_FULLFSYNC
isn’t supported. (See helpful Twitter thread.) Some (SQLite, MariaDB, LevelDB) fall back to fsync
on any error, and others only fall back on specific errors (BerkeleyDB 4.8 falls back only on ENOTSUP
, which is why this PR may not fully fix #26455, as the wallet is getting the error ENOTTY
.)
This PR
I propose to follow that general strategy and fall back on fsync
if F_FULLFSYNC
fails for any reason, while preserving both error codes for debugging.
(I think we should also print the error strings using SysErrorString
rather than print the raw platform-dependent error codes, but I wanted to keep this PR as atomic as possible and save those changes (4 or 5 lines in addition to these) for another PR (which I’d be happy to submit – or modify this PR to include).)