Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
12 changes: 11 additions & 1 deletion src/Caching/Memory/src/MemoryCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Microsoft.Extensions.Caching.Memory
Expand Down Expand Up @@ -74,6 +75,8 @@ public int Count
// internal for testing
internal long Size { get => Interlocked.Read(ref _cacheSize); }

internal ILogger Logger { private get; set; }
Comment thread
JunTaoLuo marked this conversation as resolved.
Outdated

private ICollection<KeyValuePair<object, CacheEntry>> EntriesCollection => _entries;

/// <inheritdoc />
Expand Down Expand Up @@ -341,18 +344,25 @@ 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);
}

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:
Expand Down Expand Up @@ -481,4 +491,4 @@ private static void ValidateCacheKey(object key)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>In-memory cache implementation of Microsoft.Extensions.Caching.Memory.IMemoryCache.</Description>
Expand All @@ -11,6 +11,7 @@
<ItemGroup>
<Reference Include="Microsoft.Extensions.Caching.Abstractions" />
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<Reference Include="Microsoft.Extensions.Logging" />
Comment thread
JunTaoLuo marked this conversation as resolved.
Outdated
<Reference Include="Microsoft.Extensions.Options" />
</ItemGroup>

Expand Down
9 changes: 6 additions & 3 deletions src/Caching/Memory/test/CapacityTests.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// 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;
using System.Threading;
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()
Expand Down Expand Up @@ -117,6 +118,8 @@ public async Task DoNotAddIfSizeOverflows()
SizeLimit = long.MaxValue
});

cache.Logger = Logger;

var entryOptions = new MemoryCacheEntryOptions { Size = long.MaxValue };
var sem = new SemaphoreSlim(0, 1);
entryOptions.PostEvictionCallbacks.Add(new PostEvictionCallbackRegistration
Expand Down Expand Up @@ -408,4 +411,4 @@ public void NoCompactionWhenNoMaximumEntriesCountSpecified()
Assert.Equal(6, cache.Count);
}
}
}
}
8 changes: 4 additions & 4 deletions src/Caching/Memory/test/MemoryCacheSetAndRemoveTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

We don't need to pass the token since we check via cts.IsCancellationRequested inside the tasks. Alternatively we can catch the TaskCancelledException from WaitAll

});

var task1 = Task.Run(() =>
{
Expand All @@ -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(() =>
{
Expand All @@ -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));
Expand Down Expand Up @@ -643,4 +643,4 @@ private class TestKey
public override int GetHashCode() => 0;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="$(MSBuildThisFileDirectory)..\..\..\Logging\Logging.Testing\src\build\Microsoft.Extensions.Logging.Testing.props" />

<PropertyGroup>
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<Reference Include="Microsoft.Extensions.Caching.Memory" />
<Reference Include="Microsoft.Extensions.DependencyInjection" />
<Reference Include="Microsoft.Extensions.Logging.Testing" />
</ItemGroup>

</Project>