diff --git a/src/Neo/IO/Caching/KeyedCollectionSlim.cs b/src/Neo/IO/Caching/KeyedCollectionSlim.cs new file mode 100644 index 0000000000..935faf36b2 --- /dev/null +++ b/src/Neo/IO/Caching/KeyedCollectionSlim.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +namespace Neo.IO.Caching; + +abstract class KeyedCollectionSlim where TKey : notnull +{ + private readonly LinkedList _items = new(); + private readonly Dictionary> dict = new(); + + public int Count => dict.Count; + public TItem First => _items.First.Value; + + protected abstract TKey GetKeyForItem(TItem item); + + public void Add(TItem item) + { + var key = GetKeyForItem(item); + var node = _items.AddLast(item); + if (!dict.TryAdd(key, node)) + { + _items.RemoveLast(); + throw new ArgumentException("An element with the same key already exists in the collection."); + } + } + + public bool Contains(TKey key) => dict.ContainsKey(key); + + public void Remove(TKey key) + { + if (dict.Remove(key, out var node)) + _items.Remove(node); + } + + public void RemoveFirst() + { + var key = GetKeyForItem(_items.First.Value); + dict.Remove(key); + _items.RemoveFirst(); + } +} diff --git a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs index ad6350a777..dfd21c63b8 100644 --- a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -19,7 +19,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Net; @@ -30,7 +29,7 @@ namespace Neo.Network.P2P partial class RemoteNode { private class Timer { } - private class PendingKnownHashesCollection : KeyedCollection + private class PendingKnownHashesCollection : KeyedCollectionSlim { protected override UInt256 GetKeyForItem((UInt256, DateTime) item) { @@ -412,9 +411,9 @@ private void OnTimer() DateTime oneMinuteAgo = TimeProvider.Current.UtcNow.AddMinutes(-1); while (pendingKnownHashes.Count > 0) { - var (_, time) = pendingKnownHashes[0]; + var (_, time) = pendingKnownHashes.First; if (oneMinuteAgo <= time) break; - pendingKnownHashes.RemoveAt(0); + pendingKnownHashes.RemoveFirst(); } if (oneMinuteAgo > lastSent) EnqueueMessage(Message.Create(MessageCommand.Ping, PingPayload.Create(NativeContract.Ledger.CurrentIndex(system.StoreView))));