feat: harden storage, schema persistence, fair benches, fix wire crash
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled

Core storage: hash MemTable, WAL group commit, L0 compaction rebuild,
reader-writer lock, and a global StorageGate so HTTP workers and TCP
share the LSM safely under multi-thread access.

Schema: durable CREATE/ALTER/DROP under _schema:tables:* with full LSM
restore on open. Executor types/values/schema split into query/exec/.

Wire protocol: switch default MM to ARC — ORC cycle collector segfaulted
after ~20 async INSERTs. Fair multi-tier benchmarks (SQLite/HTTP/wire/PG)
and honesty docs for mixed-tier comparisons.
This commit is contained in:
2026-07-18 16:55:50 +03:00
parent aa4ab11210
commit 8db5cfe7e1
31 changed files with 3131 additions and 797 deletions
+96 -63
View File
@@ -1,110 +1,143 @@
#!/usr/bin/env python3
"""Generate a real comparison report from BaraDB and PostgreSQL benchmark results."""
"""Generate benchmark reports.
Modes:
python3 benchmarks/generate_report.py # legacy PG vs embedded (with warning)
python3 benchmarks/generate_report.py --fair # multi-tier fair report from fair_bench.py
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
def format_ops(ops_per_sec):
def format_ops(ops_per_sec: float) -> str:
if ops_per_sec >= 1_000_000:
return f"{ops_per_sec/1_000_000:.2f}M"
elif ops_per_sec >= 1_000:
if ops_per_sec >= 1_000:
return f"{ops_per_sec/1_000:.2f}K"
else:
return f"{ops_per_sec:.2f}"
return f"{ops_per_sec:.2f}"
def format_time(seconds):
def format_time(seconds: float) -> str:
if seconds < 0.001:
return f"{seconds*1000:.3f}ms"
elif seconds < 1:
if seconds < 1:
return f"{seconds*1000:.1f}ms"
else:
return f"{seconds:.3f}s"
return f"{seconds:.3f}s"
def main():
root = Path(__file__).parent
def gen_fair(out: Path) -> int:
fair_path = ROOT / "fair_benchmark_results.json"
if not fair_path.exists():
print("Missing fair_benchmark_results.json — run: python3 benchmarks/fair_bench.py")
return 1
payload = json.loads(fair_path.read_text())
# fair_bench already writes FAIR_COMPARISON.md; re-emit for consistency
sys.path.insert(0, str(ROOT / "benchmarks"))
from fair_bench import write_markdown # type: ignore
with open(root.parent / "benchmark_results.json") as f:
write_markdown(payload, out)
return 0
def gen_legacy() -> int:
"""Legacy report: PG client-server vs BaraDB *embedded* — always labeled unfair."""
bara_path = ROOT / "benchmark_results.json"
pg_path = ROOT / "pg_benchmark_results.json"
if not bara_path.exists() or not pg_path.exists():
print("Need benchmark_results.json and pg_benchmark_results.json")
print(" nimble bench && python3 benchmarks/pg_bench.py")
return 1
with open(bara_path) as f:
bara = json.load(f)
with open(root.parent / "pg_benchmark_results.json") as f:
with open(pg_path) as f:
pg = json.load(f)
bara_map = {r["name"]: r for r in bara["results"]}
pg_map = {k: v for k, v in pg.items()}
# pg_bench may write list or dict
if isinstance(pg, dict) and "results" in pg:
pg_map = {r["name"]: r for r in pg["results"]}
elif isinstance(pg, list):
pg_map = {r["name"]: r for r in pg}
else:
pg_map = pg # old flat dict by name
report = []
report.append("# BaraDB vs PostgreSQL — Real Benchmark Results")
report.append("# BaraDB vs PostgreSQL — LEGACY (mixed tiers)")
report.append("")
report.append("Generated from actual execution on:")
report.append(f"- **CPU:** AMD Ryzen 9 5900X")
report.append(f"- **PostgreSQL:** 15.18 (local)")
report.append(f"- **BaraDB:** git `{bara['gitSha']}`")
report.append("> ⚠️ **Unfair comparison warning**")
report.append(">")
report.append("> PostgreSQL numbers include **client-server** round-trips.")
report.append("> BaraDB numbers are **in-process embedded** LSM (no network, no SQL).")
report.append("> Use `python3 benchmarks/fair_bench.py` + `--fair` for honest tiers.")
report.append("")
report.append("## Methodology")
report.append(f"- **BaraDB git:** `{bara.get('gitSha', 'unknown')}`")
report.append("")
report.append("- PostgreSQL: single-row INSERT/SELECT via psycopg2 (client-server overhead included)")
report.append("- BaraDB: in-process Nim code (no network overhead)")
report.append("- Same dataset sizes for both systems")
report.append("")
report.append("## Results")
report.append("")
report.append("| Test | PostgreSQL | BaraDB | Speedup |")
report.append("|------|-----------|--------|---------|")
report.append("| Test | PostgreSQL (C/S) | BaraDB (embedded) | Ratio (not a fair speedup) |")
report.append("|------|------------------|-------------------|----------------------------|")
rows = [
("KV Write (100K)", pg_map.get("KV Write"), bara_map.get("LSM-Write")),
("KV Read (100K)", pg_map.get("KV Read"), bara_map.get("LSM-Read")),
("BTree Insert (100K)", pg_map.get("BTree Insert"), bara_map.get("BTree-Insert")),
("BTree Get (100K)", pg_map.get("BTree Get"), bara_map.get("BTree-Get")),
("BTree Scan (1K ranges)", pg_map.get("BTree Scan"), bara_map.get("BTree-Scan")),
("FTS Index (10K docs)", pg_map.get("FTS Index"), bara_map.get("FTS-Index")),
("FTS Search (1K queries)", pg_map.get("FTS Search"), bara_map.get("FTS-Search")),
("KV Write", pg_map.get("KV Write"), bara_map.get("LSM-Write")),
("KV Read", pg_map.get("KV Read"), bara_map.get("LSM-Read")),
("BTree Insert", pg_map.get("BTree Insert"), bara_map.get("BTree-Insert")),
("BTree Get", pg_map.get("BTree Get"), bara_map.get("BTree-Get")),
("BTree Scan", pg_map.get("BTree Scan"), bara_map.get("BTree-Scan")),
("FTS Index", pg_map.get("FTS Index"), bara_map.get("FTS-Index")),
("FTS Search", pg_map.get("FTS Search"), bara_map.get("FTS-Search")),
]
total_pg_time = 0
total_bara_time = 0
for name, p, b in rows:
if p is None or b is None:
continue
pg_ops = p["opsPerSec"]
ba_ops = b["opsPerSec"]
ratio = ba_ops / pg_ops
winner = "BaraDB" if ratio > 1 else "PostgreSQL"
total_pg_time += p["seconds"]
total_bara_time += b["seconds"]
ratio = ba_ops / pg_ops if pg_ops else 0
report.append(
f"| {name} | {format_ops(pg_ops)}/s ({format_time(p['seconds'])}) | "
f"{format_ops(ba_ops)}/s ({format_time(b['seconds'])}) | "
f"{ratio:.1f}x ({winner}) |"
f"{ratio:.1f}x (mixed tiers) |"
)
report.append("")
report.append("## Summary")
report.append("## Prefer fair suite")
report.append("")
report.append(f"- **Total PostgreSQL time:** {total_pg_time:.3f}s")
report.append(f"- **Total BaraDB time:** {total_bara_time:.3f}s")
overall = total_pg_time / total_bara_time
report.append(f"- **Overall speedup:** BaraDB is **{overall:.1f}x faster**")
report.append("")
report.append("## Notes")
report.append("")
report.append("- PostgreSQL includes network round-trip and SQL parsing overhead per operation.")
report.append("- BaraDB runs in-process with zero serialization/network cost.")
report.append("- For embedded/single-node use cases, BaraDB shows significant advantage.")
report.append("- PostgreSQL FTS Search with GIN index outperforms BaraDB on query throughput.")
report.append("- PostgreSQL excels at durability, replication, and complex ACID transactions.")
report.append("```bash")
report.append("nim c -d:release -r benchmarks/bench_all.nim")
report.append("python3 benchmarks/fair_bench.py")
report.append("python3 benchmarks/generate_report.py --fair")
report.append("```")
report.append("")
output = "\n".join(report)
print(output)
out = ROOT / "benchmarks" / "REAL_COMPARISON.md"
out.write_text("\n".join(report) + "\n")
print(f"Wrote {out} (legacy mixed-tier; see warning banner)")
return 0
with open(root / "REAL_COMPARISON.md", "w") as f:
f.write(output)
print(f"\nReport saved to {root / 'REAL_COMPARISON.md'}")
def main():
ap = argparse.ArgumentParser()
ap.add_argument(
"--fair",
action="store_true",
help="Emit multi-tier fair report from fair_benchmark_results.json",
)
ap.add_argument(
"-o",
"--output",
default=str(ROOT / "benchmarks" / "FAIR_COMPARISON.md"),
help="Output path for --fair mode",
)
args = ap.parse_args()
if args.fair:
return gen_fair(Path(args.output))
return gen_legacy()
if __name__ == "__main__":
main()
sys.exit(main())