Skip to content

Commit 7556eaa

Browse files
authored
[ST] 1. Catalog2Dnx: Apply caching control to package version index (#10685)
* add * update
1 parent 35f7292 commit 7556eaa

5 files changed

Lines changed: 132 additions & 8 deletions

File tree

src/Catalog/Dnx/DnxCatalogCollector.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,15 @@ protected override Task<IEnumerable<CatalogCommitItemBatch>> CreateBatchesAsync(
7979
return Task.FromResult(batches);
8080
}
8181

82-
protected override Task<bool> FetchAsync(
82+
protected override async Task<bool> FetchAsync(
8383
CollectorHttpClient client,
8484
ReadWriteCursor front,
8585
ReadCursor back,
8686
CancellationToken cancellationToken)
8787
{
88-
return CatalogCommitUtilities.ProcessCatalogCommitsAsync(
88+
await DnxPackageVersionIndexCacheControl.LoadPackageIdsToIncludeAsync(_storageFactory.Create(), _logger, cancellationToken);
89+
90+
return await CatalogCommitUtilities.ProcessCatalogCommitsAsync(
8991
client,
9092
front,
9193
back,
@@ -156,7 +158,7 @@ await catalogEntries.ForEachAsync(_maxConcurrentCommitItemsWithinBatch, async ca
156158
cancellationToken);
157159
var areRequiredPropertiesPresent = await AreRequiredPropertiesPresentAsync(destinationStorage, destinationUri);
158160

159-
if (isNupkgSynchronized && isPackageInIndex && areRequiredPropertiesPresent)
161+
if (isNupkgSynchronized && areRequiredPropertiesPresent && isPackageInIndex && !DnxPackageVersionIndexCacheControl.PackageIdsToInclude.Contains(packageId))
160162
{
161163
_logger.LogInformation("No changes detected: {Id}/{Version}", packageId, normalizedPackageVersion);
162164

src/Catalog/Dnx/DnxMaker.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ public async Task UpdatePackageVersionIndexAsync(string id, Action<HashSet<NuGet
219219
// Store versions (sorted)
220220
result.Sort();
221221

222-
await storage.SaveAsync(resourceUri, CreateContent(result.Select(version => version.ToNormalizedString())), cancellationToken);
222+
await storage.SaveAsync(resourceUri, CreateContentForPackageVersionIndex(id, result.Select(version => version.ToNormalizedString())), cancellationToken);
223223
}
224224
else
225225
{
@@ -260,10 +260,10 @@ private static HashSet<NuGetVersion> GetVersions(string json)
260260
return result;
261261
}
262262

263-
private StorageContent CreateContent(IEnumerable<string> versions)
263+
private StorageContent CreateContentForPackageVersionIndex(string id, IEnumerable<string> versions)
264264
{
265265
JObject obj = new JObject { { "versions", new JArray(versions) } };
266-
return new StringStorageContent(obj.ToString(), "application/json", Constants.NoStoreCacheControl);
266+
return new StringStorageContent(obj.ToString(), "application/json", DnxPackageVersionIndexCacheControl.GetCacheControl(id, _logger));
267267
}
268268

269269
private async Task<Uri> SaveNupkgAsync(Stream nupkgStream, CatalogStorage storage, string id, string version, CancellationToken cancellationToken)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Microsoft.Extensions.Logging;
8+
using Newtonsoft.Json.Linq;
9+
using NuGet.Services.Metadata.Catalog.Persistence;
10+
11+
namespace NuGet.Services.Metadata.Catalog.Dnx
12+
{
13+
public static class DnxPackageVersionIndexCacheControl
14+
{
15+
private const string DefaultCacheControlForPackageVersionIndex = "max-age=10";
16+
private const string BlobNameOfPackageIdsToInclude = "PackageIdsToIncludeForCachingPackageVersionIndex.json";
17+
18+
public static HashSet<string> PackageIdsToInclude = new HashSet<string>();
19+
20+
public static string GetCacheControl(string id, ILogger logger)
21+
{
22+
if (PackageIdsToInclude.Contains(id))
23+
{
24+
logger.LogInformation("Add caching to the package version index of Package Id: {id}.", id);
25+
26+
return DefaultCacheControlForPackageVersionIndex;
27+
}
28+
else
29+
{
30+
return Constants.NoStoreCacheControl;
31+
}
32+
}
33+
34+
public static async Task LoadPackageIdsToIncludeAsync(IStorage storage, ILogger logger, CancellationToken cancellationToken)
35+
{
36+
if (!storage.Exists(BlobNameOfPackageIdsToInclude))
37+
{
38+
logger.LogInformation("{BlobName} does not exist, at {Address}.", BlobNameOfPackageIdsToInclude, storage.BaseAddress);
39+
40+
return;
41+
}
42+
43+
logger.LogInformation("Loading the list of Package Ids from {BlobName}, at {Address}.", BlobNameOfPackageIdsToInclude, storage.BaseAddress);
44+
45+
PackageIdsToInclude = new HashSet<string>();
46+
string jsonFile = await storage.LoadStringAsync(storage.ResolveUri(BlobNameOfPackageIdsToInclude), cancellationToken);
47+
if (jsonFile != null)
48+
{
49+
JObject obj = JObject.Parse(jsonFile);
50+
JArray ids = obj["ids"] as JArray;
51+
if (ids != null)
52+
{
53+
foreach (JToken id in ids)
54+
{
55+
PackageIdsToInclude.Add(id.ToString().ToLowerInvariant());
56+
}
57+
}
58+
}
59+
60+
logger.LogInformation("Loaded the list of Package Ids (Count: {Count}) from {BlobName}, at {Address}.", PackageIdsToInclude.Count, BlobNameOfPackageIdsToInclude, storage.BaseAddress);
61+
}
62+
}
63+
}

src/Catalog/Persistence/IStorage.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -27,6 +27,7 @@ Task<OptimisticConcurrencyControlToken> GetOptimisticConcurrencyControlTokenAsyn
2727
Task<string> LoadStringAsync(Uri resourceUri, CancellationToken cancellationToken);
2828
Uri ResolveUri(string relativeUri);
2929
Task SaveAsync(Uri resourceUri, StorageContent content, CancellationToken cancellationToken);
30+
bool Exists(string fileName);
3031

3132
/// <summary>
3233
/// Updates the cache control header on the provided resource URI (blob). This method throws an exception if
@@ -38,4 +39,4 @@ Task<OptimisticConcurrencyControlToken> GetOptimisticConcurrencyControlTokenAsyn
3839
/// <returns>True if the Cache-Control changes, false if the Cache-Control already matched the provided value.</returns>
3940
Task<bool> UpdateCacheControlAsync(Uri resourceUri, string cacheControl, CancellationToken cancellationToken);
4041
}
41-
}
42+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.Extensions.Logging;
9+
using Moq;
10+
using NuGet.Services.Metadata.Catalog;
11+
using NuGet.Services.Metadata.Catalog.Dnx;
12+
using NuGet.Services.Metadata.Catalog.Persistence;
13+
using Xunit;
14+
15+
namespace CatalogTests.Dnx
16+
{
17+
public class DnxPackageVersionIndexCacheControlTests
18+
{
19+
[Fact]
20+
public async Task LoadPackageIdsToIncludeAsync_BlobDoesNotExist()
21+
{
22+
var storage = new Mock<IStorage>();
23+
storage.Setup(s => s.Exists(It.IsAny<string>())).Returns(false);
24+
25+
DnxPackageVersionIndexCacheControl.PackageIdsToInclude = new HashSet<string>();
26+
27+
await DnxPackageVersionIndexCacheControl.LoadPackageIdsToIncludeAsync(storage.Object, Mock.Of<ILogger>(), It.IsAny<CancellationToken>());
28+
29+
Assert.Empty(DnxPackageVersionIndexCacheControl.PackageIdsToInclude);
30+
}
31+
32+
[Theory]
33+
[InlineData("{\"ids\":[]}", 0)]
34+
[InlineData("{\"ids\":[\"PackageId1\",\"packageid1\"]}", 1)]
35+
[InlineData("{\"ids\":[\"PackageId1\",\"PackageId2\"]}", 2)]
36+
public async Task LoadPackageIdsToIncludeAsync_BlobExists(string json, int count)
37+
{
38+
var storage = new Mock<IStorage>();
39+
storage.Setup(s => s.Exists(It.IsAny<string>())).Returns(true);
40+
storage.Setup(x => x.LoadStringAsync(It.IsAny<Uri>(), It.IsAny<CancellationToken>())).ReturnsAsync(json);
41+
42+
DnxPackageVersionIndexCacheControl.PackageIdsToInclude = new HashSet<string>();
43+
44+
await DnxPackageVersionIndexCacheControl.LoadPackageIdsToIncludeAsync(storage.Object, Mock.Of<ILogger>(), It.IsAny<CancellationToken>());
45+
46+
Assert.Equal(count, DnxPackageVersionIndexCacheControl.PackageIdsToInclude.Count);
47+
}
48+
49+
[Fact]
50+
public void GetCacheControl()
51+
{
52+
DnxPackageVersionIndexCacheControl.PackageIdsToInclude = new HashSet<string>() { "packageid1" };
53+
54+
Assert.Equal("max-age=10", DnxPackageVersionIndexCacheControl.GetCacheControl("packageid1", Mock.Of<ILogger>()));
55+
Assert.Equal(Constants.NoStoreCacheControl, DnxPackageVersionIndexCacheControl.GetCacheControl("packageid2", Mock.Of<ILogger>()));
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)