Skip to content
Snippets Groups Projects
Commit 83091c14 authored by Georges Racinet's avatar Georges Racinet
Browse files

rust-index: avoid some cloning in find_gca_candidates()

Instead of keeping the information whether the current revision is
poisoned on `current_seen`, we extract it as a boolean.

This also allows us to simplify the explanation of `seen[r].is_poisoned()`,
as the exceptional case where it is poisoned right after `r` has been
determined to be a solution does no longer exist.
parent 89ce6a49
No related branches found
No related tags found
2 merge requests!737Improvements to the Rust index's performance,!708Implement pure rust revlog Index
......@@ -1091,10 +1091,11 @@
// will give a result or trigger inspection of other revisions
let mut interesting = revcount;
// poisoned means that the rev is already known to be a common
// ancestor, BUT when first encountered in the loop, not a maximal
// common ancestor.
// The algorithm works on a vector of bit sets, indexed by revision
// numbers and iterated on reverse order.
// An entry in this vector is poisoned if and only if the corresponding
// revision is a common, yet not maximal ancestor.
// The principle of the algorithm is as follows:
// For a revision `r`, when entering the loop, `seen[r]` is either
// poisoned or the sub set of `revs` of which `r` is an ancestor.
......@@ -1097,9 +1098,9 @@
// The principle of the algorithm is as follows:
// For a revision `r`, when entering the loop, `seen[r]` is either
// poisoned or the sub set of `revs` of which `r` is an ancestor.
// In the latter case if it "is" `revs`, we have a maximal common
// ancestor.
// In this sub set is full, then `r` is a solution and its parents
// have to be poisoned.
//
// At each iteration, the bit sets of the parents are updated by
// union with `seen[r]`.
......@@ -1114,9 +1115,9 @@
// - Early return in case it is detected that one of the incoming revs
// is a common ancestor of all of them.
while current_rev.0 >= 0 && interesting > 0 {
let mut current_seen = seen[current_rev.0 as usize].clone();
let current_seen = seen[current_rev.0 as usize].clone();
if current_seen.is_empty() {
current_rev = Revision(current_rev.0 - 1);
continue;
}
......@@ -1118,9 +1119,10 @@
if current_seen.is_empty() {
current_rev = Revision(current_rev.0 - 1);
continue;
}
if !current_seen.is_poisoned() {
let mut poison = current_seen.is_poisoned();
if !poison {
interesting -= 1;
if current_seen.is_full_range(revcount) {
candidates.push(current_rev);
......@@ -1124,8 +1126,7 @@
interesting -= 1;
if current_seen.is_full_range(revcount) {
candidates.push(current_rev);
seen[current_rev.0 as usize].poison();
current_seen.poison(); // avoid recloning
poison = true;
// Being a common ancestor, if `current_rev` is among
// the input revisions, it is *the* answer.
......@@ -1141,7 +1142,7 @@
continue;
}
let parent_seen = &seen[parent.0 as usize];
if !current_seen.is_poisoned() {
if !poison {
// Without the `interesting` accounting, this block would
// be logically equivalent to: parent_seen |= current_seen
// The parent counts as interesting if it was not already
......@@ -1159,9 +1160,7 @@
if !parent_seen.is_empty() && !parent_seen.is_poisoned() {
interesting -= 1;
}
// equivalent to poisoning parent, which we should do to
// avoid the cloning.
seen[parent.0 as usize] = current_seen.clone();
seen[parent.0 as usize].poison();
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment