Skip to content

Writes are not durable: no fsync between write and rename #175

Description

@xxfast

FileCodec.encode and VersionedCodec.encode write to a staging file, close it, then atomicMove it into place. Closing flushes the userspace buffer to the OS, but nothing forces the data to disk. kotlinx-io has no fsync in its API: RawSink exposes flush() only, and FileSystem has atomicMove with no sync counterpart.

A rename is a metadata operation and can land durably while the data blocks have not. On a hard kill or power loss that leaves a file that exists with zero length, which is the classic rename-without-fsync failure.

Worth investigating as the cause of #80, #157 and #162. All three show JSON input: with nothing after it, so empty files rather than truncated or interleaved ones, and in #80 and #162 it is the two-byte .version file that comes back empty. That fits a durability gap better than it fits concurrent writers. It would also explain why it clustered on one reporter's device and nobody could reproduce it on demand.

#172 stopped these from crashing, and #174 removes a separate corruption route, but neither addresses this. A store that silently empties itself is still data loss.

Likely needs an upstream request to kotlinx-io or a platform-specific expect/actual sync, so worth confirming the diagnosis before picking either.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions