diff --git a/core/dr-catalog/examples/catalog_bench.rs b/core/dr-catalog/examples/catalog_bench.rs index b39d54f..3445995 100644 --- a/core/dr-catalog/examples/catalog_bench.rs +++ b/core/dr-catalog/examples/catalog_bench.rs @@ -1,6 +1,6 @@ //! What the catalog's routine reads cost on a real library, off the GUI. //! -//! cargo run --release -p dr-catalog --example catalog_bench -- CATALOG.sqlite [FACES_DIR] +//! cargo run --release -p dr-catalog --example catalog_bench -- CATALOG.sqlite [FACES_DIR] [--remote PEER.sqlite] //! //! Times `Catalog::open` — which every worker thread pays, including the //! develop view's fetch of each original and each neighbour it prefetches — @@ -13,6 +13,13 @@ //! count), whose `library` module is private; their SQL is spelled here as //! it is spelled there, and has to be kept in step by hand. //! +//! `--remote` also times a merge with another device's catalog — the +//! server snapshot — which is the pass where the two disagree: faces one +//! side found and the other did not, boxes that moved. The merge with a copy +//! of itself matches every face by its box and never reaches that work. The +//! first of its runs writes what the peer brought; the rest are the steady +//! state, so compare two builds from two fresh copies of one catalog. +//! //! The figures are for reading side by side before and after a change; they //! are not a gate. Compare the `cpu` column when the machine is busy. The //! answers are printed too, so two builds can be checked for agreeing. @@ -23,7 +30,15 @@ use std::time::{Duration, Instant}; use dr_catalog::{keywords, rating, schema, Catalog}; fn main() { - let args: Vec = std::env::args().skip(1).collect(); + let mut args: Vec = std::env::args().skip(1).collect(); + let peer = args.iter().position(|a| a == "--remote").map(|at| { + let path = args.get(at + 1).map(PathBuf::from).unwrap_or_else(|| { + eprintln!("--remote needs a catalog"); + std::process::exit(2); + }); + args.drain(at..at + 2); + path + }); let Some(path) = args.first().map(PathBuf::from) else { eprintln!("usage: catalog_bench CATALOG.sqlite"); std::process::exit(2); @@ -117,6 +132,19 @@ fn main() { let _ = std::fs::remove_file(&scratch); let _ = std::fs::remove_file(&remote); + if let Some(peer) = &peer { + // A copy, so nothing the merge does to its input reaches the file + // the caller named. + std::fs::copy(peer, &remote).unwrap(); + let mut first = None; + time("merge_remote_catalog (--remote)", 5, || { + let report = catalog.merge_remote_catalog(&remote).unwrap(); + first.get_or_insert(report); + }); + println!(" first pass: {first:?}"); + let _ = std::fs::remove_file(&remote); + } + // The face half of a sync pass, against a copy of the face store: both // directions in the steady state, where nothing is new either way. if let Some(faces) = args.get(1).map(PathBuf::from) {