Merge remote-tracking branch 'origin/v12/dev' into v13/dev

This commit is contained in:
Bjarke Berg
2024-03-15 15:05:17 +01:00
11 changed files with 126 additions and 33 deletions

View File

@@ -9,6 +9,9 @@ namespace Umbraco.Cms.Core.Cache;
/// </summary>
public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
private static readonly TimeSpan _readLockTimeout = TimeSpan.FromSeconds(5);
private static readonly TimeSpan _writeLockTimeout = TimeSpan.FromSeconds(5);
private readonly ReaderWriterLockSlim _locker = new(LockRecursionPolicy.SupportsRecursion);
private bool _disposedValue;
@@ -33,7 +36,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
Lazy<object?>? result;
try
{
_locker.EnterReadLock();
if (_locker.TryEnterReadLock(_readLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when getting item");
}
result = MemoryCache.Get(key) as Lazy<object?>; // null if key not found
}
finally
@@ -195,7 +201,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing item");
}
if (MemoryCache[key] == null)
{
return;
@@ -223,8 +232,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
var isInterface = type.IsInterface;
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing by type");
}
// ToArray required to remove
foreach (var key in MemoryCache
.Where(x =>
@@ -259,7 +270,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing by generic type");
}
Type typeOfT = typeof(T);
var isInterface = typeOfT.IsInterface;
@@ -296,7 +310,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing generic type with predicate");
}
Type typeOfT = typeof(T);
var isInterface = typeOfT.IsInterface;
@@ -338,7 +355,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
{
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cache when clearing with prefix");
}
// ToArray required to remove
foreach (var key in MemoryCache
@@ -365,7 +385,10 @@ public class ObjectCacheAppCache : IAppPolicyCache, IDisposable
try
{
_locker.EnterWriteLock();
if (_locker.TryEnterWriteLock(_writeLockTimeout) is false)
{
throw new TimeoutException("Timeout exceeded to the memory cach when clearing by regex");
}
// ToArray required to remove
foreach (var key in MemoryCache

View File

@@ -13,8 +13,7 @@ public class LockingMechanism : ILockingMechanism
{
private readonly IDistributedLockingMechanismFactory _distributedLockingMechanismFactory;
private readonly ILogger<LockingMechanism> _logger;
private readonly object _lockQueueLocker = new();
private readonly object _dictionaryLocker = new();
private readonly object _locker = new();
private StackQueue<(DistributedLockType lockType, TimeSpan timeout, Guid instanceId, int lockId)>? _queuedLocks;
private HashSet<int>? _readLocks;
private Dictionary<Guid, Dictionary<int, int>>? _readLocksDictionary;
@@ -35,12 +34,12 @@ public class LockingMechanism : ILockingMechanism
}
/// <inheritdoc />
public void ReadLock(Guid instanceId, TimeSpan? timeout = null, params int[] lockIds) => LazyReadLockInner(instanceId, timeout, lockIds);
public void ReadLock(Guid instanceId, TimeSpan? timeout = null, params int[] lockIds) => EagerReadLockInner(instanceId, timeout, lockIds);
public void ReadLock(Guid instanceId, params int[] lockIds) => ReadLock(instanceId, null, lockIds);
/// <inheritdoc />
public void WriteLock(Guid instanceId, TimeSpan? timeout = null, params int[] lockIds) => LazyWriteLockInner(instanceId, timeout, lockIds);
public void WriteLock(Guid instanceId, TimeSpan? timeout = null, params int[] lockIds) => EagerReadLockInner(instanceId, timeout, lockIds);
public void WriteLock(Guid instanceId, params int[] lockIds) => WriteLock(instanceId, null, lockIds);
@@ -64,7 +63,7 @@ public class LockingMechanism : ILockingMechanism
/// <param name="lockIds">Array of lock object identifiers.</param>
private void EagerWriteLockInner(Guid instanceId, TimeSpan? timeout, params int[] lockIds)
{
lock (_dictionaryLocker)
lock (_locker)
{
foreach (var lockId in lockIds)
{
@@ -106,7 +105,7 @@ public class LockingMechanism : ILockingMechanism
/// <param name="lockIds">Array of lock object identifiers.</param>
private void EagerReadLockInner(Guid instanceId, TimeSpan? timeout, params int[] lockIds)
{
lock (_dictionaryLocker)
lock (_locker)
{
foreach (var lockId in lockIds)
{
@@ -219,7 +218,7 @@ public class LockingMechanism : ILockingMechanism
private void LazyLockInner(DistributedLockType lockType, Guid instanceId, TimeSpan? timeout = null, params int[] lockIds)
{
lock (_lockQueueLocker)
lock (_locker)
{
if (_queuedLocks == null)
{
@@ -239,7 +238,7 @@ public class LockingMechanism : ILockingMechanism
/// <param name="instanceId">Instance ID of the scope to clear.</param>
public void ClearLocks(Guid instanceId)
{
lock (_dictionaryLocker)
lock (_locker)
{
_readLocksDictionary?.Remove(instanceId);
_writeLocksDictionary?.Remove(instanceId);
@@ -294,7 +293,7 @@ public class LockingMechanism : ILockingMechanism
/// </summary>
public void EnsureLocks(Guid scopeInstanceId)
{
lock (_lockQueueLocker)
lock (_locker)
{
if (!(_queuedLocks?.Count > 0))
{