Skip to content

Commit

Permalink
update cache system
Browse files Browse the repository at this point in the history
  • Loading branch information
0xF6 committed Aug 31, 2024
1 parent 50f8f8f commit a15c487
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 73 deletions.
1 change: 1 addition & 0 deletions registry.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=firestore/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Metapackage/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=prerelease/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=traceparent/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
70 changes: 53 additions & 17 deletions src/controllers/SearchController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,45 @@ namespace core.controllers;
using services;
using services.searchs;

public class PackageCacheSystem(IMemoryCache cache)
{
public bool TryGetPackage(string name, string version, out Package? pkg)
=> cache.TryGetValue($"packages/{name}/{version}", out pkg);

public void SetPackage(string name, string version, Package? pkg)
=> cache.Set($"packages/{name}/{version}", pkg, TimeSpan.FromDays(30));

public void InvalidatePackage(string name, string version)
{
if (TryGetPackage(name, version, out _))
cache.Remove($"packages/{name}/{version}");
}

public bool TryGetSearchResult(SearchRequest request, out IReadOnlyList<Package> result)
{
var r = cache.TryGetValue<IReadOnlyList<Package>>(request, out var list);

result = list ?? new List<Package>();

return r;
}

public void SetSearchResult(SearchRequest request, IReadOnlyList<Package> result)
=> cache.Set(request, result, new MemoryCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1),
Priority = CacheItemPriority.Low,
Size = 1024
});
}

