From dff76228f103f36118f19c4492e20cd46f234fb8 Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 8 Nov 2026 19:40:54 +0000 Subject: access: read once what rules read at the same heads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bench_screening shows judging at about 17 µs of a change's 25: some two and a half reads at its heads (the policy, bans, its node's member entry, whether there is a registry, the sealed declarations), each costing as much as working out what the heads cover. Screening judges most of a batch at the same heads, and those reads are the same for every change judged there. Keep them (rules::Reads), by node and by user where they depend on one, while the heads stay the same; screening keeps one for a batch. What the heads hold doesn't change as the document takes changes, so nothing goes stale but by other heads. The benchmark breakdown shows judging so and afresh. --- src/access/screen.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/access/screen.rs') diff --git a/src/access/screen.rs b/src/access/screen.rs index 690e032..1c6c8c7 100644 --- a/src/access/screen.rs +++ b/src/access/screen.rs @@ -384,6 +384,8 @@ pub(crate) fn apply( // What the accepted, not applied yet, touch: a change making a map at one of these // paths is judged with them in (`rules`' maps made where there are none). let mut unapplied: BTreeSet = BTreeSet::new(); + // What the rules read at the heads judged at, kept while they stay the same. + let mut reads = rules::Reads::default(); for (index, change) in ready.iter().enumerate() { let hash = change.hash(); let committer = committers[index].as_deref(); @@ -464,7 +466,7 @@ pub(crate) fn apply( let seen_at: Vec = seen_at.into_iter().collect(); let root = change.deps().is_empty(); let judged = if judging || root { - rules::judge( + rules::judge_reading( doc, epoch, &rules::Change { @@ -476,6 +478,7 @@ pub(crate) fn apply( paths: &paths[index], ops: &ops[index], }, + &mut reads, ) } else { Ok(()) -- cgit v1.3.1