Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions crates/no-mistakes/src/edge_index/prepared.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::{CanonicalEdge, EdgeDirection, EdgeIndex, NodeAliases};
use std::collections::{BTreeSet, HashMap, HashSet};
use crate::fx::{fx_map_with_capacity, FxHashMap};
use std::collections::HashSet;
use std::hash::Hash;

/// Typed relationships prepared once for public-name root lookup and projection.
Expand All @@ -10,8 +11,8 @@ use std::hash::Hash;
#[derive(Debug, Clone)]
pub(crate) struct PreparedRelationshipIndex<Node, Kind> {
index: EdgeIndex<Node, Kind>,
public_names: HashMap<Node, String>,
nodes_by_name: HashMap<String, Vec<Node>>,
public_names: FxHashMap<Node, String>,
nodes_by_name: FxHashMap<String, Vec<Node>>,
aliases: NodeAliases<Node>,
}

Expand All @@ -30,7 +31,7 @@ where
// A typed node often appears in many relationships. Public rendering
// can require path normalization/allocation, so derive it once per
// distinct typed node before sorting or grouping its edges.
let mut public_names = HashMap::<Node, String>::new();
let mut public_names = fx_map_with_capacity(edges.len());
Comment thread
jonathanong marked this conversation as resolved.
for edge in &edges {
public_names
.entry(edge.from.clone())
Expand All @@ -39,6 +40,10 @@ where
.entry(edge.to.clone())
.or_insert_with(|| public_node(&edge.to));
}
// First-pass capacity is raw edge count; unique nodes are fewer when
// the same job is enqueued from many sites. Drop the spare buckets so
// the retained index does not keep that construction over-allocation.
public_names.shrink_to_fit();
let public_name = |node: &Node| {
public_names
.get(node)
Expand All @@ -54,28 +59,27 @@ where
});
edges.dedup();

// A BTreeSet preserves the pre-existing sorted typed-root vectors
// without repeatedly scanning a high-collision public-name bucket.
let mut grouped_nodes = HashMap::<&str, BTreeSet<Node>>::new();
// Sort/dedup each bucket once so typed-root vectors stay ordered.
let mut grouped_nodes: FxHashMap<&str, Vec<Node>> = fx_map_with_capacity(edges.len());
Comment thread
jonathanong marked this conversation as resolved.
for edge in &edges {
grouped_nodes
.entry(public_name(&edge.from).as_str())
.or_default()
.insert(edge.from.clone());
.push(edge.from.clone());
grouped_nodes
.entry(public_name(&edge.to).as_str())
.or_default()
.insert(edge.to.clone());
.push(edge.to.clone());
Comment thread
jonathanong marked this conversation as resolved.
}
for nodes in grouped_nodes.values_mut() {
nodes.sort();
nodes.dedup();
}
let aliases = NodeAliases::from_groups(grouped_nodes.values().cloned());
let mut nodes_by_name = fx_map_with_capacity(grouped_nodes.len());
for (name, nodes) in grouped_nodes {
nodes_by_name.insert(name.to_owned(), nodes);
}
let aliases = NodeAliases::from_groups(
grouped_nodes
.values()
.map(|nodes| nodes.iter().cloned().collect::<Vec<_>>()),
);
let nodes_by_name = grouped_nodes
.into_iter()
.map(|(name, nodes)| (name.to_owned(), nodes.into_iter().collect()))
.collect();

Self {
index: EdgeIndex::from_unique_edges_in_order(edges),
Expand Down Expand Up @@ -170,6 +174,8 @@ fn project_first_seen<Input, Output>(
where
Output: Clone + Eq + Hash,
{
// Projected `Output` is a public report edge (paths/jobs from repo
// source), not an interned analysis key. Keep SipHash here.
let mut seen = HashSet::new();
values
.into_iter()
Expand Down
Loading