From 2226d543f9145e6ff7582e89627180f719146b87 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sat, 26 Sep 2026 12:30:30 -0400 Subject: [PATCH] Time a develop landing in catalog_bench Landing on a photograph in develop opens the catalog once to fetch the original and once more per prefetched neighbour to ask whether the cache already holds it: five opens, each running the whole backfill. The bench timed one open but not the landing, so the cost of the shape was not visible and a fix to it could not be measured. Two figures now, both against an empty cache so the question is asked the same way whatever the answer: the five-open shape the app had, and the two-open shape where the prefetch worker keeps one connection for its batch. On a copy of the reference catalog (23,582 images) under load, the five-open landing costs ~80 ms of CPU. --- core/dr-catalog/examples/catalog_bench.rs | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/core/dr-catalog/examples/catalog_bench.rs b/core/dr-catalog/examples/catalog_bench.rs index fda9265..b39d54f 100644 --- a/core/dr-catalog/examples/catalog_bench.rs +++ b/core/dr-catalog/examples/catalog_bench.rs @@ -36,6 +36,49 @@ fn main() { drop(Catalog::open(&path).unwrap()); }); + // One develop landing, in the two shapes the app has had. Five opens is + // what `fetch_original` and a `holds_original` per prefetched neighbour + // cost when each asked on a connection of its own; two is the fetch plus + // one connection the prefetch worker keeps for its batch's row checks. + // Five images from the library, against an empty cache: the question is + // asked the same way whatever the answer. + let images: Vec = { + let c = Catalog::open(&path).unwrap(); + let mut stmt = c + .connection() + .prepare("SELECT id FROM images ORDER BY id LIMIT 5 OFFSET 1000") + .unwrap(); + let ids = stmt + .query_map([], |r| r.get::<_, i64>(0)) + .unwrap() + .map(|id| dr_types::ImageId(id.unwrap() as u64)) + .collect(); + ids + }; + let cache_dir = path.with_extension("bench-cache"); + let budget = dr_catalog::Budget::default(); + time("landing: 5 opens (fetch + 4 row checks)", 20, || { + let store = dr_catalog::Cache::open(&cache_dir, budget).unwrap(); + let c = Catalog::open(&path).unwrap(); + let _ = store.load(c.connection(), images[0], 0).unwrap(); + for &image in &images[1..] { + let store = dr_catalog::Cache::open(&cache_dir, budget).unwrap(); + let c = Catalog::open(&path).unwrap(); + let _ = store.holds_original(c.connection(), image); + } + }); + time("landing: 2 opens (fetch + held row checks)", 20, || { + let store = dr_catalog::Cache::open(&cache_dir, budget).unwrap(); + let c = Catalog::open(&path).unwrap(); + let _ = store.load(c.connection(), images[0], 0).unwrap(); + let held = Catalog::open(&path).unwrap(); + for &image in &images[1..] { + let store = dr_catalog::Cache::open(&cache_dir, budget).unwrap(); + let _ = store.holds_original(held.connection(), image); + } + }); + let _ = std::fs::remove_dir_all(&cache_dir); + let catalog = Catalog::open(&path).unwrap(); let conn = catalog.connection(); time("schema::backfill (all steps)", 20, || {