Skip to content

Commit 04e2019

Browse files
committed
Add some more details on SlateDb data structure mapping
1 parent 890a557 commit 04e2019

1 file changed

Lines changed: 28 additions & 13 deletions

File tree

open-log/rfcs/0001-storage.md

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,31 @@ This approach simplifies ingestion by avoiding per-key sequence tracking. The tr
6161

6262
If SlateDB supports multi-writer in the future, each writer would maintain its own sequence counter. This design assumes each key would still have a single writer—interleaving appends from multiple writers to the same key would break monotonic ordering within that key's log.
6363

64+
### SST Representation
65+
66+
Open-log proposes two enhancements to SlateDB's SST structure to support efficient `scan` and `count` operations.
67+
68+
#### Block Record Counts
69+
70+
Each block entry in the SST index would include a cumulative record count:
71+
72+
```
73+
Block Entry: | block_offset | cumulative_record_count | first_key |
74+
```
75+
76+
This enables counting records in a range by scanning the LSM at the index level rather than reading all entries. Block boundaries may not align with the query range, so the first and last blocks in each overlapping level may need to be read for exact counts. An approximate count can be computed from the index alone.
77+
78+
#### Bloom Filter Granularity
79+
80+
SlateDB SSTs include bloom filters to accelerate point lookups. For open-log, the bloom filter should be keyed on the log key alone, not the composite SlateDB key which includes the sequence number. This allows the bloom filter to indicate whether a given log is present in an SST, reducing the blocks read during `scan` or `count` queries.
81+
82+
### Append-Only Scan Optimization
83+
84+
In a typical key-value store, range scans must concurrently merge all LSM levels because any level may contain the most recent value for a given key. The append-only structure of open-log provides a stronger guarantee: newer entries are always in higher levels (L0 and recent sorted runs), while older entries settle into deeper levels through compaction.
85+
86+
This ordering guarantee enables level-by-level iteration rather than concurrent merging. For queries targeting the tip of a log, we can avoid loading blocks from older levels entirely. This improves performance and prevents cache thrashing from loading historical data that isn't needed.
87+
88+
How this optimization can be exposed in SlateDB remains to be explored.
6489

6590
### Write API
6691

@@ -108,19 +133,9 @@ impl OpenLog {
108133
}
109134
```
110135

111-
### Lag and Count (under consideration)
112-
113-
Lag is a critical metric for tracking progress reading from a log. Without contiguous sequence numbers, computing lag requires additional bookkeeping. The approach under consideration augments SlateDB's SST index structure.
114-
115-
Each block entry in the SST index would include a cumulative record count:
116-
117-
```
118-
Block Entry: | block_offset | cumulative_record_count | first_key |
119-
```
120-
121-
To count records in a range, we scan the LSM at the index level rather than reading all entries. However, block boundaries may not align with the query range. Within each level of the LSM that overlaps our target range, we may need to read the first and last blocks from that range to determine the exact offset relative to block boundaries.
136+
### Count API (under consideration)
122137

123-
An approximate count could be offered based on the index alone without reading any blocks—useful when exact counts are not required.
138+
Lag is a critical metric for tracking progress reading from a log. Without contiguous sequence numbers, computing lag requires the SST enhancements described in [SST Representation](#sst-representation).
124139

125140
```rust
126141
// TODO: decide which SlateDB ScanOptions parameters to pass through
@@ -133,7 +148,7 @@ impl OpenLog {
133148
}
134149
```
135150

136-
This mirrors the scan API but returns a count rather than entries.
151+
This mirrors the scan API but returns a count rather than entries. The `approximate` option allows counting from the index alone without reading boundary blocks.
137152

138153
## Alternatives
139154

0 commit comments

Comments
 (0)