Skip to content
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

Change how runtime dependencies are included in new dependency resolver #6211

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from

Conversation

jeffkl
Copy link
Contributor

@jeffkl jeffkl commented Jan 7, 2025

Bug

Fixes: NuGet/Home#13800

Description

This updates how runtime dependencies are handled in the new resolver. Currently, the resolver loops through each pair of target framework and runtime identifier, calling ResolverUtility.FindLibraryEntryAsync() for each dependency. This results in the code calling FindLibraryEntryAsync() multiple times for the same dependency for each runtime of the same framework. The legacy resolver caches calls to FindLibraryEntryAsync() for each target framework, regardless of the runtime identifier. Runtime specific packages generally have unique IDs so it works.

The data returned by FindLibraryEntryAsync() includes a RemoteMatch which specifies the dependencies according to a project or .nuspec. When the resolver is resolving a graph for a runtime specific graph, it mutates the list by augmenting any runtime packages specified in runtime.json. However, when lock files are in use, the resolver needs to ensure that its calling FindLibraryEntryAsync() when a runtime is specified, otherwise in locked mode it cannot find the packages in the packages.lock.json.

This change introduces a second caching layer, which is target framework/runtime identifier and dependency ID specific. Calls to FindLibraryEntryCachedAsync() remain cached by target framework and dependency ID. Then for each runtime identifier, the runtime dependencies are merged into the list of dependencies and that list is cached. This ensures that each call to FindLibraryEntryAsync() only happens once per target framework/dependency but that runtime specific graphs still look up dependencies in lock files correctly.

Its a potential breaking change that the new resolver will be enabled by default if lock files are being used. We'll need to discuss whether or not this is okay.

PR Checklist

  • Meaningful title, helpful description and a linked NuGet/Home issue
  • Added tests
  • Link to an issue or pull request to update docs if this PR changes settings, environment variables, new feature, etc.

@jeffkl jeffkl requested a review from a team as a code owner January 7, 2025 16:55
@jeffkl jeffkl changed the title WIP Change how runtime dependencies are included in new dependency resolver Jan 7, 2025
Copy link
Member

@nkolev92 nkolev92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the overall approach makes sense.

There is some refactoring that I have a tougher time with, and we'll probably need to sync offline.

I think it'd be great to differentiate between that and the functional changes.

@jeffkl jeffkl force-pushed the dev-jeffkl-fix-runtimedependnecies2 branch from 72022c7 to 2aea2e1 Compare January 7, 2025 22:58
@jeffkl jeffkl added the Merge next release PRs that should not be merged until the dev branch targets the next release label Jan 7, 2025
Copy link
Member

@nkolev92 nkolev92 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

There might be some opportunities for perf improvements but those can come later.

/// <summary>
/// Represents a cache key for storing <see cref="ResolvedLibraryEntry" /> items in a dictionary with a unique <see cref="FrameworkRuntimePair" /> and <see cref="LibraryRangeIndex" />.
/// </summary>
private readonly struct ResolvedLibraryEntryCacheKey : IEquatable<ResolvedLibraryEntryCacheKey>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an added cost from the constant hashing of FrameworkRuntimePair?
I see that the type is immutable, so they may be an opportunity to improve the performance there by caching the hash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Merge next release PRs that should not be merged until the dev branch targets the next release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reenable new algorithm resolution with lock files
4 participants