From 2ec0fc99cc1f6e6ca082ae07b1e34f7503cbf9b2 Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Mon, 19 Feb 2024 22:54:10 +0900 Subject: [PATCH] revset: ad-hoc optimization for range queries containing unwanted wanted heads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In my linux stable mirror, this makes the default log revset evaluation super fast. immutable_heads(), if configured properly, includes many historical branch heads which are also the visible heads. revsets/immutable_heads().. --------------------------- 0 12.27 117.1±0.77m 3 1.00 9.5±0.08m --- cli/testing/bench-revsets-git.txt | 2 ++ lib/src/default_index/revset_engine.rs | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cli/testing/bench-revsets-git.txt b/cli/testing/bench-revsets-git.txt index 602afa143e..ff474c4708 100644 --- a/cli/testing/bench-revsets-git.txt +++ b/cli/testing/bench-revsets-git.txt @@ -16,6 +16,8 @@ v2.39.0::v2.40.0 # Tags and branches tags() branches() +# Local changes +(tags() | remote_branches()).. # Intersection of range with a small subset tags() & ::v2.40.0 v2.39.0 & ::v2.40.0 diff --git a/lib/src/default_index/revset_engine.rs b/lib/src/default_index/revset_engine.rs index e186e60fbd..f5644c6e9a 100644 --- a/lib/src/default_index/revset_engine.rs +++ b/lib/src/default_index/revset_engine.rs @@ -764,8 +764,16 @@ impl<'index> EvaluationContext<'index> { } => { let root_set = self.evaluate(roots)?; let root_positions = root_set.positions(index).collect_vec(); + // Pre-filter heads so queries like 'immutable_heads()..' can + // terminate early. immutable_heads() usually includes some + // visible heads, which can be trivially rejected. let head_set = self.evaluate(heads)?; - let head_positions = head_set.positions(index).collect_vec(); + let head_positions = difference_by( + head_set.positions(index), + root_positions.iter().copied(), + |pos1, pos2| pos1.cmp(pos2).reverse(), + ) + .collect_vec(); if generation == &GENERATION_RANGE_FULL { Ok(Box::new(RevWalkRevset::new(move |index| { Box::new(index.walk_revs(&head_positions, &root_positions))