Interview Prep Zoneby CuriouserLabs

Question 3 of 5 · architect level

write() returned — is my data safe? Explain the durability chain and what fsync actually promises.

🎤 Say this first

No. write() typically means 'copied into the page cache' — the kernel flushes dirty pages later (seconds!). Power loss eats everything not yet written back. The durability chain is: your buffer → page cache (write) → device (fsync — kernel submits and waits) → actually persistent only past the device's volatile write cache (the kernel sends flush/FUA; consumer SSDs sometimes lie; enterprise drives have power-loss protection). And after appending a file you must also fsync the directory to persist the name→inode entry. Every database's commit path is: append WAL → fsync → then ack the client — durability is exactly as strong as your fsync discipline.

The full picture

The append-durably checklist (what databases actually do)
// 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; fdatasync skips 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.

🔄 Likely follow-up questions

  • Group commit: how do databases amortize fsync without breaking the durability promise?
  • What does fsyncgate imply for retrying failed writes?
  • How would you design an fsync policy for an event store: per-write, interval, or replication-based?