diff --git a/Duplicati/Library/Main/Operation/Restore/BlockManager.cs b/Duplicati/Library/Main/Operation/Restore/BlockManager.cs
index 3891a1533..01361ec51 100644
--- a/Duplicati/Library/Main/Operation/Restore/BlockManager.cs
+++ b/Duplicati/Library/Main/Operation/Restore/BlockManager.cs
@@ -78,6 +78,10 @@ namespace Duplicati.Library.Main.Operation.Restore
///
private int readers = 0;
///
+ /// Internal stopwatch for profiling the cache eviction.
+ ///
+ private readonly Stopwatch sw_cacheevict;
+ ///
/// Internal stopwatch for profiling the `CheckCounts` method.
///
private readonly Stopwatch sw_checkcounts;
@@ -108,9 +112,13 @@ namespace Duplicati.Library.Main.Operation.Restore
{
m_options = options;
m_volume_request = volume_request;
- var cache_options = new MemoryCacheOptions();
- m_block_cache = new MemoryCache(cache_options);
+ if (m_options.RestoreCacheMax > 0)
+ {
+ var cache_options = new MemoryCacheOptions();
+ m_block_cache = new MemoryCache(cache_options);
+ }
this.readers = readers;
+ sw_cacheevict = options.InternalProfiling ? new () : null;
sw_checkcounts = options.InternalProfiling ? new () : null;
sw_get_wait = options.InternalProfiling ? new () : null;
@@ -147,7 +155,7 @@ namespace Duplicati.Library.Main.Operation.Restore
{
// Evict the block from the cache and check if the volume is no longer needed.
m_blockcount.Remove(blockRequest.BlockID);
- m_block_cache.Remove(blockRequest.BlockID);
+ m_block_cache?.Remove(blockRequest.BlockID);
}
else // block_count < 0
{
@@ -184,7 +192,7 @@ namespace Duplicati.Library.Main.Operation.Restore
public Task Get(BlockRequest block_request)
{
// Check if the block is already in the cache, and return it if it is.
- if (m_block_cache.TryGetValue(block_request.BlockID, out byte[] value))
+ if (m_block_cache != null && m_block_cache.TryGetValue(block_request.BlockID, out byte[] value))
{
CheckCounts(block_request);
return Task.FromResult(value);
@@ -219,13 +227,20 @@ namespace Duplicati.Library.Main.Operation.Restore
///
public void Set(BlockRequest blockRequest, byte[] value)
{
- m_block_cache.Set(blockRequest.BlockID, value);
+ m_block_cache?.Set(blockRequest.BlockID, value);
// Notify any waiters that the block is available.
if (m_waiters.TryRemove(blockRequest.BlockID, out var tcs))
{
tcs.SetResult(value);
}
+
+ sw_cacheevict?.Start();
+ if (m_block_cache?.Count * m_options.Blocksize > m_options.RestoreCacheMax)
+ {
+ m_block_cache?.Compact(m_options.RestoreCacheEvict);
+ }
+ sw_cacheevict?.Stop();
}
///
@@ -267,7 +282,7 @@ namespace Duplicati.Library.Main.Operation.Restore
if (m_options.InternalProfiling)
{
- Logging.Log.WriteProfilingMessage(LOGTAG, "InternalTimings", null, $"Sleepable dictionary - CheckCounts: {sw_checkcounts.ElapsedMilliseconds}ms, Get wait: {sw_get_wait.ElapsedMilliseconds}ms");
+ Logging.Log.WriteProfilingMessage(LOGTAG, "InternalTimings", null, $"Sleepable dictionary - CheckCounts: {sw_checkcounts.ElapsedMilliseconds}ms, Get wait: {sw_get_wait.ElapsedMilliseconds}ms, Cache evict: {sw_cacheevict.ElapsedMilliseconds}ms");
}
}