Skip to content

Commit e718a5a

Browse files
authored
Merge pull request #9488 from Byron/graph-segmentation
integration-checks: performance
2 parents 80d6a18 + 9a619e0 commit e718a5a

File tree

9 files changed

+278
-97
lines changed

9 files changed

+278
-97
lines changed

Cargo.lock

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but-core/src/ref_metadata.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,11 @@ pub struct WorkspaceStack {
158158
pub struct WorkspaceStackBranch {
159159
/// The name of the branch.
160160
pub ref_name: gix::refs::FullName,
161-
/// Archived represents the state when series/branch has been integrated and is below the merge base with the current target branch.
162-
/// This would occur when the branch has been merged at the remote and the workspace has been updated with that change.
163-
///
164-
/// Note that this is a cache to help speed up certain operations.
165-
/// NOTE: This is more like a proof of concept and for backwards compatibility - maybe we will make it go away.
166-
// TODO: given that most operations require a graph walk, will this really be necessary if a graph cache is used consistently?
167-
// Staleness can be a problem if targets can be changed after the fact. At least we'd need to recompute it.
161+
/// If `true`, the branch is now underneath the lower-base of the workspace after a workspace update.
162+
/// This means it's not interesting anymore, by all means, but we'd still have to keep it available and list
163+
/// these segments as being part of the workspace when creating PRs. Their descriptions contain references
164+
/// to archived segments, which simply shouldn't disappear just yet.
165+
/// However, they may disappear once the whole stack has been integrated and the workspace has moved past it.
168166
pub archived: bool,
169167
}
170168

crates/but-graph/src/projection/workspace.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,28 +97,65 @@ pub struct Target {
9797
impl Target {
9898
/// Return `None` if `ref_name` wasn't found as segment in `graph`.
9999
/// This can happen if a reference is configured, but not actually present as reference.
100-
fn from_ref_name(ref_name: &gix::refs::FullName, graph: &Graph) -> Option<Self> {
100+
/// Note that `commits_ahead` isn't set yet, see [`Self::compute_and_set_commits_ahead()`].
101+
fn from_ref_name_without_commits_ahead(
102+
ref_name: &gix::refs::FullName,
103+
graph: &Graph,
104+
) -> Option<Self> {
101105
let target_segment = graph.inner.node_indices().find_map(|n| {
102106
let s = &graph[n];
103107
(s.ref_name.as_ref() == Some(ref_name)).then_some(s)
104108
})?;
105109
Some(Target {
106110
ref_name: ref_name.to_owned(),
107111
segment_index: target_segment.id,
108-
commits_ahead: {
109-
// Find all remote commits but stop traversing when there is segments without remotes.
110-
let mut count = 0;
111-
graph.visit_all_segments_until(target_segment.id, Direction::Outgoing, |s| {
112-
let remote_commits = s.commits.iter().filter(|c| c.flags.is_remote()).count();
113-
count += remote_commits;
114-
remote_commits != s.commits.len()
115-
});
116-
count
117-
},
112+
commits_ahead: 0,
113+
})
114+
}
115+
116+
fn compute_and_set_commits_ahead(
117+
&mut self,
118+
graph: &Graph,
119+
lower_bound_segment: Option<SegmentIndex>,
120+
) {
121+
let lower_bound = lower_bound_segment.map(|sidx| (sidx, graph[sidx].generation));
122+
self.commits_ahead = 0;
123+
Self::visit_upstream_commits(graph, self.segment_index, lower_bound, |s| {
124+
self.commits_ahead += s.commits.len();
118125
})
119126
}
120127
}
121128

129+
/// Utilities
130+
impl Target {
131+
/// Visit all segments whose commits would be considered 'upstream', or part of the target branch
132+
/// whose tip is identified with `target_segment`. The `lower_bound_segment_and_generation` is another way
133+
/// to stop the traversal.
134+
pub fn visit_upstream_commits(
135+
graph: &Graph,
136+
target_segment: SegmentIndex,
137+
lower_bound_segment_and_generation: Option<(SegmentIndex, usize)>,
138+
mut visit: impl FnMut(&Segment),
139+
) {
140+
graph.visit_all_segments_until(target_segment, Direction::Outgoing, |s| {
141+
let prune = true;
142+
if lower_bound_segment_and_generation.is_some_and(
143+
|(lower_bound, lower_bound_generation)| {
144+
s.id == lower_bound || s.generation > lower_bound_generation
145+
},
146+
) || s
147+
.commits
148+
.iter()
149+
.any(|c| c.flags.contains(CommitFlags::InWorkspace))
150+
{
151+
return prune;
152+
}
153+
visit(s);
154+
!prune
155+
});
156+
}
157+
}
158+
122159
impl Graph {
123160
/// Analyse the current graph starting at its [entrypoint](Self::lookup_entrypoint()).
124161
///
@@ -196,9 +233,9 @@ impl Graph {
196233
id: ws_tip_segment.id,
197234
kind,
198235
stacks: vec![],
199-
target: metadata
200-
.as_ref()
201-
.and_then(|md| Target::from_ref_name(md.target_ref.as_ref()?, self)),
236+
target: metadata.as_ref().and_then(|md| {
237+
Target::from_ref_name_without_commits_ahead(md.target_ref.as_ref()?, self)
238+
}),
202239
extra_target: self.extra_target,
203240
metadata,
204241
lower_bound_segment_id: None,
@@ -352,6 +389,9 @@ impl Graph {
352389
);
353390
}
354391

392+
if let Some(target) = ws.target.as_mut() {
393+
target.compute_and_set_commits_ahead(self, ws.lower_bound_segment_id);
394+
}
355395
ws.mark_remote_reachability()?;
356396
Ok(ws)
357397
}
@@ -834,6 +874,8 @@ impl std::fmt::Debug for Workspace<'_> {
834874
.field("id", &self.id.index())
835875
.field("stacks", &self.stacks)
836876
.field("metadata", &self.metadata)
877+
.field("target", &self.target)
878+
.field("extra_target", &self.extra_target)
837879
.finish()
838880
}
839881
}

crates/but-workspace/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ itertools = "0.14"
3030
url = { version = "2.5.4", features = ["serde"] }
3131
md5 = "0.8.0"
3232
tracing.workspace = true
33+
# For SPMC channel
34+
flume = "0.11.1"
3335

3436
[dev-dependencies]
3537
but-testsupport.workspace = true

0 commit comments

Comments
 (0)