3.1 KiB
+++
title = "SQLite cache for list performance"
priority = 3
status = "todo"
ticket_type = "feature"
dependencies = []
+++
Add an optional SQLite cache in .nbd/cache.db to accelerate nbd list and nbd ready for large ticket stores.
Motivation
list_tickets currently does O(n) file reads on every call. For stores with hundreds of tickets this is measurably slow. A SQLite cache avoids re-reading unchanged files by comparing file modification times (mtimes).
Approach
Crate dependency
Add turso to Cargo.toml (file-based SQLite, no sync feature needed):
turso = "0.4.3"
Note: Turso requires tokio. The existing
async-stdruntime innbdmust be replaced withtokio(or a compatibility shim used). Recommendation: switch#[async_std::main]to#[tokio::main]and updateCargo.tomlaccordingly.
store.rs additions
New async function open_cache(root: &Path) -> Result<turso::Connection>:
- Opens (or creates)
.nbd/cache.dbviaturso::Builder::new_local(path).build().await?. - Runs a migration:
CREATE TABLE IF NOT EXISTS tickets (id TEXT PRIMARY KEY, json TEXT NOT NULL, mtime INTEGER NOT NULL).
New function list_tickets_cached(root: &Path) -> Result<Vec<Ticket>>:
- Open cache via
open_cache. - Read directory listing to get file names and mtimes.
- For each file: query the DB (
connection.query(...).await?) for a row with matching mtime; if found, use cached JSON; otherwise read file, parse, and upsert withconnection.execute(...).await?. - Delete DB rows for IDs no longer on disk.
- Return deserialized tickets sorted by priority desc.
Keep existing list_tickets as the non-cached fallback. cmd_list and cmd_ready use list_tickets_cached, falling back to list_tickets on error.
Turso API reference
- Open local file DB:
turso::Builder::new_local("path/to/file.db").build().await? - Execute (INSERT/UPDATE/DELETE):
conn.execute("SQL", params).await? - Query rows:
let mut rows = conn.query("SQL", params).await? - Iterate rows:
while let Some(row) = rows.next().await? { row.get_value(0)? }
Migration strategy
- The cache is always optional. If
cache.dbcan't be opened or any cache operation fails, fall back tolist_tickets(log a warning to stderr). - The cache is never the source of truth — the JSON files are. The cache is always reconstructable by deleting
.nbd/cache.db.
Decision point
Decide whether to enable the cache unconditionally or gate it behind a flag (--cache / NBD_CACHE=1). Recommendation: enable by default once the feature is stable.
Tests
- Unit test: cache hit returns same data as direct file read.
- Unit test: cache miss (mtime changed) re-reads the file.
- Unit test: deleted ticket is evicted from cache.
- Performance test (optional): benchmark 1000-ticket list with and without cache.
Files touched
Cargo.toml— addturso, replaceasync-stdwithtokiosrc/main.rs— switch to#[tokio::main]src/store.rs—open_cache,list_tickets_cachedsrc/tests.rs— cache unit testsdocs/ARCHITECTURE.md— document the cache layer