db-07 Observation
The canonical scenario
We build two SSTables (call them newer.sst and older.sst) and compact them
in the order [newer, older].
newer.sst — produced from this MemTable scenario
memtable new
memtable bulk 50 # key0..key49 -> val0..val49
memtable put "key10" "NEW-10"
memtable del "key5"
So newer.sst contains 50 distinct keys, of which key10 has value "NEW-10",
key5 is a tombstone, and the other 48 are val<i>.
older.sst — produced from this MemTable scenario
memtable new
memtable bulk 100 # key0..key99 -> val0..val99
memtable put "key50" "OLD-50"
So older.sst contains 100 distinct keys, of which key50 is "OLD-50" and
the others are val<i>.
Expected merged output
For every key the table picks the first input that contains it:
| Key range / specific key | Winner | Value |
|---|---|---|
| key0..key4 | newer | val0..val4 |
| key5 | newer | Tombstone |
| key6..key9 | newer | val6..val9 |
| key10 | newer | "NEW-10" |
| key11..key49 | newer | val11..val49 |
| key50 | older | "OLD-50" |
| key51..key99 | older | val51..val99 |
Total distinct keys: 100. Tombstones: 1 (key5). Values: 99.
"What broken looks like"
| Bug | Symptom |
|---|---|
| Tiebreaker swapped (older wins) | key10 → "val10" instead of "NEW-10"; key5 → "val5" instead of tombstone. |
| Forget to drain duplicates | SstWriter::add returns Unsorted error (or "keys not strictly ascending"). |
| Byte-vs-string comparison | Output sha256 differs across languages on ASCII-only input only if a sort breaks. |
Tombstone dropped when drop_tombstones=false | Output has 99 keys instead of 100; key5 missing. |
Tombstone kept when drop_tombstones=true at bot | Output has 100 keys instead of 99; key5 still present as tombstone. |
With drop_tombstones=true
Same inputs, run as bottom-level compaction:
- key5 disappears entirely (newer's only entry for key5 was a tombstone).
- 99 keys total, all values.
Hex of the absolute simplest compaction
Compacting [A, B] where A = [("k", T)] and B = [("k", V, "v")]:
drop_tombstones=false: output is an SSTable with one entry("k", T). File size = 4 (block hdr) + 4+4+1 (entry hdr) + 1 (key) + 0 (value) + 4 (index count) + 4+8+8+1 (one index entry) + 32 (footer) = 79 bytes. This is the same assstable buildof a MemTable containing only("k", T).drop_tombstones=true: output is the empty SSTable, exactly 36 bytes.
Cross-language sha256 must match for both cases.