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!
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.
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.
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.
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 ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With