Skip to content

Commit f06d44e

Browse files
Use forget for module resolver database (#13438)
## Summary A tiny bit faster and the `red-knot` CLI does the same thing.
1 parent 653c090 commit f06d44e

File tree

1 file changed

+95
-90
lines changed

1 file changed

+95
-90
lines changed

Diff for: crates/ruff/src/commands/analyze_graph.rs

+95-90
Original file line numberDiff line numberDiff line change
@@ -67,102 +67,105 @@ pub(crate) fn analyze_graph(
6767
.into(),
6868
)?;
6969

70-
// Create a cache for resolved globs.
71-
let glob_resolver = Arc::new(Mutex::new(GlobResolver::default()));
72-
73-
// Collect and resolve the imports for each file.
74-
let result = Arc::new(Mutex::new(Vec::new()));
75-
let inner_result = Arc::clone(&result);
76-
77-
rayon::scope(move |scope| {
78-
for resolved_file in paths {
79-
let Ok(resolved_file) = resolved_file else {
80-
continue;
81-
};
70+
let imports = {
71+
// Create a cache for resolved globs.
72+
let glob_resolver = Arc::new(Mutex::new(GlobResolver::default()));
73+
74+
// Collect and resolve the imports for each file.
75+
let result = Arc::new(Mutex::new(Vec::new()));
76+
let inner_result = Arc::clone(&result);
77+
let db = db.snapshot();
78+
79+
rayon::scope(move |scope| {
80+
for resolved_file in paths {
81+
let Ok(resolved_file) = resolved_file else {
82+
continue;
83+
};
84+
85+
let path = resolved_file.path();
86+
let package = path
87+
.parent()
88+
.and_then(|parent| package_roots.get(parent))
89+
.and_then(Clone::clone);
90+
91+
// Resolve the per-file settings.
92+
let settings = resolver.resolve(path);
93+
let string_imports = settings.analyze.detect_string_imports;
94+
let include_dependencies = settings.analyze.include_dependencies.get(path).cloned();
95+
96+
// Skip excluded files.
97+
if (settings.file_resolver.force_exclude || !resolved_file.is_root())
98+
&& match_exclusion(
99+
resolved_file.path(),
100+
resolved_file.file_name(),
101+
&settings.analyze.exclude,
102+
)
103+
{
104+
continue;
105+
}
82106

83-
let path = resolved_file.path();
84-
let package = path
85-
.parent()
86-
.and_then(|parent| package_roots.get(parent))
87-
.and_then(Clone::clone);
88-
89-
// Resolve the per-file settings.
90-
let settings = resolver.resolve(path);
91-
let string_imports = settings.analyze.detect_string_imports;
92-
let include_dependencies = settings.analyze.include_dependencies.get(path).cloned();
93-
94-
// Skip excluded files.
95-
if (settings.file_resolver.force_exclude || !resolved_file.is_root())
96-
&& match_exclusion(
97-
resolved_file.path(),
98-
resolved_file.file_name(),
99-
&settings.analyze.exclude,
100-
)
101-
{
102-
continue;
103-
}
107+
// Ignore non-Python files.
108+
let source_type = match settings.analyze.extension.get(path) {
109+
None => match SourceType::from(&path) {
110+
SourceType::Python(source_type) => source_type,
111+
SourceType::Toml(_) => {
112+
debug!("Ignoring TOML file: {}", path.display());
113+
continue;
114+
}
115+
},
116+
Some(language) => PySourceType::from(language),
117+
};
118+
if matches!(source_type, PySourceType::Ipynb) {
119+
debug!("Ignoring Jupyter notebook: {}", path.display());
120+
continue;
121+
}
104122

105-
// Ignore non-Python files.
106-
let source_type = match settings.analyze.extension.get(path) {
107-
None => match SourceType::from(&path) {
108-
SourceType::Python(source_type) => source_type,
109-
SourceType::Toml(_) => {
110-
debug!("Ignoring TOML file: {}", path.display());
111-
continue;
123+
// Convert to system paths.
124+
let Ok(package) = package.map(SystemPathBuf::from_path_buf).transpose() else {
125+
warn!("Failed to convert package to system path");
126+
continue;
127+
};
128+
let Ok(path) = SystemPathBuf::from_path_buf(resolved_file.into_path()) else {
129+
warn!("Failed to convert path to system path");
130+
continue;
131+
};
132+
133+
let db = db.snapshot();
134+
let glob_resolver = glob_resolver.clone();
135+
let root = root.clone();
136+
let result = inner_result.clone();
137+
scope.spawn(move |_| {
138+
// Identify any imports via static analysis.
139+
let mut imports =
140+
ModuleImports::detect(&db, &path, package.as_deref(), string_imports)
141+
.unwrap_or_else(|err| {
142+
warn!("Failed to generate import map for {path}: {err}");
143+
ModuleImports::default()
144+
});
145+
146+
debug!("Discovered {} imports for {}", imports.len(), path);
147+
148+
// Append any imports that were statically defined in the configuration.
149+
if let Some((root, globs)) = include_dependencies {
150+
let mut glob_resolver = glob_resolver.lock().unwrap();
151+
imports.extend(glob_resolver.resolve(root, globs));
112152
}
113-
},
114-
Some(language) => PySourceType::from(language),
115-
};
116-
if matches!(source_type, PySourceType::Ipynb) {
117-
debug!("Ignoring Jupyter notebook: {}", path.display());
118-
continue;
119-
}
120-
121-
// Convert to system paths.
122-
let Ok(package) = package.map(SystemPathBuf::from_path_buf).transpose() else {
123-
warn!("Failed to convert package to system path");
124-
continue;
125-
};
126-
let Ok(path) = SystemPathBuf::from_path_buf(resolved_file.into_path()) else {
127-
warn!("Failed to convert path to system path");
128-
continue;
129-
};
130153

131-
let db = db.snapshot();
132-
let glob_resolver = glob_resolver.clone();
133-
let root = root.clone();
134-
let result = inner_result.clone();
135-
scope.spawn(move |_| {
136-
// Identify any imports via static analysis.
137-
let mut imports =
138-
ModuleImports::detect(&db, &path, package.as_deref(), string_imports)
139-
.unwrap_or_else(|err| {
140-
warn!("Failed to generate import map for {path}: {err}");
141-
ModuleImports::default()
142-
});
143-
144-
debug!("Discovered {} imports for {}", imports.len(), path);
145-
146-
// Append any imports that were statically defined in the configuration.
147-
if let Some((root, globs)) = include_dependencies {
148-
let mut glob_resolver = glob_resolver.lock().unwrap();
149-
imports.extend(glob_resolver.resolve(root, globs));
150-
}
154+
// Convert the path (and imports) to be relative to the working directory.
155+
let path = path
156+
.strip_prefix(&root)
157+
.map(SystemPath::to_path_buf)
158+
.unwrap_or(path);
159+
let imports = imports.relative_to(&root);
151160

152-
// Convert the path (and imports) to be relative to the working directory.
153-
let path = path
154-
.strip_prefix(&root)
155-
.map(SystemPath::to_path_buf)
156-
.unwrap_or(path);
157-
let imports = imports.relative_to(&root);
158-
159-
result.lock().unwrap().push((path, imports));
160-
});
161-
}
162-
});
161+
result.lock().unwrap().push((path, imports));
162+
});
163+
}
164+
});
163165

164-
// Collect the results.
165-
let imports = Arc::into_inner(result).unwrap().into_inner()?;
166+
// Collect the results.
167+
Arc::into_inner(result).unwrap().into_inner()?
168+
};
166169

167170
// Generate the import map.
168171
let import_map = match args.direction {
@@ -173,6 +176,8 @@ pub(crate) fn analyze_graph(
173176
// Print to JSON.
174177
println!("{}", serde_json::to_string_pretty(&import_map)?);
175178

179+
std::mem::forget(db);
180+
176181
Ok(ExitStatus::Success)
177182
}
178183

0 commit comments

Comments
 (0)