Skip to content

Commit 5474c61

Browse files
authored
Refactor candidate selector for batch prefetching (#2832)
Batch prefetching needs more information from the candidate selector, so i've split `select` into methods. Split out from #2452. No functional changes.
1 parent a0b8d1a commit 5474c61

File tree

2 files changed

+70
-38
lines changed

2 files changed

+70
-38
lines changed

crates/uv-resolver/src/candidate_selector.rs

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,31 @@ impl CandidateSelector {
7070
pub(crate) fn select<'a, InstalledPackages: InstalledPackagesProvider>(
7171
&'a self,
7272
package_name: &'a PackageName,
73-
range: &'a Range<Version>,
73+
range: &Range<Version>,
74+
version_maps: &'a [VersionMap],
75+
preferences: &'a Preferences,
76+
installed_packages: &'a InstalledPackages,
77+
exclusions: &'a Exclusions,
78+
) -> Option<Candidate<'a>> {
79+
if let Some(preferred) = Self::get_preferred(
80+
package_name,
81+
range,
82+
version_maps,
83+
preferences,
84+
installed_packages,
85+
exclusions,
86+
) {
87+
return Some(preferred);
88+
}
89+
90+
self.select_no_preference(package_name, range, version_maps)
91+
}
92+
93+
/// Get a preferred version if one exists. This is the preference from a lockfile or a locally
94+
/// installed version.
95+
fn get_preferred<'a, InstalledPackages: InstalledPackagesProvider>(
96+
package_name: &'a PackageName,
97+
range: &Range<Version>,
7498
version_maps: &'a [VersionMap],
7599
preferences: &'a Preferences,
76100
installed_packages: &'a InstalledPackages,
@@ -141,8 +165,12 @@ impl CandidateSelector {
141165
}
142166
}
143167

144-
// Determine the appropriate prerelease strategy for the current package.
145-
let allow_prerelease = match &self.prerelease_strategy {
168+
None
169+
}
170+
171+
/// Determine the appropriate prerelease strategy for the current package.
172+
fn allow_prereleases(&self, package_name: &PackageName) -> AllowPreRelease {
173+
match &self.prerelease_strategy {
146174
PreReleaseStrategy::Disallow => AllowPreRelease::No,
147175
PreReleaseStrategy::Allow => AllowPreRelease::Yes,
148176
PreReleaseStrategy::IfNecessary => AllowPreRelease::IfNecessary,
@@ -160,54 +188,58 @@ impl CandidateSelector {
160188
AllowPreRelease::IfNecessary
161189
}
162190
}
163-
};
191+
}
192+
}
164193

194+
/// Select a [`Candidate`] without checking for version preference such as an existing
195+
/// lockfile.
196+
pub(crate) fn select_no_preference<'a>(
197+
&'a self,
198+
package_name: &'a PackageName,
199+
range: &Range<Version>,
200+
version_maps: &'a [VersionMap],
201+
) -> Option<Candidate> {
165202
tracing::trace!(
166-
"selecting candidate for package {:?} with range {:?} with {} remote versions",
203+
"selecting candidate for package {} with range {:?} with {} remote versions",
167204
package_name,
168205
range,
169206
version_maps.iter().map(VersionMap::len).sum::<usize>(),
170207
);
171-
match &self.resolution_strategy {
172-
ResolutionStrategy::Highest => version_maps.iter().find_map(|version_map| {
208+
let highest = self.use_highest_version(package_name);
209+
let allow_prerelease = self.allow_prereleases(package_name);
210+
211+
if highest {
212+
version_maps.iter().find_map(|version_map| {
173213
Self::select_candidate(
174214
version_map.iter().rev(),
175215
package_name,
176216
range,
177217
allow_prerelease,
178218
)
179-
}),
180-
ResolutionStrategy::Lowest => version_maps.iter().find_map(|version_map| {
219+
})
220+
} else {
221+
version_maps.iter().find_map(|version_map| {
181222
Self::select_candidate(version_map.iter(), package_name, range, allow_prerelease)
182-
}),
223+
})
224+
}
225+
}
226+
227+
/// By default, we select the latest version, but we also allow using the lowest version instead
228+
/// to check the lower bounds.
229+
pub(crate) fn use_highest_version(&self, package_name: &PackageName) -> bool {
230+
match &self.resolution_strategy {
231+
ResolutionStrategy::Highest => true,
232+
ResolutionStrategy::Lowest => false,
183233
ResolutionStrategy::LowestDirect(direct_dependencies) => {
184-
if direct_dependencies.contains(package_name) {
185-
version_maps.iter().find_map(|version_map| {
186-
Self::select_candidate(
187-
version_map.iter(),
188-
package_name,
189-
range,
190-
allow_prerelease,
191-
)
192-
})
193-
} else {
194-
version_maps.iter().find_map(|version_map| {
195-
Self::select_candidate(
196-
version_map.iter().rev(),
197-
package_name,
198-
range,
199-
allow_prerelease,
200-
)
201-
})
202-
}
234+
!direct_dependencies.contains(package_name)
203235
}
204236
}
205237
}
206238

207239
/// Select the first-matching [`Candidate`] from a set of candidate versions and files,
208240
/// preferring wheels over source distributions.
209241
fn select_candidate<'a>(
210-
versions: impl Iterator<Item = (&'a Version, VersionMapDistHandle<'a>)>,
242+
versions: impl Iterator<Item = (&'a Version, VersionMapDistHandle<'a>)> + ExactSizeIterator,
211243
package_name: &'a PackageName,
212244
range: &Range<Version>,
213245
allow_prerelease: AllowPreRelease,
@@ -219,10 +251,8 @@ impl CandidateSelector {
219251
}
220252

221253
let mut prerelease = None;
222-
let mut steps = 0;
223-
for (version, maybe_dist) in versions {
224-
steps += 1;
225-
254+
let versions_len = versions.len();
255+
for (step, (version, maybe_dist)) in versions.enumerate() {
226256
let candidate = if version.any_prerelease() {
227257
if range.contains(version) {
228258
match allow_prerelease {
@@ -235,7 +265,7 @@ impl CandidateSelector {
235265
after {} steps: {:?} version",
236266
package_name,
237267
range,
238-
steps,
268+
step,
239269
version,
240270
);
241271
// If pre-releases are allowed, treat them equivalently
@@ -276,7 +306,7 @@ impl CandidateSelector {
276306
after {} steps: {:?} version",
277307
package_name,
278308
range,
279-
steps,
309+
step,
280310
version,
281311
);
282312
Candidate::new(package_name, version, dist)
@@ -308,7 +338,7 @@ impl CandidateSelector {
308338
after {} steps",
309339
package_name,
310340
range,
311-
steps,
341+
versions_len,
312342
);
313343
match prerelease {
314344
None => None,

crates/uv-resolver/src/version_map.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ impl VersionMap {
152152
/// which can be used to lazily request a [`CompatibleDist`]. This is
153153
/// useful in cases where one can skip materializing a full distribution
154154
/// for each version.
155-
pub(crate) fn iter(&self) -> impl DoubleEndedIterator<Item = (&Version, VersionMapDistHandle)> {
155+
pub(crate) fn iter(
156+
&self,
157+
) -> impl DoubleEndedIterator<Item = (&Version, VersionMapDistHandle)> + ExactSizeIterator {
156158
match self.inner {
157159
VersionMapInner::Eager(ref map) => {
158160
either::Either::Left(map.iter().map(|(version, dist)| {

0 commit comments

Comments
 (0)