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

MemoryCache eviction restructure #280

wants to merge 22 commits into from

Conversation

JunTaoLuo
Copy link
Contributor

@JunTaoLuo JunTaoLuo commented Mar 10, 2017

#221 Need to review API changes and then continue with additional todos

TODO:

  • tests
  • doc comments
  • perf
  • samples?

public interface IMemoryCacheEvictionStrategy
{
// TODO: doc comments
IEnumerable<CacheEntry> GetEntriesToEvict(IEnumerable<CacheEntry> entries, DateTimeOffset now);
Copy link
Member

Choose a reason for hiding this comment

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

Should this be IList<CacheEntry>? This structure worries me a little because it requires the caller to do a LINQ query (or some equivalent) by default. We should add a micro benchmark to see what the performance overhead of this is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea although this is the most generic collection, it may be a little too limited in terms of operations that are available on it.

Copy link
Member

Choose a reason for hiding this comment

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

Rather than returning a list, maybe just call a method / set a property on a given entry to mark it for eviction. Evict()

Copy link
Member

Choose a reason for hiding this comment

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

Actually, SetExpired pretty much already does that.

Copy link
Member

Choose a reason for hiding this comment

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

I like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would work.

Copy link
Member

@Tratcher Tratcher left a comment

Choose a reason for hiding this comment

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

Concerned about the abstraction leaking, but I'll take another look when I have more screens available.


namespace Microsoft.Extensions.Caching.Memory
{
public class DefaultMemoryCacheEvictionStrategy : IMemoryCacheEvictionStrategy
Copy link
Member

Choose a reason for hiding this comment

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

Avoid the word Default in type names

@JunTaoLuo
Copy link
Contributor Author

Any actionable changes to the API before I continue working on this @davidfowl @Tratcher ?

@@ -9,7 +9,7 @@

namespace Microsoft.Extensions.Caching.Memory
{
internal class CacheEntry : ICacheEntry
public class CacheEntry : ICacheEntry
Copy link
Member

Choose a reason for hiding this comment

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

CacheEntry is the wrong view to expose to the eviction algorithm. This view is the one used for creating the entry so Value is settable, all the expirations are settable, AbsoluteExpirationRelativeToNow is relative to entry creation rather than the expiration scan, etc..

There should be a different interface/view exposed for creation vs eviction, even if the same object implements both internally.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll give this a try

public interface IMemoryCacheEvictionStrategy
{
// TODO: doc comments
IEnumerable<CacheEntry> GetEntriesToEvict(IEnumerable<CacheEntry> entries, DateTimeOffset now);
Copy link
Member

Choose a reason for hiding this comment

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

Rather than returning a list, maybe just call a method / set a property on a given entry to mark it for eviction. Evict()

public interface IMemoryCacheEvictionStrategy
{
// TODO: doc comments
IEnumerable<CacheEntry> GetEntriesToEvict(IEnumerable<CacheEntry> entries, DateTimeOffset now);
Copy link
Member

Choose a reason for hiding this comment

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

Actually, SetExpired pretty much already does that.

@@ -148,7 +136,6 @@ public static ICacheEntry SetOptions(this ICacheEntry entry, MemoryCacheEntryOpt
entry.AbsoluteExpiration = options.AbsoluteExpiration;
entry.AbsoluteExpirationRelativeToNow = options.AbsoluteExpirationRelativeToNow;
entry.SlidingExpiration = options.SlidingExpiration;
entry.Priority = options.Priority;
Copy link
Member

Choose a reason for hiding this comment

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

Removing Priority is unfortunate but I understand. Do we have another way to add custom metadata for the eviction algorithm without embedding it in the value itself? What if ICacheEntry had a transparent object EvictionMetadata property?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure about this since EvictionMetadata may not make sense when all components share the same memory cache in DI. Would each component then have to know what to set the EvictionMetadata to? Also, what is the overhead of embedding the information in the value itself over having this field (would need to test this in a microbenchmark).

Copy link
Member

Choose a reason for hiding this comment

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

All components share an eviction strategy anyways, and if the metadata were embedded in the value you'd have the same problem of everyone having to know about it.

Copy link
Member

Choose a reason for hiding this comment

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

Sample?


private void TimerLoop(object state)
{
if (EvictionCallback())
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to have logic to prevent this from being re-entrant.

@Tratcher
Copy link
Member

Think about the error handling for this new extensibility, especially on the timer thread.

@@ -11,9 +11,9 @@ public class MemoryCacheOptions : IOptions<MemoryCacheOptions>
{
public ISystemClock Clock { get; set; }

public bool CompactOnMemoryPressure { get; set; } = true;
public IMemoryCacheEvictionStrategy EvictionStrategy { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

Why are these options rather than DI injected?

public interface IMemoryCacheEvictionTrigger : IDisposable
{
// TODO: doc comments
Func<bool> EvictionCallback { get; set; }
Copy link
Member

Choose a reason for hiding this comment

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

void Initialize(Func<bool> evictionCallback); or make it a parameter to Resume

{
return _isExpired || CheckForExpiredTime(now) || CheckForExpiredTokens();
}

internal void SetExpired(EvictionReason reason)
public void SetExpired(EvictionReason reason)
Copy link
Member

Choose a reason for hiding this comment

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

It's a little odd for this to be public. The only EvictionReason that would make sense for the eviction algorithm to set would be Capacity. Expired is the next best reason, but CheckExpired should set that. Maybe make a new method that's just Evict and always uses Capacity as the reason?

@@ -16,9 +13,9 @@ namespace Microsoft.Extensions.Caching.Memory
/// An implementation of <see cref="IMemoryCache"/> using a dictionary to
/// store its entries.
/// </summary>
public class MemoryCache : IMemoryCache
public partial class MemoryCache : IMemoryCache
Copy link
Member

Choose a reason for hiding this comment

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

partial?

@JunTaoLuo
Copy link
Contributor Author

Closing this PR, we decided to remove the Gen2 GC trigger and allow users to downcast to use Compact on MemoryCache instead.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants