struct Inner {
file: File,
path: PathBuf,
written: u64,
next_seq: u64,
dirty: bool,
pending: [BTreeSet<u64>; 3],
retired: Vec<(PathBuf, File)>,
}Fields§
§file: File§path: PathBuf§written: u64Bytes written to the current segment, tracked rather than stated so
the roll check costs nothing.
next_seq: u64The next sequence to hand out. Monotonic across segments and restarts.
dirty: boolSet by append, cleared by sync. Without it a quiet server syncs an
unchanged file on every tick, which on macOS is a 4 ms barrier bought
for nothing.
pending: [BTreeSet<u64>; 3]Every sequence this log has handed out that no block has published yet,
per signal, indexed by Signal::index.
This is what makes more than one flusher per signal safe. A block claims
a watermark by name and crate::block::wal_watermarks takes the
maximum, which is only sound if frames reach blocks in sequence order —
see Wal::append_then. Shard a signal’s flusher and they no longer
do: shard 1 can publish frame 6 while shard 0 still holds frame 5, and
the maximum would say 7. So the watermark stops being “one past what
this block holds” and becomes “the oldest frame nobody has published”,
which is Wal::watermark_for. Frames leave the set only on a
successful publish, so a block that fails to land cannot be claimed
past either — a hole the single-flusher version had, because a failed
publish dropped its sequences and the next block’s maximum stepped
straight over them.
ponytail: a BTreeSet walked for its minimum, on the reasoning that it
holds one entry per export in flight — tens, not millions — and is
touched once per append under a lock the append already holds. If a
deployment ever runs deep enough queues for the removals to show up,
the shape that replaces it is a per-shard “oldest held” cell plus the
channel’s own ordering.
retired: Vec<(PathBuf, File)>Segments that have been rolled past but not yet forced, handed to the
next Wal::sync.
This list exists because the obvious alternative — syncing the outgoing
segment inside roll — puts a 4 ms F_FULLFSYNC on one appender in
every SEGMENT_BYTES, and benches/wal_bench.rs measured exactly that:
at 1 MiB bodies a segment rolls every 64 appends, so the stall landed on
1.5% of them and the p99 was 7.2 ms against a 5 ms SLA. A rare stall is
still a stall, and a tail latency is made of rare things.
Auto Trait Implementations§
impl Freeze for Inner
impl RefUnwindSafe for Inner
impl Send for Inner
impl Sync for Inner
impl Unpin for Inner
impl UnsafeUnpin for Inner
impl UnwindSafe for Inner
Blanket Implementations§
impl<T> Allocation for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].