fix(resolver): cache known versions by package name#1188
Conversation
|
Warning Review limit reached
More reviews will be available in 58 minutes and 52 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthrough
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@dhellmann This alone might not fix the issue |
…ython-wheel-build#1187 exempt_versions Cover top-level == pin scenarios where transitive deps use a different requirement specifier. These validate the python-wheel-build#1157 exempt_versions fix; session-cache coverage remains in python-wheel-build#1188. Co-Authored-By: Claude <claude@anthropic.com> Signed-off-by: Lalatendu Mohanty <lmohanty@redhat.com> Co-authored-by: Cursor <cursoragent@cursor.com>
tiran
left a comment
There was a problem hiding this comment.
IMO the suggestion from 1187 is not the best solution. Breadth-first resolution of top-level requirements should solve the issue, too.
@tiran I agree that 1187 is not the best solution however, I think the BFS approach will make things more complicated. I see the following challenges:
Some points to consider:
Let me know what you think / whether I am missing anything. cc @LalatenduMohanty @dhellmann |
UPDATE: I posted this before reading Doug's comment here: #1187 (comment) |
|
@dhellmann @LalatenduMohanty @tiran I have implemented Doug's suggestion which was discussed here in my latest commit |
| if rule_key not in self._resolved_rules: | ||
| # Rule not seen before — resolve from graph or network and | ||
| # extend the package-level known-versions cache. | ||
| self._resolve_and_extend(req, req_type, pre_built, parent_req) |
There was a problem hiding this comment.
Since we're updating 2 data structures now, we need a lock to make sure it's thread safe.
There was a problem hiding this comment.
Good catch, I did not think about it. I have pushed this implementation in latest commit:
resolve()holdsself._lockaround the check + extend + filter block_resolve_and_extend()andresolve()call the unlocked_extend_known_versions()/_get_matching_versions()(no nested
locking)- The public
extend_known_versions()/get_matching_versions()acquire the lock themselves, for external callers inbootstrapper.py
Does this make sense?
Replace the per-requirement-string resolution cache with a package-level known-versions cache, as discussed in issue python-wheel-build#1187. The resolver now: 1. Tracks which requirement rules have been resolved to avoid redundant network calls. 2. Accumulates all discovered versions into a package-level cache keyed by (normalized_name, pre_built). 3. Filters the accumulated versions by the current specifier, returning the widest available set. This ensures that versions discovered in one context (e.g., top-level with cooldown bypass finding v2.0) are visible to later lookups with different specifiers (e.g., transitive A>=1.0 will see v2.0 even though its own network call only found v1.5). Co-Authored-By: Claude <claude@anthropic.com> Closes: python-wheel-build#1187 Signed-off-by: Rohan Devasthale <rdevasth@redhat.com>
dhellmann
left a comment
There was a problem hiding this comment.
This looks good to me but I'm reluctant to approve and merge it late on a Friday.
| if rule_key not in self._resolved_rules: | ||
| # Rule not seen before — resolve from graph or network and | ||
| # extend the package-level known-versions cache. | ||
| self._resolve_and_extend(req, req_type, pre_built, parent_req) |
There was a problem hiding this comment.
This looks safe. If we were worried about the resolver running in multiple threads then we would probably want to not hold the lock for so long, because that would make this part of the code a bottleneck. We would want to try to organize the order of operations so that the resolution happened outside of the locked region and only operations to save state happen within the locked region. I don't think it's worth reorganizing the code to make that easy right now, though, because we are not using multiple threads to resolve rules.
Replace the per-requirement-string resolution cache with a
package-level known-versions cache, as discussed in issue #1187.
The resolver now:
redundant network calls.
keyed by (normalized_name, pre_built).
returning the widest available set.
This ensures that versions discovered in one context (e.g., top-level
with cooldown bypass finding v2.0) are visible to later lookups with
different specifiers (e.g., transitive A>=1.0 will see v2.0 even
though its own network call only found v1.5).
Co-Authored-By: Claude claude@anthropic.com
Closes: #1187
Signed-off-by: Rohan Devasthale rdevasth@redhat.com