From 1456b4b91a81852ce787eb0ebf0afba88c7e3780 Mon Sep 17 00:00:00 2001 From: Suho Lee Date: Wed, 21 Aug 2024 14:27:05 +0900 Subject: [PATCH] tmp --- .../Libplanet.Node.Executable.csproj | 2 + .../Libplanet.Node.Executable/PluginLoader.cs | 90 +++++++++++++++++++ sdk/node/Libplanet.Node.Executable/Program.cs | 25 ++++++ .../appsettings.Development.json | 9 +- .../Services/BlockChainServiceTest.cs | 3 +- sdk/node/Libplanet.Node/PluginLoadContext.cs | 36 ++++++++ .../Services/BlockChainService.cs | 27 ++++-- .../Libplanet.Node/Services/SwarmService.cs | 11 ++- src/Libplanet.Action/ActionEvaluator.cs | 4 +- .../IPolicyActionsRegistry.cs | 36 ++++++++ src/Libplanet.Action/PolicyActionsRegistry.cs | 2 +- .../Transports/NetMQTransport.cs | 12 +-- .../RocksDBKeyValueStore.cs | 20 +++-- src/Libplanet.Store/BlockSet.cs | 23 ++--- src/Libplanet.Store/HashNodeCache.cs | 60 ++----------- src/Libplanet.Store/Libplanet.Store.csproj | 1 + .../Trie/CacheableKeyValueStore.cs | 5 ++ .../Trie/DefaultKeyValueStore.cs | 5 ++ src/Libplanet.Store/Trie/IKeyValueStore.cs | 5 ++ .../Trie/MemoryKeyValueStore.cs | 5 ++ src/Libplanet.Store/TrieStateStore.Commit.cs | 21 ++--- .../Blockchain/Policies/BlockPolicy.cs | 6 +- .../Blockchain/Policies/IBlockPolicy.cs | 2 +- .../Blockchain/Policies/NullBlockPolicy.cs | 2 +- .../Libplanet.Explorer.Executable/Program.cs | 2 +- 25 files changed, 291 insertions(+), 123 deletions(-) create mode 100644 sdk/node/Libplanet.Node.Executable/PluginLoader.cs create mode 100644 sdk/node/Libplanet.Node/PluginLoadContext.cs create mode 100644 src/Libplanet.Action/IPolicyActionsRegistry.cs diff --git a/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj b/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj index d43112eaed4..620462b7549 100644 --- a/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj +++ b/sdk/node/Libplanet.Node.Executable/Libplanet.Node.Executable.csproj @@ -12,6 +12,7 @@ + @@ -21,6 +22,7 @@ + diff --git a/sdk/node/Libplanet.Node.Executable/PluginLoader.cs b/sdk/node/Libplanet.Node.Executable/PluginLoader.cs new file mode 100644 index 00000000000..edecb11b409 --- /dev/null +++ b/sdk/node/Libplanet.Node.Executable/PluginLoader.cs @@ -0,0 +1,90 @@ +using System.Reflection; +using Libplanet.Action; +using Libplanet.Action.Loader; +using Libplanet.Blockchain.Policies; + +namespace Libplanet.Node.API; + +public static class PluginLoader +{ + public static IActionLoader LoadActionLoader(string relativePath, string typeName) + { + Assembly assembly = LoadPlugin(relativePath); + IEnumerable loaders = Create(assembly); + foreach (IActionLoader loader in loaders) + { + if (loader.GetType().FullName == typeName) + { + return loader; + } + } + + throw new ApplicationException( + $"Can't find {typeName} in {assembly} from {assembly.Location}. " + + $"Available types: {string + .Join(",", loaders.Select(x => x.GetType().FullName))}"); + } + + public static IPolicyActionsRegistry LoadPolicyActionRegistry( + string relativePath, + string typeName) + { + Assembly assembly = LoadPlugin(relativePath); + IEnumerable policies = Create(assembly); + foreach (IPolicyActionsRegistry policy in policies) + { + if (policy.GetType().FullName == typeName) + { + return policy; + } + } + + throw new ApplicationException( + $"Can't find {typeName} in {assembly} from {assembly.Location}. " + + $"Available types: {string + .Join(",", policies.Select(x => x.GetType().FullName))}"); + } + + private static IEnumerable Create(Assembly assembly) + where T : class + { + int count = 0; + + foreach (Type type in assembly.GetTypes()) + { + if (typeof(T).IsAssignableFrom(type)) + { + T result = Activator.CreateInstance(type) as T; + if (result != null) + { + count++; + yield return result; + } + } + } + + if (count == 0) + { + string availableTypes = string.Join(",", assembly.GetTypes().Select(t => t.FullName)); + throw new ApplicationException( + $"Can't find any type which implements ICommand in {assembly} from {assembly.Location}.\n" + + $"Available types: {availableTypes}"); + } + } + + private static Assembly LoadPlugin(string relativePath) + { + // Navigate up to the solution root + string root = Path.GetFullPath(Path.Combine( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName(typeof(Program).Assembly.Location))))))); + + string pluginLocation = Path.GetFullPath(Path.Combine(root, relativePath.Replace('\\', Path.DirectorySeparatorChar))); + Console.WriteLine($"Loading commands from: {pluginLocation}"); + PluginLoadContext loadContext = new PluginLoadContext(pluginLocation); + return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation))); + } +} diff --git a/sdk/node/Libplanet.Node.Executable/Program.cs b/sdk/node/Libplanet.Node.Executable/Program.cs index 53ccd302d64..616209efe80 100644 --- a/sdk/node/Libplanet.Node.Executable/Program.cs +++ b/sdk/node/Libplanet.Node.Executable/Program.cs @@ -3,6 +3,8 @@ using Libplanet.Node.Options.Schema; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Server.Kestrel.Core; +using Serilog; +using Serilog.Events; var builder = WebHost.CreateDefaultBuilder(args); var assemblies = new string[] @@ -14,6 +16,16 @@ builder.ConfigureLogging(logging => { logging.AddConsole(); + + // Logging setting + var loggerConfig = new LoggerConfiguration(); + loggerConfig = loggerConfig.MinimumLevel.Information(); + loggerConfig = loggerConfig + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .Enrich.FromLogContext() + .WriteTo.Console(); + + Log.Logger = loggerConfig.CreateLogger(); }); builder.ConfigureKestrel((context, options) => { @@ -26,6 +38,19 @@ }); builder.ConfigureServices((context, services) => { +// string pluginPath = "/Users/bin_bash_shell/Workspaces/planetarium/NineChronicles/" + +// "lib9c/Lib9c.NCActionLoader/bin/Debug/net6.0/Lib9c.NCActionLoader.dll"; +// string actionLoaderType = "Lib9c.NCActionLoader.NineChroniclesActionLoader"; +// string blockPolicyType = "Lib9c.NCActionLoader.NineChroniclesPolicyActionRegistry"; +// IActionLoader actionLoader = PluginLoader.LoadActionLoader(pluginPath, actionLoaderType); +// IPolicyActionsRegistry policyActionRegistry = +// PluginLoader.LoadPolicyActionRegistry(pluginPath, blockPolicyType); + +// Libplanet.Crypto.CryptoConfig.CryptoBackend = new Secp256k1CryptoBackend(); + +// builder.Services.AddSingleton(actionLoader); +// builder.Services.AddSingleton(policyActionRegistry); + services.AddGrpc(); services.AddGrpcReflection(); services.AddLibplanetNode(context.Configuration); diff --git a/sdk/node/Libplanet.Node.Executable/appsettings.Development.json b/sdk/node/Libplanet.Node.Executable/appsettings.Development.json index 734f125c83e..eb63d43e77b 100644 --- a/sdk/node/Libplanet.Node.Executable/appsettings.Development.json +++ b/sdk/node/Libplanet.Node.Executable/appsettings.Development.json @@ -16,9 +16,16 @@ }, "Swarm": { "IsEnabled": true, - "AppProtocolVersion": "200210/AB2da648b9154F2cCcAFBD85e0Bc3d51f97330Fc/MEUCIQCBr..8VdITFe9nMTobl4akFid.s8G2zy2pBidAyRXSeAIgER77qX+eywjgyth6QYi7rQw5nK3KXO6cQ6ngUh.CyfU=/ZHU5OnRpbWVzdGFtcHUxMDoyMDI0LTA3LTMwZQ==" + "AppProtocolVersion": "200210/AB2da648b9154F2cCcAFBD85e0Bc3d51f97330Fc/MEUCIQCBr..8VdITFe9nMTobl4akFid.s8G2zy2pBidAyRXSeAIgER77qX+eywjgyth6QYi7rQw5nK3KXO6cQ6ngUh.CyfU=/ZHU5OnRpbWVzdGFtcHUxMDoyMDI0LTA3LTMwZQ==", + "BlocksyncSeedPeer": "027bd36895d68681290e570692ad3736750ceaab37be402442ffb203967f98f7b6,9c-main-tcp-seed-1.planetarium.dev:31234" }, "Validator": { "IsEnabled": true + }, + "Store": { + "Type": 0, + "RootPath": "/Users/jeesu/Projects/Storage/Chain", + "StoreName": "9c-main-snapshot-slim", + "StateStoreName": "9c-main-snapshot-slim/states" } } diff --git a/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs b/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs index dd8461585ed..da8fc1d9c7a 100644 --- a/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs +++ b/sdk/node/Libplanet.Node.Tests/Services/BlockChainServiceTest.cs @@ -1,3 +1,4 @@ +using Libplanet.Action.Loader; using Libplanet.Blockchain; using Libplanet.Crypto; using Libplanet.Node.Options; @@ -32,7 +33,7 @@ public void Create_Test() genesisOptions: genesisOptions, storeOptions: storeOptions, policyService: policyService, - actionLoaderProviders: [], + actionLoader: TypedActionLoader.Create(), logger: logger); var blockChain = blockChainService.BlockChain; diff --git a/sdk/node/Libplanet.Node/PluginLoadContext.cs b/sdk/node/Libplanet.Node/PluginLoadContext.cs new file mode 100644 index 00000000000..387ce52f09a --- /dev/null +++ b/sdk/node/Libplanet.Node/PluginLoadContext.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.Loader; + +namespace Libplanet.Node; + +public class PluginLoadContext : AssemblyLoadContext +{ + private AssemblyDependencyResolver _resolver; + + public PluginLoadContext(string pluginPath) + { + _resolver = new AssemblyDependencyResolver(pluginPath); + } + + protected override Assembly Load(AssemblyName assemblyName) + { + string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); + if (assemblyPath != null) + { + return LoadFromAssemblyPath(assemblyPath); + } + + return null; + } + + protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) + { + string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); + if (libraryPath != null) + { + return LoadUnmanagedDllFromPath(libraryPath); + } + + return IntPtr.Zero; + } +} diff --git a/sdk/node/Libplanet.Node/Services/BlockChainService.cs b/sdk/node/Libplanet.Node/Services/BlockChainService.cs index 2f528bce875..56842bf6c14 100644 --- a/sdk/node/Libplanet.Node/Services/BlockChainService.cs +++ b/sdk/node/Libplanet.Node/Services/BlockChainService.cs @@ -38,7 +38,8 @@ public BlockChainService( IOptions genesisOptions, IOptions storeOptions, PolicyService policyService, - IEnumerable actionLoaderProviders, + IActionLoader actionLoader, + IPolicyActionsRegistry policyActions, ILogger logger) { _synchronizationContext = SynchronizationContext.Current ?? new(); @@ -48,7 +49,8 @@ public BlockChainService( storeOptions: storeOptions.Value, stagePolicy: policyService.StagePolicy, renderers: [this], - actionLoaders: [.. actionLoaderProviders.Select(item => item.GetActionLoader())]); + actionLoader: actionLoader, + policyActions: policyActions); } public event EventHandler? BlockAppended; @@ -84,7 +86,7 @@ void Action(object? state) } } - _logger.LogInformation("#{Height}: Block appended.", newTip.Index); + _logger.LogInformation("#{Height}: Block appended", newTip.Index); BlockAppended?.Invoke(this, new(newTip)); } } @@ -94,20 +96,27 @@ private static BlockChain CreateBlockChain( StoreOptions storeOptions, IStagePolicy stagePolicy, IRenderer[] renderers, - IActionLoader[] actionLoaders) + IActionLoader actionLoader, + IPolicyActionsRegistry policyActions) { var (store, stateStore) = CreateStore(storeOptions); - var actionLoader = new AggregateTypedActionLoader(actionLoaders); var actionEvaluator = new ActionEvaluator( - policyActionsRegistry: new(), + policyActionsRegistry: policyActions, stateStore, actionLoader); var genesisBlock = CreateGenesisBlock(genesisOptions); var policy = new BlockPolicy( - blockInterval: TimeSpan.FromSeconds(10), - getMaxTransactionsPerBlock: _ => int.MaxValue, - getMaxTransactionsBytes: _ => long.MaxValue); + policyActionsRegistry: policyActions, + blockInterval: TimeSpan.FromSeconds(8), + validateNextBlockTx: (chain, transaction) => null, + validateNextBlock: (chain, block) => null, + getMaxTransactionsBytes: l => long.MaxValue, + getMinTransactionsPerBlock: l => 0, + getMaxTransactionsPerBlock: l => int.MaxValue, + getMaxTransactionsPerSignerPerBlock: l => int.MaxValue + ); + var blockChainStates = new BlockChainStates(store, stateStore); if (store.GetCanonicalChainId() is null) { diff --git a/sdk/node/Libplanet.Node/Services/SwarmService.cs b/sdk/node/Libplanet.Node/Services/SwarmService.cs index 1c9f99c4937..7835d3017c8 100644 --- a/sdk/node/Libplanet.Node/Services/SwarmService.cs +++ b/sdk/node/Libplanet.Node/Services/SwarmService.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using System.Net; using Libplanet.Common; using Libplanet.Crypto; @@ -184,9 +185,17 @@ private static async Task CreateTransport( var appProtocolVersionOptions = new Net.Options.AppProtocolVersionOptions { AppProtocolVersion = appProtocolVersion, + TrustedAppProtocolVersionSigners = new HashSet() + { + PublicKey.FromHex("030ffa9bd579ee1503ce008394f687c182279da913bfaec12baca34e79698a7cd1"), + }.ToImmutableHashSet(), }; var hostOptions = new Net.Options.HostOptions(endPoint.Host, [], endPoint.Port); - return await NetMQTransport.Create(privateKey, appProtocolVersionOptions, hostOptions); + return await NetMQTransport.Create( + privateKey, + appProtocolVersionOptions, + hostOptions, + TimeSpan.FromSeconds(60)); } private static ConsensusReactorOption CreateConsensusReactorOption( diff --git a/src/Libplanet.Action/ActionEvaluator.cs b/src/Libplanet.Action/ActionEvaluator.cs index 8d6eda0bbb7..a27967b4ac4 100644 --- a/src/Libplanet.Action/ActionEvaluator.cs +++ b/src/Libplanet.Action/ActionEvaluator.cs @@ -24,7 +24,7 @@ namespace Libplanet.Action public class ActionEvaluator : IActionEvaluator { private readonly ILogger _logger; - private readonly PolicyActionsRegistry _policyActionsRegistry; + private readonly IPolicyActionsRegistry _policyActionsRegistry; private readonly IStateStore _stateStore; private readonly IActionLoader _actionLoader; @@ -40,7 +40,7 @@ public class ActionEvaluator : IActionEvaluator /// A implementation using /// action type lookup. public ActionEvaluator( - PolicyActionsRegistry policyActionsRegistry, + IPolicyActionsRegistry policyActionsRegistry, IStateStore stateStore, IActionLoader actionTypeLoader) { diff --git a/src/Libplanet.Action/IPolicyActionsRegistry.cs b/src/Libplanet.Action/IPolicyActionsRegistry.cs new file mode 100644 index 00000000000..545340d41d0 --- /dev/null +++ b/src/Libplanet.Action/IPolicyActionsRegistry.cs @@ -0,0 +1,36 @@ +using System.Collections.Immutable; + +namespace Libplanet.Action +{ + public interface IPolicyActionsRegistry + { + /// + /// An array of to execute and be rendered at the beginning + /// for every block, if any. + ImmutableArray BeginBlockActions + { + get; + } + /// + /// An array of to execute and be rendered at the end + /// for every block, if any. + ImmutableArray EndBlockActions + { + get; + } + /// + /// An array of to execute and be rendered at the beginning + /// for every transaction, if any. + ImmutableArray BeginTxActions + { + get; + } + /// + /// An array of to execute and be rendered at the end + /// for every transaction, if any. + ImmutableArray EndTxActions + { + get; + } + } +} diff --git a/src/Libplanet.Action/PolicyActionsRegistry.cs b/src/Libplanet.Action/PolicyActionsRegistry.cs index e9793899bd6..fb25d957127 100644 --- a/src/Libplanet.Action/PolicyActionsRegistry.cs +++ b/src/Libplanet.Action/PolicyActionsRegistry.cs @@ -4,7 +4,7 @@ namespace Libplanet.Action { - public class PolicyActionsRegistry + public class PolicyActionsRegistry : IPolicyActionsRegistry { /// /// A class containing policy actions to evaluate at each situation. diff --git a/src/Libplanet.Net/Transports/NetMQTransport.cs b/src/Libplanet.Net/Transports/NetMQTransport.cs index cb70133db43..7b97ba83f8d 100644 --- a/src/Libplanet.Net/Transports/NetMQTransport.cs +++ b/src/Libplanet.Net/Transports/NetMQTransport.cs @@ -454,8 +454,7 @@ await _requests.Writer.WriteAsync( oce ), peer, - content, - reqId + content ); } catch (OperationCanceledException oce2) @@ -476,7 +475,7 @@ await _requests.Writer.WriteAsync( { a?.SetStatus(ActivityStatusCode.Error); a?.AddTag("Exception", nameof(ChannelClosedException)); - throw WrapCommunicationFailException(ce.InnerException ?? ce, peer, content, reqId); + throw WrapCommunicationFailException(ce.InnerException ?? ce, peer, content); } catch (Exception e) { @@ -964,14 +963,9 @@ await Task.Factory.StartNew( private CommunicationFailException WrapCommunicationFailException( Exception innerException, BoundPeer peer, - MessageContent message, - Guid reqId + MessageContent message ) { - const string errMsg = - "Failed to send and receive replies from {Peer} for request " + - "{Message} {RequestId}."; - _logger.Error(innerException, errMsg, peer, message, reqId); return new CommunicationFailException( $"Failed to send and receive replies from {peer} for request {message}.", message.Type, diff --git a/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs b/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs index 029cb17a156..0c9cb0be6c3 100644 --- a/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs +++ b/src/Libplanet.RocksDBStore/RocksDBKeyValueStore.cs @@ -69,6 +69,7 @@ namespace Libplanet.RocksDBStore public class RocksDBKeyValueStore : IKeyValueStore { private readonly RocksDb _keyValueDb; + private WriteBatch _writeBatch; private bool _disposed = false; /// @@ -89,6 +90,7 @@ public RocksDBKeyValueStore( .SetHardPendingCompactionBytesLimit(1038176821042); _keyValueDb = RocksDBUtils.OpenRocksDb(options, path, type: type); + _writeBatch = new WriteBatch(); Type = type; } @@ -101,26 +103,22 @@ public byte[] Get(in KeyBytes key) => _keyValueDb.Get(key.ToByteArray()) /// public void Set(in KeyBytes key, byte[] value) { - _keyValueDb.Put(key.ToByteArray(), value); + _writeBatch.Put(key.ToByteArray(), value); } /// public void Set(IDictionary values) { - using var writeBatch = new WriteBatch(); - foreach (KeyValuePair kv in values) { - writeBatch.Put(kv.Key.ToByteArray(), kv.Value); + _writeBatch.Put(kv.Key.ToByteArray(), kv.Value); } - - _keyValueDb.Write(writeBatch); } /// public void Delete(in KeyBytes key) { - _keyValueDb.Remove(key.ToByteArray()); + _writeBatch.Delete(key.ToByteArray()); } /// @@ -128,7 +126,7 @@ public void Delete(IEnumerable keys) { foreach (KeyBytes key in keys) { - _keyValueDb.Remove(key.ToByteArray()); + _writeBatch.Delete(key.ToByteArray()); } } @@ -156,6 +154,12 @@ public IEnumerable ListKeys() } } + public void Commit() + { + _keyValueDb.Write(_writeBatch); + _writeBatch = new WriteBatch(); + } + public void TryCatchUpWithPrimary() { _keyValueDb.TryCatchUpWithPrimary(); diff --git a/src/Libplanet.Store/BlockSet.cs b/src/Libplanet.Store/BlockSet.cs index 61ff0736e96..f57cf001896 100644 --- a/src/Libplanet.Store/BlockSet.cs +++ b/src/Libplanet.Store/BlockSet.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Caching; +using Jitbit.Utils; using Libplanet.Types.Blocks; namespace Libplanet.Store @@ -10,12 +11,12 @@ namespace Libplanet.Store public class BlockSet : IReadOnlyDictionary { private readonly IStore _store; - private readonly LRUCache _cache; + private readonly FastCache _fastCache; public BlockSet(IStore store, int cacheSize = 4096) { _store = store; - _cache = new LRUCache(cacheSize, Math.Max(cacheSize / 64, 8)); + _fastCache = new FastCache(); } public IEnumerable Keys => @@ -68,7 +69,7 @@ public Block this[BlockHash key] value.ValidateTimestamp(); _store.PutBlock(value); - _cache.AddReplace(value.Hash, value); + _fastCache.AddOrUpdate(value.Hash, value, TimeSpan.FromMinutes(1)); } } @@ -82,7 +83,7 @@ public bool Remove(BlockHash key) { bool deleted = _store.DeleteBlock(key); - _cache.Remove(key); + _fastCache.Remove(key); return deleted; } @@ -153,23 +154,15 @@ public IEnumerator> GetEnumerator() private Block? GetBlock(BlockHash key) { - if (_cache.TryGet(key, out Block cached)) + if (_fastCache.TryGet(key, out Block cached)) { - if (_store.ContainsBlock(key)) - { - return cached; - } - else - { - // The cached block had been deleted on _store... - _cache.Remove(key); - } + return cached; } Block? fetched = _store.GetBlock(key); if (fetched is { }) { - _cache.AddReplace(key, fetched); + _fastCache.AddOrUpdate(key, fetched, TimeSpan.FromMinutes(1)); } return fetched; diff --git a/src/Libplanet.Store/HashNodeCache.cs b/src/Libplanet.Store/HashNodeCache.cs index 37145e1ca25..47d783234ac 100644 --- a/src/Libplanet.Store/HashNodeCache.cs +++ b/src/Libplanet.Store/HashNodeCache.cs @@ -1,11 +1,9 @@ -using System.Diagnostics; +using System; using System.Security.Cryptography; -using System.Threading; using Bencodex.Types; +using Jitbit.Utils; using Libplanet.Common; using Libplanet.Store.Trie; -using LruCacheNet; -using Serilog; namespace Libplanet.Store { @@ -14,37 +12,17 @@ namespace Libplanet.Store /// public class HashNodeCache { - // FIXME: Tuned to 9c mainnet. Should be refactored to accept cache size as an argument. - private const int _cacheSize = 524_288; - private const int _reportPeriod = 60_000; - - private LruCache, IValue> _cache; - private Stopwatch _stopwatch; - private int _attempts; - private int _hits; - private object _reportLock; + private FastCache, IValue> _fastCache; internal HashNodeCache() { - _cache = new LruCache, IValue>(_cacheSize); - _stopwatch = new Stopwatch(); - _attempts = 0; - _hits = 0; - _reportLock = new object(); - _stopwatch.Start(); + _fastCache = new FastCache, IValue>(); } public bool TryGetValue(HashDigest hash, out IValue? value) { - lock (_reportLock) + if (_fastCache.TryGet(hash, out value)) { - Report(); - } - - Interlocked.Increment(ref _attempts); - if (_cache.TryGetValue(hash, out value)) - { - Interlocked.Increment(ref _hits); return true; } else @@ -56,33 +34,7 @@ public bool TryGetValue(HashDigest hash, out IValue? value) public void AddOrUpdate(HashDigest hash, IValue value) { - _cache.AddOrUpdate(hash, value); - } - - private void Report() - { - long period = _stopwatch.ElapsedMilliseconds; - if (period > _reportPeriod) - { - Log - .ForContext("Source", nameof(HashNodeCache)) - .ForContext("Tag", "Metric") - .ForContext("Subtag", "HashNodeCacheReport") - .Debug( - "Successfully fetched {HitCount} cached values out of last " + - "{AttemptCount} attempts with hitrate of {HitRate} and " + - "{CacheUsed}/{CacheSize} cache in use during last {PeriodMs} ms", - _hits, - _attempts, - (double)_hits / _attempts, - _cache.Count, - _cache.Capacity, - period); - - _stopwatch.Restart(); - Interlocked.Exchange(ref _attempts, 0); - Interlocked.Exchange(ref _hits, 0); - } + _fastCache.AddOrUpdate(hash, value, TimeSpan.FromMinutes(1)); } } } diff --git a/src/Libplanet.Store/Libplanet.Store.csproj b/src/Libplanet.Store/Libplanet.Store.csproj index 6d61716151c..c17b8a6256b 100644 --- a/src/Libplanet.Store/Libplanet.Store.csproj +++ b/src/Libplanet.Store/Libplanet.Store.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs b/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs index 43d9e8f59cd..4c75235a000 100644 --- a/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs +++ b/src/Libplanet.Store/Trie/CacheableKeyValueStore.cs @@ -79,6 +79,11 @@ public bool Exists(in KeyBytes key) /// public IEnumerable ListKeys() => _keyValueStore.ListKeys(); + public void Commit() + { + throw new NotSupportedException(); + } + /// public void Dispose() { diff --git a/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs b/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs index a864ec0f15a..241482b54d4 100644 --- a/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs +++ b/src/Libplanet.Store/Trie/DefaultKeyValueStore.cs @@ -152,6 +152,11 @@ public IEnumerable ListKeys() => _root.EnumerateFiles(UPath.Root) .Select(path => KeyBytes.FromHex(path.GetName())); + public void Commit() + { + throw new NotSupportedException(); + } + private UPath DataPath(in KeyBytes key) => UPath.Root / key.Hex; } diff --git a/src/Libplanet.Store/Trie/IKeyValueStore.cs b/src/Libplanet.Store/Trie/IKeyValueStore.cs index 216b61dacb5..298fa833659 100644 --- a/src/Libplanet.Store/Trie/IKeyValueStore.cs +++ b/src/Libplanet.Store/Trie/IKeyValueStore.cs @@ -56,5 +56,10 @@ public interface IKeyValueStore : IDisposable /// All keys in an arbitrary order. The order might be vary for each call. /// public IEnumerable ListKeys(); + + /// + /// Commits the changes to the store. + /// + public void Commit(); } } diff --git a/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs b/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs index 1ab2acff69f..7b7b0a37c7c 100644 --- a/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs +++ b/src/Libplanet.Store/Trie/MemoryKeyValueStore.cs @@ -62,5 +62,10 @@ void IDisposable.Dispose() IEnumerable IKeyValueStore.ListKeys() => _dictionary.Keys; + + public void Commit() + { + throw new NotSupportedException(); + } } } diff --git a/src/Libplanet.Store/TrieStateStore.Commit.cs b/src/Libplanet.Store/TrieStateStore.Commit.cs index 259f467d7be..d585922b494 100644 --- a/src/Libplanet.Store/TrieStateStore.Commit.cs +++ b/src/Libplanet.Store/TrieStateStore.Commit.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -28,7 +29,7 @@ public ITrie Commit(ITrie trie) } else { - var writeBatch = new WriteBatch(StateKeyValueStore, 4096); + var writeBatch = new WriteBatch(StateKeyValueStore); INode newRoot = Commit(root, writeBatch, _cache); // It assumes embedded node if it's not HashNode. @@ -138,32 +139,20 @@ private static HashNode Write( private class WriteBatch { private readonly IKeyValueStore _store; - private readonly int _batchSize; - private readonly Dictionary _batch; - public WriteBatch(IKeyValueStore store, int batchSize) + public WriteBatch(IKeyValueStore store) { _store = store; - _batchSize = batchSize; - _batch = new Dictionary(_batchSize); } - public bool ContainsKey(KeyBytes key) => _batch.ContainsKey(key); - public void Add(KeyBytes key, byte[] value) { - _batch[key] = value; - - if (_batch.Count == _batchSize) - { - Flush(); - } + _store.Set(key, value); } public void Flush() { - _store.Set(_batch); - _batch.Clear(); + _store.Commit(); } } } diff --git a/src/Libplanet/Blockchain/Policies/BlockPolicy.cs b/src/Libplanet/Blockchain/Policies/BlockPolicy.cs index 63366847532..63b1f24196a 100644 --- a/src/Libplanet/Blockchain/Policies/BlockPolicy.cs +++ b/src/Libplanet/Blockchain/Policies/BlockPolicy.cs @@ -22,7 +22,7 @@ public class BlockPolicy : IBlockPolicy private readonly Func _validateNextBlock; - private readonly PolicyActionsRegistry _policyActionsRegistry; + private readonly IPolicyActionsRegistry _policyActionsRegistry; private readonly Func _getMaxTransactionsBytes; private readonly Func _getMinTransactionsPerBlock; private readonly Func _getMaxTransactionsPerBlock; @@ -73,7 +73,7 @@ public class BlockPolicy : IBlockPolicy /// Goes to . Set to a constant function /// of 10 by default. public BlockPolicy( - PolicyActionsRegistry? policyActionsRegistry = null, + IPolicyActionsRegistry? policyActionsRegistry = null, TimeSpan? blockInterval = null, Func? validateNextBlockTx = null, @@ -169,7 +169,7 @@ public BlockPolicy( } } - public PolicyActionsRegistry PolicyActionsRegistry => _policyActionsRegistry; + public IPolicyActionsRegistry PolicyActionsRegistry => _policyActionsRegistry; /// /// Targeted time interval between two consecutive s. diff --git a/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs b/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs index 7de700e2680..ba97914b349 100644 --- a/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs +++ b/src/Libplanet/Blockchain/Policies/IBlockPolicy.cs @@ -24,7 +24,7 @@ public interface IBlockPolicy /// /// A set of policy s to evaluate at each situation. /// - PolicyActionsRegistry PolicyActionsRegistry { get; } + IPolicyActionsRegistry PolicyActionsRegistry { get; } /// /// Checks if a can be included in a yet to be mined diff --git a/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs b/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs index 8e679648b36..19a28fea5d4 100644 --- a/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs +++ b/src/Libplanet/Blockchain/Policies/NullBlockPolicy.cs @@ -21,7 +21,7 @@ public NullBlockPolicy( public ISet
BlockedMiners { get; } = new HashSet
(); - public PolicyActionsRegistry PolicyActionsRegistry => new PolicyActionsRegistry(); + public IPolicyActionsRegistry PolicyActionsRegistry => new PolicyActionsRegistry(); public ImmutableArray BeginBlockActions => ImmutableArray.Empty; diff --git a/tools/Libplanet.Explorer.Executable/Program.cs b/tools/Libplanet.Explorer.Executable/Program.cs index 2c852312405..d3c2126f30a 100644 --- a/tools/Libplanet.Explorer.Executable/Program.cs +++ b/tools/Libplanet.Explorer.Executable/Program.cs @@ -378,7 +378,7 @@ public DumbBlockPolicy(BlockPolicy blockPolicy) _impl = blockPolicy; } - public PolicyActionsRegistry PolicyActionsRegistry => _impl.PolicyActionsRegistry; + public IPolicyActionsRegistry PolicyActionsRegistry => _impl.PolicyActionsRegistry; public int GetMinTransactionsPerBlock(long index) => _impl.GetMinTransactionsPerBlock(index);