[AllowAnonymous]
[ApiController]
public class SearchController(
ISearchService searchService,
IPackageService packageService,
IUrlGenerator urlGenerator,
IMemoryCache cache)
IUrlGenerator urlGenerator,
PackageCacheSystem cacheSystem)
: Controller
{
[HttpGet("@/package/{name}/{version}")]
Expand All @@ -23,9 +55,9 @@ public async Task<ActionResult<Package>> FindByName(string name, string version,
if (string.IsNullOrEmpty(version))
return BadRequest(new { message = "version cannot be null" });

if (cache.TryGetValue((name, version), out Package? package))
return Json(package);

if (cacheSystem.TryGetPackage(name, version, out var package))
return Json(package);
var ver = version switch
{
Package.LatestTag or null => new (0, 0, 0, 0, "", Package.LatestTag),
Expand All @@ -41,11 +73,8 @@ public async Task<ActionResult<Package>> FindByName(string name, string version,
result.Icon = result.HasEmbeddedIcon
? urlGenerator.GetPackageIconDownloadUrl(result.Name, result.Version)
: result.Icon;

if (version!.Equals(Package.LatestTag) || version.Equals(Package.NextTag))
return Json(result);

cache.Set((name, version), result, TimeSpan.FromDays(2));

cacheSystem.SetPackage(name, version!, result);
return Json(result);
}

Expand All @@ -58,7 +87,7 @@ public async Task<ActionResult<IReadOnlyList<Package>>> SearchAsync(
[FromQuery]string? packageType = null,
[FromQuery]string? framework = null,
CancellationToken cancellationToken = default)
{
{
var request = new SearchRequest
{
Skip = skip,
Expand All @@ -68,15 +97,22 @@ public async Task<ActionResult<IReadOnlyList<Package>>> SearchAsync(
PackageType = packageType,
Framework = framework,
Query = query ?? string.Empty,
};
};

if (cacheSystem.TryGetSearchResult(request, out var result))
return Json(result);

result = await searchService.SearchAsync(request, cancellationToken);

return Json(await searchService.SearchAsync(request, cancellationToken));
cacheSystem.SetSearchResult(request, result);

return Json(result);
}

[HttpGet("@/search/lint")]
public async Task<ActionResult<AutocompleteResponse>> AutocompleteAsync(
[FromQuery(Name = "q")] string autocompleteQuery = null,
[FromQuery(Name = "id")] string versionsQuery = null,
[FromQuery(Name = "q")] string? autocompleteQuery = null,
[FromQuery(Name = "id")] string? versionsQuery = null,
[FromQuery]bool prerelease = false,
[FromQuery]int skip = 0,
[FromQuery]int take = 20,
Expand Down Expand Up @@ -104,7 +140,7 @@ public async Task<ActionResult<AutocompleteResponse>> AutocompleteAsync(
PackageType = packageType,
Skip = skip,
Take = take,
Query = autocompleteQuery,
Query = autocompleteQuery ?? "",
};

return await searchService.AutocompleteAsync(request, cancellationToken);
Expand All @@ -113,7 +149,7 @@ public async Task<ActionResult<AutocompleteResponse>> AutocompleteAsync(

[HttpGet("@/search/dependents")]
public async Task<ActionResult<DependentsResponse>> DependentsAsync(
[FromQuery] string packageId = null,
[FromQuery] string? packageId = null,
CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(packageId))
Expand Down
28 changes: 12 additions & 16 deletions src/logic/DependencyInjectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace core;

using controllers;
using core.services;
using core.services.searchs;
using Google.Cloud.Firestore;
Expand Down Expand Up @@ -37,25 +38,19 @@ private static void AddConfiguration(this IServiceCollection services)
private static void AddRegistryServices(this IServiceCollection services)
{
services.AddAutoMapper(x => x.AddMaps(typeof(Mappers)));
services.AddSingleton(x =>
services.AddSingleton(x => new ConverterRegistry
{
var converters = new ConverterRegistry();

converters.Add(new PackageAuthorConverter());
converters.Add(new GuidConverter());
converters.Add(new PackageUrlsConverter());
converters.Add(new PackageReferenceConverter());

return converters;
new PackageAuthorConverter(),
new GuidConverter(),
new PackageUrlsConverter(),
new PackageReferenceConverter()
});
services.AddProvider((provider, configuration)
=>
{
var a = new FirestoreDbBuilder();
a.ConverterRegistry = provider.GetService<ConverterRegistry>();
a.ProjectId = configuration.GetDatabaseConnectionString();
return a.Build();
});
=> new FirestoreDbBuilder
{
ConverterRegistry = provider.GetService<ConverterRegistry>(),
ProjectId = configuration.GetDatabaseConnectionString()
}.Build());
services.AddSingleton(GetServiceFromProviders<FirestoreDb>);

services.TryAddSingleton<NullSearchIndexer>();
Expand Down Expand Up @@ -89,6 +84,7 @@ private static void AddRegistryServices(this IServiceCollection services)
services.TryAddTransient<FirebasePackageService>();
services.TryAddTransient<GoogleCloudStorageService>();
services.TryAddTransient<FirestoreSearchService>();
services.AddSingleton<PackageCacheSystem>();

}

Expand Down
17 changes: 6 additions & 11 deletions src/logic/services/PackageStorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ namespace core.services;
using Newtonsoft.Json;
using NuGet.Versioning;

public class PackageStorageService : IPackageStorageService
public class PackageStorageService(
IStorageService storage,
ILogger<PackageStorageService> logger)
: IPackageStorageService
{
private const string PackagesPathPrefix = "packages";

Expand All @@ -13,16 +16,8 @@ public class PackageStorageService : IPackageStorageService
private const string ReadmeContentType = "text/markdown";
private const string IconContentType = "image/xyz";

private readonly IStorageService _storage;
private readonly ILogger<PackageStorageService> _logger;

public PackageStorageService(
IStorageService storage,
ILogger<PackageStorageService> logger)
{
_storage = storage ?? throw new ArgumentNullException(nameof(storage));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
private readonly IStorageService _storage = storage ?? throw new ArgumentNullException(nameof(storage));
private readonly ILogger<PackageStorageService> _logger = logger ?? throw new ArgumentNullException(nameof(logger));

public async Task SavePackageContentAsync(
Package package,
Expand Down
11 changes: 1 addition & 10 deletions src/logic/services/firebase/FirebasePackageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,20 +125,14 @@ public async Task<IReadOnlyList<Package>> FindAsync(string id, bool includeUnlis
.ToList()
.AsReadOnly();
}

private static readonly Dictionary<(string, NuGetVersion), Package> _cachePackages = new ();



public async Task<Package?> FindOrNullAsync(
string id,
NuGetVersion version,
bool includeUnlisted,
CancellationToken cancellationToken)
{
if (!version.Metadata.Equals("next") || !version.Metadata.Equals("latest"))
if (_cachePackages.ContainsKey((id, version)))
return _cachePackages[(id, version)];

var entity = await _operationBuilder.Retrieve(id, version);

if (entity == null)
Expand All @@ -147,9 +141,6 @@ public async Task<IReadOnlyList<Package>> FindAsync(string id, bool includeUnlis
return null;

var result = mapper.Map<Package>(entity);

if (!version.Metadata.Equals("next") || !version.Metadata.Equals("latest"))
_cachePackages[(id, version)] = result;
return result;
}

Expand Down
51 changes: 32 additions & 19 deletions src/logic/services/searchs/FirestoreSearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace core.services.searchs;

using System.Diagnostics.CodeAnalysis;
using AutoMapper;
using controllers;
using core.services.searchs.models;
using Google.Cloud.Firestore;
using Newtonsoft.Json;
Expand All @@ -12,13 +13,13 @@ public class OwnerIsNotMatchException : Exception

}

public class FireOperationBuilder(FirestoreDb firestore, IMapper mapper, IServiceProvider serviceProvider)
public class FireOperationBuilder(FirestoreDb firestore, IMapper mapper, IServiceProvider serviceProvider, PackageCacheSystem cacheSystem)
{
public CollectionReference PackagesReference { get; private set; } = firestore.Collection("packages");
public CollectionReference PackagesLinks { get; private set; } = firestore.Collection("packages-links");

public DocumentReference Document(string path) => firestore.Document(path);
public CollectionReference Collecton(string path) => firestore.Collection(path);
public CollectionReference Collection(string path) => firestore.Collection(path);

public async Task<PackageEntity?> Retrieve(string packageId, NuGetVersion packageVersion)
{
Expand All @@ -31,16 +32,16 @@ public class FireOperationBuilder(FirestoreDb firestore, IMapper mapper, IServic

var result = packageVersion switch
{
{ Metadata: "next" } when packageRoot.ContainsField("next") => await packageRoot
.GetValue<DocumentReference>("next")
{ Metadata: Package.NextTag } when packageRoot.ContainsField(Package.NextTag) => await packageRoot
.GetValue<DocumentReference>(Package.NextTag)
.GetSnapshotAsync(),
{ Metadata: "next" } when !packageRoot.ContainsField("next") => await packageRoot
.GetValue<DocumentReference>("latest")
{ Metadata: Package.NextTag } when !packageRoot.ContainsField(Package.NextTag) => await packageRoot
.GetValue<DocumentReference>(Package.LatestTag)
.GetSnapshotAsync(),
{ Metadata: "latest" } => await packageRoot
.GetValue<DocumentReference>("latest")
{ Metadata: Package.LatestTag } => await packageRoot
.GetValue<DocumentReference>(Package.LatestTag)
.GetSnapshotAsync(),
{ } => await PackagesReference
not null => await PackagesReference
.Document(packageId)
.Collection("v")
.Document(packageVersion.ToNormalizedString())
Expand Down Expand Up @@ -76,6 +77,8 @@ public async Task<WriteResult> AddPackage(Package package, UserRecord owner)

var verified = false;
var isServiced = false;
var isWorkload = false;
var isMetapackage = false;

await using var scope = serviceProvider.CreateAsyncScope();
var userService = scope.ServiceProvider.GetRequiredService<IUserService>();
Expand All @@ -97,13 +100,20 @@ public async Task<WriteResult> AddPackage(Package package, UserRecord owner)
throw new OwnerIsNotMatchException();
if (snapshot.ContainsField("IsVerified"))
verified = snapshot.GetValue<bool>("IsVerified");
if (snapshot.ContainsField("IsServiced"))
isServiced = snapshot.GetValue<bool>("IsServiced");
if (snapshot.ContainsField("HasServicedPackage"))
isServiced = snapshot.GetValue<bool>("HasServicedPackage");
isWorkload = snapshot.ContainsField("IsWorkload") ?
snapshot.GetValue<bool>("IsWorkload") :
package.IsWorkload;
if (snapshot.ContainsField("HasMetapackage"))
isMetapackage = snapshot.GetValue<bool>("HasMetapackage");
}


entity.IsVerified = verified;
entity.HasServicedPackage = isServiced;
entity.HasServicedPackage = isServiced;
entity.IsWorkload = isWorkload;
entity.HasMetapackage = isMetapackage;

var result = await PackagesReference
.Document(entity.Id)
Expand All @@ -125,15 +135,18 @@ public async Task<WriteResult> AddPackage(Package package, UserRecord owner)

nextVersion = nextVersion.version >= latestVersion.version ? nextVersion : latestVersion;

var versionKv = new Dictionary<string, object>
{
var kv = new Dictionary<string, object>
{
{ "latest", latestVersion.path },
{ "next", nextVersion.path }
};
{ Package.LatestTag, latestVersion.path },
{ Package.NextTag , nextVersion.path }
};

await document.UpdateAsync(kv);
}
if (latestVersion.version == package.Version)
cacheSystem.InvalidatePackage(package.Name, Package.LatestTag);
if (nextVersion.version == package.Version)
cacheSystem.InvalidatePackage(package.Name, Package.NextTag);

await document.UpdateAsync(versionKv);
return result;
}

Expand Down

0 comments on commit a15c487

Please sign in to comment.