pub struct Memtable { /* private fields */ }Expand description
A concurrent in-memory write buffer for time-series data.
Points are stored in a crossbeam_skiplist::SkipMap keyed by
MemtableKey (series_key_hash, timestamp). The skip list provides
lock-free concurrent inserts and ordered iteration.
§Deduplication
If a point with the same (series_key_hash, timestamp) already exists,
the new value overwrites the old one (last-write-wins).
Implementations§
Source§impl Memtable
impl Memtable
Sourcepub fn insert(&self, point: &Point) -> Result<()>
pub fn insert(&self, point: &Point) -> Result<()>
Insert a point into the memtable.
The point is stored keyed by (series_key_hash, timestamp). If a
point with the same key already exists, it is overwritten
(last-write-wins).
§Errors
Returns MemtableError::Frozen if the memtable has been frozen.
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 with an associated WAL sequence number.
Updates the min/max WAL sequence tracking in addition to inserting the point.
§Errors
Returns MemtableError::Frozen if the memtable has been frozen.
Sourcepub fn insert_batch(&self, points: &[Point]) -> Result<usize>
pub fn insert_batch(&self, points: &[Point]) -> Result<usize>
Insert a batch of points in one call.
More efficient than calling insert in a loop because:
The frozen check is performed once.
Strings are pre-interned and the measurement index is updated in
a single write-lock acquisition.
Size adjustments are accumulated locally and flushed with a single
fetch_add.
Returns the number of points successfully inserted.
§Errors
Returns MemtableError::Frozen if the memtable has been frozen.
Sourcepub fn insert_batch_with_wal_seq(
&self,
points: &[Point],
wal_seq: u64,
) -> Result<usize>
pub fn insert_batch_with_wal_seq( &self, points: &[Point], wal_seq: u64, ) -> Result<usize>
Insert a batch of points with an associated WAL sequence number.
Uses the batch to set the WAL sequence range, then delegates to
insert_batch.
§Errors
Returns MemtableError::Frozen if the memtable has been frozen.
Sourcepub fn scan(
&self,
series_key: &SeriesKey,
min_ts: Timestamp,
max_ts: Timestamp,
) -> Vec<Point>
pub fn scan( &self, series_key: &SeriesKey, min_ts: Timestamp, max_ts: Timestamp, ) -> Vec<Point>
Scan points for a specific series within a time range.
Returns points sorted by timestamp for the series identified by
series_key. Only points within [min_ts, max_ts] are returned.
Uses canonical form comparison (not hash) to avoid false positives
from hash collisions.
Sourcepub fn scan_range(&self, min_ts: Timestamp, max_ts: Timestamp) -> Vec<Point>
pub fn scan_range(&self, min_ts: Timestamp, max_ts: Timestamp) -> Vec<Point>
Scan all points across all series within a time range.
Returns all points sorted by (series_key_hash, timestamp).
Note: this is intentionally O(N) — it scans all series.
For measurement-scoped queries (the common case), use
scan_measurement which leverages the measurement index for
O(S × log N) per-series range scans.
Sourcepub fn scan_all(&self) -> Vec<Point>
pub fn scan_all(&self) -> Vec<Point>
Scan all points in the memtable, sorted by (series_key_hash, timestamp).
Sourcepub fn scan_measurement(
&self,
measurement: &str,
min_ts: Timestamp,
max_ts: Timestamp,
) -> Vec<Point>
pub fn scan_measurement( &self, measurement: &str, min_ts: Timestamp, max_ts: Timestamp, ) -> Vec<Point>
Scan all points belonging to a specific measurement within a time range.
Uses a secondary measurement index to perform targeted range scans per series hash, achieving O(S × log N) complexity instead of O(N) full-table iteration, where S is the number of distinct series for the measurement.
Sourcepub fn series_canonical_forms(&self) -> Vec<Arc<str>>
pub fn series_canonical_forms(&self) -> Vec<Arc<str>>
The canonical form of every series this memtable holds.
The cardinality budget is derived from what the database holds, and a memtable holds series no segment does yet — so a repair that consulted only the segments on disk would release a series written a second ago and then count it again on the next write.
series_tags is already keyed by canonical form, so this walks the
map rather than scanning the points.
Hand every (tag key, tag value) pair this memtable holds to f.
Label discovery has to answer from the memtable as well as from the
segments: the tag inverted index is built at flush, so a series
written a second ago is in no segment and therefore in no index, and
an answer drawn from the index alone omits exactly the labels a fresh
database has. A visitor rather than a Vec, because the caller is
building a set and the pairs repeat once per series.
Sourcepub fn interner_bytes(&self) -> usize
pub fn interner_bytes(&self) -> usize
Returns the estimated memory usage in bytes.
Heap bytes held by this memtable’s string interner.
Reported separately from estimated_size,
which counts rows and index entries: the interner holds the tag keys,
tag values and measurement names, so it grows with cardinality rather
than with row count and is the term a high-cardinality workload sees
first.
Sourcepub fn estimated_size(&self) -> usize
pub fn estimated_size(&self) -> usize
Includes the measurement_index DashMap overhead.
Sourcepub fn min_wal_seq(&self) -> Option<u64>
pub fn min_wal_seq(&self) -> Option<u64>
Returns the minimum WAL sequence number tracked.
Returns None if no WAL sequences have been recorded.
Sourcepub fn max_wal_seq(&self) -> Option<u64>
pub fn max_wal_seq(&self) -> Option<u64>
Returns the maximum WAL sequence number tracked.
Returns None if no WAL sequences have been recorded.
Sourcepub fn freeze(&self)
pub fn freeze(&self)
Freeze this memtable, preventing any further inserts.
After freezing, all insert calls will return
MemtableError::Frozen.
Source§impl Memtable
impl Memtable
Sourcepub fn to_record_batches(&self) -> Vec<MeasurementBatch>
pub fn to_record_batches(&self) -> Vec<MeasurementBatch>
Every row, as one Arrow batch per measurement, built straight from the skip-list entries.
This is what a flush hands the segment writer. It replaced
to_points() on that path: materialising a full memtable as
Points — two BTreeMaps each — cost a kilobyte a row and made the
flush of an 8 MB memtable peak at ten times that. A batch is the
columns themselves, and the writer encodes it without another copy.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Memtable
impl !RefUnwindSafe for Memtable
impl !UnwindSafe for Memtable
impl Send for Memtable
impl Sync for Memtable
impl Unpin for Memtable
impl UnsafeUnpin for Memtable
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