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

Cache control for project.json restore #120

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/NuGet.Commands/RestoreCommand.cs
Expand Up @@ -181,9 +181,9 @@ public async Task<RestoreResult> ExecuteAsync(CancellationToken token)
}

context.LocalLibraryProviders.Add(
new SourceRepositoryDependencyProvider(nugetRepository, _log));
new SourceRepositoryDependencyProvider(nugetRepository, _log, _request.CacheContext));

foreach (var provider in _request.Sources.Select(s => CreateProviderFromSource(s, _request.NoCache)))
foreach (var provider in _request.Sources.Select(s => CreateProviderFromSource(s, _request.CacheContext)))
{
context.RemoteLibraryProviders.Add(provider);
}
Expand Down Expand Up @@ -861,12 +861,12 @@ private async Task InstallPackageAsync(RemoteMatch installItem, string packagesD
token: token);
}

private IRemoteDependencyProvider CreateProviderFromSource(PackageSource source, bool noCache)
private IRemoteDependencyProvider CreateProviderFromSource(PackageSource source, SourceCacheContext cacheContext)
{
_log.LogVerbose(Strings.FormatLog_UsingSource(source.Source));

var nugetRepository = Repository.Factory.GetCoreV3(source.Source);
return new SourceRepositoryDependencyProvider(nugetRepository, _log, noCache);
return new SourceRepositoryDependencyProvider(nugetRepository, _log, cacheContext);
}
}
}
8 changes: 6 additions & 2 deletions src/NuGet.Commands/RestoreRequest.cs
@@ -1,11 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using NuGet.Configuration;
using NuGet.Frameworks;
using NuGet.ProjectModel;
using NuGet.Protocol.Core.Types;

namespace NuGet.Commands
{
Expand All @@ -26,6 +28,8 @@ public RestoreRequest(PackageSpec project, IEnumerable<PackageSource> sources, s
CompatibilityProfiles = new HashSet<FrameworkRuntimePair>();

PackagesDirectory = packagesDirectory;

CacheContext = new SourceCacheContext();
}

/// <summary>
Expand Down Expand Up @@ -69,9 +73,9 @@ public RestoreRequest(PackageSpec project, IEnumerable<PackageSource> sources, s
public int MaxDegreeOfConcurrency { get; set; } = DefaultDegreeOfConcurrency;

/// <summary>
/// If set, ignore the cache when downloading packages
/// Cache settings
/// </summary>
public bool NoCache { get; set; }
public SourceCacheContext CacheContext { get; set; }

/// <summary>
/// Additional compatibility profiles to check compatibility with.
Expand Down
15 changes: 4 additions & 11 deletions src/NuGet.DependencyResolver/SourceRepositoryDependencyProvider.cs
Expand Up @@ -18,24 +18,17 @@ public class SourceRepositoryDependencyProvider : IRemoteDependencyProvider
{
private readonly SourceRepository _sourceRepository;
private readonly ILogger _logger;
private readonly bool _noCache;
private readonly SourceCacheContext _cacheContext;
private FindPackageByIdResource _findPackagesByIdResource;

public SourceRepositoryDependencyProvider(
SourceRepository sourceRepository,
ILogger logger)
: this(sourceRepository, logger, noCache: false)
{
}

public SourceRepositoryDependencyProvider(
SourceRepository sourceRepository,
ILogger logger,
bool noCache)
SourceCacheContext cacheContext)
{
_sourceRepository = sourceRepository;
_logger = logger;
_noCache = noCache;
_cacheContext = cacheContext;
}

public bool IsHttp => _sourceRepository.PackageSource.IsHttp;
Expand Down Expand Up @@ -156,7 +149,7 @@ private async Task EnsureResource()
{
_findPackagesByIdResource = await _sourceRepository.GetResourceAsync<FindPackageByIdResource>();
_findPackagesByIdResource.Logger = _logger;
_findPackagesByIdResource.NoCache = _noCache;
_findPackagesByIdResource.CacheContext = _cacheContext;
}
}
}
Expand Down
95 changes: 95 additions & 0 deletions src/NuGet.Protocol.Core.Types/SourceCacheContext.cs
@@ -0,0 +1,95 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;

