pub struct FlushController { /* private fields */ }Expand description
Manages the active and frozen memtable lifecycle.
The controller holds an active memtable that accepts writes, and optionally a frozen memtable that is being flushed. Writes go to the active memtable; when the flush threshold is reached, the active memtable is frozen and swapped for a fresh one.
Implementations§
Source§impl FlushController
impl FlushController
Sourcepub fn new(config: FlushConfig) -> Self
pub fn new(config: FlushConfig) -> Self
Create a new flush controller with the given configuration.
Sourcepub fn active_memtable(&self) -> Arc<Memtable> ⓘ
pub fn active_memtable(&self) -> Arc<Memtable> ⓘ
Get a reference to the active memtable.
Sourcepub fn frozen_memtable(&self) -> Option<Arc<Memtable>>
pub fn frozen_memtable(&self) -> Option<Arc<Memtable>>
Get a reference to the frozen memtable, if any.
Sourcepub fn insert(&self, point: &Point) -> Result<()>
pub fn insert(&self, point: &Point) -> Result<()>
Insert a point into the active memtable.
§Errors
Returns MemtableError::CapacityExceeded if the total memory
(active + frozen) exceeds the configured maximum.
Sourcepub fn insert_with_wal_seq(&self, point: &Point, wal_seq: u64) -> Result<()>
pub fn insert_with_wal_seq(&self, point: &Point, wal_seq: u64) -> Result<()>
Insert a point that is already durable in the WAL at wal_seq.
No capacity check. Admission control runs before the WAL append; what the WAL holds is inserted unconditionally, because a record that is durable but in no memtable is a record the next flush’s WAL floor may pass — and then it is lost. The same applies to replay at open: rejecting an acknowledged record for being over a memory cap is silent data loss, not backpressure.
§Errors
Returns MemtableError::Frozen if the active memtable was frozen
concurrently — which the freeze/insert lock order makes impossible
from this method.
Sourcepub fn frozen_count(&self) -> usize
pub fn frozen_count(&self) -> usize
How many memtables are frozen and waiting to be flushed.
Sourcepub fn is_idle(&self) -> bool
pub fn is_idle(&self) -> bool
true when neither the active memtable nor any frozen one holds a
point.
Sourcepub fn should_flush(&self) -> bool
pub fn should_flush(&self) -> bool
Check whether the flush threshold has been reached.
Sourcepub fn freeze_and_swap(&self) -> Result<()>
pub fn freeze_and_swap(&self) -> Result<()>
Freeze the active memtable and swap in a fresh one.
The frozen memtable is stored for later flushing.
§Errors
Returns an error if there is already a frozen memtable that hasn’t been flushed yet.
Sourcepub fn flush_frozen(&self) -> Result<Vec<FlushResult>>
pub fn flush_frozen(&self) -> Result<Vec<FlushResult>>
Flush the oldest frozen memtable to segment files.
Equivalent to flush_frozen_with with a
registration step that does nothing.
§Errors
See flush_frozen_with.
Sourcepub fn flush_frozen_with<F>(&self, register: F) -> Result<Vec<FlushResult>>
pub fn flush_frozen_with<F>(&self, register: F) -> Result<Vec<FlushResult>>
Flush the oldest frozen memtable to segment files and hand the
results to register before letting the memtable go.
Groups points by measurement and writes one .csx segment per
measurement, so each segment holds exactly one measurement.
The frozen memtable is released only after every segment is
written and register has returned Ok. If either fails, the
files written so far are removed and the memtable stays at the head
of the frozen queue for the next attempt — otherwise a failed write
drops the only in-memory copy while the next flush raises the WAL
floor past its records. Registration is inside the same window: a
segment on disk but not in the catalog is an orphan the next open
deletes.
One flush per controller at a time; a concurrent caller waits.
§Errors
Returns MemtableError::NoFrozenMemtable if nothing is frozen or
the frozen memtable is empty (it is discarded), the segment writer’s
error, or register’s error.
Sourcepub fn scan(
&self,
series_key: &SeriesKey,
min_ts: i64,
max_ts: i64,
) -> Vec<Point>
pub fn scan( &self, series_key: &SeriesKey, min_ts: i64, max_ts: i64, ) -> Vec<Point>
Scan both active and frozen memtables for a specific series.
Deduplicated by timestamp, newest write wins — the active memtable first, then the frozen queue newest to oldest.
The result is a set, in no particular order.
ShardRouter sorts by timestamp across
shards, and every caller reaches this through it.
§Consistency
Both memtable references are obtained under a single scope
following frozen→active lock order (matching freeze_and_swap).
This prevents a race where freeze_and_swap() moves data
between the two reads.
Sourcepub fn scan_all(&self) -> Vec<Point>
pub fn scan_all(&self) -> Vec<Point>
Scan all points across both active and frozen memtables.
Deduplicated by (series, timestamp), newest write wins. Unordered —
see scan_measurement.
Sourcepub fn scan_measurement(
&self,
measurement: &str,
min_ts: i64,
max_ts: i64,
) -> Vec<Point>
pub fn scan_measurement( &self, measurement: &str, min_ts: i64, max_ts: i64, ) -> Vec<Point>
Scan points for a specific measurement across active and frozen memtables.
Deduplicated by (series, timestamp), newest write wins — the
active memtable first, then the frozen queue newest to oldest.
The result is a set, in no particular order.
ShardRouter sorts by timestamp across
shards, and every caller reaches this through it.
Sourcepub fn all_series_canonical_forms(&self) -> Vec<Arc<str>>
pub fn all_series_canonical_forms(&self) -> Vec<Arc<str>>
Every series held by this shard’s active and frozen memtables.
Hand every tag pair this shard holds in memory to f.
Sourcepub fn total_memory(&self) -> usize
pub fn total_memory(&self) -> usize
Returns the total estimated memory across active and all frozen memtables.
Sourcepub fn total_interner_memory(&self) -> usize
pub fn total_interner_memory(&self) -> usize
Heap bytes held by the interners of the active and frozen memtables.
Sourcepub fn min_unflushed_wal_seq(&self) -> Option<u64>
pub fn min_unflushed_wal_seq(&self) -> Option<u64>
The smallest WAL sequence number held by a memtable that is not yet in a segment — active or frozen.
This is what the WAL floor is capped by. It used to consult the active memtable only, so a frozen memtable still being written — or left behind by a failed flush — was invisible, and a concurrent flush of another shard raised the floor past its records.
Sourcepub fn write_stall_delay(&self) -> Duration
pub fn write_stall_delay(&self) -> Duration
Compute graduated write stall delay based on memory pressure.
Returns Duration::ZERO when memory usage is below the soft limit.
Between the soft limit and the hard limit, returns a linearly
increasing delay up to max_stall_delay. At or above the hard
limit, callers should use check_capacity which returns an error.
This implements RocksDB-style graduated backpressure: as the memtable fills up, writes slow down proportionally, giving the flush thread time to drain without triggering hard rejections.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for FlushController
impl !RefUnwindSafe for FlushController
impl !UnwindSafe for FlushController
impl Send for FlushController
impl Sync for FlushController
impl Unpin for FlushController
impl UnsafeUnpin for FlushController
Blanket Implementations§
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
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more