-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query facts from root during resolution #263
Comments
Oh I see I think. Basically preloading the resolution with all the root dependencies as incompatibilities. WAIT, isn’t that supposed to be already? |
For this specific case, I could query the root requirements from our preprocessing. But PubGrub learns more facts during resolution, so it would be great if I could ask the state of what we currently know for certain; it would certainly be the cleaner solution than doing this without pubgrub. Say we start with |
Right, so what we know for sure, at any given time, is the set of incompatibilities inside Line 22 in fe65959
As far as I remember, we haven’t yet worked on optimizing that set of incompatibilities (except removing duplicates maybe?) so these are basically unstructured info. The accumulated structured info, solved per package, is actually inside the partial solution, and more precisely, inside the pubgrub/src/internal/partial_solution.rs Line 75 in fe65959
So I think what you are interested in an |
The only assignments that you can know for sure are those gathered from either the root, or another package where there is no other choice anymore, for example packages picked with exact versions, or that are definitely needed from the root, and for which there is only 1 version choice left. I’m wondering if there could be a way to snapshot somehow these states, and/or if they could just be derived from the reduction work still needed on the set of incompatibilities. |
Actually, I had forgotten about it because it was framed as an error message improvements, but Jacob did improve the merging of incompats in #163, at least in one case. |
Most of what I'm about to say you already know, but I'm talking it out to clarify my own thoughts. I would love to provide better APIs for querying the incompatibility/partial_solution data during resolution. Along with other heuristics about how resolution is going. (In my case I have packages that represent "features" that I know a priori are going to have singleton requirements on the package they augment, so I would like choose_version straight to the only version that will work.) All Incompatibilities are unchangeable facts in some literal but unhelpful way. Given that your writing your own resolution loop you can look directly at
|
I'm looking for querying only the facts that don't depend on the decisions made so far. The background are the following two cases: We have a pathological but very common case with urllib3, boto3 and botocore. We select a version of urllib3, then have to go through a lot of version of boto3 to find one that is compatible with that version of urllib3. We speed this up from 45s to 2s (cold resolve) by batch prefetching boto3 (astral-sh/uv#2452). Each version of boto3 depends on one version of botocore, so we also need to prefetch botocore, or we have all those versions of boto3, but spend 25s waiting on all the botocore versions (astral-sh/uv#2452, fig. 3). But for any given boto3, only one botocore version remains allowed, we only have compatibility with one botocore version so we need to prefetch incompatible botocore versions. The other case is sentry: We have Instead, I want to ask what we know for sure: For botocore, it's I'm trying to not touch |
I think adding something to PartialSolution like: /// Retrieve intersection of terms related to package that will not chage.
// It is pub for UV
pub fn unchanging_term_intersection_for_package(
&self,
package: &DP::P,
) -> Option<&Term<DP::VS>> {
let pa = self.package_assignments.get(package)?;
let idx_newer = pa
.dated_derivations
.as_slice()
.partition_point(|dd| dd.decision_level <= DecisionLevel(1));
let idx = idx_newer.checked_sub(1)?;
Some(&pa.dated_derivations[idx].accumulated_intersection)
} which should be the intersection of all of the incompatibilities that have been proven to be unchangeable. (As I mentioned above, the "has been proven" is doing a lot of work here.) I would also experiment with putting that on top of #257 which is more aggressive about declaring things unchangeable. |
When prefetching, we want to avoid prefetching packages we will certainly reject. `PartialSolution::unchanging_term_for_package` returns the terms from root that a certain independent from the current partial solution. See pubgrub-rs#263 (comment)
Thank you that's perfect! |
Started using this in astral-sh#32 and astral-sh/uv#8246 🎉 |
Background When uv queries multiple versions of a package in a row, it will start to prefetch many versions. In this, I tried resolving https://github.com/getsentry/sentry/blob/51281a6abd8ff4a93d2cebc04e1d5fc7aa9c4c11/requirements-base.txt, which has
sentry-kafka-schemas>=0.1.50
. We try a lot of versions (until eventually realizing we went down the wrong path), but we're also trying versions <0.1.50 since for the motivating example (boto/botocore/urllib3), the partial solution would forbid prefetching.It would be great to have an API to query unchangeable facts about package version, i.e. incompatibilities with root, such as
sentry-kafka-schemas>=0.1.50
being always true, to avoid doing the wrong batch prefetching. We can subsequently apply this to our other prefetching, too.The text was updated successfully, but these errors were encountered: