Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
e7c1d57
Disable trial object downloads in debug builds without private sources
rockeet Sep 12, 2026
c06699c
Route Topling non-concurrent inserts through caller hint.
rockeet Sep 13, 2026
060a317
Add hint and concurrent-insert switches to memtablerep_bench.
rockeet Sep 13, 2026
bee2a65
Add a CSPP twin of the ToplingDB fillseq CI suite
rockeet Sep 13, 2026
ee4642a
Skip empty range-del table in ShouldFlushNow
rockeet Sep 19, 2026
77c82cb
Defer UpdateFlushState on hinted inserts until FinishHint
rockeet Sep 19, 2026
efe77d0
Mark rare bloom and first-seqno checks UNLIKELY in MemTable::Add
rockeet Sep 19, 2026
659c283
ci: fold memtablerep write/read us/op into Elapsed time
rockeet Sep 19, 2026
b425de1
Use ConvertToSST for eligible MemTables on DB close
rockeet Sep 26, 2026
a84c9c6
Honor small max_open_files limits for cheap DB open
rockeet Sep 26, 2026
0ef56e1
Add an opt-in option for MemTable crash-safe recovery
rockeet Sep 26, 2026
79af951
Add crash-safe recovery methods to MemTableRepFactory
rockeet Sep 26, 2026
7ecae6c
Enforce option constraints for MemTable crash-safe recovery
rockeet Sep 26, 2026
09f3a2c
Add SeekToFileOffset to the WAL reader
rockeet Sep 26, 2026
a2cc14c
DB Recovery: Utilize MemTable's Crash-Safe capability
rockeet Sep 27, 2026
45c2995
DB Recovery: Recover when the WAL kind changes
rockeet Sep 27, 2026
c91b5e8
DB Recovery: Bench Open after an abnormal exit
rockeet Sep 27, 2026
57d2443
DB Recovery: Use volatile AVX stores for pubseq publication
rockeet Sep 27, 2026
eca9a37
docs: link crash-safe recovery and data-structure guides
rockeet Oct 2, 2026
e1e7809
Track recoverable MemTable files in the MANIFEST
rockeet Oct 3, 2026
cd79ca7
Recover registered MemTables with stable DB file numbers
rockeet Oct 3, 2026
6faf82c
Revert "Recover registered MemTables with stable DB file numbers"
rockeet Oct 4, 2026
0fd5be3
Revert "Track recoverable MemTable files in the MANIFEST"
rockeet Oct 4, 2026
afd4095
Test immutable MemTable conversion modes
rockeet Oct 4, 2026
0b1a3d4
Fail flush when ConvertToSST fails
rockeet Oct 4, 2026
63ebb2e
Use cached MemTable conversion capability
rockeet Oct 4, 2026
6437b71
Exercise MemTable precreation in unit tests
rockeet Oct 5, 2026
a18eb10
Inject WAL seek errors after the seek operation
rockeet Oct 5, 2026
f63e72c
Share immutable MemTable conversion capabilities
rockeet Oct 5, 2026
e39dcf4
Sanitize MemTable merge thresholds for ConvertToSST
rockeet Oct 5, 2026
b74db85
Skip MemPurge for FileMmap MemTables
rockeet Oct 5, 2026
7e8b8b0
Validate FileMmap recovery configuration
rockeet Oct 5, 2026
91c49a8
Encode recoverable MemTable files in VersionEdit
rockeet Oct 5, 2026
af59c71
Maintain the committed MemTable file inventory per column family
rockeet Oct 5, 2026
eaeba37
Restore FastRange64 for lock stripe selection
rockeet Oct 5, 2026
5e5b05a
Separate AVX pubseq publication from the odd/even protocol
rockeet Oct 5, 2026
9eca109
Track FileMmap MemTables through creation, flush, and recovery
rockeet Oct 5, 2026
1abbaa1
Test MemTable registration during cache handoff and GC
rockeet Oct 5, 2026
048c2c9
Test crash windows around MemTable inventory commits
rockeet Oct 5, 2026
6a7b550
Test CSPP DumpMem header initialization
rockeet Oct 5, 2026
d2761bc
Verify file-owned visibility of recovered SSTs
rockeet Oct 5, 2026
4fddef8
Document the 100/80-column wrapping rule
rockeet Oct 6, 2026
11c0a73
Verify persistent MemTable statistics across writer lifetimes
rockeet Oct 6, 2026
a2331cc
Test persistent statistics with concurrent and duplicate inserts
rockeet Oct 6, 2026
8a561b6
Test interrupted reconstruction of MemTable WAL statistics
rockeet Oct 6, 2026
042855a
Allow compaction of tables with inexact visible entry counts
rockeet Oct 6, 2026
0668b03
Test repeated avoid-flush close cycles after crash-safe recovery
rockeet Oct 7, 2026
dd3030d
Add file-backed MemTable reps to memtablerep_bench
rockeet Oct 7, 2026
ac3d063
Improve MemTableRep benchmark key encoding and random-read measurements
rockeet Oct 7, 2026
7951012
Use GetPIK for native MemTableRep benchmark lookups
rockeet Oct 7, 2026
e51047e
Add readreverse to memtablerep_bench
rockeet Oct 7, 2026
e5f69d8
Update rockside for the crash-safe enterprise benchmark sample
rockeet Oct 7, 2026
ef838f4
Inline FindFileInRangeTmpl into its callers
rockeet Oct 9, 2026
f2c40c3
Inline GetContext construction into its callers under LTO
rockeet Oct 9, 2026
e4ff3d7
Cut two per-read steps out of db_bench's read loops
rockeet Oct 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 161 additions & 8 deletions .github/scripts/bench_logs_to_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
YAML_USED_NAMES = (
"db_bench-fillrandom.yaml",
"db_bench-fillseq.yaml",
"db_bench-fillseq-cspp.yaml",
)
ENGINE_LABELS = {
"zipkeyonly": "ToplingDB zipkeyonly",
Expand Down Expand Up @@ -137,7 +138,7 @@ def format_iec(num_bytes: int) -> str:
return f"{n:.1f}{units[idx]}"


SHM_WORKLOADS = ("fillrandom", "fillseq")
SHM_WORKLOADS = ("fillrandom", "fillseq", "fillseq-cspp")
SHM_WORKLOAD_LABELS = SHM_SUITE_LABELS


Expand All @@ -160,7 +161,14 @@ def load_shm_usages(eng_dir: Path) -> Dict[str, Optional[Dict[str, int]]]:
return out


RSS_WORKLOADS = ("fillrandom", "fillseq", "fillrandom-omit", "fillseq-omit")
RSS_WORKLOADS = (
"fillrandom",
"fillseq",
"fillrandom-omit",
"fillseq-omit",
"fillseq-cspp",
"fillseq-cspp-omit",
)


def parse_rss_usage(text: str) -> Optional[int]:
Expand Down Expand Up @@ -240,6 +248,10 @@ def _bytes(eng: str, wl: str, key: str) -> Optional[int]:

rows_html = []
for wl in SHM_WORKLOADS:
if wl == "fillseq-cspp" and all(
_bytes(e, wl, "allocated_bytes") is None for e in ENGINES
):
continue
cells = [f"<td>{html.escape(SHM_WORKLOAD_LABELS.get(wl, wl))}</td>"]
for e in ENGINES:
b = _bytes(e, wl, "allocated_bytes")
Expand Down Expand Up @@ -633,6 +645,26 @@ def build_db_bench_compare(
LAZY_ENGINES = ("zipkeyonly", "zipkeyvalue", "rocksdb-v8.10")


def _has_topling_fillseq_cspp(engines: Dict[str, Any]) -> bool:
return any(
bool((engines.get(e) or {}).get("db_bench_fillseq_cspp"))
for e in TOPLING_ENGINES
)


def _db_bench_by_engine(
engines: Dict[str, Any],
*,
topling_key: str,
rocks_key: str = "db_bench",
) -> Dict[str, List[Dict[str, str]]]:
out: Dict[str, List[Dict[str, str]]] = {}
for e in ENGINES:
key = topling_key if e in TOPLING_ENGINES else rocks_key
out[e] = (engines.get(e) or {}).get(key) or []
return out


def _hl(text: str, kind: str) -> str:
"""Color a short phrase: kind is 'faster' (green) or 'slower' (red)."""
return f'<span class="{kind}">{html.escape(text)}</span>'
Expand Down Expand Up @@ -762,11 +794,51 @@ def _cost_ratio_cell(baseline: Optional[float], subject: Optional[float]) -> str
)
_CSPP_METRICS_LOW = (
"Elapsed time",
"write us/op",
"read us/op",
)


def _memtablerep_elapsed_display(
mmap: Dict[str, str], bench: str, elapsed_raw: str
) -> str:
"""Append write/read us/op onto the Elapsed time cell."""
write_us = mmap.get(f"{bench}|write us/op")
read_us = mmap.get(f"{bench}|read us/op")
extras: List[str] = []
if write_us and read_us:
extras.append(f"write {write_us} us/op")
extras.append(f"read {read_us} us/op")
elif write_us:
extras.append(f"{write_us} us/op")
elif read_us:
extras.append(f"{read_us} us/op")
if not extras:
return elapsed_raw or "—"
base = elapsed_raw or "—"
return f"{base} ({', '.join(extras)})"


def _fold_memtablerep_usop(rows: List[Dict[str, str]]) -> List[Dict[str, str]]:
"""Drop standalone us/op rows; fold them into Elapsed time."""
mmap = _metric_map(rows)
out: List[Dict[str, str]] = []
for row in rows:
metric = row["metric"]
if metric in ("write us/op", "read us/op"):
continue
if metric == "Elapsed time":
out.append(
{
**row,
"value": _memtablerep_elapsed_display(
mmap, row["benchmark"], row["value"]
),
}
)
else:
out.append(row)
return out


def build_memtablerep_compare(
cspp_rows: List[Dict[str, str]],
skiplist_topling: List[Dict[str, str]],
Expand Down Expand Up @@ -806,6 +878,11 @@ def build_memtablerep_compare(
_metric_number(c_raw),
_metric_number(r_raw),
)
if metric == "Elapsed time":
o_raw = _memtablerep_elapsed_display(offset_skiplist, bench, o_raw)
c_raw = _memtablerep_elapsed_display(cspp, bench, c_raw)
t_raw = _memtablerep_elapsed_display(skip_t, bench, t_raw)
r_raw = _memtablerep_elapsed_display(skip_r, bench, r_raw)
if metric in _CSPP_METRICS_HIGH:
offset_skiplist_ratio = _throughput_ratio_cell(r_n, o_n)
cspp_ratio = _throughput_ratio_cell(r_n, c_n)
Expand Down Expand Up @@ -860,13 +937,22 @@ def _load_engine_logs(log_root: Path) -> Dict[str, Dict[str, Any]]:
)
omit_fr_rows: List[Dict[str, str]] = []
omit_fs_rows: List[Dict[str, str]] = []
omit_fs_cspp_rows: List[Dict[str, str]] = []
fs_cspp_path = eng_dir / "db_bench-fillseq-cspp.log"
fs_cspp_rows: List[Dict[str, str]] = []
if fs_cspp_path.is_file():
fs_cspp_rows = parse_db_bench(
fs_cspp_path.read_text(encoding="utf-8", errors="replace")
)
if eng == "rocksdb-v8.10":
# Reuse readseq×3 from the main fill* suites (no separate omit/scan pass).
omit_fr_rows = _readseq_rows(fr_rows)
omit_fs_rows = _readseq_rows(db_rows)
omit_fs_cspp_rows = omit_fs_rows
else:
omit_fr = eng_dir / "db_bench-fillrandom-omit.log"
omit_fs = eng_dir / "db_bench-fillseq-omit.log"
omit_fs_cspp = eng_dir / "db_bench-fillseq-cspp-omit.log"
if omit_fr.is_file():
omit_fr_rows = parse_db_bench(
omit_fr.read_text(encoding="utf-8", errors="replace")
Expand All @@ -875,6 +961,10 @@ def _load_engine_logs(log_root: Path) -> Dict[str, Dict[str, Any]]:
omit_fs_rows = parse_db_bench(
omit_fs.read_text(encoding="utf-8", errors="replace")
)
if omit_fs_cspp.is_file():
omit_fs_cspp_rows = parse_db_bench(
omit_fs_cspp.read_text(encoding="utf-8", errors="replace")
)
skiplist_rows: List[Dict[str, str]] = []
cspp_rows: List[Dict[str, str]] = []
offset_skiplist_rows: List[Dict[str, str]] = []
Expand All @@ -893,8 +983,10 @@ def _load_engine_logs(log_root: Path) -> Dict[str, Dict[str, Any]]:
result[eng] = {
"db_bench": db_rows,
"db_bench_fillrandom": fr_rows,
"db_bench_fillseq_cspp": fs_cspp_rows,
"db_bench_omit_fillrandom": omit_fr_rows,
"db_bench_omit_fillseq": omit_fs_rows,
"db_bench_omit_fillseq_cspp": omit_fs_cspp_rows,
"memtablerep_skiplist": skiplist_rows,
"memtablerep_cspp": cspp_rows,
"memtablerep_OffsetSkipList": offset_skiplist_rows,
Expand Down Expand Up @@ -1117,6 +1209,15 @@ def _build_per_engine_details(engines_data: Dict[str, Any]) -> str:
detail_parts.append(
_table(db_bench_detail_keys, data["db_bench"], db_bench_detail_keys)
)
if data.get("db_bench_fillseq_cspp"):
detail_parts.append("<h4>db_bench (fillseq suite, CSPP)</h4>")
detail_parts.append(
_table(
db_bench_detail_keys,
data["db_bench_fillseq_cspp"],
db_bench_detail_keys,
)
)
if eng in TOPLING_ENGINES:
if data.get("db_bench_omit_fillrandom"):
detail_parts.append(
Expand All @@ -1140,12 +1241,23 @@ def _build_per_engine_details(engines_data: Dict[str, Any]) -> str:
db_bench_detail_keys,
)
)
if data.get("db_bench_omit_fillseq_cspp"):
detail_parts.append(
"<h4>db_bench omit lazy-load (fillseq CSPP DB)</h4>"
)
detail_parts.append(
_table(
db_bench_detail_keys,
data["db_bench_omit_fillseq_cspp"],
db_bench_detail_keys,
)
)
if data.get("memtablerep_skiplist"):
detail_parts.append("<h4>memtablerep_bench (skiplist)</h4>")
detail_parts.append(
_table(
["benchmark", "metric", "value"],
data["memtablerep_skiplist"],
_fold_memtablerep_usop(data["memtablerep_skiplist"]),
["benchmark", "metric", "value"],
)
)
Expand All @@ -1154,7 +1266,7 @@ def _build_per_engine_details(engines_data: Dict[str, Any]) -> str:
detail_parts.append(
_table(
["benchmark", "metric", "value"],
data["memtablerep_cspp"],
_fold_memtablerep_usop(data["memtablerep_cspp"]),
["benchmark", "metric", "value"],
)
)
Expand All @@ -1165,7 +1277,7 @@ def _build_per_engine_details(engines_data: Dict[str, Any]) -> str:
detail_parts.append(
_table(
["benchmark", "metric", "value"],
data["memtablerep_OffsetSkipList"],
_fold_memtablerep_usop(data["memtablerep_OffsetSkipList"]),
["benchmark", "metric", "value"],
)
)
Expand Down Expand Up @@ -1208,22 +1320,30 @@ def emit(args: argparse.Namespace) -> None:
"db_bench-fillrandom.log",
"db_bench-fillrandom-omit.log",
"db_bench-fillseq-omit.log",
"db_bench-fillseq-cspp.log",
"db_bench-fillseq-cspp-omit.log",
"memtablerep_bench-skiplist.log",
"memtablerep_bench-cspp.log",
"memtablerep_bench-OffsetSkipList.log",
"shm_usage.txt",
"shm_usage-fillrandom.txt",
"shm_usage-fillseq.txt",
"shm_usage-fillseq-cspp.txt",
"rss_usage-fillrandom.txt",
"rss_usage-fillseq.txt",
"rss_usage-fillrandom-omit.txt",
"rss_usage-fillseq-omit.txt",
"rss_usage-fillseq-cspp.txt",
"rss_usage-fillseq-cspp-omit.txt",
"statm_series-fillrandom.txt",
"statm_series-fillseq.txt",
"statm_series-fillseq-cspp.txt",
"time-fillrandom.txt",
"time-fillseq.txt",
"time-fillrandom-omit.txt",
"time-fillseq-omit.txt",
"time-fillseq-cspp.txt",
"time-fillseq-cspp-omit.txt",
"bench_settings.txt",
*YAML_USED_NAMES,
"engine-meta.json",
Expand Down Expand Up @@ -1360,12 +1480,18 @@ def emit(args: argparse.Namespace) -> None:
"db_bench_fillrandom": engines_data.get(eng, {}).get(
"db_bench_fillrandom", []
),
"db_bench_fillseq_cspp": engines_data.get(eng, {}).get(
"db_bench_fillseq_cspp", []
),
"db_bench_omit_fillrandom": engines_data.get(eng, {}).get(
"db_bench_omit_fillrandom", []
),
"db_bench_omit_fillseq": engines_data.get(eng, {}).get(
"db_bench_omit_fillseq", []
),
"db_bench_omit_fillseq_cspp": engines_data.get(eng, {}).get(
"db_bench_omit_fillseq_cspp", []
),
"shm_usage": engines_data.get(eng, {}).get("shm_usage")
or {wl: None for wl in SHM_WORKLOADS},
"rss_usage": rss_by_eng.get(eng)
Expand Down Expand Up @@ -1457,12 +1583,17 @@ def _render_latest_section(
eng_rss_raw = engines.get(e, {}).get("rss_usage") or {}
rss_data[e] = {wl: v for wl, v in eng_rss_raw.items()}
if e in ROCKSDB_ENGINES:
for src, dst in (("fillrandom", "fillrandom-omit"), ("fillseq", "fillseq-omit")):
for src, dst in (
("fillrandom", "fillrandom-omit"),
("fillseq", "fillseq-omit"),
("fillseq-cspp", "fillseq-cspp-omit"),
):
if rss_data[e].get(dst) is None and rss_data[e].get(src) is not None:
rss_data[e][dst] = rss_data[e][src]
if (
rss_data[e].get("fillrandom-omit") is not None
or rss_data[e].get("fillseq-omit") is not None
or rss_data[e].get("fillseq-cspp-omit") is not None
):
rss_derived_engines.add(e)
if pages_root is not None:
Expand All @@ -1484,6 +1615,26 @@ def _render_latest_section(
omit_fs_table = build_lazy_load_compare(
{e: engines.get(e, {}).get("db_bench_omit_fillseq") or [] for e in LAZY_ENGINES}
)
fs_cspp_compare = ""
omit_fs_cspp_block = ""
if _has_topling_fillseq_cspp(engines):
fs_cspp_compare = (
"<h3>Comparison: db_bench fillseq suite (CSPP) (perf)</h3>\n"
'<p class="meta">Same as fillrandom, except ToplingDB fillseq uses CSPP. '
"RocksDB fillseq benefits from shortcuts: <code>trivial_move</code> on "
"non-overlapping SSTs; <code>refit level</code> skips zstd on L6: faster, "
"larger size. Seqno-zeroing compact still runs.</p>\n"
f"{build_db_bench_compare(_db_bench_by_engine(engines, topling_key='db_bench_fillseq_cspp'))}"
)
omit_fs_cspp_block = (
"<h4>scan-omit-value on data from fillseq (CSPP)</h4>\n"
+ build_lazy_load_compare(
{
e: engines.get(e, {}).get("db_bench_omit_fillseq_cspp") or []
for e in LAZY_ENGINES
}
)
)

t_eng = engines.get("zipkeyonly") or {}
r_eng = engines.get("rocksdb-v8.10") or {}
Expand Down Expand Up @@ -1533,12 +1684,14 @@ def _render_latest_section(
<h3>Comparison: db_bench fillseq suite (perf)</h3>
<p class="meta">Same as fillrandom, except ToplingDB fillseq uses OffsetSkipList (fillrandom still uses CSPP). RocksDB fillseq benefits from shortcuts: <code>trivial_move</code> on non-overlapping SSTs; <code>refit level</code> skips zstd on L6: faster, larger size. Seqno-zeroing compact still runs.</p>
{db_compare_fs}
{fs_cspp_compare}
<h3>Lazy load demo (scan; RocksDB v8.10 baseline)</h3>
<p class="meta">zipkey* needs an extra omit pass: scan_omit_key/value enables lazy value load (no real value load). RocksDB has no lazy load, so the baseline is readseq×3 already present in the main fill* suite (no extra pass). RocksDB nextwithkey cells are =readseq. master omitted here (v8.10 is the stronger RocksDB baseline). {_color_sign()}.</p>
<h4>scan-omit-value on data from fillrandom</h4>
{omit_fr_table}
<h4>scan-omit-value on data from fillseq</h4>
{omit_fs_table}
{omit_fs_cspp_block}
<h3>memtablerep_bench: OffsetSkipList and CSPP vs skiplist</h3>
<p class="meta">Focus: {_hl('OffsetSkipList / CSPP (ToplingDB)', 'faster')} vs skiplist. Baseline = RocksDB v8.10 skiplist. {_color_sign()}.</p>
{memtablerep_compare}
Expand Down
Loading