0
0
mirror of https://github.com/sp-tarkov/loot-dump-processor.git synced 2025-02-13 02:30:45 -05:00

Refactored storage layer to improve thread safety and code consistency

This commit is contained in:
bluextx 2025-01-11 11:26:11 +03:00
parent 6cdf3c1a9d
commit 02802ddc10
9 changed files with 54 additions and 98 deletions

View File

@ -22,9 +22,6 @@ public static class Program
await using var serviceProvider = services.BuildServiceProvider();
// Setup Data storage
DataStorageFactory.GetInstance().Setup();
// startup the pipeline
var pipeline = serviceProvider.GetRequiredService<IPipeline>();
await pipeline.Execute();

View File

@ -2,13 +2,14 @@ namespace LootDumpProcessor.Storage;
public abstract class AbstractKey(string[] indexes) : IKey
{
private string[] _indexes = indexes;
public abstract KeyType GetKeyType();
public string SerializedKey
{
get => string.Join("|", indexes);
set => indexes = value.Split("|");
get => string.Join("|", _indexes);
set => _indexes = value.Split("|");
}
public string[] GetLookupIndex() => indexes;
public string[] GetLookupIndex() => _indexes;
}

View File

@ -1,3 +1,4 @@
using System.Collections.Concurrent;
using LootDumpProcessor.Storage.Implementations.File;
using LootDumpProcessor.Storage.Implementations.Memory;
@ -5,9 +6,7 @@ namespace LootDumpProcessor.Storage;
public static class DataStorageFactory
{
private static readonly Dictionary<DataStorageTypes, IDataStorage> _dataStorage = new();
private static object lockObject = new();
private static readonly ConcurrentDictionary<DataStorageTypes, IDataStorage> DataStorage = new();
/**
* Requires LootDumpProcessorContext to be initialized before using
@ -15,23 +14,18 @@ public static class DataStorageFactory
public static IDataStorage GetInstance() =>
GetInstance(LootDumpProcessorContext.GetConfig().DataStorageConfig.DataStorageType);
public static IDataStorage GetInstance(DataStorageTypes type)
private static IDataStorage GetInstance(DataStorageTypes type)
{
IDataStorage dataStorage;
lock (lockObject)
{
if (!_dataStorage.TryGetValue(type, out dataStorage))
{
dataStorage = type switch
{
DataStorageTypes.File => new FileDataStorage(),
DataStorageTypes.Memory => new MemoryDataStorage(),
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
if (DataStorage.TryGetValue(type, out var dataStorage)) return dataStorage;
_dataStorage.Add(type, dataStorage);
}
}
dataStorage = type switch
{
DataStorageTypes.File => new FileDataStorage(),
DataStorageTypes.Memory => new MemoryDataStorage(),
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
DataStorage.TryAdd(type, dataStorage);
return dataStorage;
}

View File

@ -2,9 +2,8 @@ namespace LootDumpProcessor.Storage;
public interface IDataStorage
{
void Setup();
void Store<T>(T t) where T : IKeyable;
bool Exists(IKey t);
T GetItem<T>(IKey key) where T : IKeyable;
void Store<TEntity>(TEntity entity) where TEntity : IKeyable;
TEntity? GetItem<TEntity>(IKey key) where TEntity : IKeyable;
bool Exists(IKey key);
void Clear();
}

View File

@ -2,19 +2,14 @@ namespace LootDumpProcessor.Storage.Implementations.File;
public class FileDataStorage : IDataStorage
{
public void Setup()
public void Store<TEntity>(TEntity entity) where TEntity : IKeyable
{
StoreHandlerFactory.GetInstance(entity.GetKey().GetKeyType()).Store(entity);
}
public void Store<T>(T t) where T : IKeyable
{
StoreHandlerFactory.GetInstance(t.GetKey().GetKeyType()).Store(t);
}
public bool Exists(IKey key) => StoreHandlerFactory.GetInstance(key.GetKeyType()).Exists(key);
public bool Exists(IKey t) => StoreHandlerFactory.GetInstance(t.GetKeyType()).Exists(t);
public T GetItem<T>(IKey key) where T : IKeyable =>
StoreHandlerFactory.GetInstance(key.GetKeyType()).Retrieve<T>(key);
public T GetItem<T>(IKey key) where T : IKeyable => StoreHandlerFactory.GetInstance(key.GetKeyType()).Retrieve<T>(key);
public void Clear()
{

View File

@ -5,27 +5,27 @@ namespace LootDumpProcessor.Storage.Implementations.File.Handlers;
public abstract class AbstractStoreHandler : IStoreHandler
{
public void Store<T>(T obj, bool failIfDuplicate = true) where T : IKeyable
public void Store<TEntity>(TEntity entity, bool failIfDuplicate = true) where TEntity : IKeyable
{
var locationWithFile = GetLocation(obj.GetKey());
var locationWithFile = GetLocation(entity.GetKey());
if (System.IO.File.Exists(locationWithFile) && failIfDuplicate)
throw new Exception($"Attempted to save duplicated object into data storage: {locationWithFile}");
System.IO.File.WriteAllText(locationWithFile, JsonSerializer.Serialize(obj, JsonSerializerSettings.Default));
System.IO.File.WriteAllText(locationWithFile, JsonSerializer.Serialize(entity, JsonSerializerSettings.Default));
}
public T? Retrieve<T>(IKey obj) where T : IKeyable
public TEntity? Retrieve<TEntity>(IKey key) where TEntity : IKeyable
{
var locationWithFile = GetLocation(obj);
var locationWithFile = GetLocation(key);
if (!System.IO.File.Exists(locationWithFile)) return default;
return JsonSerializer.Deserialize<T>(System.IO.File.ReadAllText(locationWithFile),
return JsonSerializer.Deserialize<TEntity>(System.IO.File.ReadAllText(locationWithFile),
JsonSerializerSettings.Default);
}
public bool Exists(IKey obj)
public bool Exists(IKey key)
{
var locationWithFile = GetLocation(obj);
var locationWithFile = GetLocation(key);
return System.IO.File.Exists(locationWithFile);
}

View File

@ -2,7 +2,7 @@ namespace LootDumpProcessor.Storage.Implementations.File;
public interface IStoreHandler
{
void Store<T>(T obj, bool failIfDuplicate = true) where T : IKeyable;
T? Retrieve<T>(IKey obj) where T : IKeyable;
bool Exists(IKey obj);
void Store<TEntity>(TEntity entity, bool failIfDuplicate = true) where TEntity : IKeyable;
TEntity? Retrieve<TEntity>(IKey key) where TEntity : IKeyable;
bool Exists(IKey key);
}

View File

@ -1,28 +1,23 @@
using System.Collections.Concurrent;
using LootDumpProcessor.Storage.Implementations.File.Handlers;
namespace LootDumpProcessor.Storage.Implementations.File;
public class StoreHandlerFactory
{
private static Dictionary<KeyType, IStoreHandler> _handlers = new();
private static object lockObject = new();
private static readonly ConcurrentDictionary<KeyType, IStoreHandler> Handlers = new();
public static IStoreHandler GetInstance(KeyType type)
{
IStoreHandler handler;
lock (lockObject)
if (Handlers.TryGetValue(type, out var handler)) return handler;
handler = type switch
{
if (!_handlers.TryGetValue(type, out handler))
{
handler = type switch
{
KeyType.Unique => new FlatStoreHandler(),
KeyType.Subdivisioned => new SubdivisionedStoreHandler(),
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
_handlers.Add(type, handler);
}
}
KeyType.Unique => new FlatStoreHandler(),
KeyType.Subdivisioned => new SubdivisionedStoreHandler(),
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};
Handlers.TryAdd(type, handler);
return handler;
}

View File

@ -1,47 +1,22 @@
using System.Collections.Concurrent;
namespace LootDumpProcessor.Storage.Implementations.Memory;
public class MemoryDataStorage : IDataStorage
{
private static readonly Dictionary<string, object> CachedObjects = new();
private static readonly object _cacheObjectLock = new();
private readonly ConcurrentDictionary<string, object> _storage = new();
public void Setup()
public void Store<TEntity>(TEntity entity) where TEntity : IKeyable =>
_storage.TryAdd(GetLookupKey(entity.GetKey()), entity);
public TEntity? GetItem<TEntity>(IKey key) where TEntity : IKeyable
{
}
public void Store<T>(T t) where T : IKeyable
{
lock (_cacheObjectLock)
{
CachedObjects.Add(GetLookupKey(t.GetKey()), t);
}
}
public bool Exists(IKey t)
{
lock (_cacheObjectLock)
{
return CachedObjects.ContainsKey(GetLookupKey(t));
}
}
public T? GetItem<T>(IKey key) where T : IKeyable
{
lock (_cacheObjectLock)
{
if (CachedObjects.TryGetValue(GetLookupKey(key), out var value)) return (T)value;
}
if (_storage.TryGetValue(GetLookupKey(key), out var value)) return (TEntity)value;
return default;
}
private string GetLookupKey(IKey key) => string.Join("-", key.GetLookupIndex());
public bool Exists(IKey key) => _storage.ContainsKey(GetLookupKey(key));
public void Clear()
{
lock (_cacheObjectLock)
{
CachedObjects.Clear();
}
}
private string GetLookupKey(IKey key) => string.Join("-", key.GetLookupIndex());
public void Clear() => _storage.Clear();
}