From 76f9d9aa9e45b77cf5b3c39b6c739ca9df430d42 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Wed, 3 Aug 2022 23:21:40 +0800 Subject: [PATCH] Optimize RemoteNode (#2800) --- src/Neo/IO/Caching/KeyedCollectionSlim.cs | 41 +++++++++++++++++++ .../Network/P2P/RemoteNode.ProtocolHandler.cs | 7 ++-- 2 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/Neo/IO/Caching/KeyedCollectionSlim.cs 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))));