diff --git a/src/Neo/Persistence/DataCache.cs b/src/Neo/Persistence/DataCache.cs index f70d0000ff..558ce4eaca 100644 --- a/src/Neo/Persistence/DataCache.cs +++ b/src/Neo/Persistence/DataCache.cs @@ -42,9 +42,20 @@ public class Trackable(StorageItem item, TrackState state) public TrackState State { get; set; } = state; } + /// + /// Delegate for storage entries + /// + /// DataCache + /// Key + /// Item + public delegate void OnEntryDelegate(DataCache sender, StorageKey key, StorageItem item); + private readonly Dictionary _dictionary = []; private readonly HashSet? _changeSet; + public event OnEntryDelegate? OnRead; + public event OnEntryDelegate? OnUpdate; + /// /// True if DataCache is readOnly /// @@ -145,7 +156,7 @@ public virtual void Commit() trackable.State = TrackState.None; break; case TrackState.Changed: - UpdateInternal(key, trackable.Item); + UpdateInternalWrapper(key, trackable.Item); trackable.State = TrackState.None; break; case TrackState.Deleted: @@ -218,7 +229,7 @@ public void Delete(StorageKey key) } else { - var item = TryGetInternal(key); + var item = TryGetInternalWrapper(key); if (item == null) return; _dictionary.Add(key, new Trackable(item, TrackState.Deleted)); _changeSet?.Add(key); @@ -390,7 +401,7 @@ public bool Contains(StorageKey key) } else { - var item = TryGetInternal(key); + var item = TryGetInternalWrapper(key); if (item == null) { if (factory == null) return null; @@ -407,6 +418,21 @@ public bool Contains(StorageKey key) } } + private StorageItem? TryGetInternalWrapper(StorageKey key) + { + var item = TryGetInternal(key); + if (item == null) return null; + + OnRead?.Invoke(this, key, item); + return item; + } + + private void UpdateInternalWrapper(StorageKey key, StorageItem value) + { + UpdateInternal(key, value); + OnUpdate?.Invoke(this, key, value); + } + /// /// Reads a specified entry from the cache. /// If the entry is not in the cache, it will be automatically loaded from the underlying storage. @@ -440,7 +466,7 @@ public StorageItem GetOrAdd(StorageKey key, Func factory) } else { - var item = TryGetInternal(key); + var item = TryGetInternalWrapper(key); if (item == null) { trackable = new Trackable(factory(), TrackState.Added); @@ -538,7 +564,7 @@ public StorageItem GetOrAdd(StorageKey key, Func factory) return null; return trackable.Item; } - var value = TryGetInternal(key); + var value = TryGetInternalWrapper(key); if (value == null) return null; _dictionary.Add(key, new Trackable(value, TrackState.None)); return value; diff --git a/src/Neo/Persistence/IStore.cs b/src/Neo/Persistence/IStore.cs index ba833f7220..6a79ff0549 100644 --- a/src/Neo/Persistence/IStore.cs +++ b/src/Neo/Persistence/IStore.cs @@ -23,6 +23,18 @@ public interface IStore : IWriteStore, IDisposable { + /// + /// Delegate for OnNewSnapshot + /// + /// Store + /// Snapshot + public delegate void OnNewSnapshotDelegate(IStore sender, IStoreSnapshot snapshot); + + /// + /// Event raised when a new snapshot is created + /// + public event OnNewSnapshotDelegate? OnNewSnapshot; + /// /// Creates a snapshot of the database. /// diff --git a/src/Neo/Persistence/Providers/MemoryStore.cs b/src/Neo/Persistence/Providers/MemoryStore.cs index 2786ed4953..cbe8f3d748 100644 --- a/src/Neo/Persistence/Providers/MemoryStore.cs +++ b/src/Neo/Persistence/Providers/MemoryStore.cs @@ -27,6 +27,9 @@ public class MemoryStore : IStore { private readonly ConcurrentDictionary _innerData = new(ByteArrayEqualityComparer.Default); + /// + public event IStore.OnNewSnapshotDelegate? OnNewSnapshot; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Delete(byte[] key) { @@ -38,7 +41,9 @@ public void Dispose() { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public IStoreSnapshot GetSnapshot() { - return new MemorySnapshot(this, _innerData); + var snapshot = new MemorySnapshot(this, _innerData); + OnNewSnapshot?.Invoke(this, snapshot); + return snapshot; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs index ae58cfeaab..c5c3eccce9 100644 --- a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs @@ -25,6 +25,9 @@ internal class Store : IStore, IEnumerable> private readonly DB _db; private readonly Options _options; + /// + public event IStore.OnNewSnapshotDelegate? OnNewSnapshot; + public Store(string path) { _options = new Options @@ -47,8 +50,12 @@ public void Dispose() _options.Dispose(); } - public IStoreSnapshot GetSnapshot() => - new Snapshot(this, _db); + public IStoreSnapshot GetSnapshot() + { + var snapshot = new Snapshot(this, _db); + OnNewSnapshot?.Invoke(this, snapshot); + return snapshot; + } public void Put(byte[] key, byte[] value) => _db.Put(WriteOptions.Default, key, value); diff --git a/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs b/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs index 82f295647a..b94f20a924 100644 --- a/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs +++ b/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs @@ -22,6 +22,9 @@ internal class Store : IStore { private readonly RocksDb _db; + /// + public event IStore.OnNewSnapshotDelegate? OnNewSnapshot; + public Store(string path) { _db = RocksDb.Open(Options.Default, Path.GetFullPath(path)); @@ -34,7 +37,9 @@ public void Dispose() public IStoreSnapshot GetSnapshot() { - return new Snapshot(this, _db); + var snapshot = new Snapshot(this, _db); + OnNewSnapshot?.Invoke(this, snapshot); + return snapshot; } /// diff --git a/tests/Neo.UnitTests/Persistence/UT_DataCache.cs b/tests/Neo.UnitTests/Persistence/UT_DataCache.cs index 35103222ae..aadd1ad404 100644 --- a/tests/Neo.UnitTests/Persistence/UT_DataCache.cs +++ b/tests/Neo.UnitTests/Persistence/UT_DataCache.cs @@ -19,84 +19,89 @@ using System.Linq; using System.Text; -namespace Neo.UnitTests.IO.Caching +namespace Neo.UnitTests.Persistence { [TestClass] public class UT_DataCache { - private readonly MemoryStore store = new(); - private StoreCache myDataCache; + private readonly MemoryStore _store = new(); + private StoreCache _myDataCache; - private static readonly StorageKey key1 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key1") }; - private static readonly StorageKey key2 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key2") }; - private static readonly StorageKey key3 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key3") }; - private static readonly StorageKey key4 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key4") }; - private static readonly StorageKey key5 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key5") }; + private static readonly StorageKey s_key1 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key1") }; + private static readonly StorageKey s_key2 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key2") }; + private static readonly StorageKey s_key3 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key3") }; + private static readonly StorageKey s_key4 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key4") }; + private static readonly StorageKey s_key5 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key5") }; - private static readonly StorageItem value1 = new(Encoding.UTF8.GetBytes("value1")); - private static readonly StorageItem value2 = new(Encoding.UTF8.GetBytes("value2")); - private static readonly StorageItem value3 = new(Encoding.UTF8.GetBytes("value3")); - private static readonly StorageItem value4 = new(Encoding.UTF8.GetBytes("value4")); - private static readonly StorageItem value5 = new(Encoding.UTF8.GetBytes("value5")); + private static readonly StorageItem s_value1 = new(Encoding.UTF8.GetBytes("value1")); + private static readonly StorageItem s_value2 = new(Encoding.UTF8.GetBytes("value2")); + private static readonly StorageItem s_value3 = new(Encoding.UTF8.GetBytes("value3")); + private static readonly StorageItem s_value4 = new(Encoding.UTF8.GetBytes("value4")); + private static readonly StorageItem s_value5 = new(Encoding.UTF8.GetBytes("value5")); [TestInitialize] public void Initialize() { - myDataCache = new(store, false); + _myDataCache = new(_store, false); } [TestMethod] public void TestAccessByKey() { - myDataCache.Add(key1, value1); - myDataCache.Add(key2, value2); + _myDataCache.Add(s_key1, s_value1); + _myDataCache.Add(s_key2, s_value2); - Assert.IsTrue(myDataCache[key1].EqualsTo(value1)); + Assert.IsTrue(_myDataCache[s_key1].EqualsTo(s_value1)); // case 2 read from inner - store.Put(key3.ToArray(), value3.ToArray()); - Assert.IsTrue(myDataCache[key3].EqualsTo(value3)); + _store.Put(s_key3.ToArray(), s_value3.ToArray()); + Assert.IsTrue(_myDataCache[s_key3].EqualsTo(s_value3)); } [TestMethod] public void TestAccessByNotFoundKey() { - Action action = () => + Assert.ThrowsExactly(() => { - var item = myDataCache[key1]; - }; - Assert.ThrowsExactly(action); + _ = _myDataCache[s_key1]; + }); } [TestMethod] public void TestAccessByDeletedKey() { - store.Put(key1.ToArray(), value1.ToArray()); - myDataCache.Delete(key1); + _store.Put(s_key1.ToArray(), s_value1.ToArray()); + _myDataCache.Delete(s_key1); - Action action = () => + Assert.ThrowsExactly(() => { - var item = myDataCache[key1]; - }; - Assert.ThrowsExactly(action); + _ = _myDataCache[s_key1]; + }); } [TestMethod] public void TestAdd() { - myDataCache.Add(key1, value1); - Assert.AreEqual(value1, myDataCache[key1]); + var read = 0; + var updated = 0; + _myDataCache.OnRead += (sender, key, value) => { read++; }; + _myDataCache.OnUpdate += (sender, key, value) => { updated++; }; + _myDataCache.Add(s_key1, s_value1); - Action action = () => myDataCache.Add(key1, value1); + Assert.AreEqual(s_value1, _myDataCache[s_key1]); + Assert.AreEqual(0, read); + Assert.AreEqual(0, updated); + + Action action = () => _myDataCache.Add(s_key1, s_value1); Assert.ThrowsExactly(action); - store.Put(key2.ToArray(), value2.ToArray()); - myDataCache.Delete(key2); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key2)).Select(u => u.Value.State).FirstOrDefault()); - myDataCache.Add(key2, value2); - Assert.AreEqual(TrackState.Changed, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key2)).Select(u => u.Value.State).FirstOrDefault()); + _store.Put(s_key2.ToArray(), s_value2.ToArray()); + _myDataCache.Delete(s_key2); + Assert.AreEqual(TrackState.Deleted, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key2)).Select(u => u.Value.State).FirstOrDefault()); + _myDataCache.Add(s_key2, s_value2); + Assert.AreEqual(TrackState.Changed, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key2)).Select(u => u.Value.State).FirstOrDefault()); - action = () => myDataCache.Add(key2, value2); + action = () => _myDataCache.Add(s_key2, s_value2); Assert.ThrowsExactly(action); } @@ -104,138 +109,156 @@ public void TestAdd() public void TestCommit() { using var store = new MemoryStore(); - store.Put(key2.ToArray(), value2.ToArray()); - store.Put(key3.ToArray(), value3.ToArray()); + store.Put(s_key2.ToArray(), s_value2.ToArray()); + store.Put(s_key3.ToArray(), s_value3.ToArray()); using var snapshot = store.GetSnapshot(); using var myDataCache = new StoreCache(snapshot); - myDataCache.Add(key1, value1); - Assert.AreEqual(TrackState.Added, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key1)).Select(u => u.Value.State).FirstOrDefault()); + var read = 0; + var updated = 0; + myDataCache.OnRead += (sender, key, value) => { read++; }; + myDataCache.OnUpdate += (sender, key, value) => { updated++; }; + + myDataCache.Add(s_key1, s_value1); + Assert.AreEqual(TrackState.Added, myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key1)).Select(u => u.Value.State).FirstOrDefault()); + Assert.AreEqual(0, read); + Assert.AreEqual(0, updated); + + myDataCache.Delete(s_key2); + + Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key2)).Select(u => u.Value.State).FirstOrDefault()); + Assert.AreEqual(1, read); + Assert.AreEqual(0, updated); + Assert.AreEqual(TrackState.None, myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key3)).Select(u => u.Value.State).FirstOrDefault()); - myDataCache.Delete(key2); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key2)).Select(u => u.Value.State).FirstOrDefault()); + myDataCache.Delete(s_key3); - Assert.AreEqual(TrackState.None, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.Value.State).FirstOrDefault()); - myDataCache.Delete(key3); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.Value.State).FirstOrDefault()); - myDataCache.Add(key3, value4); - Assert.AreEqual(TrackState.Changed, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.Value.State).FirstOrDefault()); + Assert.AreEqual(2, read); + Assert.AreEqual(0, updated); + Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key3)).Select(u => u.Value.State).FirstOrDefault()); + + myDataCache.Add(s_key3, s_value4); + Assert.AreEqual(TrackState.Changed, myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key3)).Select(u => u.Value.State).FirstOrDefault()); + Assert.AreEqual(2, read); + Assert.AreEqual(0, updated); // If we use myDataCache after it is committed, it will return wrong result. myDataCache.Commit(); - Assert.AreEqual(0, myDataCache.GetChangeSet().Count()); - Assert.IsTrue(store.TryGet(key1.ToArray()).SequenceEqual(value1.ToArray())); - Assert.IsNull(store.TryGet(key2.ToArray())); - Assert.IsTrue(store.TryGet(key3.ToArray()).SequenceEqual(value4.ToArray())); + Assert.AreEqual(0, myDataCache.GetChangeSet().Count()); + Assert.AreEqual(2, read); + Assert.AreEqual(1, updated); + Assert.IsTrue(store.TryGet(s_key1.ToArray()).SequenceEqual(s_value1.ToArray())); + Assert.IsNull(store.TryGet(s_key2.ToArray())); + Assert.IsTrue(store.TryGet(s_key3.ToArray()).SequenceEqual(s_value4.ToArray())); - Assert.IsTrue(myDataCache.TryGet(key1).Value.ToArray().SequenceEqual(value1.ToArray())); + Assert.IsTrue(myDataCache.TryGet(s_key1).Value.ToArray().SequenceEqual(s_value1.ToArray())); // Though value is deleted from the store, the value can still be gotten from the snapshot cache. - Assert.IsTrue(myDataCache.TryGet(key2).Value.ToArray().SequenceEqual(value2.ToArray())); - Assert.IsTrue(myDataCache.TryGet(key3).Value.ToArray().SequenceEqual(value4.ToArray())); + Assert.IsTrue(myDataCache.TryGet(s_key2).Value.ToArray().SequenceEqual(s_value2.ToArray())); + Assert.IsTrue(myDataCache.TryGet(s_key3).Value.ToArray().SequenceEqual(s_value4.ToArray())); } [TestMethod] public void TestCreateSnapshot() { - Assert.IsNotNull(myDataCache.CloneCache()); + Assert.IsNotNull(_myDataCache.CloneCache()); } [TestMethod] public void TestDelete() { using var store = new MemoryStore(); - store.Put(key2.ToArray(), value2.ToArray()); + store.Put(s_key2.ToArray(), s_value2.ToArray()); using var snapshot = store.GetSnapshot(); using var myDataCache = new StoreCache(snapshot); - myDataCache.Add(key1, value1); - myDataCache.Delete(key1); - Assert.IsNull(store.TryGet(key1.ToArray())); + myDataCache.Add(s_key1, s_value1); + myDataCache.Delete(s_key1); + Assert.IsNull(store.TryGet(s_key1.ToArray())); - myDataCache.Delete(key2); + myDataCache.Delete(s_key2); myDataCache.Commit(); - Assert.IsNull(store.TryGet(key2.ToArray())); + Assert.IsNull(store.TryGet(s_key2.ToArray())); } [TestMethod] public void TestFind() { - myDataCache.Add(key1, value1); - myDataCache.Add(key2, value2); + _myDataCache.Add(s_key1, s_value1); + _myDataCache.Add(s_key2, s_value2); - store.Put(key3.ToArray(), value3.ToArray()); - store.Put(key4.ToArray(), value4.ToArray()); + _store.Put(s_key3.ToArray(), s_value3.ToArray()); + _store.Put(s_key4.ToArray(), s_value4.ToArray()); - var k1 = key1.ToArray(); - var items = myDataCache.Find(k1); - Assert.AreEqual(key1, items.ElementAt(0).Key); - Assert.AreEqual(value1, items.ElementAt(0).Value); + var k1 = s_key1.ToArray(); + var items = _myDataCache.Find(k1); + Assert.AreEqual(s_key1, items.ElementAt(0).Key); + Assert.AreEqual(s_value1, items.ElementAt(0).Value); Assert.AreEqual(1, items.Count()); // null and empty with the forward direction -> finds everything. - items = myDataCache.Find(null); + items = _myDataCache.Find(null); Assert.AreEqual(4, items.Count()); - items = myDataCache.Find([]); + items = _myDataCache.Find([]); Assert.AreEqual(4, items.Count()); // null and empty with the backwards direction -> miserably fails. - Action action = () => myDataCache.Find(null, SeekDirection.Backward); + Action action = () => _myDataCache.Find(null, SeekDirection.Backward); Assert.ThrowsExactly(action); - action = () => myDataCache.Find([], SeekDirection.Backward); + action = () => _myDataCache.Find([], SeekDirection.Backward); Assert.ThrowsExactly(action); - items = myDataCache.Find(k1, SeekDirection.Backward); - Assert.AreEqual(key1, items.ElementAt(0).Key); - Assert.AreEqual(value1, items.ElementAt(0).Value); + items = _myDataCache.Find(k1, SeekDirection.Backward); + Assert.AreEqual(s_key1, items.ElementAt(0).Key); + Assert.AreEqual(s_value1, items.ElementAt(0).Value); Assert.AreEqual(1, items.Count()); - var prefix = k1.Take(k1.Count() - 1).ToArray(); // Just the "key" part to match everything. - items = myDataCache.Find(prefix); + var prefix = k1.Take(k1.Length - 1).ToArray(); // Just the "key" part to match everything. + items = _myDataCache.Find(prefix); Assert.AreEqual(4, items.Count()); - Assert.AreEqual(key1, items.ElementAt(0).Key); - Assert.AreEqual(value1, items.ElementAt(0).Value); - Assert.AreEqual(key2, items.ElementAt(1).Key); - Assert.AreEqual(value2, items.ElementAt(1).Value); - Assert.AreEqual(key3, items.ElementAt(2).Key); - Assert.IsTrue(items.ElementAt(2).Value.EqualsTo(value3)); - Assert.AreEqual(key4, items.ElementAt(3).Key); - Assert.IsTrue(items.ElementAt(3).Value.EqualsTo(value4)); - - items = myDataCache.Find(prefix, SeekDirection.Backward); + Assert.AreEqual(s_key1, items.ElementAt(0).Key); + Assert.AreEqual(s_value1, items.ElementAt(0).Value); + Assert.AreEqual(s_key2, items.ElementAt(1).Key); + Assert.AreEqual(s_value2, items.ElementAt(1).Value); + Assert.AreEqual(s_key3, items.ElementAt(2).Key); + Assert.IsTrue(items.ElementAt(2).Value.EqualsTo(s_value3)); + Assert.AreEqual(s_key4, items.ElementAt(3).Key); + Assert.IsTrue(items.ElementAt(3).Value.EqualsTo(s_value4)); + + items = _myDataCache.Find(prefix, SeekDirection.Backward); Assert.AreEqual(4, items.Count()); - Assert.AreEqual(key4, items.ElementAt(0).Key); - Assert.IsTrue(items.ElementAt(0).Value.EqualsTo(value4)); - Assert.AreEqual(key3, items.ElementAt(1).Key); - Assert.IsTrue(items.ElementAt(1).Value.EqualsTo(value3)); - Assert.AreEqual(key2, items.ElementAt(2).Key); - Assert.AreEqual(value2, items.ElementAt(2).Value); - Assert.AreEqual(key1, items.ElementAt(3).Key); - Assert.AreEqual(value1, items.ElementAt(3).Value); - - items = myDataCache.Find(key5); + Assert.AreEqual(s_key4, items.ElementAt(0).Key); + Assert.IsTrue(items.ElementAt(0).Value.EqualsTo(s_value4)); + Assert.AreEqual(s_key3, items.ElementAt(1).Key); + Assert.IsTrue(items.ElementAt(1).Value.EqualsTo(s_value3)); + Assert.AreEqual(s_key2, items.ElementAt(2).Key); + Assert.AreEqual(s_value2, items.ElementAt(2).Value); + Assert.AreEqual(s_key1, items.ElementAt(3).Key); + Assert.AreEqual(s_value1, items.ElementAt(3).Value); + + items = _myDataCache.Find(s_key5); Assert.AreEqual(0, items.Count()); } [TestMethod] public void TestSeek() { - myDataCache.Add(key1, value1); - myDataCache.Add(key2, value2); + _myDataCache.Add(s_key1, s_value1); + _myDataCache.Add(s_key2, s_value2); - store.Put(key3.ToArray(), value3.ToArray()); - store.Put(key4.ToArray(), value4.ToArray()); + _store.Put(s_key3.ToArray(), s_value3.ToArray()); + _store.Put(s_key4.ToArray(), s_value4.ToArray()); - var items = myDataCache.Seek(key3.ToArray(), SeekDirection.Backward).ToArray(); - Assert.AreEqual(key3, items[0].Key); - Assert.IsTrue(items[0].Value.EqualsTo(value3)); - Assert.AreEqual(key2, items[1].Key); - Assert.IsTrue(items[1].Value.EqualsTo(value2)); + var items = _myDataCache.Seek(s_key3.ToArray(), SeekDirection.Backward).ToArray(); + Assert.AreEqual(s_key3, items[0].Key); + Assert.IsTrue(items[0].Value.EqualsTo(s_value3)); + Assert.AreEqual(s_key2, items[1].Key); + Assert.IsTrue(items[1].Value.EqualsTo(s_value2)); Assert.AreEqual(3, items.Length); - items = myDataCache.Seek(key5.ToArray(), SeekDirection.Forward).ToArray(); + items = [.. _myDataCache.Seek(s_key5.ToArray(), SeekDirection.Forward)]; Assert.AreEqual(0, items.Length); } @@ -243,73 +266,73 @@ public void TestSeek() public void TestFindRange() { var store = new MemoryStore(); - store.Put(key3.ToArray(), value3.ToArray()); - store.Put(key4.ToArray(), value4.ToArray()); + store.Put(s_key3.ToArray(), s_value3.ToArray()); + store.Put(s_key4.ToArray(), s_value4.ToArray()); var myDataCache = new StoreCache(store); - myDataCache.Add(key1, value1); - myDataCache.Add(key2, value2); - - var items = myDataCache.FindRange(key3.ToArray(), key5.ToArray()).ToArray(); - Assert.AreEqual(key3, items[0].Key); - Assert.IsTrue(items[0].Value.EqualsTo(value3)); - Assert.AreEqual(key4, items[1].Key); - Assert.IsTrue(items[1].Value.EqualsTo(value4)); + myDataCache.Add(s_key1, s_value1); + myDataCache.Add(s_key2, s_value2); + + var items = myDataCache.FindRange(s_key3.ToArray(), s_key5.ToArray()).ToArray(); + Assert.AreEqual(s_key3, items[0].Key); + Assert.IsTrue(items[0].Value.EqualsTo(s_value3)); + Assert.AreEqual(s_key4, items[1].Key); + Assert.IsTrue(items[1].Value.EqualsTo(s_value4)); Assert.AreEqual(2, items.Length); // case 2 Need to sort the cache of myDataCache store = new(); - store.Put(key4.ToArray(), value4.ToArray()); - store.Put(key3.ToArray(), value3.ToArray()); + store.Put(s_key4.ToArray(), s_value4.ToArray()); + store.Put(s_key3.ToArray(), s_value3.ToArray()); myDataCache = new(store); - myDataCache.Add(key1, value1); - myDataCache.Add(key2, value2); - - items = myDataCache.FindRange(key3.ToArray(), key5.ToArray()).ToArray(); - Assert.AreEqual(key3, items[0].Key); - Assert.IsTrue(items[0].Value.EqualsTo(value3)); - Assert.AreEqual(key4, items[1].Key); - Assert.IsTrue(items[1].Value.EqualsTo(value4)); + myDataCache.Add(s_key1, s_value1); + myDataCache.Add(s_key2, s_value2); + + items = [.. myDataCache.FindRange(s_key3.ToArray(), s_key5.ToArray())]; + Assert.AreEqual(s_key3, items[0].Key); + Assert.IsTrue(items[0].Value.EqualsTo(s_value3)); + Assert.AreEqual(s_key4, items[1].Key); + Assert.IsTrue(items[1].Value.EqualsTo(s_value4)); Assert.AreEqual(2, items.Length); // case 3 FindRange by Backward store = new(); - store.Put(key4.ToArray(), value4.ToArray()); - store.Put(key3.ToArray(), value3.ToArray()); - store.Put(key5.ToArray(), value5.ToArray()); + store.Put(s_key4.ToArray(), s_value4.ToArray()); + store.Put(s_key3.ToArray(), s_value3.ToArray()); + store.Put(s_key5.ToArray(), s_value5.ToArray()); myDataCache = new(store); - myDataCache.Add(key1, value1); - myDataCache.Add(key2, value2); - - items = myDataCache.FindRange(key5.ToArray(), key3.ToArray(), SeekDirection.Backward).ToArray(); - Assert.AreEqual(key5, items[0].Key); - Assert.IsTrue(items[0].Value.EqualsTo(value5)); - Assert.AreEqual(key4, items[1].Key); - Assert.IsTrue(items[1].Value.EqualsTo(value4)); + myDataCache.Add(s_key1, s_value1); + myDataCache.Add(s_key2, s_value2); + + items = [.. myDataCache.FindRange(s_key5.ToArray(), s_key3.ToArray(), SeekDirection.Backward)]; + Assert.AreEqual(s_key5, items[0].Key); + Assert.IsTrue(items[0].Value.EqualsTo(s_value5)); + Assert.AreEqual(s_key4, items[1].Key); + Assert.IsTrue(items[1].Value.EqualsTo(s_value4)); Assert.AreEqual(2, items.Length); } [TestMethod] public void TestGetChangeSet() { - myDataCache.Add(key1, value1); - Assert.AreEqual(TrackState.Added, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key1)).Select(u => u.Value.State).FirstOrDefault()); - myDataCache.Add(key2, value2); - Assert.AreEqual(TrackState.Added, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key2)).Select(u => u.Value.State).FirstOrDefault()); - - store.Put(key3.ToArray(), value3.ToArray()); - store.Put(key4.ToArray(), value4.ToArray()); - myDataCache.Delete(key3); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.Value.State).FirstOrDefault()); - myDataCache.Delete(key4); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key4)).Select(u => u.Value.State).FirstOrDefault()); - - var items = myDataCache.GetChangeSet(); - int i = 0; + _myDataCache.Add(s_key1, s_value1); + Assert.AreEqual(TrackState.Added, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key1)).Select(u => u.Value.State).FirstOrDefault()); + _myDataCache.Add(s_key2, s_value2); + Assert.AreEqual(TrackState.Added, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key2)).Select(u => u.Value.State).FirstOrDefault()); + + _store.Put(s_key3.ToArray(), s_value3.ToArray()); + _store.Put(s_key4.ToArray(), s_value4.ToArray()); + _myDataCache.Delete(s_key3); + Assert.AreEqual(TrackState.Deleted, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key3)).Select(u => u.Value.State).FirstOrDefault()); + _myDataCache.Delete(s_key4); + Assert.AreEqual(TrackState.Deleted, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key4)).Select(u => u.Value.State).FirstOrDefault()); + + var items = _myDataCache.GetChangeSet(); + var i = 0; foreach (var item in items) { i++; @@ -324,58 +347,58 @@ public void TestGetChangeSet() [TestMethod] public void TestGetAndChange() { - myDataCache.Add(key1, value1); - Assert.AreEqual(TrackState.Added, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key1)).Select(u => u.Value.State).FirstOrDefault()); - store.Put(key2.ToArray(), value2.ToArray()); - store.Put(key3.ToArray(), value3.ToArray()); - myDataCache.Delete(key3); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.Value.State).FirstOrDefault()); + _myDataCache.Add(s_key1, s_value1); + Assert.AreEqual(TrackState.Added, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key1)).Select(u => u.Value.State).FirstOrDefault()); + _store.Put(s_key2.ToArray(), s_value2.ToArray()); + _store.Put(s_key3.ToArray(), s_value3.ToArray()); + _myDataCache.Delete(s_key3); + Assert.AreEqual(TrackState.Deleted, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key3)).Select(u => u.Value.State).FirstOrDefault()); StorageItem value_bk_1 = new(Encoding.UTF8.GetBytes("value_bk_1")); StorageItem value_bk_2 = new(Encoding.UTF8.GetBytes("value_bk_2")); StorageItem value_bk_3 = new(Encoding.UTF8.GetBytes("value_bk_3")); StorageItem value_bk_4 = new(Encoding.UTF8.GetBytes("value_bk_4")); - Assert.IsTrue(myDataCache.GetAndChange(key1, () => value_bk_1).EqualsTo(value1)); - Assert.IsTrue(myDataCache.GetAndChange(key2, () => value_bk_2).EqualsTo(value2)); - Assert.IsTrue(myDataCache.GetAndChange(key3, () => value_bk_3).EqualsTo(value_bk_3)); - Assert.IsTrue(myDataCache.GetAndChange(key4, () => value_bk_4).EqualsTo(value_bk_4)); + Assert.IsTrue(_myDataCache.GetAndChange(s_key1, () => value_bk_1).EqualsTo(s_value1)); + Assert.IsTrue(_myDataCache.GetAndChange(s_key2, () => value_bk_2).EqualsTo(s_value2)); + Assert.IsTrue(_myDataCache.GetAndChange(s_key3, () => value_bk_3).EqualsTo(value_bk_3)); + Assert.IsTrue(_myDataCache.GetAndChange(s_key4, () => value_bk_4).EqualsTo(value_bk_4)); } [TestMethod] public void TestGetOrAdd() { - myDataCache.Add(key1, value1); - Assert.AreEqual(TrackState.Added, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key1)).Select(u => u.Value.State).FirstOrDefault()); - store.Put(key2.ToArray(), value2.ToArray()); - store.Put(key3.ToArray(), value3.ToArray()); - myDataCache.Delete(key3); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.Value.State).FirstOrDefault()); + _myDataCache.Add(s_key1, s_value1); + Assert.AreEqual(TrackState.Added, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key1)).Select(u => u.Value.State).FirstOrDefault()); + _store.Put(s_key2.ToArray(), s_value2.ToArray()); + _store.Put(s_key3.ToArray(), s_value3.ToArray()); + _myDataCache.Delete(s_key3); + Assert.AreEqual(TrackState.Deleted, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key3)).Select(u => u.Value.State).FirstOrDefault()); StorageItem value_bk_1 = new(Encoding.UTF8.GetBytes("value_bk_1")); StorageItem value_bk_2 = new(Encoding.UTF8.GetBytes("value_bk_2")); StorageItem value_bk_3 = new(Encoding.UTF8.GetBytes("value_bk_3")); StorageItem value_bk_4 = new(Encoding.UTF8.GetBytes("value_bk_4")); - Assert.IsTrue(myDataCache.GetOrAdd(key1, () => value_bk_1).EqualsTo(value1)); - Assert.IsTrue(myDataCache.GetOrAdd(key2, () => value_bk_2).EqualsTo(value2)); - Assert.IsTrue(myDataCache.GetOrAdd(key3, () => value_bk_3).EqualsTo(value_bk_3)); - Assert.IsTrue(myDataCache.GetOrAdd(key4, () => value_bk_4).EqualsTo(value_bk_4)); + Assert.IsTrue(_myDataCache.GetOrAdd(s_key1, () => value_bk_1).EqualsTo(s_value1)); + Assert.IsTrue(_myDataCache.GetOrAdd(s_key2, () => value_bk_2).EqualsTo(s_value2)); + Assert.IsTrue(_myDataCache.GetOrAdd(s_key3, () => value_bk_3).EqualsTo(value_bk_3)); + Assert.IsTrue(_myDataCache.GetOrAdd(s_key4, () => value_bk_4).EqualsTo(value_bk_4)); } [TestMethod] public void TestTryGet() { - myDataCache.Add(key1, value1); - Assert.AreEqual(TrackState.Added, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key1)).Select(u => u.Value.State).FirstOrDefault()); - store.Put(key2.ToArray(), value2.ToArray()); - store.Put(key3.ToArray(), value3.ToArray()); - myDataCache.Delete(key3); - Assert.AreEqual(TrackState.Deleted, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.Value.State).FirstOrDefault()); - - Assert.IsTrue(myDataCache.TryGet(key1).EqualsTo(value1)); - Assert.IsTrue(myDataCache.TryGet(key2).EqualsTo(value2)); - Assert.IsNull(myDataCache.TryGet(key3)); + _myDataCache.Add(s_key1, s_value1); + Assert.AreEqual(TrackState.Added, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key1)).Select(u => u.Value.State).FirstOrDefault()); + _store.Put(s_key2.ToArray(), s_value2.ToArray()); + _store.Put(s_key3.ToArray(), s_value3.ToArray()); + _myDataCache.Delete(s_key3); + Assert.AreEqual(TrackState.Deleted, _myDataCache.GetChangeSet().Where(u => u.Key.Equals(s_key3)).Select(u => u.Value.State).FirstOrDefault()); + + Assert.IsTrue(_myDataCache.TryGet(s_key1).EqualsTo(s_value1)); + Assert.IsTrue(_myDataCache.TryGet(s_key2).EqualsTo(s_value2)); + Assert.IsNull(_myDataCache.TryGet(s_key3)); } [TestMethod] @@ -383,24 +406,24 @@ public void TestFindInvalid() { using var store = new MemoryStore(); using var myDataCache = new StoreCache(store); - myDataCache.Add(key1, value1); + myDataCache.Add(s_key1, s_value1); - store.Put(key2.ToArray(), value2.ToArray()); - store.Put(key3.ToArray(), value3.ToArray()); - store.Put(key4.ToArray(), value3.ToArray()); + store.Put(s_key2.ToArray(), s_value2.ToArray()); + store.Put(s_key3.ToArray(), s_value3.ToArray()); + store.Put(s_key4.ToArray(), s_value3.ToArray()); var items = myDataCache.Find(SeekDirection.Forward).GetEnumerator(); items.MoveNext(); - Assert.AreEqual(key1, items.Current.Key); + Assert.AreEqual(s_key1, items.Current.Key); - myDataCache.TryGet(key3); // GETLINE + myDataCache.TryGet(s_key3); // GETLINE items.MoveNext(); - Assert.AreEqual(key2, items.Current.Key); + Assert.AreEqual(s_key2, items.Current.Key); items.MoveNext(); - Assert.AreEqual(key3, items.Current.Key); + Assert.AreEqual(s_key3, items.Current.Key); items.MoveNext(); - Assert.AreEqual(key4, items.Current.Key); + Assert.AreEqual(s_key4, items.Current.Key); Assert.IsFalse(items.MoveNext()); } }