From e515b716f052e9c4c0542d98c85096ed167a3af0 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 10 Jul 2014 10:24:04 +0200 Subject: [PATCH] U4-4931 - also for ObjectCacheRuntime provider Conflicts: src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs --- .../Cache/ObjectCacheRuntimeCacheProvider.cs | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs index 945a4588d2..edf1ba5aa6 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs @@ -19,11 +19,29 @@ namespace Umbraco.Core.Cache private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); internal ObjectCache MemoryCache; + // an object that represent a value that has not been created yet + protected readonly object ValueNotCreated = new object(); + public ObjectCacheRuntimeCacheProvider() { MemoryCache = new MemoryCache("in-memory"); } + protected object GetSafeLazyValue(Lazy lazy, bool onlyIfValueIsCreated = false) + { + try + { + // if onlyIfValueIsCreated, do not trigger value creation + // must return something, though, to differenciate from null values + if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated; + return lazy.Value; + } + catch + { + return null; + } + } + #region Clear public virtual void ClearAllCache() @@ -53,7 +71,8 @@ namespace Umbraco.Core.Cache { // x.Value is Lazy and not null, its value may be null // remove null values as well, does not hurt - var value = ((Lazy) x.Value).Value; + // get non-created as NonCreatedValue & exceptions as null + var value = GetSafeLazyValue((Lazy)x.Value, true); return value == null || value.GetType().ToString().InvariantEquals(typeName); }) .Select(x => x.Key) @@ -72,7 +91,8 @@ namespace Umbraco.Core.Cache { // x.Value is Lazy and not null, its value may be null // remove null values as well, does not hurt - var value = ((Lazy)x.Value).Value; + // get non-created as NonCreatedValue & exceptions as null + var value = GetSafeLazyValue((Lazy)x.Value, true); return value == null || value.GetType() == typeOfT; }) .Select(x => x.Key) @@ -91,7 +111,8 @@ namespace Umbraco.Core.Cache { // x.Value is Lazy and not null, its value may be null // remove null values as well, does not hurt - var value = ((Lazy)x.Value).Value; + // get non-created as NonCreatedValue & exceptions as null + var value = GetSafeLazyValue((Lazy)x.Value, true); if (value == null) return true; return value.GetType() == typeOfT && predicate(x.Key, (T) value); @@ -132,35 +153,42 @@ namespace Umbraco.Core.Cache public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) { + KeyValuePair[] entries; using (new ReadLock(_locker)) { - return MemoryCache + entries = MemoryCache .Where(x => x.Key.InvariantStartsWith(keyStartsWith)) - .Select(x => ((Lazy) x.Value).Value) - .Where(x => x != null) // backward compat, don't store null values in the cache - .ToList(); + .ToArray(); // evaluate while locked } + return entries + .Select(x => GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null + .Where(x => x != null) // backward compat, don't store null values in the cache + .ToList(); } public IEnumerable GetCacheItemsByKeyExpression(string regexString) { + KeyValuePair[] entries; using (new ReadLock(_locker)) { - return MemoryCache + entries = MemoryCache .Where(x => Regex.IsMatch(x.Key, regexString)) - .Select(x => ((Lazy) x.Value).Value) - .Where(x => x != null) // backward compat, don't store null values in the cache - .ToList(); + .ToArray(); // evaluate while locked } + return entries + .Select(x => GetSafeLazyValue((Lazy)x.Value)) // return exceptions as null + .Where(x => x != null) // backward compat, don't store null values in the cache + .ToList(); } public object GetCacheItem(string cacheKey) { + Lazy result; using (new ReadLock(_locker)) { - var result = MemoryCache.Get(cacheKey) as Lazy; - return result == null ? null : result.Value; + result = MemoryCache.Get(cacheKey) as Lazy; // null if key not found } + return result == null ? null : GetSafeLazyValue(result); // return exceptions as null } public object GetCacheItem(string cacheKey, Func getCacheItem) @@ -177,12 +205,12 @@ namespace Umbraco.Core.Cache using (var lck = new UpgradeableReadLock(_locker)) { result = MemoryCache.Get(cacheKey) as Lazy; - if (result == null || (result.IsValueCreated && result.Value == null)) + if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null { - lck.UpgradeToWriteLock(); - result = new Lazy(getCacheItem); var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles); + + lck.UpgradeToWriteLock(); MemoryCache.Set(cacheKey, result, policy); } }