From 1e696956506fa2162cb93b777c3bca268be9bd28 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 19 Mar 2024 09:23:11 +0000 Subject: [PATCH] Added missing locks and use timeout on all of them in ObjectCacheAppCache (#15902) * Added missing locks, and ensure we have timeout on all of them * Wrap the removable of objects from the hashset in a lock * remove old comment * Exit correct lock --- src/Umbraco.Core/Cache/ObjectCacheAppCache.cs | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs index c7fc343787..1bdfec2450 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheAppCache.cs @@ -88,8 +88,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable object[] entries; try { - _locker.EnterReadLock(); - + if (_locker.TryEnterReadLock(_readLockTimeout) is false) + { + throw new TimeoutException("Timeout exceeded to the memory cache when getting item"); + } entries = _keys.Where(predicate) .Select(key => MemoryCache.Get(key)) .WhereNotNull() @@ -125,11 +127,15 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable if (result == null || SafeLazy.GetSafeLazyValue(result, true) == null) { result = SafeLazy.GetSafeLazy(factory); + MemoryCacheEntryOptions options = GetOptions(timeout, isSliding); try { - _locker.EnterWriteLock(); + if (_locker.TryEnterWriteLock(_writeLockTimeout) is false) + { + throw new TimeoutException("Timeout exceeded to the memory cache when using factory to insert"); + } // NOTE: This does an add or update MemoryCache.Set(key, result, options); @@ -173,12 +179,26 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable { return; // do not store null values (backward compat) } - MemoryCacheEntryOptions options = GetOptions(timeout, isSliding); - // NOTE: This does an add or update - MemoryCache.Set(key, result, options); - _keys.Add(key); + try + { + if (_locker.TryEnterWriteLock(_writeLockTimeout) is false) + { + throw new TimeoutException("Cannot insert value into cache, due to timeout for lock."); + } + + // NOTE: This does an add or update + MemoryCache.Set(key, result, options); + _keys.Add(key); + } + finally + { + if (_locker.IsWriteLockHeld) + { + _locker.ExitWriteLock(); + } + } } /// @@ -348,6 +368,23 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable } // Ensure key is removed from set when evicted from cache - return options.RegisterPostEvictionCallback((key, _, _, _) => _keys.Remove((string)key)); + return options.RegisterPostEvictionCallback((key, _, _, _) => + { + try + { + if (_locker.TryEnterWriteLock(_writeLockTimeout) is false) + { + throw new TimeoutException("Timeout exceeded to the memory cache when using factory to insert"); + } + _keys.Remove((string)key); + } + finally + { + if (_locker.IsWriteLockHeld) + { + _locker.ExitWriteLock(); + } + } + }); } }