v0.2.1 — bounded query performance patch
A performance patch for the local-first event store: queries are now answered by a bounded newest-first index merge instead of collecting every matching event before applying the limit.
What changed
Store.queryopens one reverse cursor per index prefix (per author / kind / tag value), parks each on its newest in-range key, and k-way merges on the indexes' order-preserving[time][id]key suffix — yielding results globally newest-first and stopping atlimit. Query cost is now proportional to the events returned, not to the total matching history. (#33, #35)- The store benchmark now measures the hottest client shape — a 20-author, kind-1, 500-note home feed — alongside the single-author profile query. (#34)
Numbers
BENCH_N=100000 zig build bench -Doptimize=ReleaseFast (100k stored events, warm cache, Apple M2 Pro):
| Query | v0.2.0 | v0.2.1 |
|---|---|---|
| Home feed — 20 authors, kind 1, limit 500 | ~25.8 ms | ~0.28 ms (~93×) |
| Profile — 1 author, limit 500 | ~0.67 ms | ~0.24 ms (~2.8×) |
Ordering and filter semantics are unchanged (created_at desc, id desc; Filter.matches still validates every result) — the full existing test suite passes untouched, with new tests pinning cross-stream tie-breaks and tag key-region edge cases. 109 tests passing, CI green on Linux and macOS.
Install
zig fetch --save https://github.com/zig-nostr/nostr/archive/refs/tags/v0.2.1.tar.gzWhat's next
Milestone A5: a native signer with NIP-49 at-rest encryption and a NIP-46 bunker (remote signing with per-request approval).