I'm trying to use (a derivative of) the Sitecore CustomCache
class in my solution but am seeing that during the course of my load testing, certain values are not being retrieved from the cache and are being re-requested (and hence re-added to the cache). I'm trying to adopt the double-checked locking pattern. From the console debug statements added to my code, I am even seeing that the same thread is not retrieving the cached value immediately after setting it, although it does later serve the value from cache.
I'm wondering if there is simply a bug in the code, or if I'm just trying to do this in the wrong way?
I have created a class in my solution that inherits Sitecore.Caching.CustomCache
public class CustomCache : Sitecore.Caching.CustomCache
{
public CustomCache(string name, long maxSize) : base(name, maxSize)
{
}
public CustomCache(long maxSize) : base("My.Foundation.Cache", maxSize)
{
}
public void AddCacheObject(string key, object value)
{
InnerCache.Add(key, value);
}
public object GetCacheObject(string key)
{
return !InnerCache.ContainsKey(key) ? null : InnerCache.GetValue(key);
}
}
And I have created a wrapper around this with static methods
public class CacheManager
{
private static readonly CustomCache _customCache = new CustomCache(
Sitecore.StringUtil.ParseSizeString(
Settings.GetSetting("My.Foundation.Caching.CacheSize", "500MB")));
private static readonly object _customCacheLock = new object();
internal static object Get(string key)
{
if (_customCache == null)
{
return null;
}
return _customCache.InnerCache.GetValue(key);
}
internal static void Set(string key, object value)
{
if (_customCache == null)
{
return;
}
_customCache.AddCacheObject(key, value);
}
internal static string GetCacheKey(string key)
{
return $"{Context.Site?.Name}{Context.Database?.Name}{Context.Language?.Name}{key}";
}
public void ClearCache(object sender, EventArgs args)
{
_customCache?.Clear();
}
public static TObj GetCachedObject<TObj>(string cacheKey, Func<TObj> creator) where TObj : class
{
var fullKey = GetCacheKey(cacheKey);
var obj = Get(fullKey) as TObj;
if (obj != null)
{
System.Diagnostics.Debug.WriteLine($"CacheKey:{fullKey} (get - without lock) ThreadId:{System.Threading.Thread.CurrentThread.ManagedThreadId} RemainingSpace:{_customCache.InnerCache.RemainingSpace}");
return obj;
}
lock (_customCacheLock)
{
obj = Get(fullKey) as TObj;
if (obj != null)
{
System.Diagnostics.Debug.WriteLine($"CacheKey:{fullKey} (get - lock) ThreadId:{System.Threading.Thread.CurrentThread.ManagedThreadId} RemainingSpace:{_customCache.InnerCache.RemainingSpace}");
return obj;
}
obj = creator.Invoke();
System.Diagnostics.Debug.WriteLine($"CacheKey:{fullKey} (set - lock) ThreadId:{System.Threading.Thread.CurrentThread.ManagedThreadId} RemainingSpace:{_customCache.InnerCache.RemainingSpace}");
Set(fullKey, obj);
return obj;
}
}
}
EDIT Jeroen was correct in that I was approaching this in the wrong way and was totally correct in his suggestions. It turned out that in this instance caching was actually disabled hence the constant cache misses. Sometimes when looking at a problem we (I) look for a complex solution before double-checking the simple things...
Caching.DebugEnabled
in the config, then Sitecore logs some extra info.InnerCache.CacheWriteEnabled
when you are trying to add a value? This property is checked in theInnerCache.Add
method.