Add hash → block number index + lookup API#72
Conversation
New CF_BLOCK_HASHES maps dataset_id||hash to a block number for sub-ms
lookups, updated on ingest/fork/retention/delete (EVM-only), untouched by
compaction. delete_dataset now uses per-chunk txs to bound memory. Adds
find_block_by_hash and GET /datasets/{id}/hashes/{hash}/block. No backfill:
old chunks 404 until they age out.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
79ec945 to
ae9883d
Compare
Clear the dataset's whole hash index with one range tombstone over its CF_BLOCK_HASHES prefix, then delete all chunk metadata and the label in a single transaction. The range-delete stays outside the tx (RocksDB forbids delete_range inside a transaction); a crash between the two leaves chunks without index entries, which 404 until re-indexed, not corruption. Keeps memory bounded (no delete_cf per block) while making the metadata deletion all-or-nothing again, and re-takes the optimistic label lock. Adds BlockHashIndexKey::dataset_range for the prefix bounds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Heads-up: dogfooding this branch as
|
The hash -> block number index is now opt-in, off by default, so it can ship dark and be enabled per deployment. Only the write side honours the flag. `unindex_block_hashes` deliberately checks neither the flag nor the dataset kind: entries written while the flag was on must still be reclaimed when their chunk is pruned, or turning it off would strand them, resolving hashes to blocks that no longer exist and growing without bound. It instead probes whether the dataset holds any index entries at all - one prefix seek, no blocks table read - so an indexed dataset drains as retention rolls its chunks off, and the never-indexed case stays cheap. The flag rides DatabaseSettings -> Database -> Tx, defaulting to false on Tx::new. That default suits every transaction that never ingests a chunk (dataset creation, deletion, compaction), so only update_dataset turns it on. Tx::run carries it across optimistic-retry restarts. Dropping find_label_for_update from unindex_block_hashes also removes a redundant exclusive label read per chunk - DatasetUpdate::new already takes that lock for every update_dataset, and both un-index callers go through it. Also formats db.rs, which was left violating the repo's `trailing_comma = "Never"` by the previous commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
delete_range_cf is not officially supported on OptimisticTransactionDB (facebook/rocksdb#4812, rust-rocksdb#839 - same finding as PR #79), so purge the dataset's CF_BLOCK_HASHES prefix with bounded write batches of point deletes instead. Stays outside the metadata transaction, so crash semantics are unchanged: index gone before metadata -> hashes 404, retried next startup. Also trim the doc comments across the index code down to their load-bearing parts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Lets consumers resolve a bare block hash to its block number. Today the hash is only buried inside each chunk's Arrow
hashcolumn, so the only way to look it up is a linear scan (~0.1–0.6s, and worse as retention grows). This adds a proper index for an O(1) point lookup, plus an HTTP endpoint to use it.The motivation: services that receive a raw hash (from logs, fork events, external sources) need to map it back to a block number to keep working with the standard
/streamAPIs.What's new
hash → block numberper dataset, kept up to date automatically as chunks are ingested, forked, and pruned. Enabled for EVM datasets for now (easy to extend to other chains later).GET /datasets/{id}/hashes/{hash}/block, returning{number, hash}or404if the hash isn't found.--block-hash-index. Turning it back off stops new writes and lets existing entries drain as their chunks are pruned.Rollout notes
404until those chunks roll off via retention. Worth calling out in release notes.BLOCK_HASHEScolumn family is created at first open regardless of the flag, and RocksDB requires all existing column families to be listed when opening read-write — binaries older than this change will fail to start against an upgraded DB. Roll back only to a build that declares the new CF, or drop it manually first.Testing
Unit tests in
sqd-storagecover ingest, fork, retention, dataset deletion, and confirm compaction leaves the index intact. Manual HTTP smoke against a live hotblocks instance still recommended.🤖 Generated with Claude Code