With the default :sync-blob? true, successful write completion requires both
file and directory sync. Directory-open and directory-flush failures propagate
on every OS, including Windows. Windows now uses the system DLL through the
JDK 22+ FFM binding (GENERIC_WRITE + BACKUP_SEMANTICS, FlushFileBuffers, CloseHandle),
not a Java FileChannel directory open. Async API calls report the failure on their
result channel; blocking calls throw.
The default non-in-place sequence is: write segments, force the file, close it, atomic replacement, then force the store directory. A failure after replacement can leave the new value visible. Failure is not rollback: reconcile/retry and withhold transaction-success and durability receipts.
This deliberately changes 0.9.392, which silently ignored directory-open AccessDeniedException, including on POSIX. Windows FileChannel directory opens may be unsupported; the native Windows binding supplies the barrier instead. NTFS journaling is not treated as a substitute for a failed flush.
For disposable data, development or tests only, a caller can explicitly choose:
(connect-fs-store path
:config {:allow-unsafe-directory-sync? true})
This boolean option emits a warning at connection and permits skipping directory
sync for custom filesystems (including in-memory Jimfs) or a Windows directory
open AccessDeniedException. POSIX open errors and force errors still propagate.
Acknowledged writes may be lost after an OS crash or power loss. Do not use
this option for durable database commits or replication receipts.
Alternatively, existing :sync-blob? false explicitly disables sync altogether
and likewise does not promise crash durability. Custom filesystems without
directory-sync support must choose one of these weaker modes explicitly.
The earlier unreleased :strict-directory-sync? option is rejected: safety is
now the default, not an extra setting consumers must discover and enable.
This does not establish hardware power-loss guarantees, durability of ancestor
directory provisioning, immutable-write semantics, retention or consensus.
Administrative delete-store remains separate best-effort cleanup. Complete
repository qualification still requires filesystem/device and provisioning tests
plus the repository's marker/receipt ordering tests.
The mmap directory barrier now uses the same platform implementation and does not swallow IOExceptions. The experimental mmap mutation API does not inherit the unsafe file-store override.
The candidate release compiles the Windows binding with javac --release 22.
Unix JVMs below 22 can still load the Clojure namespaces without loading that
class. Windows file stores require JDK 22+; a Windows JVM below 22 fails explicitly
instead of silently weakening persistence. GraalVM 25 Windows/x64 is the native test target;
older Windows Native Image toolchains are not qualified by this increment.
On Linux, the packaged jar passes the JDK 21 store regression suite, and a
GraalVM CE 21.0.2 native executable built from the packaged directory-sync
namespace successfully performs the Unix barrier. This does not qualify a full
Datahike native build. Reproduction commands are in
test/windows-durability/README.md.
Run JVMs with --enable-native-access=ALL-UNNAMED. The jar includes the native
image foreign-call metadata and runtime-initialization rule for the DLL handles.
Release publication rejects jars missing the binding class. Jar staging is
separate from compiler output, so packaging cannot shadow edited Clojure sources.
The Windows batch now runs the real Konserve directory, filestore, mmap and crash simulator tests after the binding probes. A separate real child-process kill test checks that acknowledged payloads and roots survive process termination and reopen with a complete root closure. This is not an OS crash or power cut. Datahike native-image integration and initial directory provisioning remain merge gates; a successful binding survey alone is insufficient.
clojure -X:test :nses '[konserve.directory-sync-test konserve.filestore-test konserve.simulation-crash-test]'
These tests inject open/force errors, exercise sync/async writes and successful retry/reopen. Platform decisions are injected on Linux, not a Windows machine. The crash simulator tests storage ordering, not actual power-cut behavior.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |