Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

MemoryCache eviction restructure #280

Closed
wants to merge 22 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
226 changes: 113 additions & 113 deletions Caching.sln

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions samples/MemoryCacheSample/CapacityMemoryCacheEvictionTrigger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

// 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.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;

namespace MemoryCacheSample
{
class CapacityMemoryCacheEvictionTrigger : IMemoryCacheEvictionTrigger
{
private Func<int> _evictionCallback;
private int _entryLimit;
private object _evictionlock = new object();

public CapacityMemoryCacheEvictionTrigger(int entryLimit)
{
_entryLimit = entryLimit;
}

public void Dispose() { }

public void Resume(IReadOnlyCollection<IReadOnlyCacheEntry> entries)
{
if (entries.Count > _entryLimit)
{
Task.Factory.StartNew(
state => StartEviction((IReadOnlyCollection<IReadOnlyCacheEntry>)state),
entries,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
}
}

public void SetEvictionCallback(Func<int> evictionCallback)
{
_evictionCallback = evictionCallback;
}

private void StartEviction(IReadOnlyCollection<IReadOnlyCacheEntry> entries)
{
// Don't run too often
if (Monitor.TryEnter(_evictionlock))
{
try
{
_evictionCallback();
}
finally
{
Monitor.Exit(_evictionlock);
}
}
}
}
}
50 changes: 50 additions & 0 deletions samples/MemoryCacheSample/LRUMemoryCacheEvictionStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Caching.Memory;

namespace MemoryCacheSample
{
// TODO: remove this
public class LRUMemoryCacheEvictionStrategy : IMemoryCacheEvictionStrategy
{
private readonly IMemoryCacheEvictionStrategy _evictExpiredStrategy;
private readonly int _entryLimit;

public LRUMemoryCacheEvictionStrategy(int entryLimit)
{
_entryLimit = entryLimit;
_evictExpiredStrategy = new MemoryCacheEvictionStrategy();
}

public int Evict(IReadOnlyCollection<IReadOnlyCacheEntry> entries, DateTimeOffset utcNow)
{
var expiredCount = _evictExpiredStrategy.Evict(entries, utcNow);
var removalTarget = entries.Count - expiredCount - _entryLimit; // assume underflow is handled

if (removalTarget <= 0)
{
return expiredCount;
}

var removedEntries = 0;
foreach (var entry in entries.OrderBy(e => e.LastAccessed))
{
if (!entry.IsExpired)
{
entry.Evict();
removedEntries++;
}
if (removedEntries == removalTarget)
{
break;
}
}

return removalTarget + expiredCount;
}
}
}
6 changes: 0 additions & 6 deletions samples/MemoryCacheSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ public static void Main()

// Cache entry configuration:

// Stays in the cache as long as possible
result = cache.Set(
key,
new object(),
new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.NeverRemove));

// Automatically remove if not accessed in the given time
result = cache.Set(
key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,6 @@ namespace Microsoft.Extensions.Caching.Memory
{
public static class CacheEntryExtensions
{
/// <summary>
/// Sets the priority for keeping the cache entry in the cache during a memory pressure tokened cleanup.
/// </summary>
/// <param name="entry"></param>
/// <param name="priority"></param>
public static ICacheEntry SetPriority(
this ICacheEntry entry,
CacheItemPriority priority)
{
entry.Priority = priority;
return entry;
}

/// <summary>
/// Expire the cache entry if the given <see cref="IChangeToken"/> expires.
Expand Down Expand Up @@ -133,6 +121,14 @@ public static ICacheEntry SetValue(
return entry;
}

public static ICacheEntry SetEvictionMetadata(
this ICacheEntry entry,
object metadata)
{
entry.EvictionMetadata = metadata;
return entry;
}

/// <summary>
/// Applies the values of an existing <see cref="MemoryCacheEntryOptions"/> to the entry.
/// </summary>
Expand All @@ -148,7 +144,7 @@ public static ICacheEntry SetOptions(this ICacheEntry entry, MemoryCacheEntryOpt
entry.AbsoluteExpiration = options.AbsoluteExpiration;
entry.AbsoluteExpirationRelativeToNow = options.AbsoluteExpirationRelativeToNow;
entry.SlidingExpiration = options.SlidingExpiration;
entry.Priority = options.Priority;
entry.EvictionMetadata = options.EvictionMetadata;

foreach (var expirationToken in options.ExpirationTokens)
{
Expand Down
17 changes: 0 additions & 17 deletions src/Microsoft.Extensions.Caching.Abstractions/CacheItemPriority.cs

This file was deleted.

11 changes: 3 additions & 8 deletions src/Microsoft.Extensions.Caching.Abstractions/ICacheEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface ICacheEntry : IDisposable
/// Gets or sets an absolute expiration date for the cache entry.
/// </summary>
DateTimeOffset? AbsoluteExpiration { get; set; }

/// <summary>
/// Gets or sets an absolute expiration time, relative to now.
/// </summary>
Expand All @@ -38,6 +38,8 @@ public interface ICacheEntry : IDisposable
/// </summary>
TimeSpan? SlidingExpiration { get; set; }

object EvictionMetadata { get; set; }

/// <summary>
/// Gets the <see cref="IChangeToken"/> instances which cause the cache entry to expire.
/// </summary>
Expand All @@ -47,12 +49,5 @@ public interface ICacheEntry : IDisposable
/// Gets or sets the callbacks will be fired after the cache entry is evicted from the cache.
/// </summary>
IList<PostEvictionCallbackRegistration> PostEvictionCallbacks { get; }

/// <summary>
/// Gets or sets the priority for keeping the cache entry in the cache during a
/// memory pressure triggered cleanup. The default is <see cref="CacheItemPriority.Normal"/>.
/// </summary>
CacheItemPriority Priority { get; set; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,6 @@ namespace Microsoft.Extensions.Caching.Memory
{
public static class MemoryCacheEntryExtensions
{
/// <summary>
/// Sets the priority for keeping the cache entry in the cache during a memory pressure tokened cleanup.
/// </summary>
/// <param name="options"></param>
/// <param name="priority"></param>
public static MemoryCacheEntryOptions SetPriority(
this MemoryCacheEntryOptions options,
CacheItemPriority priority)
{
options.Priority = priority;
return options;
}

/// <summary>
/// Expire the cache entry if the given <see cref="IChangeToken"/> expires.
/// </summary>
Expand Down Expand Up @@ -79,6 +66,14 @@ public static MemoryCacheEntryOptions SetSlidingExpiration(
return options;
}

public static MemoryCacheEntryOptions SetEvictionMetadata(
this MemoryCacheEntryOptions options,
object metadata)
{
options.EvictionMetadata = metadata;
return options;
}

/// <summary>
/// The given callback will be fired after the cache entry is evicted from the cache.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public TimeSpan? SlidingExpiration
}
}

public object EvictionMetadata { get; set; }

/// <summary>
/// Gets the <see cref="IChangeToken"/> instances which cause the cache entry to expire.
/// </summary>
Expand All @@ -84,11 +86,5 @@ public TimeSpan? SlidingExpiration
/// </summary>
public IList<PostEvictionCallbackRegistration> PostEvictionCallbacks { get; }
= new List<PostEvictionCallbackRegistration>();

/// <summary>
/// Gets or sets the priority for keeping the cache entry in the cache during a
/// memory pressure triggered cleanup. The default is <see cref="CacheItemPriority.Normal"/>.
/// </summary>
public CacheItemPriority Priority { get; set; } = CacheItemPriority.Normal;
}
}
26 changes: 13 additions & 13 deletions src/Microsoft.Extensions.Caching.Memory/CacheEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Microsoft.Extensions.Caching.Memory
{
internal class CacheEntry : ICacheEntry
internal class CacheEntry : ICacheEntry, IReadOnlyCacheEntry
{
private bool _added = false;
private static readonly Action<object> ExpirationCallback = ExpirationTokensExpired;
Expand All @@ -19,9 +19,9 @@ internal class CacheEntry : ICacheEntry
private IList<PostEvictionCallbackRegistration> _postEvictionCallbacks;
private bool _isExpired;

internal IList<IChangeToken> _expirationTokens;
internal DateTimeOffset? _absoluteExpiration;
internal TimeSpan? _absoluteExpirationRelativeToNow;
private IList<IChangeToken> _expirationTokens;
private DateTimeOffset? _absoluteExpiration;
private TimeSpan? _absoluteExpirationRelativeToNow;
private TimeSpan? _slidingExpiration;
private IDisposable _scope;

Expand Down Expand Up @@ -147,20 +147,18 @@ public IList<PostEvictionCallbackRegistration> PostEvictionCallbacks
}
}

/// <summary>
/// Gets or sets the priority for keeping the cache entry in the cache during a
/// memory pressure triggered cleanup. The default is <see cref="CacheItemPriority.Normal"/>.
/// </summary>
public CacheItemPriority Priority { get; set; } = CacheItemPriority.Normal;

public object Key { get; private set; }

public object Value { get; set; }

internal DateTimeOffset LastAccessed { get; set; }
public DateTimeOffset LastAccessed { get; internal set; }

public bool IsExpired => _isExpired;

internal EvictionReason EvictionReason { get; private set; }

public object EvictionMetadata { get; set; }

public void Dispose()
{
if (!_added)
Expand All @@ -172,11 +170,13 @@ public void Dispose()
}
}

internal bool CheckExpired(DateTimeOffset now)
public bool CheckExpired(DateTimeOffset now)
{
return _isExpired || CheckForExpiredTime(now) || CheckForExpiredTokens();
}

public void Evict() => SetExpired(EvictionReason.Capacity);

internal void SetExpired(EvictionReason reason)
{
if (EvictionReason == EvictionReason.None)
Expand Down Expand Up @@ -205,7 +205,7 @@ private bool CheckForExpiredTime(DateTimeOffset now)
return false;
}

internal bool CheckForExpiredTokens()
private bool CheckForExpiredTokens()
{
if (_expirationTokens != null)
{
Expand Down
Loading