Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a generic cache manager in c#

I'm trying to implement a generic cache manager, however I'm not sure how to go about doing the locking.

I have the following so far, however if I have two cache entries with the same return types then I'm guessing the same lock object would be used!

public class CacheManager : ICacheManager
{
    static class TypeLock<T>
    {
        public static readonly object SyncLock = new object();
    }
    private readonly ICache _cache;
    public CacheManager(ICache cache)
    {
        if (cache == null)
            throw new ArgumentNullException("cache");

        _cache = cache;
    }

    public TResult AddCache<TResult>(string cacheKey, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
    {
        return AddCache(cacheKey, null, acquire, cacheDurationInMinutes);
    }

    public TResult AddCache<TResult>(string cacheKey, CacheDependency dependency, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
    {
        var entry = acquire.Invoke();
        if (entry != null)
        {
            if (dependency != null)
                _cache.InsertWithDependency(cacheKey, entry, dependency, DateTime.Now.AddMinutes(cacheDurationInMinutes));
            else
                _cache.Insert(cacheKey, entry, DateTime.Now.AddMinutes(cacheDurationInMinutes));
        }
        return entry;
    }

    public TResult GetOrAddCache<TResult>(string cacheKey, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
    {
        return GetOrAddCache(cacheKey, null, acquire, cacheDurationInMinutes);
    }

    public TResult GetOrAddCache<TResult>(string cacheKey, CacheDependency dependency, Func<TResult> acquire, int cacheDurationInMinutes) where TResult : class
    {
        var entry = _cache.GetItem(cacheKey) as TResult;

        if (entry == null)
        {
            lock (TypeLock<TResult>.SyncLock)
            {
                entry = _cache.GetItem(cacheKey) as TResult;
                if (entry == null)
                {
                    entry = acquire.Invoke();
                    if (entry != null)
                    {
                        if (dependency != null)
                            _cache.InsertWithDependency(cacheKey, entry, dependency,
                                                        DateTime.Now.AddMinutes(cacheDurationInMinutes));
                        else
                            _cache.Insert(cacheKey, entry, DateTime.Now.AddMinutes(cacheDurationInMinutes));
                    }
                }
            }
        }

        return entry;
    }
}

Any help would be much appreciated!

like image 274
user522627 Avatar asked Nov 22 '12 21:11

user522627


People also ask

What is CacheManager C#?

CacheManager is an open source caching framework for .NET written in C# and is available via NuGet. It supports various cache providers and implements many advanced features.

What is the use of cache manager?

For example, an application that caches customer objects might derive its key from the customer account number. A cache has an associated cache manager. A cache manager serves as a container for grouping a set of caches into one “management unit” that you can start and shut down together.


2 Answers

You are correct, this would use the same lock for all cache entries of the same type. To keep you actual caching method (memory, file, database...) independent of this cache manager, I suggest storing an extra sync object for each cache entry, so your cache entries will look for example like Tuple<object, TResult> instead of just TResult, where the object will be a new object() for each entry and will be used for locking.

like image 53
Honza Brestan Avatar answered Sep 19 '22 03:09

Honza Brestan


You should never lock in your caching code unless its really needed. Use Concurrent dictionary if you don't want to use any well known cache.

I'd also say you probably should use the System.Runtime.MemorCache instead.

Or you use a solution which does abstract this for you, like my CacheManager https://github.com/MichaCo/CacheManager ;)

like image 29
MichaC Avatar answered Sep 18 '22 03:09

MichaC