From 405082299dcd5a71ad08d15c5e457cdfee8b77ab Mon Sep 17 00:00:00 2001 From: Qiao Jin <43407364+Qiao-Jin@users.noreply.github.com> Date: Thu, 7 May 2020 14:52:13 +0800 Subject: [PATCH] Add a change list to optimize datacache commit (#1619) --- src/neo/IO/Caching/DataCache.cs | 26 +++++++++++-------- .../neo.UnitTests/IO/Caching/UT_DataCache.cs | 17 ------------ .../SmartContract/UT_Syscalls.cs | 8 +++--- tests/neo.UnitTests/UT_DataCache.cs | 18 +++---------- 4 files changed, 22 insertions(+), 47 deletions(-) diff --git a/src/neo/IO/Caching/DataCache.cs b/src/neo/IO/Caching/DataCache.cs index dd0d5221c8..687aae8f71 100644 --- a/src/neo/IO/Caching/DataCache.cs +++ b/src/neo/IO/Caching/DataCache.cs @@ -16,6 +16,7 @@ public class Trackable } private readonly Dictionary dictionary = new Dictionary(); + private readonly HashSet changeSet = new HashSet(); public TValue this[TKey key] { @@ -65,6 +66,7 @@ public void Add(TKey key, TValue value) Item = value, State = trackable == null ? TrackState.Added : TrackState.Changed }; + changeSet.Add(key); } } @@ -96,6 +98,7 @@ public void Commit() { dictionary.Remove(key); } + changeSet.Clear(); } public DataCache CreateSnapshot() @@ -114,9 +117,15 @@ public void Delete(TKey key) if (dictionary.TryGetValue(key, out Trackable trackable)) { if (trackable.State == TrackState.Added) + { dictionary.Remove(key); + changeSet.Remove(key); + } else + { trackable.State = TrackState.Deleted; + changeSet.Add(key); + } } else { @@ -128,21 +137,13 @@ public void Delete(TKey key) Item = item, State = TrackState.Deleted }); + changeSet.Add(key); } } } protected abstract void DeleteInternal(TKey key); - public void DeleteWhere(Func predicate) - { - lock (dictionary) - { - foreach (Trackable trackable in dictionary.Where(p => p.Value.State != TrackState.Deleted && predicate(p.Key, p.Value.Item)).Select(p => p.Value)) - trackable.State = TrackState.Deleted; - } - } - /// /// Find the entries that start with the `key_prefix` /// @@ -204,8 +205,8 @@ public IEnumerable GetChangeSet() { lock (dictionary) { - foreach (Trackable trackable in dictionary.Values.Where(p => p.State != TrackState.None)) - yield return trackable; + foreach (TKey key in changeSet) + yield return dictionary[key]; } } @@ -234,6 +235,7 @@ public TValue GetAndChange(TKey key, Func factory = null) else if (trackable.State == TrackState.None) { trackable.State = TrackState.Changed; + changeSet.Add(key); } } else @@ -254,6 +256,7 @@ public TValue GetAndChange(TKey key, Func factory = null) trackable.State = TrackState.Changed; } dictionary.Add(key, trackable); + changeSet.Add(key); } return trackable.Item; } @@ -282,6 +285,7 @@ public TValue GetOrAdd(TKey key, Func factory) { trackable.Item = factory(); trackable.State = TrackState.Added; + changeSet.Add(key); } else { diff --git a/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs b/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs index cd9752c819..e3cf329d43 100644 --- a/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs +++ b/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs @@ -246,23 +246,6 @@ public void TestDelete() myDataCache.InnerDict.ContainsKey(new MyKey("key2")).Should().BeFalse(); } - [TestMethod] - public void TestDeleteWhere() - { - myDataCache.Add(new MyKey("key1"), new MyValue("value1")); - myDataCache.Add(new MyKey("key2"), new MyValue("value2")); - - myDataCache.InnerDict.Add(new MyKey("key3"), new MyValue("value3")); - myDataCache.InnerDict.Add(new MyKey("key4"), new MyValue("value4")); - - myDataCache.DeleteWhere((k, v) => k.Key.StartsWith("key")); - myDataCache.Commit(); - myDataCache.TryGet(new MyKey("key1")).Should().BeNull(); - myDataCache.TryGet(new MyKey("key2")).Should().BeNull(); - myDataCache.InnerDict.ContainsKey(new MyKey("key1")).Should().BeFalse(); - myDataCache.InnerDict.ContainsKey(new MyKey("key2")).Should().BeFalse(); - } - [TestMethod] public void TestFind() { diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index c516d1a871..4a6bd90689 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -323,7 +323,7 @@ public void System_Runtime_GasLeft() public void System_Runtime_GetInvocationCounter() { ContractState contractA, contractB, contractC; - var snapshot = Blockchain.Singleton.GetSnapshot(); + var snapshot = Blockchain.Singleton.GetSnapshot().Clone(); var contracts = snapshot.Contracts; // Create dummy contracts @@ -339,9 +339,9 @@ public void System_Runtime_GetInvocationCounter() // Init A,B,C contracts // First two drops is for drop method and arguments - contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractA.ScriptHash.ToArray())); - contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractB.ScriptHash.ToArray())); - contracts.DeleteWhere((a, b) => a.ToArray().SequenceEqual(contractC.ScriptHash.ToArray())); + contracts.Delete(contractA.ScriptHash); + contracts.Delete(contractB.ScriptHash); + contracts.Delete(contractC.ScriptHash); contractA.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); contractB.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); contractC.Manifest = TestUtils.CreateDefaultManifest(contractA.ScriptHash, "dummyMain"); diff --git a/tests/neo.UnitTests/UT_DataCache.cs b/tests/neo.UnitTests/UT_DataCache.cs index 4b8ad1de74..22bcdaa26d 100644 --- a/tests/neo.UnitTests/UT_DataCache.cs +++ b/tests/neo.UnitTests/UT_DataCache.cs @@ -18,11 +18,9 @@ public void TestSetup() public void TestCachedFind_Between() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var storages = snapshot.Storages; + var storages = snapshot.Storages.CreateSnapshot(); var cache = new CloneCache(storages); - storages.DeleteWhere((k, v) => k.Id == 0); - storages.Add ( new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }, @@ -53,19 +51,15 @@ public void TestCachedFind_Between() cache.Find(new byte[5]).Select(u => u.Key.Key[1]).ToArray(), new byte[] { 0x01, 0x02, 0x03 } ); - - storages.DeleteWhere((k, v) => k.Id == 0); } [TestMethod] public void TestCachedFind_Last() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var storages = snapshot.Storages; + var storages = snapshot.Storages.CreateSnapshot(); var cache = new CloneCache(storages); - storages.DeleteWhere((k, v) => k.Id == 0); - storages.Add ( new StorageKey() { Key = new byte[] { 0x00, 0x01 }, Id = 0 }, @@ -89,19 +83,15 @@ public void TestCachedFind_Last() CollectionAssert.AreEqual(cache.Find(new byte[5]).Select(u => u.Key.Key[1]).ToArray(), new byte[] { 0x01, 0x02 } ); - - storages.DeleteWhere((k, v) => k.Id == 0); } [TestMethod] public void TestCachedFind_Empty() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var storages = snapshot.Storages; + var storages = snapshot.Storages.CreateSnapshot(); var cache = new CloneCache(storages); - storages.DeleteWhere((k, v) => k.Id == 0); - cache.Add ( new StorageKey() { Key = new byte[] { 0x00, 0x02 }, Id = 0 }, @@ -117,8 +107,6 @@ public void TestCachedFind_Empty() cache.Find(new byte[5]).Select(u => u.Key.Key[1]).ToArray(), new byte[] { 0x02 } ); - - storages.DeleteWhere((k, v) => k.Id == 0); } } }