pub enum FlushCoverage {
CoversPrecedingOperations,
Unordered,
}Expand description
Whether a flush covers the operations queued before it (M12.1, D-23 in
DESIGN-NOTES.md).
This is a required argument on Batch::flush_owned and
Batch::flush_raw rather than a field of PushOptions, because there
is no defensible default. An unflagged flush does not cover preceding
writes: it is an ordinary operation competing with them, and it frequently
wins. A default would make the obvious spelling – push the writes, then
push a flush – a silent data-loss bug rather than a missing feature, so
the decision is taken at the call site instead (D-25).
It is an enum rather than a bool for the same reason: flush(&file, true) does not say what the true decides, and this is not a parameter
anyone should have to look up.
§The barrier’s scope is the ring; the flush’s is the file
One call sets both, which makes them easy to merge, and merging them is a mistake about durability rather than about style:
- This flag is ring-wide.
Self::CoversPrecedingOperationsmeans the flush does not execute until every operation outstanding on the ring when it was reached has completed – whatever file each one targets, and whoever queued it (D-47, measured over roughly 4,500 trials). - The flush names one file.
Batch::flush_ownedtakes aFileTarget, so what a syncingFlushModepushes to stable media is that file’s data and the device cache behind it.
Completion is not durability. A write completing means the kernel took the bytes, not that they reached non-volatile media. So the barrier bounds what a flush waits for, and the flush itself bounds what is made durable, and those are different sets whenever a ring carries operations against more than one file.
The practical consequence for a caller is cost rather than correctness: operations this flush will never make durable can still make it wait. A caller who cares about that bounds it by controlling what shares the ring; this crate does not decide that (D-8), and the flush’s own target is what secures the durability of the file named.
Variants§
CoversPrecedingOperations
Wait for every operation already outstanding on the ring, then flush.
This is what makes preceding writes durable when the flush’s completion is observed, and it is what a caller closing an epoch wants.
It sets IOSQE_FLAGS_DRAIN_PRECEDING_OPS, whose reach is ring-wide
rather than per-file: it waits on every operation outstanding on the
ring when it is reached, not only the ones in this batch. So the flush
takes as long as the slowest of them, however unrelated. That cost is
real, and it is the only reason the other variant exists.
§What this does not promise
The flag is one-sided. Operations you push after this flush are not held back, and can complete before it. Measured over about 4,500 trials at a rate between 0.03% and 0.8%, and in the worst case every one of 32 subsequent writes completed first (D-47).
So this flush’s completion tells you about the past and not the future: everything outstanding when the flush was reached is durable, and nothing is implied about work submitted afterwards. If later work must not begin until the flush is durable, submit it after you have popped the flush’s completion. The ring will not sequence it for you.
An earlier version of this documentation said subsequent operations were held until the flush completed. That was wrong, and it is corrected here rather than quietly dropped because a caller may have relied on it.
Unordered
Queue the flush with no barrier: it may complete while writes pushed before it are still in flight.
Almost never what a caller wants. Its completion proves nothing about any preceding write, so using it to close an epoch loses data that the caller believes is committed – invisibly, until power is lost.
Two uses are legitimate. One is host sequencing: the caller has already observed the completions of every write in the epoch before pushing this, so the ordering is established outside the ring and the barrier would only make this flush wait on operations it has already accounted for. The other is a flush that is not being used for durability at all.