Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 63 additions & 95 deletions Modules/Caching/FileSystem/FileSystemCache.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using AsyncKeyedLock;
using GenHTTP.Api.Content.Caching;

namespace GenHTTP.Modules.Caching.FileSystem;
Expand All @@ -13,7 +14,7 @@ public sealed class FileSystemCache<T> : ICache<T>
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};

private readonly SemaphoreSlim _sync = new(1);
private readonly AsyncKeyedLocker<string> _sync = new();

#region Initialization

Expand Down Expand Up @@ -43,146 +44,113 @@ internal record Index(Dictionary<string, string> Entries, Dictionary<string, Dat

public async ValueTask<T[]> GetEntriesAsync(string key)
{
await _sync.WaitAsync();
using var _ = await _sync.LockAsync(key);
var result = new List<T>();

try
{
var result = new List<T>();
var index = await GetIndex(key);

var index = await GetIndex(key);
foreach (var entry in index.Entries)
{
var value = await GetValue(key, entry.Value);

foreach (var entry in index.Entries)
if (value != null)
{
var value = await GetValue(key, entry.Value);

if (value != null)
{
result.Add(value);
}
result.Add(value);
}

return result.ToArray();
}
finally
{
_sync.Release();
}

return result.ToArray();
}

public async ValueTask<T?> GetEntryAsync(string key, string variation)
{
await _sync.WaitAsync();
using var _ = await _sync.LockAsync(key);
var index = await GetIndex(key);

try
if (index.Entries.TryGetValue(variation, out var fileName))
{
var index = await GetIndex(key);

if (index.Entries.TryGetValue(variation, out var fileName))
{
return await GetValue(key, fileName);
}

return default;
}
finally
{
_sync.Release();
return await GetValue(key, fileName);
}

return default;
}

public async ValueTask StoreAsync(string key, string variation, T? entry)
{
await _sync.WaitAsync();
using var _ = await _sync.LockAsync(key);
var index = await GetIndex(key);

try
{
var index = await GetIndex(key);
EnsureDirectory(key);

EnsureDirectory(key);
if (index.Entries.TryGetValue(variation, out var fileName))
{
index.Expiration.Add(fileName, DateTime.UtcNow);

if (index.Entries.TryGetValue(variation, out var fileName))
if (entry == null)
{
index.Expiration.Add(fileName, DateTime.UtcNow);

if (entry == null)
{
index.Entries.Remove(variation);
}
else
{
fileName = Guid.NewGuid().ToString();

index.Entries[variation] = fileName;

await StoreValue(key, fileName, entry);
}

await StoreIndex(key, index);
index.Entries.Remove(variation);
}
else if (entry != null)
else
{
var newFile = Guid.NewGuid().ToString();

index.Entries.Add(variation, newFile);
fileName = Guid.NewGuid().ToString();

await StoreValue(key, newFile, entry);
index.Entries[variation] = fileName;

await StoreIndex(key, index);
await StoreValue(key, fileName, entry);
}

await StoreIndex(key, index);
}
finally
else if (entry != null)
{
_sync.Release();
var newFile = Guid.NewGuid().ToString();

index.Entries.Add(variation, newFile);

await StoreValue(key, newFile, entry);

await StoreIndex(key, index);
}
}

public async ValueTask StoreDirectAsync(string key, string variation, Func<Stream, ValueTask> asyncWriter)
{
await _sync.WaitAsync();
using var _ = await _sync.LockAsync(key);
var index = await GetIndex(key);

try
{
var index = await GetIndex(key);
EnsureDirectory(key);

EnsureDirectory(key);

if (index.Entries.TryGetValue(variation, out var fileName))
{
index.Expiration.Add(fileName, DateTime.UtcNow);

fileName = Guid.NewGuid().ToString();
if (index.Entries.TryGetValue(variation, out var fileName))
{
index.Expiration.Add(fileName, DateTime.UtcNow);

index.Entries[variation] = fileName;
fileName = Guid.NewGuid().ToString();

var file = new FileInfo(Path.Combine(Directory.FullName, key, fileName));
index.Entries[variation] = fileName;

await using (var streamWriter = new StreamWriter(file.FullName, false))
{
await asyncWriter(streamWriter.BaseStream);
}
var file = new FileInfo(Path.Combine(Directory.FullName, key, fileName));

await StoreIndex(key, index);
}
else
await using (var streamWriter = new StreamWriter(file.FullName, false))
{
var newFile = Guid.NewGuid().ToString();
await asyncWriter(streamWriter.BaseStream);
}

index.Entries.Add(variation, newFile);
await StoreIndex(key, index);
}
else
{
var newFile = Guid.NewGuid().ToString();

var file = new FileInfo(Path.Combine(Directory.FullName, key, newFile));
index.Entries.Add(variation, newFile);

await using (var stream = file.OpenWrite())
{
await asyncWriter(stream);
}
var file = new FileInfo(Path.Combine(Directory.FullName, key, newFile));

await StoreIndex(key, index);
await using (var stream = file.OpenWrite())
{
await asyncWriter(stream);
}
}
finally
{
_sync.Release();

await StoreIndex(key, index);
}
}

Expand Down
2 changes: 2 additions & 0 deletions Modules/Caching/GenHTTP.Modules.Caching.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

<ProjectReference Include="..\..\API\GenHTTP.Api.csproj" />

<PackageReference Include="AsyncKeyedLock" Version="7.1.8" />

<PackageReference Include="System.Text.Json" Version="10.0.1" />

</ItemGroup>
Expand Down
83 changes: 33 additions & 50 deletions Modules/Caching/Memory/MemoryCache.cs
Original file line number Diff line number Diff line change
@@ -1,82 +1,65 @@
using GenHTTP.Api.Content.Caching;
using AsyncKeyedLock;
using GenHTTP.Api.Content.Caching;
using System.Collections.Concurrent;

namespace GenHTTP.Modules.Caching.Memory;

public sealed class MemoryCache<T> : ICache<T>
{
private readonly Dictionary<string, Dictionary<string, T>> _cache = new();

private readonly SemaphoreSlim _sync = new(1);
private readonly ConcurrentDictionary<string, Dictionary<string, T>> _cache = new();
private readonly AsyncKeyedLocker<string> _sync = new();

#region Functionality

public ValueTask<T[]> GetEntriesAsync(string key)
public async ValueTask<T[]> GetEntriesAsync(string key)
{
_sync.Wait();

try
if (_cache.TryGetValue(key, out var entries))
{
if (_cache.TryGetValue(key, out var entries))
{
return new ValueTask<T[]>(entries.Values.ToArray());
}

return new ValueTask<T[]>([]);
return [.. entries.Values];
}
finally

using var _ = await _sync.LockAsync(key).ConfigureAwait(false);

if (_cache.TryGetValue(key, out entries))
{
_sync.Release();
return [.. entries.Values];
}

return [];
}

public ValueTask<T?> GetEntryAsync(string key, string variation)
public async ValueTask<T?> GetEntryAsync(string key, string variation)
{
_sync.Wait();
using var _ = await _sync.LockAsync(key).ConfigureAwait(false);

try
if (_cache.TryGetValue(key, out var entries))
{
if (_cache.TryGetValue(key, out var entries))
if (entries.TryGetValue(variation, out var value))
{
if (entries.TryGetValue(variation, out var value))
{
return new ValueTask<T?>(value);
}
return value;
}

return new ValueTask<T?>();
}
finally
{
_sync.Release();
}

return default;
}

public ValueTask StoreAsync(string key, string variation, T? entry)
public async ValueTask StoreAsync(string key, string variation, T? entry)
{
_sync.Wait();
using var _ = await _sync.LockAsync(key).ConfigureAwait(false);

try
if (!_cache.TryGetValue(key, out var value))
{
if (!_cache.TryGetValue(key, out var value))
{
value = new Dictionary<string, T>();
_cache[key] = value;
}

if (entry != null)
{
value[variation] = entry;
}
else
{
value.Remove(variation);
}
value = [];
_cache[key] = value;
}

return new ValueTask();
if (entry != null)
{
value[variation] = entry;
}
finally
else
{
_sync.Release();
value.Remove(variation);
}
}

Expand Down