Back to Rocksdb

Range Deletion Handling

docs/components/read_flow/08_range_deletions.md

11.8.15.0 KB
Original Source

Range Deletion Handling

Files: db/range_del_aggregator.h, db/range_del_aggregator.cc, db/range_tombstone_fragmenter.h, db/range_tombstone_fragmenter.cc, table/table_cache.cc

Overview

Range deletions (DeleteRange()) create tombstones that cover a range of keys [start, end). These must be integrated into both point lookup and iterator paths. The implementation uses different mechanisms for each:

  • Point lookups: Simple max_covering_tombstone_seq comparison
  • Iterators: Full RangeDelAggregator with heap-based active tombstone tracking

RangeDelAggregator Architecture

RangeDelAggregator (see RangeDelAggregator in db/range_del_aggregator.h) is abstract with two concrete implementations:

ImplementationUse CaseStrategy
ReadRangeDelAggregatorPoint lookups and iteratorsSingle stripe covering [0, snapshot_seqno]
CompactionRangeDelAggregatorCompactionMultiple stripes partitioned by snapshot boundaries

Tombstone Fragmentation

Before tombstones can be efficiently queried, overlapping tombstones are fragmented into non-overlapping segments by FragmentedRangeTombstoneList (see FragmentedRangeTombstoneList in db/range_tombstone_fragmenter.h):

Input (overlapping):

  • [a, e) @ seq=10
  • [c, g) @ seq=15
  • [f, z) @ seq=5

Output (fragmented, non-overlapping):

FragmentSequences
[a, c)10
[c, e)10, 15
[e, f)15
[f, g)15, 5
[g, z)5

Benefits: No overlaps between fragments, efficient sequence number lookup within each fragment, and compact storage.

File Boundary Truncation

TruncatedRangeDelIterator (see TruncatedRangeDelIterator in db/range_del_aggregator.cc) ensures range tombstones do not leak beyond SST file boundaries:

  • Tombstone ranges are clamped to [smallest, largest) of the source file
  • Sequence number adjustment: largest.sequence -= 1 in the general case to avoid affecting keys in the next file with the same user key
  • Exception: No adjustment when the file boundary was artificially extended by a range tombstone (kTypeRangeDeletion with kMaxSequenceNumber) or when largest.sequence == 0

Key Invariant: Range tombstones are truncated at file boundaries, preventing deletion leakage across files.

Point Lookup Integration

Point lookups use a lightweight mechanism instead of the full RangeDelAggregator:

Step 1: In TableCache::Get(), for each SST file, compute the maximum covering tombstone sequence number via MaxCoveringTombstoneSeqnum(user_key) on the file's tombstone iterator.

Step 2: Track the highest max_covering_tombstone_seq across all files searched.

Step 3: In GetContext::SaveValue(), if max_covering_tombstone_seq > parsed_key.sequence, the point key is covered by a range tombstone and is treated as deleted.

This avoids building a full RangeDelAggregator for point lookups, using a single sequence number comparison instead.

Early termination: In Version::Get(), before each file search, if max_covering_tombstone_seq > 0, the search stops immediately -- any entry found at lower levels would have a lower sequence number and be covered by the tombstone. This check is at the top of the file search loop, before TableCache::Get() is called for the next file.

Iterator Integration

For iterators, tombstones are fully integrated into MergingIterator:

Step 1: Registration -- Each child point iterator is paired with a TruncatedRangeDelIterator via MergeIteratorBuilder::AddPointAndTombstoneIterator().

Step 2: Filtering -- MergingIterator::SkipNextDeleted() checks each candidate point key against active range tombstones before exposing it to DBIter.

Step 3: Cascading seeks -- If a point key is covered, the iterator seeks past the tombstone's end key. The new position might be covered by another tombstone from a different level, causing a cascade of seeks.

ShouldDelete Algorithm

ForwardRangeDelIterator::ShouldDelete() (see ForwardRangeDelIterator in db/range_del_aggregator.cc) determines if a point key is covered by an active tombstone:

Data structures:

  • active_seqnums_: Multiset ordered by descending sequence number (highest on top)
  • active_iters_: BinaryHeap ordered by end key (tracks when tombstones stop covering)
  • inactive_iters_: BinaryHeap ordered by start key (tracks when tombstones start covering)

Algorithm:

  1. Expire finished tombstones: Pop from active_iters_ any tombstone whose end key <= current key
  2. Activate starting tombstones: Pop from inactive_iters_ any tombstone whose start key <= current key
  3. Check: If active_seqnums_ is non-empty and its highest sequence > point key's sequence, the key is deleted

Complexity: O(log K) amortized per query, where K is the number of range tombstones. Each tombstone is activated and expired at most once during a forward scan.

Key Invariant: A point key is deleted if and only if a range tombstone with higher sequence number covers it.