using SQLite; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using ZeroLevel.Services.Serialization; namespace ZeroLevel.SqLite { public sealed class DataRecord { [PrimaryKey, AutoIncrement] public long Id { get; set; } [Indexed] public string Key { get; set; } public byte[] Data { get; set; } } public sealed class UserCacheRepository : BaseSqLiteDB where T : IBinarySerializable { #region Fields private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); #endregion Fields #region Ctor public UserCacheRepository() : base(typeof(T).Name) { CreateTable(); } #endregion Ctor #region API [MethodImpl(MethodImplOptions.AggressiveInlining)] private string KEY(long userId, string name) => $"{userId}.{name}"; public bool AddOrUpdate(long userid, string name, T data) { var key = KEY(userid, name); bool update = false; _rwLock.EnterReadLock(); try { var count_obj = Count(r => r.Key == key); if (count_obj > 0) { update = true; } } catch (Exception ex) { Log.Error(ex, $"[UserCacheRepository] Fault search existing records by name ({name})"); // no return! } finally { _rwLock.ExitReadLock(); } _rwLock.EnterWriteLock(); try { var body = MessageSerializer.Serialize(data); if (update) { var r = Single(r => r.Key == key); r.Data = body; Update(r); } else { Append(new DataRecord { Data = body, Key = key }); } return true; } catch (Exception ex) { Log.Error(ex, $"[UserCacheRepository] Fault insert record in storage. UserId: {userid}. Name '{name}'. Data: {typeof(T).Name}."); } finally { _rwLock.ExitWriteLock(); } return false; } public void Remove(long userid, string name) { var key = KEY(userid, name); _rwLock.EnterWriteLock(); try { Delete(r => r.Key == key); } catch (Exception ex) { Log.Error(ex, $"[UserCacheRepository] Fault remove record from db by name '{name}'. UserId: {userid}. Data: {typeof(T).Name}."); } finally { _rwLock.ExitWriteLock(); } } public long Count(long userid, string name) { var key = KEY(userid, name); _rwLock.EnterWriteLock(); try { return Count(r => r.Key == key); } catch (Exception ex) { Log.Error(ex, $"[UserCacheRepository] Fault get count record from db by name '{name}'. UserId: {userid}. Data: {typeof(T).Name}."); } finally { _rwLock.ExitWriteLock(); } return 0; } public IEnumerable GetAll(long userid, string name) { var key = KEY(userid, name); var result = new List(); _rwLock.EnterReadLock(); try { foreach (var r in SelectBy(r=>r.Key == key)) { var data = r.Data; if (data != null) { result.Add(MessageSerializer.Deserialize(data)); } } } catch (Exception ex) { Log.Error(ex, $"[UserCacheRepository] Fault read all records by name: {name}. UserId: {userid}. Data: {typeof(T).Name}."); } finally { _rwLock.ExitReadLock(); } return result; } #endregion API #region IDisposable protected override void DisposeStorageData() { } #endregion IDisposable } }