diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs index 53d0d22fb75..0bb513b826d 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPrunerTests.cs @@ -173,7 +173,7 @@ private class TestContext public IStateReader StateReader { get; } public FullPruner Pruner { get; } public MemDb TrieDb { get; } - public MemDb CopyDb { get; } + public TestMemDb CopyDb { get; } public IProcessExitSource ProcessExitSource { get; } = Substitute.For(); @@ -250,6 +250,7 @@ public void ShouldCopyAllValues() foreach (KeyValuePair keyValuePair in TrieDb.GetAll()) { CopyDb[keyValuePair.Key].Should().BeEquivalentTo(keyValuePair.Value); + CopyDb.KeyWasWrittenWithFlags(keyValuePair.Key, WriteFlags.LowPriority | WriteFlags.DisableWAL); } } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs index ff3739761f0..fdffbf5d9fe 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/FullPruning/FullPruningDiskTest.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using FluentAssertions; +using FluentAssertions.Extensions; using Nethermind.Blockchain.FullPruning; using Nethermind.Config; using Nethermind.Core; @@ -141,7 +142,10 @@ private static async Task RunPruning(PruningTestBlockchain chain, int time, bool await WriteFileStructure(chain); - chain.PruningDb.InnerDbName.Should().Be($"State{time + 1}"); + Assert.That( + () => chain.PruningDb.InnerDbName, + Is.EqualTo($"State{time + 1}").After(1000, 100) + ); HashSet currentItems = chain.DbProvider.StateDb.GetAllValues().ToHashSet(Bytes.EqualityComparer); currentItems.IsSubsetOf(allItems).Should().BeTrue(); diff --git a/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs b/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs index 73e7e268cb0..6a6566906a5 100755 --- a/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs +++ b/src/Nethermind/Nethermind.Blockchain/FullPruning/FullPruner.cs @@ -176,10 +176,10 @@ protected virtual void RunPruning(IPruningContext pruning, Keccak statRoot) { pruning.MarkStart(); - WriteFlags writeFlags = WriteFlags.LowPriority; - if (_pruningConfig.FullPruningDisableLowPriorityWrites) + WriteFlags writeFlags = WriteFlags.DisableWAL; + if (!_pruningConfig.FullPruningDisableLowPriorityWrites) { - writeFlags = WriteFlags.None; + writeFlags |= WriteFlags.LowPriority; } using CopyTreeVisitor copyTreeVisitor = new(pruning, writeFlags, _logManager); diff --git a/src/Nethermind/Nethermind.Core/IKeyValueStore.cs b/src/Nethermind/Nethermind.Core/IKeyValueStore.cs index 972c6218d5b..da22dbe0501 100644 --- a/src/Nethermind/Nethermind.Core/IKeyValueStore.cs +++ b/src/Nethermind/Nethermind.Core/IKeyValueStore.cs @@ -36,11 +36,17 @@ public enum ReadFlags HintReadAhead = 2, } + [Flags] public enum WriteFlags { - None, + None = 0, // Hint that this is a low priority write - LowPriority, + LowPriority = 1, + + // Hint that this write does not require durable writes, as if it crash, it'll start over anyway. + DisableWAL = 2, + + LowPriorityAndNoWAL = LowPriority | DisableWAL, } } diff --git a/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs b/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs index 74379fbb923..04979065a59 100644 --- a/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs +++ b/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs @@ -39,15 +39,7 @@ public void Dispose() public void Set(ReadOnlySpan key, byte[]? value, WriteFlags flags = WriteFlags.None) { - UpdateWriteMetrics(); - if (value is null) - { - _rocksDb.Remove(key, _columnFamily, _mainDb.WriteFlagsToWriteOptions(flags)); - } - else - { - _rocksDb.Put(key, value, _columnFamily, _mainDb.WriteFlagsToWriteOptions(flags)); - } + _mainDb.SetWithColumnFamily(key, _columnFamily, value, flags); } public KeyValuePair[] this[byte[][] keys] => @@ -122,11 +114,6 @@ public void Flush() /// /// public void Clear() { throw new NotSupportedException(); } - - private void UpdateWriteMetrics() => _mainDb.UpdateWriteMetrics(); - - private void UpdateReadMetrics() => _mainDb.UpdateReadMetrics(); - public long GetSize() => _mainDb.GetSize(); public long GetCacheSize() => _mainDb.GetCacheSize(); public long GetIndexSize() => _mainDb.GetIndexSize(); diff --git a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs index b61c86ffd33..113c6ae944e 100644 --- a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs +++ b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs @@ -35,9 +35,10 @@ public class DbOnTheRocks : IDbWithSpan, ITunableDb private IntPtr? _rateLimiter; internal WriteOptions? WriteOptions { get; private set; } - internal WriteOptions? LowPriorityWriteOptions { get; private set; } - - internal ReadOptions? _readAheadReadOptions = null; + private WriteOptions? _noWalWrite; + private WriteOptions? _lowPriorityAndNoWalWrite; + private WriteOptions? _lowPriorityWriteOptions; + private ReadOptions? _readAheadReadOptions = null; internal DbOptions? DbOptions { get; private set; } @@ -396,9 +397,18 @@ protected virtual void BuildOptions(PerTableDbConfig dbConfig, Options opt WriteOptions.SetSync(dbConfig .WriteAheadLogSync); // potential fix for corruption on hard process termination, may cause performance degradation - LowPriorityWriteOptions = new WriteOptions(); - LowPriorityWriteOptions.SetSync(dbConfig.WriteAheadLogSync); - Native.Instance.rocksdb_writeoptions_set_low_pri(LowPriorityWriteOptions.Handle, true); + _noWalWrite = new WriteOptions(); + _noWalWrite.SetSync(dbConfig.WriteAheadLogSync); + _noWalWrite.DisableWal(1); + + _lowPriorityWriteOptions = new WriteOptions(); + _lowPriorityWriteOptions.SetSync(dbConfig.WriteAheadLogSync); + Native.Instance.rocksdb_writeoptions_set_low_pri(_lowPriorityWriteOptions.Handle, true); + + _lowPriorityAndNoWalWrite = new WriteOptions(); + _lowPriorityAndNoWalWrite.SetSync(dbConfig.WriteAheadLogSync); + _lowPriorityAndNoWalWrite.DisableWal(1); + Native.Instance.rocksdb_writeoptions_set_low_pri(_lowPriorityAndNoWalWrite.Handle, true); // When readahead flag is on, the next keys are expected to be after the current key. Increasing this value, // will increase the chances that the next keys will be in the cache, which reduces iops and latency. This @@ -471,6 +481,11 @@ public byte[]? this[ReadOnlySpan key] } public void Set(ReadOnlySpan key, byte[]? value, WriteFlags flags = WriteFlags.None) + { + SetWithColumnFamily(key, null, value, flags); + } + + internal void SetWithColumnFamily(ReadOnlySpan key, ColumnFamilyHandle? cf, byte[]? value, WriteFlags flags = WriteFlags.None) { if (_isDisposing) { @@ -483,11 +498,11 @@ public void Set(ReadOnlySpan key, byte[]? value, WriteFlags flags = WriteF { if (value is null) { - _db.Remove(key, null, WriteFlagsToWriteOptions(flags)); + _db.Remove(key, cf, WriteFlagsToWriteOptions(flags)); } else { - _db.Put(key, value, null, WriteFlagsToWriteOptions(flags)); + _db.Put(key, value, cf, WriteFlagsToWriteOptions(flags)); } } catch (RocksDbSharpException e) @@ -499,9 +514,19 @@ public void Set(ReadOnlySpan key, byte[]? value, WriteFlags flags = WriteF public WriteOptions? WriteFlagsToWriteOptions(WriteFlags flags) { - if (flags == WriteFlags.LowPriority) + if ((flags & WriteFlags.LowPriorityAndNoWAL) != 0) + { + return _lowPriorityAndNoWalWrite; + } + + if ((flags & WriteFlags.DisableWAL) != 0) + { + return _noWalWrite; + } + + if ((flags & WriteFlags.LowPriority) != 0) { - return LowPriorityWriteOptions; + return _lowPriorityWriteOptions; } return WriteOptions; diff --git a/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs b/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs index 75e95750bae..6b7a9587138 100644 --- a/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs +++ b/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs @@ -40,94 +40,20 @@ public void TearDown() } [Test] - public void Smoke_test() + public void WriteOptions_is_correct() { IDbConfig config = new DbConfig(); DbOnTheRocks db = new(DbPath, GetRocksDbSettings(DbPath, "Blocks"), config, LimboLogs.Instance); - db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; - Assert.That(db[new byte[] { 1, 2, 3 }], Is.EqualTo(new byte[] { 4, 5, 6 })); WriteOptions? options = db.WriteFlagsToWriteOptions(WriteFlags.LowPriority); - RocksDbSharp.Native.Instance.rocksdb_writeoptions_get_low_pri(options.Handle).Should().BeTrue(); - - db.Set(new byte[] { 2, 3, 4 }, new byte[] { 5, 6, 7 }, WriteFlags.LowPriority); - Assert.That(db[new byte[] { 2, 3, 4 }], Is.EqualTo(new byte[] { 5, 6, 7 })); - } - - [Test] - public void Smoke_test_readahead() - { - IDbConfig config = new DbConfig(); - DbOnTheRocks db = new("blocks", GetRocksDbSettings("blocks", "Blocks"), config, LimboLogs.Instance); - db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; - Assert.That(db.Get(new byte[] { 1, 2, 3 }, ReadFlags.HintReadAhead), Is.EqualTo(new byte[] { 4, 5, 6 })); - } - - [Test] - public void Smoke_test_span() - { - IDbConfig config = new DbConfig(); - DbOnTheRocks db = new(DbPath, GetRocksDbSettings(DbPath, "Blocks"), config, LimboLogs.Instance); - byte[] key = new byte[] { 1, 2, 3 }; - byte[] value = new byte[] { 4, 5, 6 }; - db.PutSpan(key, value); - Span readSpan = db.GetSpan(key); - Assert.That(readSpan.ToArray(), Is.EqualTo(new byte[] { 4, 5, 6 })); - db.DangerousReleaseMemory(readSpan); - } - - [Test] - public void Smoke_test_column_db() - { - IDbConfig config = new DbConfig(); - using ColumnsDb columnsDb = new(DbPath, GetRocksDbSettings(DbPath, "Blocks"), config, - LimboLogs.Instance, new List() { ReceiptsColumns.Blocks }); - IDbWithSpan? db = columnsDb.GetColumnDb(ReceiptsColumns.Blocks); - db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; - Assert.That(db[new byte[] { 1, 2, 3 }], Is.EqualTo(new byte[] { 4, 5, 6 })); - } - - [Test] - public void Can_get_all_on_empty() - { - IDbConfig config = new DbConfig(); - DbOnTheRocks db = new("testIterator", GetRocksDbSettings("testIterator", "TestIterator"), config, LimboLogs.Instance); - try - { - // ReSharper disable once ReturnValueOfPureMethodIsNotUsed - _ = db.GetAll().ToList(); - } - finally - { - db.Clear(); - db.Dispose(); - } - } - - [Test] - public void Smoke_test_iterator() - { - IDbConfig config = new DbConfig(); - DbOnTheRocks db = new(DbPath, GetRocksDbSettings(DbPath, "Blocks"), config, LimboLogs.Instance); - db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; - - KeyValuePair[] allValues = db.GetAll().ToArray()!; - allValues[0].Key.Should().BeEquivalentTo(new byte[] { 1, 2, 3 }); - allValues[0].Value.Should().BeEquivalentTo(new byte[] { 4, 5, 6 }); - } + Native.Instance.rocksdb_writeoptions_get_low_pri(options.Handle).Should().BeTrue(); - [Test] - public void Columns_db_smoke_test_iterator() - { - IDbConfig config = new DbConfig(); - using ColumnsDb columnsDb = new(DbPath, GetRocksDbSettings(DbPath, "Blocks"), config, - LimboLogs.Instance, new List() { ReceiptsColumns.Blocks }); - IDbWithSpan? db = columnsDb.GetColumnDb(ReceiptsColumns.Blocks); - db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; + options = db.WriteFlagsToWriteOptions(WriteFlags.LowPriority | WriteFlags.DisableWAL); + Native.Instance.rocksdb_writeoptions_get_low_pri(options.Handle).Should().BeTrue(); + Native.Instance.rocksdb_writeoptions_get_disable_WAL(options.Handle).Should().Be(true); - KeyValuePair[] allValues = db.GetAll().ToArray()!; - allValues[0].Key.Should().BeEquivalentTo(new byte[] { 1, 2, 3 }); - allValues[0].Value.Should().BeEquivalentTo(new byte[] { 4, 5, 6 }); + options = db.WriteFlagsToWriteOptions(WriteFlags.DisableWAL); + Native.Instance.rocksdb_writeoptions_get_disable_WAL(options.Handle).Should().Be(true); } [Test] @@ -245,35 +171,111 @@ private static RocksDbSettings GetRocksDbSettings(string dbPath, string dbName) WriteBufferSize = (ulong)1.KiB() }; } + } - [Test] - public void Test_columndb_put_and_get_span_correctly_store_value() + [TestFixture(true)] + [TestFixture(false)] + [Parallelizable(ParallelScope.None)] + public class DbOnTheRocksDbTests + { + string DbPath => "testdb/" + TestContext.CurrentContext.Test.Name; + private IDbWithSpan _db = null!; + IDisposable? _dbDisposable = null!; + + private bool _useColumnDb = false; + + public DbOnTheRocksDbTests(bool useColumnDb) { - string path = Path.Join(Path.GetTempPath(), "test"); - Directory.CreateDirectory(path); - try + _useColumnDb = useColumnDb; + } + + [SetUp] + public void Setup() + { + if (Directory.Exists(DbPath)) + { + Directory.Delete(DbPath, true); + } + + Directory.CreateDirectory(DbPath); + if (_useColumnDb) { IDbConfig config = new DbConfig(); - using ColumnsDb columnDb = new(path, GetRocksDbSettings(DbPath, "Blocks"), config, + ColumnsDb columnsDb = new(DbPath, GetRocksDbSettings(DbPath, "Blocks"), config, LimboLogs.Instance, new List() { ReceiptsColumns.Blocks }); + _dbDisposable = columnsDb; - using IDbWithSpan db = columnDb.GetColumnDb(ReceiptsColumns.Blocks); - - Keccak key = Keccak.Compute("something"); - Keccak value = Keccak.Compute("something"); - - db.KeyExists(key.Bytes).Should().BeFalse(); - db.PutSpan(key.Bytes, value.Bytes); - db.KeyExists(key.Bytes).Should().BeTrue(); - Span data = db.GetSpan(key.Bytes); - data.SequenceEqual(value.Bytes); - db.DangerousReleaseMemory(data); + _db = (ColumnDb)columnsDb.GetColumnDb(ReceiptsColumns.Blocks); } - finally + else { - Directory.Delete(path, true); + IDbConfig config = new DbConfig(); + _db = new DbOnTheRocks(DbPath, GetRocksDbSettings(DbPath, "Blocks"), config, LimboLogs.Instance); + _dbDisposable = _db; } } + + [TearDown] + public void TearDown() + { + _dbDisposable?.Dispose(); + } + + [Test] + public void Smoke_test() + { + _db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; + Assert.That(_db[new byte[] { 1, 2, 3 }], Is.EqualTo(new byte[] { 4, 5, 6 })); + + _db.Set(new byte[] { 2, 3, 4 }, new byte[] { 5, 6, 7 }, WriteFlags.LowPriority); + Assert.That(_db[new byte[] { 2, 3, 4 }], Is.EqualTo(new byte[] { 5, 6, 7 })); + } + + [Test] + public void Smoke_test_readahead() + { + _db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; + Assert.That(_db.Get(new byte[] { 1, 2, 3 }, ReadFlags.HintReadAhead), Is.EqualTo(new byte[] { 4, 5, 6 })); + } + + [Test] + public void Smoke_test_span() + { + byte[] key = new byte[] { 1, 2, 3 }; + byte[] value = new byte[] { 4, 5, 6 }; + _db.PutSpan(key, value); + Span readSpan = _db.GetSpan(key); + Assert.That(readSpan.ToArray(), Is.EqualTo(new byte[] { 4, 5, 6 })); + _db.DangerousReleaseMemory(readSpan); + } + + private static RocksDbSettings GetRocksDbSettings(string dbPath, string dbName) + { + return new(dbName, dbPath) + { + BlockCacheSize = (ulong)1.KiB(), + CacheIndexAndFilterBlocks = false, + WriteBufferNumber = 4, + WriteBufferSize = (ulong)1.KiB() + }; + } + + [Test] + public void Can_get_all_on_empty() + { + _ = _db.GetAll().ToList(); + } + + [Test] + public void Smoke_test_iterator() + { + _db[new byte[] { 1, 2, 3 }] = new byte[] { 4, 5, 6 }; + + KeyValuePair[] allValues = _db.GetAll().ToArray()!; + allValues[0].Key.Should().BeEquivalentTo(new byte[] { 1, 2, 3 }); + allValues[0].Value.Should().BeEquivalentTo(new byte[] { 4, 5, 6 }); + } + } class CorruptedDbOnTheRocks : DbOnTheRocks diff --git a/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs b/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs index f94f7b27dd4..63ef3b8885c 100755 --- a/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs +++ b/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs @@ -171,6 +171,7 @@ RocksDbSettings ClonedDbSettings() private void FinishPruning() { + _pruningContext?.CloningDb?.Flush(); IDb oldDb = Interlocked.Exchange(ref _currentDb, _pruningContext?.CloningDb); ClearOldDb(oldDb); } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs index e1d398615ed..d7ddb8626be 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProvider.cs @@ -271,15 +271,18 @@ public void AddCodes(ValueKeccak[] requestedHashes, byte[][] codes) { HashSet set = requestedHashes.ToHashSet(); - for (int i = 0; i < codes.Length; i++) + using (IBatch writeBatch = _dbProvider.CodeDb.StartBatch()) { - byte[] code = codes[i]; - ValueKeccak codeHash = ValueKeccak.Compute(code); - - if (set.Remove(codeHash)) + for (int i = 0; i < codes.Length; i++) { - Interlocked.Add(ref Metrics.SnapStateSynced, code.Length); - _dbProvider.CodeDb.Set(codeHash, code); + byte[] code = codes[i]; + ValueKeccak codeHash = ValueKeccak.Compute(code); + + if (set.Remove(codeHash)) + { + Interlocked.Add(ref Metrics.SnapStateSynced, code.Length); + writeBatch[codeHash.Bytes] = code; + } } } diff --git a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs index 43003d0c8eb..527256f3821 100644 --- a/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs +++ b/src/Nethermind/Nethermind.Synchronization/SnapSync/SnapProviderHelper.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading; +using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Serialization.Rlp; @@ -73,7 +74,7 @@ public static (AddRangeResult result, bool moreChildrenToRight, IList ReorgBoundaryReached { diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs index b5f479f0090..1723623b4c9 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs @@ -204,7 +204,7 @@ public int CachedNodesCount } } - public void CommitNode(long blockNumber, NodeCommitInfo nodeCommitInfo) + public void CommitNode(long blockNumber, NodeCommitInfo nodeCommitInfo, WriteFlags writeFlags = WriteFlags.None) { if (blockNumber < 0) throw new ArgumentOutOfRangeException(nameof(blockNumber)); EnsureCommitSetExistsForBlock(blockNumber); @@ -234,7 +234,7 @@ public void CommitNode(long blockNumber, NodeCommitInfo nodeCommitInfo) if (!_pruningStrategy.PruningEnabled) { - Persist(node, blockNumber); + Persist(node, blockNumber, writeFlags); } CommittedNodesCount++; @@ -269,7 +269,7 @@ private TrieNode SaveOrReplaceInDirtyNodesCache(NodeCommitInfo nodeCommitInfo, T return node; } - public void FinishBlockCommit(TrieType trieType, long blockNumber, TrieNode? root) + public void FinishBlockCommit(TrieType trieType, long blockNumber, TrieNode? root, WriteFlags writeFlags = WriteFlags.None) { if (blockNumber < 0) throw new ArgumentOutOfRangeException(nameof(blockNumber)); EnsureCommitSetExistsForBlock(blockNumber); @@ -290,7 +290,7 @@ public void FinishBlockCommit(TrieType trieType, long blockNumber, TrieNode? roo bool shouldPersistSnapshot = _persistenceStrategy.ShouldPersist(set.BlockNumber); if (shouldPersistSnapshot) { - Persist(set); + Persist(set, writeFlags); } else { @@ -623,9 +623,9 @@ private void CreateCommitSet(long blockNumber) /// for the block represented by this commit set. /// /// A commit set of a block which root is to be persisted. - private void Persist(BlockCommitSet commitSet) + private void Persist(BlockCommitSet commitSet, WriteFlags writeFlags = WriteFlags.None) { - void PersistNode(TrieNode tn) => Persist(tn, commitSet.BlockNumber); + void PersistNode(TrieNode tn) => Persist(tn, commitSet.BlockNumber, writeFlags); try { @@ -652,7 +652,7 @@ private void Persist(BlockCommitSet commitSet) PruneCurrentSet(); } - private void Persist(TrieNode currentNode, long blockNumber) + private void Persist(TrieNode currentNode, long blockNumber, WriteFlags writeFlags = WriteFlags.None) { _currentBatch ??= _keyValueStore.StartBatch(); if (currentNode is null) @@ -669,7 +669,7 @@ private void Persist(TrieNode currentNode, long blockNumber) // to prevent it from being removed from cache and also want to have it persisted. if (_logger.IsTrace) _logger.Trace($"Persisting {nameof(TrieNode)} {currentNode} in snapshot {blockNumber}."); - _currentBatch[currentNode.Keccak.Bytes] = currentNode.FullRlp; + _currentBatch.Set(currentNode.Keccak.Bytes, currentNode.FullRlp, writeFlags); currentNode.IsPersisted = true; currentNode.LastSeen = Math.Max(blockNumber, currentNode.LastSeen ?? 0); PersistedNodesCount++;