A Dump through driver/yaml issues one fsync and it is 2.2ms of a 2.38ms save on ext4 (#186), or 88% of the operation.
Nothing lets a caller decline it.
For a config file a process is about to re-read, or a file being written in a test, or any of the cases where the atomic rename is the point and surviving a kernel panic is not, that is the whole cost of the operation spent on a guarantee the caller did not ask for.
koanf, viper's non-atomic write and a plain os.WriteFile all sit between 210µs and 380µs; ferry with the same fsync removed sits at 390µs and ties koanf.
The decision this needs
No ADR owns durability policy for a driver, so this is an unmade decision rather than a correction to an existing one - do not amend an ADR into saying something it never decided, and do not open a new one without asking the owner first.
#155 is the precedent for the shape: a driver-level Option on the constructor, decided in the ticket.
The question is only which way the default points:
- unsynced default,
Durable() opts in - matches every library ferry is measured against, makes the common case fast, and means a caller who wants the journal commit says so. The atomic rename stays unconditional either way, because that is what protects the operator's file from a half-written document and it costs 53µs.
- synced default,
Unsynced() opts out - preserves today's behaviour for anyone already relying on it, which as of this ticket is nobody outside the repo.
Recommendation is the first: atomicity is the promise doc.go makes and it is kept in both, durability is the expensive one, and a library that silently spends 2.2ms per save on it has made a choice for the caller.
The owner decides; the ticket does not.
Scope
Parent: #186
Blocked by: #187
A
Dumpthroughdriver/yamlissues one fsync and it is 2.2ms of a 2.38ms save on ext4 (#186), or 88% of the operation.Nothing lets a caller decline it.
For a config file a process is about to re-read, or a file being written in a test, or any of the cases where the atomic rename is the point and surviving a kernel panic is not, that is the whole cost of the operation spent on a guarantee the caller did not ask for.
koanf, viper's non-atomic write and a plain
os.WriteFileall sit between 210µs and 380µs; ferry with the same fsync removed sits at 390µs and ties koanf.The decision this needs
No ADR owns durability policy for a driver, so this is an unmade decision rather than a correction to an existing one - do not amend an ADR into saying something it never decided, and do not open a new one without asking the owner first.
#155 is the precedent for the shape: a driver-level
Optionon the constructor, decided in the ticket.The question is only which way the default points:
Durable()opts in - matches every library ferry is measured against, makes the common case fast, and means a caller who wants the journal commit says so. The atomic rename stays unconditional either way, because that is what protects the operator's file from a half-written document and it costs 53µs.Unsynced()opts out - preserves today's behaviour for anyone already relying on it, which as of this ticket is nobody outside the repo.Recommendation is the first: atomicity is the promise
doc.gomakes and it is kept in both, durability is the expensive one, and a library that silently spends 2.2ms per save on it has made a choice for the caller.The owner decides; the ticket does not.
Scope
NewSink(path string, opts ...Option), variadic and backward compatible.doc.go's "Saving is atomic" section says what is and is not guaranteed, and the option's own godoc says what the caller is buying or declining. Neither prints a measurement (AGENTS.md).Parent: #186
Blocked by: #187