namespace NuGet.Protocol.Core.Types
{
/// <summary>
/// Cache control settings for the V3 disk cache.
/// </summary>
public class SourceCacheContext
{
/// <summary>
/// Default amount of time to cache version lists.
/// </summary>
private static readonly TimeSpan DefaultCacheAgeLimitList = TimeSpan.FromMinutes(30);

/// <summary>
/// Default amount of time to cache nupkgs.
/// </summary>
private static readonly TimeSpan DefaultCacheAgeLimitNupkg = TimeSpan.FromHours(24);

/// <summary>
/// If set, ignore the disk cache when listing and downloading packages
/// </summary>
public bool NoCache { get; set; }

/// <summary>
/// Package version lists from the server older than this date
/// will be fetched from the server.
/// </summary>
/// <remarks>This will be ignored if <see cref="NoCache"/> is true.</remarks>
/// <remarks>If the value is null the default expiration will be used.</remarks>
public DateTimeOffset? ListMaxAge { get; set; }

/// <summary>
/// Nupkgs from the server older than this date will be fetched from the server.
/// </summary>
/// <remarks>This will be ignored if <see cref="NoCache"/> is true.</remarks>
/// <remarks>If the value is null the default expiration will be used.</remarks>
public DateTimeOffset? NupkgMaxAge { get; set; }


/// <summary>
/// Package version lists from the server older than this time span
/// will be fetched from the server.
/// </summary>
public TimeSpan ListMaxAgeTimeSpan
{
get
{
return GetCacheTime(ListMaxAge, DefaultCacheAgeLimitList);
}
}

/// <summary>
/// Packages from the server older than this time span
/// will be fetched from the server.
/// </summary>
public TimeSpan NupkgMaxAgeTimeSpan
{
get
{
return GetCacheTime(ListMaxAge, DefaultCacheAgeLimitNupkg);
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be NupkgMaxAge

}
}

private TimeSpan GetCacheTime(DateTimeOffset? maxAge, TimeSpan defaultTime)
{
var timeSpan = TimeSpan.Zero;

if (!NoCache)
{
// Default
timeSpan = defaultTime;

// If the max age is set use that instead of the default
if (ListMaxAge.HasValue)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be maxAge

{
var difference = DateTimeOffset.UtcNow.Subtract(ListMaxAge.Value);

Debug.Assert(difference >= TimeSpan.Zero, "Invalid cache time");

if (difference >= TimeSpan.Zero)
{
timeSpan = difference;
}
}
}

return timeSpan;
}
}
}
2 changes: 1 addition & 1 deletion src/NuGet.Protocol.Core.v3/FindPackageByIdResource.cs
Expand Up @@ -13,7 +13,7 @@ namespace NuGet.Protocol.Core.Types
{
public abstract class FindPackageByIdResource : INuGetResource
{
public virtual bool NoCache { get; set; }
public virtual SourceCacheContext CacheContext { get; set; }

public virtual ILogger Logger { get; set; }

Expand Down
Expand Up @@ -37,9 +37,6 @@ public class HttpFileSystemBasedFindPackageByIdResource : FindPackageByIdResourc
private readonly IReadOnlyList<Uri> _baseUris;
private bool _ignored;

private TimeSpan _cacheAgeLimitList;
private TimeSpan _cacheAgeLimitNupkg;

public HttpFileSystemBasedFindPackageByIdResource(IReadOnlyList<Uri> baseUris, Func<Task<HttpHandlerResource>> handlerFactory)
{
if (baseUris == null)
Expand Down Expand Up @@ -69,23 +66,10 @@ public override ILogger Logger
}
}

public override bool NoCache
public override SourceCacheContext CacheContext
{
get { return base.NoCache; }
set
{
base.NoCache = value;
if (value)
{
_cacheAgeLimitList = TimeSpan.Zero;
_cacheAgeLimitNupkg = TimeSpan.Zero;
}
else
{
_cacheAgeLimitList = TimeSpan.FromMinutes(30);
_cacheAgeLimitNupkg = TimeSpan.FromHours(24);
}
}
get { return base.CacheContext; }
set { base.CacheContext = value; }
}

public bool IgnoreFailure { get; set; }
Expand Down Expand Up @@ -159,7 +143,7 @@ private async Task<IEnumerable<PackageInfo>> FindPackagesByIdAsync(string id, Ca
var results = new List<PackageInfo>();
using (var data = await _httpSource.GetAsync(uri,
$"list_{id}",
retry == 0 ? _cacheAgeLimitList : TimeSpan.Zero,
retry == 0 ? CacheContext.ListMaxAgeTimeSpan : TimeSpan.Zero,
ignoreNotFounds: true,
cancellationToken: cancellationToken))
{
Expand Down Expand Up @@ -269,7 +253,7 @@ private async Task<NupkgEntry> OpenNupkgStreamAsyncCore(PackageInfo package, Can
using (var data = await _httpSource.GetAsync(
package.ContentUri,
"nupkg_" + package.Id + "." + package.Version.ToNormalizedString(),
retry == 0 ? _cacheAgeLimitNupkg : TimeSpan.Zero,
retry == 0 ? CacheContext.NupkgMaxAgeTimeSpan : TimeSpan.Zero,
cancellationToken))
{
return new NupkgEntry
Expand Down
Expand Up @@ -39,9 +39,6 @@ public class RemoteV2FindPackageByIdResource : FindPackageByIdResource
private readonly Dictionary<string, Task<NupkgEntry>> _nupkgCache = new Dictionary<string, Task<NupkgEntry>>(StringComparer.OrdinalIgnoreCase);
private bool _ignored;

private TimeSpan _cacheAgeLimitList;
private TimeSpan _cacheAgeLimitNupkg;

public RemoteV2FindPackageByIdResource(PackageSource packageSource, Func<Task<HttpHandlerResource>> handlerFactory)
{
_baseUri = packageSource.Source.EndsWith("/") ? packageSource.Source : (packageSource.Source + "/");
Expand All @@ -62,23 +59,10 @@ public override ILogger Logger
}
}

public override bool NoCache
public override SourceCacheContext CacheContext
{
get { return base.NoCache; }
set
{
base.NoCache = value;
if (value)
{
_cacheAgeLimitList = TimeSpan.Zero;
_cacheAgeLimitNupkg = TimeSpan.Zero;
}
else
{
_cacheAgeLimitList = TimeSpan.FromMinutes(30);
_cacheAgeLimitNupkg = TimeSpan.FromHours(24);
}
}
get { return base.CacheContext; }
set { base.CacheContext = value; }
}

public bool IgnoreFailure { get; set; }
Expand Down Expand Up @@ -157,7 +141,11 @@ private async Task<IEnumerable<PackageInfo>> FindPackagesByIdAsyncCore(string id
// However, (1) In most cases the pages grow rather than shrink;
// (2) cache for pages is valid for only 30 min.
// So we decide to leave current logic and observe.
using (var data = await _httpSource.GetAsync(uri, $"list_{id}_page{page}", retry == 0 ? _cacheAgeLimitList : TimeSpan.Zero, cancellationToken))
using (var data = await _httpSource.GetAsync(
uri,
$"list_{id}_page{page}",
retry == 0 ? CacheContext.ListMaxAgeTimeSpan : TimeSpan.Zero,
cancellationToken))
{
try
{
Expand Down Expand Up @@ -289,7 +277,7 @@ private async Task<NupkgEntry> OpenNupkgStreamAsyncCore(PackageInfo package, Can
using (var data = await _httpSource.GetAsync(
package.ContentUri,
"nupkg_" + package.Id + "." + package.Version,
retry == 0 ? _cacheAgeLimitNupkg : TimeSpan.Zero,
retry == 0 ? CacheContext.NupkgMaxAgeTimeSpan : TimeSpan.Zero,
cancellationToken))
{
return new NupkgEntry
Expand Down
Expand Up @@ -27,8 +27,6 @@ public class RemoteV3FindPackageByIdResource : FindPackageByIdResource
private readonly HttpSource _httpSource;

private DependencyInfoResource _dependencyInfoResource;
private TimeSpan _cacheAgeLimitList;
private TimeSpan _cacheAgeLimitNupkg;

public RemoteV3FindPackageByIdResource(SourceRepository sourceRepository, Func<Task<HttpHandlerResource>> handlerFactory)
{
Expand All @@ -48,23 +46,10 @@ public override ILogger Logger
}
}

public override bool NoCache
public override SourceCacheContext CacheContext
{
get { return base.NoCache; }
set
{
base.NoCache = value;
if (value)
{
_cacheAgeLimitList = TimeSpan.Zero;
_cacheAgeLimitNupkg = TimeSpan.Zero;
}
else
{
_cacheAgeLimitList = TimeSpan.FromMinutes(30);
_cacheAgeLimitNupkg = TimeSpan.FromHours(24);
}
}
get { return base.CacheContext; }
set { base.CacheContext = value; }
}

public override async Task<IEnumerable<NuGetVersion>> GetAllVersionsAsync(string id, CancellationToken cancellationToken)
Expand Down Expand Up @@ -186,7 +171,7 @@ private async Task<NupkgEntry> OpenNupkgStreamAsyncCore(RemoteSourceDependencyIn
using (var data = await _httpSource.GetAsync(
package.ContentUri,
"nupkg_" + package.Identity.Id + "." + package.Identity.Version.ToNormalizedString(),
retry == 0 ? _cacheAgeLimitNupkg : TimeSpan.Zero,
retry == 0 ? CacheContext.NupkgMaxAgeTimeSpan : TimeSpan.Zero,
cancellationToken))
{
return new NupkgEntry
Expand Down