This repository has been archived by the owner on Jul 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add registration updater to update all of the hives for a single pack…
…age ID (#723) Progress on NuGet/NuGetGallery#7739
- Loading branch information
1 parent
f29586c
commit 359bf1e
Showing
5 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
src/NuGet.Jobs.Catalog2Registration/IRegistrationUpdater.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// 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.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using NuGet.Protocol.Catalog; | ||
using NuGet.Services.Metadata.Catalog; | ||
|
||
namespace NuGet.Jobs.Catalog2Registration | ||
{ | ||
public interface IRegistrationUpdater | ||
{ | ||
Task UpdateAsync( | ||
string id, | ||
IReadOnlyList<CatalogCommitItem> entries, | ||
IReadOnlyDictionary<CatalogCommitItem, PackageDetailsCatalogLeaf> entryToLeaf); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
src/NuGet.Jobs.Catalog2Registration/RegistrationUpdater.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// 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.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using NuGet.Protocol.Catalog; | ||
using NuGet.Services.Metadata.Catalog; | ||
using NuGet.Services.Metadata.Catalog.Helpers; | ||
|
||
namespace NuGet.Jobs.Catalog2Registration | ||
{ | ||
public class RegistrationUpdater : IRegistrationUpdater | ||
{ | ||
private static readonly Dictionary<HiveType, IReadOnlyList<HiveType>> HiveToReplicaHives = new Dictionary<HiveType, IReadOnlyList<HiveType>> | ||
{ | ||
{ | ||
HiveType.Legacy, | ||
new List<HiveType> { HiveType.Gzipped } | ||
}, | ||
{ | ||
HiveType.SemVer2, | ||
new List<HiveType>() | ||
}, | ||
}; | ||
|
||
private readonly IHiveUpdater _hiveUpdater; | ||
private readonly IOptionsSnapshot<Catalog2RegistrationConfiguration> _options; | ||
private readonly ILogger<RegistrationUpdater> _logger; | ||
|
||
public RegistrationUpdater( | ||
IHiveUpdater hiveUpdater, | ||
IOptionsSnapshot<Catalog2RegistrationConfiguration> options, | ||
ILogger<RegistrationUpdater> logger) | ||
{ | ||
_hiveUpdater = hiveUpdater ?? throw new ArgumentNullException(nameof(hiveUpdater)); | ||
_options = options ?? throw new ArgumentNullException(nameof(options)); | ||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||
|
||
if (_options.Value.MaxConcurrentHivesPerId <= 0) | ||
{ | ||
throw new ArgumentOutOfRangeException( | ||
nameof(options), | ||
$"The {nameof(Catalog2RegistrationConfiguration.MaxConcurrentHivesPerId)} must be greater than zero."); | ||
} | ||
} | ||
|
||
public async Task UpdateAsync( | ||
string id, | ||
IReadOnlyList<CatalogCommitItem> entries, | ||
IReadOnlyDictionary<CatalogCommitItem, PackageDetailsCatalogLeaf> entryToLeaf) | ||
{ | ||
var registrationCommitTimestamp = DateTimeOffset.UtcNow; | ||
var hives = new ConcurrentBag<HiveType>(HiveToReplicaHives.Keys); | ||
await ParallelAsync.Repeat( | ||
async () => | ||
{ | ||
await Task.Yield(); | ||
while (hives.TryTake(out var hive)) | ||
{ | ||
await ProcessHiveAsync(hive, id, entries, entryToLeaf, registrationCommitTimestamp); | ||
} | ||
}, | ||
_options.Value.MaxConcurrentHivesPerId); | ||
} | ||
|
||
private async Task ProcessHiveAsync( | ||
HiveType hive, | ||
string id, | ||
IReadOnlyList<CatalogCommitItem> entries, | ||
IReadOnlyDictionary<CatalogCommitItem, PackageDetailsCatalogLeaf> entryToLeaf, | ||
DateTimeOffset registrationCommitTimestamp) | ||
{ | ||
var registrationCommitId = Guid.NewGuid().ToString(); | ||
var registrationCommit = new CatalogCommit(registrationCommitId, registrationCommitTimestamp); | ||
using (_logger.BeginScope( | ||
"Processing package {PackageId}, " + | ||
"hive {Hive}, " + | ||
"replica hives {ReplicaHives}, " + | ||
"registration commit ID {RegistrationCommitId}, " + | ||
"registration commit timestamp {RegistrationCommitTimestamp:O}.", | ||
id, | ||
hive, | ||
HiveToReplicaHives[hive], | ||
registrationCommitId, | ||
registrationCommitTimestamp)) | ||
{ | ||
_logger.LogInformation("Processing {Count} catalog commit items.", entries.Count); | ||
await _hiveUpdater.UpdateAsync(hive, HiveToReplicaHives[hive], id, entries, entryToLeaf, registrationCommit); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
tests/NuGet.Jobs.Catalog2Registration.Tests/RegistrationUpdaterFacts.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// 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.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Options; | ||
using Moq; | ||
using NuGet.Protocol.Catalog; | ||
using NuGet.Services; | ||
using NuGet.Services.Metadata.Catalog; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace NuGet.Jobs.Catalog2Registration | ||
{ | ||
public class RegistrationUpdaterFacts | ||
{ | ||
public class UpdateAsync : Facts | ||
{ | ||
public UpdateAsync(ITestOutputHelper output) : base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public async Task UsesDifferentCommitIdButSameCommitTimestamp() | ||
{ | ||
var commits = new ConcurrentBag<CatalogCommit>(); | ||
HiveUpdater | ||
.Setup(x => x.UpdateAsync( | ||
It.IsAny<HiveType>(), | ||
It.IsAny<IReadOnlyList<HiveType>>(), | ||
It.IsAny<string>(), | ||
It.IsAny<IReadOnlyList<CatalogCommitItem>>(), | ||
It.IsAny<IReadOnlyDictionary<CatalogCommitItem, PackageDetailsCatalogLeaf>>(), | ||
It.IsAny<CatalogCommit>())) | ||
.Returns(Task.CompletedTask) | ||
.Callback<HiveType, IReadOnlyList<HiveType>, string, IReadOnlyList<CatalogCommitItem>, IReadOnlyDictionary<CatalogCommitItem, PackageDetailsCatalogLeaf>, CatalogCommit>( | ||
(h, r, i, e, l, c) => commits.Add(c)); | ||
|
||
await Target.UpdateAsync(Id, Entries, EntryToLeaf); | ||
|
||
Assert.Equal(2, commits.Count); | ||
Assert.Single(commits.Select(x => x.Timestamp).Distinct()); | ||
Assert.Equal(2, commits.Select(x => x.Id).Distinct().Count()); | ||
} | ||
|
||
[Fact] | ||
public async Task UsesProperReplicaHives() | ||
{ | ||
await Target.UpdateAsync(Id, Entries, EntryToLeaf); | ||
|
||
HiveUpdater.Verify( | ||
x => x.UpdateAsync( | ||
It.IsAny<HiveType>(), | ||
It.IsAny<IReadOnlyList<HiveType>>(), | ||
It.IsAny<string>(), | ||
It.IsAny<IReadOnlyList<CatalogCommitItem>>(), | ||
It.IsAny<IReadOnlyDictionary<CatalogCommitItem, PackageDetailsCatalogLeaf>>(), | ||
It.IsAny<CatalogCommit>()), | ||
Times.Exactly(2)); | ||
HiveUpdater.Verify( | ||
x => x.UpdateAsync( | ||
HiveType.Legacy, | ||
It.Is<IReadOnlyList<HiveType>>(r => r.Count == 1 && r[0] == HiveType.Gzipped), | ||
Id, | ||
Entries, | ||
EntryToLeaf, | ||
It.IsAny<CatalogCommit>()), | ||
Times.Once); | ||
HiveUpdater.Verify( | ||
x => x.UpdateAsync( | ||
HiveType.SemVer2, | ||
It.Is<IReadOnlyList<HiveType>>(r => r.Count == 0), | ||
Id, | ||
Entries, | ||
EntryToLeaf, | ||
It.IsAny<CatalogCommit>()), | ||
Times.Once); | ||
} | ||
} | ||
|
||
public abstract class Facts | ||
{ | ||
public Facts(ITestOutputHelper output) | ||
{ | ||
HiveUpdater = new Mock<IHiveUpdater>(); | ||
Options = new Mock<IOptionsSnapshot<Catalog2RegistrationConfiguration>>(); | ||
Logger = output.GetLogger<RegistrationUpdater>(); | ||
|
||
Config = new Catalog2RegistrationConfiguration(); | ||
Config.MaxConcurrentHivesPerId = 1; | ||
Id = "NuGet.Versioning"; | ||
Entries = new List<CatalogCommitItem>(); | ||
EntryToLeaf = new Dictionary<CatalogCommitItem, PackageDetailsCatalogLeaf>(); | ||
|
||
Options.Setup(x => x.Value).Returns(() => Config); | ||
|
||
Target = new RegistrationUpdater( | ||
HiveUpdater.Object, | ||
Options.Object, | ||
Logger); | ||
} | ||
|
||
public Mock<IHiveUpdater> HiveUpdater { get; } | ||
public Mock<IOptionsSnapshot<Catalog2RegistrationConfiguration>> Options { get; } | ||
public RecordingLogger<RegistrationUpdater> Logger { get; } | ||
public Catalog2RegistrationConfiguration Config { get; } | ||
public string Id { get; } | ||
public List<CatalogCommitItem> Entries { get; } | ||
public Dictionary<CatalogCommitItem, PackageDetailsCatalogLeaf> EntryToLeaf { get; } | ||
public RegistrationUpdater Target { get; } | ||
} | ||
} | ||
} |