Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow precache to clear in background #7438

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@

namespace Nethermind.Consensus.Processing;

public class BlockCachePreWarmer(ReadOnlyTxProcessingEnvFactory envFactory, ISpecProvider specProvider, ILogManager logManager, IWorldState? targetWorldState = null) : IBlockCachePreWarmer
public class BlockCachePreWarmer(ReadOnlyTxProcessingEnvFactory envFactory, ISpecProvider specProvider, ILogManager logManager, PreBlockCaches? preBlockCaches = null) : IBlockCachePreWarmer
{
private readonly ObjectPool<IReadOnlyTxProcessorSource> _envPool = new DefaultObjectPool<IReadOnlyTxProcessorSource>(new ReadOnlyTxProcessingEnvPooledObjectPolicy(envFactory), Environment.ProcessorCount);
private readonly ObjectPool<SystemTransaction> _systemTransactionPool = new DefaultObjectPool<SystemTransaction>(new DefaultPooledObjectPolicy<SystemTransaction>(), Environment.ProcessorCount);
private readonly ILogger _logger = logManager.GetClassLogger<BlockCachePreWarmer>();

public Task PreWarmCaches(Block suggestedBlock, Hash256? parentStateRoot, AccessList? systemTxAccessList, CancellationToken cancellationToken = default)
{
if (targetWorldState is not null)
if (preBlockCaches is not null)
{
if (targetWorldState.ClearCache())
if (preBlockCaches.ClearImmediate())
{
if (_logger.IsWarn) _logger.Warn("Caches are not empty. Clearing them.");
if (_logger.IsDebug) _logger.Debug("Caches are not empty. Clearing them.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generally should not happen in normal execution, why lower to Debug?

}

var physicalCoreCount = RuntimeInformation.PhysicalCoreCount;
Expand All @@ -53,9 +53,7 @@ public Task PreWarmCaches(Block suggestedBlock, Hash256? parentStateRoot, Access
// Parent state root is null for genesis block
private static bool IsGenesisBlock(Hash256? parentStateRoot) => parentStateRoot is null;

public void ClearCaches() => targetWorldState?.ClearCache();

public Task ClearCachesInBackground() => targetWorldState?.ClearCachesInBackground() ?? Task.CompletedTask;
public void ClearCaches() => preBlockCaches?.ClearImmediate();

private void PreWarmCachesParallel(Block suggestedBlock, Hash256 parentStateRoot, ParallelOptions parallelOptions, CancellationToken cancellationToken)
{
Expand Down
11 changes: 4 additions & 7 deletions src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Nethermind.Blockchain;
using Nethermind.Blockchain.BeaconBlockRoot;
using Nethermind.Blockchain.Blocks;
using Nethermind.Blockchain.Find;
using Nethermind.Blockchain.Receipts;
using Nethermind.Consensus.Rewards;
using Nethermind.Consensus.Validators;
Expand Down Expand Up @@ -58,7 +57,7 @@ public partial class BlockProcessor(
private readonly IBlockProcessor.IBlockTransactionsExecutor _blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor));
private readonly IBlockhashStore _blockhashStore = blockHashStore ?? throw new ArgumentNullException(nameof(blockHashStore));
private const int MaxUncommittedBlocks = 64;
private readonly Func<Task, Task> _clearCaches = _ => preWarmer.ClearCachesInBackground();
private readonly Action<Task> _clearCaches = _ => preWarmer.ClearCaches();

/// <summary>
/// We use a single receipt tracer for all blocks. Internally receipt tracer forwards most of the calls
Expand Down Expand Up @@ -121,11 +120,12 @@ the previous head state.*/

(processedBlock, receipts) = ProcessOne(suggestedBlock, options, blockTracer);
// Block is processed, we can cancel the prewarm task
preWarmTask = preWarmTask.ContinueWith(_clearCaches).Unwrap();
preWarmTask.ContinueWith(_clearCaches, TaskContinuationOptions.ExecuteSynchronously);
cancellationTokenSource.Cancel();
}
else
{
preWarmer?.ClearCaches();
(processedBlock, receipts) = ProcessOne(suggestedBlock, options, blockTracer);
}

Expand Down Expand Up @@ -168,11 +168,8 @@ the previous head state.*/
{
_logger.Trace($"Encountered exception {ex} while processing blocks.");
RestoreBranch(previousBranchStateRoot);
throw;
}
finally
{
preWarmer?.ClearCaches();
throw;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ public interface IBlockCachePreWarmer
{
Task PreWarmCaches(Block suggestedBlock, Hash256 parentStateRoot, AccessList? systemTxAccessList, CancellationToken cancellationToken = default);
void ClearCaches();
Task ClearCachesInBackground();
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ protected TestBlockchain()

public static TransactionBuilder<Transaction> BuildSimpleTransaction => Builders.Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyA).To(AccountB);

private PreBlockCaches PreBlockCaches { get; } = new PreBlockCaches();

protected virtual async Task<TestBlockchain> Build(ISpecProvider? specProvider = null, UInt256? initialValues = null, bool addBlockOnStart = true)
{
Timestamper = new ManualTimestamper(new DateTime(2020, 2, 15, 12, 50, 30, DateTimeKind.Utc));
Expand All @@ -129,7 +131,7 @@ protected virtual async Task<TestBlockchain> Build(ISpecProvider? specProvider =
EthereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId);
DbProvider = await CreateDbProvider();
TrieStore = new TrieStore(StateDb, LogManager);
State = new WorldState(TrieStore, DbProvider.CodeDb, LogManager, new PreBlockCaches());
State = new WorldState(TrieStore, DbProvider.CodeDb, LogManager, PreBlockCaches);

// Eip4788 precompile state account
if (specProvider?.GenesisSpec?.IsBeaconBlockRootAvailable ?? false)
Expand Down Expand Up @@ -381,7 +383,7 @@ protected virtual IBlockProcessor CreateBlockProcessor() =>
preWarmer: CreateBlockCachePreWarmer());

protected virtual IBlockCachePreWarmer CreateBlockCachePreWarmer() =>
new BlockCachePreWarmer(new ReadOnlyTxProcessingEnvFactory(WorldStateManager, BlockTree, SpecProvider, LogManager, WorldStateManager.GlobalWorldState), SpecProvider, LogManager, WorldStateManager.GlobalWorldState);
new BlockCachePreWarmer(new ReadOnlyTxProcessingEnvFactory(WorldStateManager, BlockTree, SpecProvider, LogManager, WorldStateManager.GlobalWorldState), SpecProvider, LogManager, PreBlockCaches);

public async Task WaitForNewHead()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ public static bool NoResizeClear<TKey, TValue>(this ConcurrentDictionary<TKey, T

using var handle = dictionary.AcquireLock();

// Recheck under lock
if (dictionary is null || dictionary.IsEmpty)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dictionary?.IsEmpty == false

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dictionary?.IsEmpty == false

Crashes with that

dictionary?.IsEmpty ?? true works though

{
return false;
}

ClearCache<TKey, TValue>.Clear(dictionary);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ protected virtual Task InitBlockchain()
setApi.TxPoolInfoProvider = new TxPoolInfoProvider(chainHeadInfoProvider.AccountStateProvider, txPool);
setApi.GasPriceOracle = new GasPriceOracle(getApi.BlockTree!, getApi.SpecProvider, _api.LogManager, blocksConfig.MinGasPrice);
BlockCachePreWarmer? preWarmer = blocksConfig.PreWarmStateOnBlockProcessing
? new(new(_api.WorldStateManager!, _api.BlockTree!, _api.SpecProvider, _api.LogManager, _api.WorldState), _api.SpecProvider, _api.LogManager, _api.WorldState)
? new(new(_api.WorldStateManager!, _api.BlockTree!, _api.SpecProvider, _api.LogManager, _api.WorldState), _api.SpecProvider, _api.LogManager, preBlockCaches)
: null;
IBlockProcessor mainBlockProcessor = setApi.MainBlockProcessor = CreateBlockProcessor(preWarmer);

Expand Down
5 changes: 0 additions & 5 deletions src/Nethermind/Nethermind.State/IWorldState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Threading.Tasks;
using Nethermind.Core;
using Nethermind.Core.Collections;
using Nethermind.Core.Crypto;
Expand Down Expand Up @@ -113,8 +112,4 @@ public interface IWorldState : IJournal<Snapshot>, IReadOnlyStateProvider

void CommitTree(long blockNumber);
ArrayPoolList<AddressAsKey>? GetAccountChanges();

bool ClearCache() => false;

Task ClearCachesInBackground() => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,6 @@ public void CommitTrees(long blockNumber)
_toUpdateRoots.Clear();
// only needed here as there is no control over cached storage size otherwise
_storages.Clear();
_preBlockCache?.NoResizeClear();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed now?

}

private StorageTree GetOrCreateStorage(Address address)
Expand Down
5 changes: 0 additions & 5 deletions src/Nethermind/Nethermind.State/PreBlockCaches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class PreBlockCaches
private static int LockPartitions => CollectionExtensions.LockPartitions;

private readonly Func<bool>[] _clearCaches;
private readonly Action _clearAllCaches;

private readonly ConcurrentDictionary<StorageCell, byte[]> _storageCache = new(LockPartitions, InitialCapacity);
private readonly ConcurrentDictionary<AddressAsKey, Account> _stateCache = new(LockPartitions, InitialCapacity);
Expand All @@ -36,17 +35,13 @@ public PreBlockCaches()
_rlpCache.NoResizeClear,
_precompileCache.NoResizeClear
];

_clearAllCaches = () => ClearImmediate();
}

public ConcurrentDictionary<StorageCell, byte[]> StorageCache => _storageCache;
public ConcurrentDictionary<AddressAsKey, Account> StateCache => _stateCache;
public ConcurrentDictionary<NodeKey, byte[]?> RlpCache => _rlpCache;
public ConcurrentDictionary<PrecompileCacheKey, (ReadOnlyMemory<byte>, bool)> PrecompileCache => _precompileCache;

public Task ClearCachesInBackground() => Task.Run(_clearAllCaches);

public bool ClearImmediate()
{
bool isDirty = false;
Expand Down
1 change: 0 additions & 1 deletion src/Nethermind/Nethermind.State/StateProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,6 @@ public void CommitTree(long blockNumber)
}

_tree.Commit(blockNumber);
_preBlockCache?.NoResizeClear();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed now?

}

public static void CommitBranch()
Expand Down
4 changes: 0 additions & 4 deletions src/Nethermind/Nethermind.State/WorldState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,9 +271,5 @@ public void CreateAccountIfNotExists(Address address, in UInt256 balance, in UIn
ArrayPoolList<AddressAsKey>? IWorldState.GetAccountChanges() => _stateProvider.ChangedAddresses();

PreBlockCaches? IPreBlockCaches.Caches => PreBlockCaches;

public bool ClearCache() => PreBlockCaches?.ClearImmediate() == true;

public Task ClearCachesInBackground() => PreBlockCaches?.ClearCachesInBackground() ?? Task.CompletedTask;
}
}
Loading