New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Will there be GetEnumerator() for MemoryCache ? #36554
Comments
No current plans for it. The idea is that the moment after you enumerate - or even while you enumerate, the cache may have purged some of the entries. Can you share more about why you want this? BTW we are looking at adding more diagnostic-related info to the cache system. |
I am trying to build the cache like replica of the db table, so that it avoid frequent db hit in my project of device farm monitoring and management. And there's also one API which needs to read all the device info from the cache. |
Have a look at https://github.com/aspnet/Caching/issues/129. Would that solve some of your needs? |
Seems not really, as I was looking for using cache as replica of authoritative master and control when to write the cache to DB. So I need 'select *' from cache as from db table. |
@ardpx If you have a single entry point where you insert data, you can populate a list of keys yourself, right? Making this general, is kind of dangerous for the issues Eilon outlined above. |
This class is not supposed to provide |
Do you mean you're storing the updated data in cache, and later sending the updates to the database? A problem you will have there is the cache can remove them before you commit the changes. If you're using the cache to reduce "read" operations that's a perfectly fine idea, but if you're looking to have background or batched "write" operations you should consider creating a class to queue up the work items which will be committed later. You can so that with a singleton service that holds a list of work item classes. |
I would need the getenumerator too. |
There are many times when I would love the be able to read (or delete) all of the cache entries based on a prefix. For example, I sometimes want to clear every cache entry containing a Product object because a user just changed our discount rates. Ideally I would write Currently I just clear the whole cache, which of course removes unrelated items. |
The ticket is bit old but still relevant in my case. |
I want to monitor the memory usage, space consumed by each key in the cache created within the application. |
I want to echo similar comments above. I'm migrating from the old HTTPContext cache which did have an enumerator in it. I have sets of keys that all start with a specific string that I want to delete. Yes, I COULD keep a list of keys in my own array, but then I'd be writing additional code to maintain information that already exists in the cache. For Javascript objects, this is simply cache.keys(). Why not something simple like that? |
Not sure why this basic scenario isn't supported - most modern cache providers support enumerating keys - one core scenario like many others pointed out is the ability to delete keys with a certain prefix. Necessary if you're maintaining IMemoryCache as a singleton and want to avoid deleting all items in the cache at once. |
Tracking cache keys myself is at best a hacky and dangerous solution. If the |
I was performing an audit of First of all, same as for
When it comes to the enumeration, we have two options: make The disadvantage of the first approach is the clutter IDE gives me for everything that implements The disadvantage of the latter approach is lack of good discoverability. @bartonjs @stephentoub Which approach would you recommend? |
Those glyphs at the bottom of the IntelliSense popup allow you to filter out extension methods if you don't want to see them.
The bigger disadvantage is it means you can't use LINQ (or, at least, to use LINQ you need to play tricks like writing your own iterator and then using LINQ over that). I assume that's something folks would like to be able to do.
If we want to address this issue, I'd want to see it implement the interface. It could do so explicitly rather than implicitly and then you could also have a GetEnumerator that returns a struct if there were allocation concerns; then foreach'ing over it directly wouldn't allocate but you'd still be able to use extension methods on IEnumerable, and they'd use whatever explicit GetEnumerator implementation was provided with whatever object it wants to return. |
I can't think of any places where we've done (2) without also doing (1), off the top of my head. One way to get fairly close is to add something like |
Background and Motivation
Many (more than twenty by looking at the number of reactions) of our customers have expressed the need of this API in #36554. So far most of them were forced to use ugly workarounds like creating a wrapper around Proposed APIExpose namespace Microsoft.Extensions.Caching.Memory
{
public class MemoryCache
{
+ public IEnumerable<object> Keys { get; }
} Usage ExamplesMemoryCache cache = new(new MemoryCacheOptions());
cache.Set("key1", "value1");
cache.Set("key2", "value2");
foreach (object key in cache.Keys)
{
if (key is string text && text.StartsWith("key"))
{
cache.Remove(key);
}
} Alternative DesignsExtending
RisksThis proposal avoids a risk of breaking change, by not extending the However, our users may not understand the concept of a snapshot and:
But this has not stopped us from adding this API to |
ConcurrentDictionary implements IDictionary, so it had to have Keys (at least explicitly). And from my perspective we made a mistake giving it the semantics we did. Didn't you spend a bunch of time reducing overheads in MemoryCache? And now we'd be implementing a property with O(N) allocation on every property read? |
@stephentoub What other options do we have considering that:
|
public IEnumerable<object> GetKeys()
{
foreach (KeyValuePair<object, CacheEntry> pairs in _dictionary)
{
yield return pairs.Key;
}
} ? |
@stephentoub I've given it a try in 4275180 and updated the proposal (I was unaware of the fact it's possible to enumerate over concurrent dictionary and modify it at the same time). Thanks, it was great idea! |
namespace Microsoft.Extensions.Caching.Memory
{
public partial class MemoryCache
{
public IEnumerable<object> Keys { get; }
}
} |
@adamsitnik I am attempting to implement an actuator to provide info about the cache/clear it as per how spring boot does it (https://docs.spring.io/spring-boot/docs/current/actuator-api/htmlsingle/#caches) and i would propose we make a change to the data model being returned to provide additional metadata and this is the best time to do it before it is released. I have created a proposal #98251 to cover this for the memory cache option could you take a look. Note we should be able to address the breaking change aspect by providing a default implementation. |
LINK to the proposal: #36554 (comment)
Just wonder if there would be GetEnumerator() for MemoryCache, as supported in System.Runtime.Caching.Memorycache?
The text was updated successfully, but these errors were encountered: