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

Invalidate http cache when a package has been deleted from a feed #1319

Merged
merged 1 commit into from
Apr 18, 2017

Conversation

emgarten
Copy link
Member

This change adds support for invalidating the http cache on a per package id basis when a 404 is received. As part of that finding the original casing of the package has been moved into the GetDependency request where the package is downloaded to disk.

Perf improvements along with this:

  • Packages are downloaded only if they are the best match, previously this was done a per feed basis which caused unneeded downloads
  • Added additional caching for nuspecs and dependency info

For NuGet.sln this improves noop restore by around 15%
The http cache size goes from 312M -> 235M due to no longer downloading extra packages.

Refactored dependency walker logic for finding the best match into ResolverUtility.cs to make it easier to test.

Cache invalidation flow:

  1. A InvalidCacheProtocolException is thrown when an expected package does not exist
  2. Requests are made using a new cache context with a max age of the current time, and a flag set to clear out in memory caches along the way as the new call is made. This ensures that other calls will not re-populate the cache from the file on disk.

Fixes NuGet/Home#5023
Fixes NuGet/Home#5012

}

return await result;
Copy link
Contributor

Choose a reason for hiding this comment

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

The result is always awaited. Therefore it's not necessary to have a complicated cache data structure with AsyncLazy as a value.

Copy link
Member Author

Choose a reason for hiding this comment

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

That isn't what I was seeing in the debugger. It was previously a task and getting hit multiple times. Changing to AsyncLazy fixed the issue. I don't know why a regular task would have done this, but I saw it happen several times during restore.

/// <summary>
/// Cache on LibraryRange and TargetFramework
/// </summary>
private class DependencyInfoCacheKey : IEquatable<DependencyInfoCacheKey>
Copy link
Contributor

Choose a reason for hiding this comment

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

As an alternative, this could be just a formatted string as a key. This would eliminate the need in the separate key class.

Copy link
Member Author

Choose a reason for hiding this comment

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

The class should be faster, right? This uses hashcodecombiner and equals on the same objects.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not necessarily faster but rather simpler. We implemented credentials cache with similar approach in CredentialService.

Copy link
Member Author

@emgarten emgarten Apr 18, 2017

Choose a reason for hiding this comment

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

I found the same cache key class existed under LibraryRangeCacheKey and switched to that, removing this private class.

I would normally agree with simplifying here, but this path in the walk is critical for perf. Every package in the unflattened graph needs to be resolved, which is much larger than the number you see in the final flattened graph in the assets file. And for each TFM/RID combination, across every project.

// Clear the on disk and memory caches during the next request.
currentCacheContext = currentCacheContext.Clone();
currentCacheContext.MaxAge = DateTimeOffset.UtcNow;
currentCacheContext.RefreshMemoryCache = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider encapsulating the above 3 lines into a factory method. This would make RefershMemoryCache truly immutable.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good suggestion, I'll add a helper to SourceCacheContext for this.

catch (PackageNotFoundProtocolException ex)
{
// 2nd failure, the feed is likely corrupt or removing packages too fast to keep up with.
if (match.Provider.IsHttp && match.Provider.Source != null)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can be used in when above.

Copy link
Contributor

@alpaix alpaix left a comment

Choose a reason for hiding this comment

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

LGTM. Just couple of minor notes.

@emgarten emgarten force-pushed the dev-emgarten-cacheInvalidation branch from 763dcbb to f169b3f Compare April 18, 2017 05:54
This change adds support for invalidating the http cache on a per package id basis when a 404 is received. As part of that finding the original casing of the package has been moved into the GetDependency request where the package is downloaded to disk.

Perf improvements along with this:
* Packages are downloaded only if they are the best match, previously this was done a per feed basis which caused unneeded downloads
* Added additional caching for nuspecs and dependency info

Fixes NuGet/Home#5023
Fixes NuGet/Home#5012

Addressing feedback
@emgarten emgarten force-pushed the dev-emgarten-cacheInvalidation branch from f169b3f to 26e8bc0 Compare April 18, 2017 06:34
@emgarten emgarten merged commit 527488e into dev Apr 18, 2017
@emgarten emgarten deleted the dev-emgarten-cacheInvalidation branch April 18, 2017 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants