huge commit for advanced stats feature.
broke data out into its own library. may be breaking changes with existing plugins
This commit is contained in:
114
Data/Helpers/LookupCache.cs
Normal file
114
Data/Helpers/LookupCache.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using Data.Abstractions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
|
||||
namespace Data.Helpers
|
||||
{
|
||||
public class LookupCache<T> : ILookupCache<T> where T : class, IUniqueId
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IDatabaseContextFactory _contextFactory;
|
||||
private Dictionary<long, T> _cachedItems;
|
||||
private readonly SemaphoreSlim _onOperation = new SemaphoreSlim(1, 1);
|
||||
|
||||
public LookupCache(ILogger<LookupCache<T>> logger, IDatabaseContextFactory contextFactory)
|
||||
{
|
||||
_logger = logger;
|
||||
_contextFactory = contextFactory;
|
||||
}
|
||||
|
||||
public async Task<T> AddAsync(T item)
|
||||
{
|
||||
await _onOperation.WaitAsync();
|
||||
T existingItem = null;
|
||||
|
||||
if (_cachedItems.ContainsKey(item.Id))
|
||||
{
|
||||
existingItem = _cachedItems[item.Id];
|
||||
}
|
||||
|
||||
if (existingItem != null)
|
||||
{
|
||||
_logger.LogDebug("Cached item already added for {type} {id} {value}", typeof(T).Name, item.Id,
|
||||
item.Value);
|
||||
_onOperation.Release();
|
||||
return existingItem;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogDebug("Adding new {type} with {id} {value}", typeof(T).Name, item.Id, item.Value);
|
||||
await using var context = _contextFactory.CreateContext();
|
||||
context.Set<T>().Add(item);
|
||||
await context.SaveChangesAsync();
|
||||
_cachedItems.Add(item.Id, item);
|
||||
return item;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Could not add item to cache for {type}", typeof(T).Name);
|
||||
throw new Exception("Could not add item to cache");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_onOperation.CurrentCount == 0)
|
||||
{
|
||||
_onOperation.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<T> FirstAsync(Func<T, bool> query)
|
||||
{
|
||||
await _onOperation.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var cachedResult = _cachedItems.Values.Where(query);
|
||||
|
||||
if (cachedResult.Any())
|
||||
{
|
||||
return cachedResult.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
if (_onOperation.CurrentCount == 0)
|
||||
{
|
||||
_onOperation.Release(1);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetAll()
|
||||
{
|
||||
return _cachedItems.Values;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await using var context = _contextFactory.CreateContext();
|
||||
_cachedItems = await context.Set<T>().ToDictionaryAsync(item => item.Id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Could not initialize caching for {cacheType}", typeof(T).Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user