pub struct MergeEntry {
pub run_index: usize,
pub key: DecoratedKey,
pub clustering_key: Option<ClusteringKey>,
pub timestamp: i64,
pub row_data: RowData,
pub complex_deletions: Vec<ComplexDeletion>,
pub range_deletion: Option<RangeTombstone>,
pub row_deletion: Option<(i64, i32)>,
pub partition_deletion: Option<(i64, i32)>,
}Expand description
Entry in the merge stream
Represents a single row from one of the input SSTables. This is the fundamental unit that flows through the merge heap.
Fields§
§run_index: usizeWhich SSTable this came from (0 = newest)
key: DecoratedKeyPartition key with token
clustering_key: Option<ClusteringKey>Clustering key (None for tables without clustering)
timestamp: i64Timestamp in microseconds since Unix epoch
row_data: RowDataRow data (live cells or tombstone)
complex_deletions: Vec<ComplexDeletion>Complex (collection / UDT) deletion markers for the multi-cell columns
of this (pk, ck) (issue #886 substrate).
Carried through the merge so the per-cell-path collection/UDT followup
(#844) and shadow-before-purge (#887) can preserve collection/UDT
deletion timestamps. reconcile_cluster unions and preserves these
across a cluster, but reconciliation does not yet consult them and
the writer does not yet apply them — defaults to empty, so output is
byte-unchanged. Population (per-element reader emit) lands in #899.
range_deletion: Option<RangeTombstone>Range-deletion marker covering a span of clustering keys (issue #886 substrate).
A first-class slot so range tombstones can flow through the merge stream
instead of being skipped by the parser; applying them to shadow covered
cells is the follow-up #846. Carried (and timestamp-max-preserved)
through reconcile_cluster but not yet consulted by reconciliation
or the writer, so output is byte-unchanged. None when this entry
carries no range deletion.
row_deletion: Option<(i64, i32)>Row-level deletion that COEXISTS with this entry’s surviving live cells (issue #932).
Some((deletion_time_micros, local_deletion_time_secs)) when a row
tombstone whose timestamp is OLDER than the surviving cells must be kept
alongside RowData::Live. RowData::Live has no row-deletion slot, so —
mirroring the carry-only complex_deletions / range_deletion fields —
the coexisting deletion rides here instead of forcing a RowData change
across ~100 RowData::Live sites. reconcile_cluster folds it into the
winning row deletion and re-attaches it to the emitted live entry;
merge_entry_to_mutation emits it as Mutation::row_tombstone. Without
this, a partial compaction that keeps newer cells would DROP the row
deletion and let older cells of other columns (in SSTables not part of the
compaction) resurrect. None for a row with no coexisting deletion.
partition_deletion: Option<(i64, i32)>Partition-level deletion (markedForDeleteAt µs, localDeletionTime s)
carried by a synthetic partition-tombstone carrier entry (issue #1072).
Some(..) ONLY on the carrier entry the reader emits for a partition
header that has a tombstone (empty RowData::Live, clustering_key: None). The merge extracts the MAX markedForDeleteAt across sources,
applies it as the OUTERMOST per-cell <= shadow floor for the whole
partition, and re-emits the surviving tombstone via
merge_entry_to_mutation (→ Mutation::partition_tombstone). Without
this a newer partition tombstone in one SSTable failed to shadow older
live rows in another, resurrecting the deleted partition. None for every
non-carrier entry.
Implementations§
Source§impl MergeEntry
impl MergeEntry
Sourcepub fn new(
run_index: usize,
key: DecoratedKey,
clustering_key: Option<ClusteringKey>,
timestamp: i64,
row_data: RowData,
) -> Self
pub fn new( run_index: usize, key: DecoratedKey, clustering_key: Option<ClusteringKey>, timestamp: i64, row_data: RowData, ) -> Self
Create a new merge entry.
The carry-only #886 substrate fields (complex_deletions,
range_deletion) default to empty/None; attach them with
with_complex_deletions /
with_range_deletion once the reader emit
surfaces them (#899).
Sourcepub fn with_complex_deletions(
self,
complex_deletions: Vec<ComplexDeletion>,
) -> Self
pub fn with_complex_deletions( self, complex_deletions: Vec<ComplexDeletion>, ) -> Self
Attach complex-deletion markers (issue #886 substrate; carry-only).
Sourcepub fn with_row_deletion(self, deletion_time: i64, ldt: i32) -> Self
pub fn with_row_deletion(self, deletion_time: i64, ldt: i32) -> Self
Attach a coexisting row-level deletion (issue #932).
deletion_time is markedForDeleteAt (microseconds); ldt is the
localDeletionTime (GC-clock seconds, 0 = not surfaced). Used when a
row’s surviving cells are newer than a row tombstone that must still be
preserved so it keeps shadowing older cells in non-compacted SSTables.
Sourcepub fn with_range_deletion(self, range_deletion: RangeTombstone) -> Self
pub fn with_range_deletion(self, range_deletion: RangeTombstone) -> Self
Attach a range-deletion marker (issue #886 substrate; carry-only).
Sourcepub fn with_partition_deletion(self, partition_deletion: (i64, i32)) -> Self
pub fn with_partition_deletion(self, partition_deletion: (i64, i32)) -> Self
Attach a partition-level deletion (issue #1072).
deletion_time is markedForDeleteAt (microseconds); ldt is the
localDeletionTime (GC-clock seconds). Marks this entry as the synthetic
partition-tombstone carrier so the merge applies the partition floor and
re-emits the surviving tombstone.
Sourcepub fn is_metadata_only_no_op(&self) -> bool
pub fn is_metadata_only_no_op(&self) -> bool
True when this entry has NO writer-emittable content at all — an empty
RowData::Live { cells: vec![] } with no row tombstone and no carried
deletion metadata. Routing such an entry to the writer would create a
PHANTOM live empty (pure-PK) row at timestamp 0 (DataWriter::merge_row_group
treats a no-op mutation as a primary-key insert), so merge filters it.
Epic #899 Phase C: a COMPLEX DELETION is consumed by the writer (a real
CellOperation::ComplexDeletion marker), so a complex-deletion-only entry
is NOT a no-op.
Issue #933: a RANGE DELETION is now ALSO consumed by the compaction writer —
merge_entry_to_mutation threads it onto the mutation’s range_tombstones,
which the writer interleaves as on-disk bound markers AND uses to shadow
covered same-partition rows. A range-deletion-only carrier is therefore NO
LONGER a no-op and MUST reach the writer (dropping it would resurrect the
covered rows it shadowed — roborev #959 High #2). In practice
reconcile_cluster never emits a truly-empty entry (one with empty cells,
no row tombstone, and no carried metadata reconciles to None), so this
guard is now effectively unreachable but kept as a defensive phantom-row
filter.
Sourcepub fn is_partition_delete_carrier(&self) -> bool
pub fn is_partition_delete_carrier(&self) -> bool
True when this entry is a synthetic partition-tombstone carrier (issue
#1072): an empty live row whose only payload is partition_deletion.
Produced by [Self::build_merge_entry] from a reader PartitionDelete.
Such an entry produces NO output row (it yields a
Mutation::partition_tombstone, not a clustering row), so the merge must
not count it toward output row counts — but it MUST reach the writer.
Trait Implementations§
Source§impl Clone for MergeEntry
Available on crate feature write-support only.Manual Clone (was #[derive(Clone)]) so the #1664 double-clone regression
guard can count MergeEntry clones via a #[cfg(test)]-gated recorder.
The clone is field-wise identical to the former derived clone (all 9 fields);
in a production (non-test) build the record() call vanishes entirely, so
this is a plain field-wise clone with ZERO added cost.
impl Clone for MergeEntry
write-support only.Manual Clone (was #[derive(Clone)]) so the #1664 double-clone regression
guard can count MergeEntry clones via a #[cfg(test)]-gated recorder.
The clone is field-wise identical to the former derived clone (all 9 fields);
in a production (non-test) build the record() call vanishes entirely, so
this is a plain field-wise clone with ZERO added cost.
Source§impl Debug for MergeEntry
impl Debug for MergeEntry
impl Eq for MergeEntry
Source§impl Ord for MergeEntry
Available on crate feature write-support only.Ord implementation for min-heap routing ONLY (not LWW winner selection).
impl Ord for MergeEntry
write-support only.Ord implementation for min-heap routing ONLY (not LWW winner selection).
This orders entries so the heap yields them grouped by partition and
clustering key. The actual equal-timestamp Delete-vs-Live winner is chosen
in merge_partition_rows (timestamp → liveness → run_index), NOT here.
Order by:
- Token (ascending)
- Key bytes (ascending, for hash collisions)
- Clustering key (ascending, schema-aware)
- Run index (ascending) - stable routing tiebreak only
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl PartialEq for MergeEntry
impl PartialEq for MergeEntry
Source§impl PartialOrd for MergeEntry
Available on crate feature write-support only.
impl PartialOrd for MergeEntry
write-support only.impl StructuralPartialEq for MergeEntry
Auto Trait Implementations§
impl Freeze for MergeEntry
impl RefUnwindSafe for MergeEntry
impl Send for MergeEntry
impl Sync for MergeEntry
impl Unpin for MergeEntry
impl UnsafeUnpin for MergeEntry
impl UnwindSafe for MergeEntry
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.