The full picture
// 1. append the record
FileChannel ch = FileChannel.open(path, WRITE, APPEND);
ch.write(buffer); // -> page cache. NOT durable.
// 2. force data (and metadata) to the device
ch.force(true); // fsync: blocks until the device acks
// 3. new file? the directory entry needs persisting too
try (FileChannel dir = FileChannel.open(path.getParent(), READ)) {
dir.force(true); // fsync the directory — the step everyone forgets
}
// Only NOW may you ack the client / advance the commit index.
// Group commit: batch many records per fsync — the entire reason
// commit latency and throughput are a trade in every database.- fsync costs real latency (~ms on NVMe with flush, worse on cloud block storage) — hence group commit (amortize one fsync over N transactions),
commit_delay-style knobs, and Kafka's stance: acks come from replication (in-memory on N brokers) by default, with flush intervals — durability by redundancy instead of per-write fsync. Being able to compare those two philosophies is the architect answer. - The 2018 'fsyncgate': Postgres discovered Linux could drop dirty pages after a failed fsync while later fsyncs report success — errors on fsync must be treated as 'state unknown: panic/re-verify', which is what Postgres now does. Quote it as the cautionary tale: even the primitive has sharp edges.
- O_DIRECT + O_DSYNC bypass and/or force through the cache for databases that self-manage;
fdatasyncskips non-essential metadata (mtime) to save a journal write. - Cloud twist: on EBS/PD, fsync durability means 'durable in the replicated volume', with its own latency profile — your storage's fsync behavior is part of your RPO math, not a Linux detail.