Skip to main content

FlushCoverage

Enum FlushCoverage 

Source
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::CoversPrecedingOperations means 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_owned takes a FileTarget, so what a syncing FlushMode pushes 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.

Trait Implementations§

Source§

impl Clone for FlushCoverage

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for FlushCoverage

Source§

impl Debug for FlushCoverage

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for FlushCoverage

Source§

impl PartialEq for FlushCoverage

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for FlushCoverage

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.