diff --git a/src/Caching/Memory/src/MemoryCache.cs b/src/Caching/Memory/src/MemoryCache.cs index f1b39e55e1a..e51c77df522 100644 --- a/src/Caching/Memory/src/MemoryCache.cs +++ b/src/Caching/Memory/src/MemoryCache.cs @@ -8,6 +8,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Caching.Memory @@ -21,6 +23,7 @@ public class MemoryCache : IMemoryCache private readonly ConcurrentDictionary _entries; private long _cacheSize = 0; private bool _disposed; + private ILogger _logger; // We store the delegates locally to prevent allocations // every time a new CacheEntry is created. @@ -35,13 +38,27 @@ public class MemoryCache : IMemoryCache /// /// The options of the cache. public MemoryCache(IOptions optionsAccessor) + : this(optionsAccessor, NullLoggerFactory.Instance) { } + + /// + /// Creates a new instance. + /// + /// The options of the cache. + /// + public MemoryCache(IOptions optionsAccessor, ILoggerFactory loggerFactory) { if (optionsAccessor == null) { throw new ArgumentNullException(nameof(optionsAccessor)); } + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + _options = optionsAccessor.Value; + _logger = loggerFactory.CreateLogger(); _entries = new ConcurrentDictionary(); _setEntry = SetEntry; @@ -341,6 +358,8 @@ private bool UpdateCacheSizeExceedsCapacity(CacheEntry entry) private void TriggerOvercapacityCompaction() { + _logger.LogDebug("Overcapacity compaction triggered"); + // Spawn background thread for compaction ThreadPool.QueueUserWorkItem(s => OvercapacityCompaction((MemoryCache)s), this); } @@ -348,11 +367,16 @@ private void TriggerOvercapacityCompaction() private static void OvercapacityCompaction(MemoryCache cache) { var currentSize = Interlocked.Read(ref cache._cacheSize); + + cache._logger.LogDebug($"Overcapacity compaction executing. Current size {currentSize}"); + var lowWatermark = cache._options.SizeLimit * (1 - cache._options.CompactionPercentage); if (currentSize > lowWatermark) { cache.Compact(currentSize - (long)lowWatermark, entry => entry.Size.Value); } + + cache._logger.LogDebug($"Overcapacity compaction executed. New size {Interlocked.Read(ref cache._cacheSize)}"); } /// Remove at least the given percentage (0.10 for 10%) of the total entries (or estimated memory?), according to the following policy: @@ -481,4 +505,4 @@ private static void ValidateCacheKey(object key) } } } -} \ No newline at end of file +} diff --git a/src/Caching/Memory/src/MemoryDistributedCache.cs b/src/Caching/Memory/src/MemoryDistributedCache.cs index bb85cb22370..a20eacc771a 100644 --- a/src/Caching/Memory/src/MemoryDistributedCache.cs +++ b/src/Caching/Memory/src/MemoryDistributedCache.cs @@ -5,6 +5,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Caching.Distributed @@ -16,13 +18,21 @@ public class MemoryDistributedCache : IDistributedCache private readonly IMemoryCache _memCache; public MemoryDistributedCache(IOptions optionsAccessor) + : this(optionsAccessor, NullLoggerFactory.Instance) { } + + public MemoryDistributedCache(IOptions optionsAccessor, ILoggerFactory loggerFactory) { if (optionsAccessor == null) { throw new ArgumentNullException(nameof(optionsAccessor)); } - _memCache = new MemoryCache(optionsAccessor.Value); + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + + _memCache = new MemoryCache(optionsAccessor.Value, loggerFactory); } public byte[] Get(string key) @@ -134,4 +144,4 @@ public void Remove(string key) return CompletedTask; } } -} \ No newline at end of file +} diff --git a/src/Caching/Memory/src/Microsoft.Extensions.Caching.Memory.csproj b/src/Caching/Memory/src/Microsoft.Extensions.Caching.Memory.csproj index f09526550a6..10c48ef6da8 100644 --- a/src/Caching/Memory/src/Microsoft.Extensions.Caching.Memory.csproj +++ b/src/Caching/Memory/src/Microsoft.Extensions.Caching.Memory.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Caching/Memory/test/CapacityTests.cs b/src/Caching/Memory/test/CapacityTests.cs index bccf795b655..418ca859926 100644 --- a/src/Caching/Memory/test/CapacityTests.cs +++ b/src/Caching/Memory/test/CapacityTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -6,11 +6,12 @@ using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory.Infrastructure; using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Logging.Testing; using Xunit; namespace Microsoft.Extensions.Caching.Memory { - public class CapacityTests + public class CapacityTests : LoggedTestBase { [Fact] public void MemoryDistributedCacheOptionsDefaultsTo200MBSizeLimit() @@ -115,7 +116,7 @@ public async Task DoNotAddIfSizeOverflows() var cache = new MemoryCache(new MemoryCacheOptions { SizeLimit = long.MaxValue - }); + }, LoggerFactory); var entryOptions = new MemoryCacheEntryOptions { Size = long.MaxValue }; var sem = new SemaphoreSlim(0, 1); @@ -408,4 +409,4 @@ public void NoCompactionWhenNoMaximumEntriesCountSpecified() Assert.Equal(6, cache.Count); } } -} \ No newline at end of file +} diff --git a/src/Caching/Memory/test/MemoryCacheSetAndRemoveTests.cs b/src/Caching/Memory/test/MemoryCacheSetAndRemoveTests.cs index 37ac2d79152..913252f18b2 100644 --- a/src/Caching/Memory/test/MemoryCacheSetAndRemoveTests.cs +++ b/src/Caching/Memory/test/MemoryCacheSetAndRemoveTests.cs @@ -553,7 +553,7 @@ public void AddAndReplaceEntries_AreThreadSafe() var entrySize = random.Next(0, 5); cache.Set(random.Next(0, 10), entrySize, new MemoryCacheEntryOptions { Size = entrySize }); } - }, cts.Token); + }); var task1 = Task.Run(() => { @@ -562,7 +562,7 @@ public void AddAndReplaceEntries_AreThreadSafe() var entrySize = random.Next(0, 5); cache.Set(random.Next(0, 10), entrySize, new MemoryCacheEntryOptions { Size = entrySize }); } - }, cts.Token); + }); var task2 = Task.Run(() => { @@ -571,7 +571,7 @@ public void AddAndReplaceEntries_AreThreadSafe() var entrySize = random.Next(0, 5); cache.Set(random.Next(0, 10), entrySize, new MemoryCacheEntryOptions { Size = entrySize }); } - }, cts.Token); + }); cts.CancelAfter(TimeSpan.FromSeconds(5)); var task3 = Task.Delay(TimeSpan.FromSeconds(7)); @@ -643,4 +643,4 @@ private class TestKey public override int GetHashCode() => 0; } } -} \ No newline at end of file +} diff --git a/src/Caching/Memory/test/Microsoft.Extensions.Caching.Memory.Tests.csproj b/src/Caching/Memory/test/Microsoft.Extensions.Caching.Memory.Tests.csproj index a2fe761c13a..d5fbce33e2f 100644 --- a/src/Caching/Memory/test/Microsoft.Extensions.Caching.Memory.Tests.csproj +++ b/src/Caching/Memory/test/Microsoft.Extensions.Caching.Memory.Tests.csproj @@ -1,5 +1,7 @@  + + $(StandardTestTfms) @@ -7,6 +9,7 @@ +