diff --git a/src/Umbraco.Infrastructure/Extensions/ScopeExtensions.cs b/src/Umbraco.Infrastructure/Extensions/ScopeExtensions.cs new file mode 100644 index 0000000000..ed2c520070 --- /dev/null +++ b/src/Umbraco.Infrastructure/Extensions/ScopeExtensions.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Umbraco.Cms.Core.Scoping; + +namespace Umbraco.Extensions +{ + public static class ScopeExtensions + { + public static void ReadLock(this IScope scope, ICollection lockIds) + { + foreach(var lockId in lockIds) + { + scope.ReadLock(lockId); + } + } + + public static void WriteLock(this IScope scope, ICollection lockIds) + { + foreach (var lockId in lockIds) + { + scope.WriteLock(lockId); + } + } + } +} diff --git a/src/Umbraco.Infrastructure/Scoping/IScope.cs b/src/Umbraco.Infrastructure/Scoping/IScope.cs index 26048f5ec2..ae062babd9 100644 --- a/src/Umbraco.Infrastructure/Scoping/IScope.cs +++ b/src/Umbraco.Infrastructure/Scoping/IScope.cs @@ -56,13 +56,13 @@ namespace Umbraco.Cms.Core.Scoping /// Read-locks some lock objects. /// /// The lock object identifiers. - void ReadLock(params int[] lockIds); + void ReadLock(int lockId); /// /// Write-locks some lock objects. /// /// The lock object identifiers. - void WriteLock(params int[] lockIds); + void WriteLock(int lockId); /// /// Write-locks some lock objects. diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 7e748cd57c..386bd7c06e 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -746,13 +746,13 @@ namespace Umbraco.Cms.Core.Scoping } /// - public void ReadLock(params int[] lockIds) => ReadLockInner(InstanceId, null, lockIds); + public void ReadLock(int lockId) => ReadLockInner(InstanceId, null, lockId); /// public void ReadLock(TimeSpan timeout, int lockId) => ReadLockInner(InstanceId, timeout, lockId); /// - public void WriteLock(params int[] lockIds) => WriteLockInner(InstanceId, null, lockIds); + public void WriteLock(int lockId) => WriteLockInner(InstanceId, null, lockId); /// public void WriteLock(TimeSpan timeout, int lockId) => WriteLockInner(InstanceId, timeout, lockId); @@ -762,18 +762,18 @@ namespace Umbraco.Cms.Core.Scoping /// /// Instance ID of the requesting scope. /// Optional database timeout in milliseconds. - /// Array of lock object identifiers. - private void ReadLockInner(Guid instanceId, TimeSpan? timeout = null, params int[] lockIds) + /// Array of lock object identifiers. + private void ReadLockInner(Guid instanceId, TimeSpan? timeout, int lockId) { if (ParentScope is not null) { // If we have a parent we delegate lock creation to parent. - ParentScope.ReadLockInner(instanceId, timeout, lockIds); + ParentScope.ReadLockInner(instanceId, timeout, lockId); } else { // We are the outermost scope, handle the lock request. - LockInner(instanceId, ref _readLockDictionary, ref _readLocks, ObtainReadLock, ObtainTimeoutReadLock, timeout, lockIds); + LockInner(instanceId, ref _readLockDictionary, ref _readLocks, ObtainReadLock, ObtainTimeoutReadLock, timeout, lockId); } } @@ -782,18 +782,18 @@ namespace Umbraco.Cms.Core.Scoping /// /// Instance ID of the requesting scope. /// Optional database timeout in milliseconds. - /// Array of lock object identifiers. - private void WriteLockInner(Guid instanceId, TimeSpan? timeout = null, params int[] lockIds) + /// Array of lock object identifiers. + private void WriteLockInner(Guid instanceId, TimeSpan? timeout, int lockId) { if (ParentScope is not null) { // If we have a parent we delegate lock creation to parent. - ParentScope.WriteLockInner(instanceId, timeout, lockIds); + ParentScope.WriteLockInner(instanceId, timeout, lockId); } else { // We are the outermost scope, handle the lock request. - LockInner(instanceId, ref _writeLockDictionary, ref _writeLocks, ObtainWriteLock, ObtainTimeoutWriteLock, timeout, lockIds); + LockInner(instanceId, ref _writeLockDictionary, ref _writeLocks, ObtainWriteLock, ObtainTimeoutWriteLock, timeout, lockId); } } @@ -808,48 +808,45 @@ namespace Umbraco.Cms.Core.Scoping /// Optional timeout parameter to specify a timeout. /// Lock identifiers to lock on. private void LockInner(Guid instanceId, ref Dictionary> locks, ref HashSet locksSet, - Action obtainLock, Action obtainLockTimeout, TimeSpan? timeout = null, - params int[] lockIds) + Action obtainLock, Action obtainLockTimeout, TimeSpan? timeout, + int lockId) { lock (_dictionaryLocker) { locksSet ??= new HashSet(); - foreach (var lockId in lockIds) + // Only acquire the lock if we haven't done so yet. + if (!locksSet.Contains(lockId)) { - // Only acquire the lock if we haven't done so yet. - if (!locksSet.Contains(lockId)) + IncrementLock(lockId, instanceId, ref locks); + locksSet.Add(lockId); + try { - IncrementLock(lockId, instanceId, ref locks); - locksSet.Add(lockId); - try + if (timeout is null) { - if (timeout is null) - { - // We just want an ordinary lock. - obtainLock(lockId); - } - else - { - // We want a lock with a custom timeout - obtainLockTimeout(lockId, timeout.Value); - } + // We just want an ordinary lock. + obtainLock(lockId); } - catch + else { - // Something went wrong and we didn't get the lock - // Since we at this point have determined that we haven't got any lock with an ID of LockID, it's safe to completely remove it instead of decrementing. - locks[instanceId].Remove(lockId); - // It needs to be removed from the HashSet as well, because that's how we determine to acquire a lock. - locksSet.Remove(lockId); - throw; + // We want a lock with a custom timeout + obtainLockTimeout(lockId, timeout.Value); } } - else + catch { - // We already have a lock, but need to update the dictionary for debugging purposes. - IncrementLock(lockId, instanceId, ref locks); + // Something went wrong and we didn't get the lock + // Since we at this point have determined that we haven't got any lock with an ID of LockID, it's safe to completely remove it instead of decrementing. + locks[instanceId].Remove(lockId); + // It needs to be removed from the HashSet as well, because that's how we determine to acquire a lock. + locksSet.Remove(lockId); + throw; } } + else + { + // We already have a lock, but need to update the dictionary for debugging purposes. + IncrementLock(lockId, instanceId, ref locks); + } } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs index 28dd937ec5..7a947a420c 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; @@ -7,6 +7,7 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services.Changes; +using Umbraco.Extensions; namespace Umbraco.Cms.Core.Services.Implement { @@ -92,7 +93,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // that one is special because it works across content, media and member types - scope.ReadLock(Cms.Core.Constants.Locks.ContentTypes, Cms.Core.Constants.Locks.MediaTypes, Cms.Core.Constants.Locks.MemberTypes); + scope.ReadLock(new[] { Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes }); return Repository.GetAllPropertyTypeAliases(); } } @@ -108,7 +109,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // that one is special because it works across content, media and member types - scope.ReadLock(Cms.Core.Constants.Locks.ContentTypes, Cms.Core.Constants.Locks.MediaTypes, Cms.Core.Constants.Locks.MemberTypes); + scope.ReadLock(new[] { Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes }); return Repository.GetAllContentTypeAliases(guids); } } @@ -124,7 +125,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // that one is special because it works across content, media and member types - scope.ReadLock(Cms.Core.Constants.Locks.ContentTypes, Cms.Core.Constants.Locks.MediaTypes, Cms.Core.Constants.Locks.MemberTypes); + scope.ReadLock(new[] { Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes }); return Repository.GetAllContentTypeIds(aliases); } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index 03bc48b334..f04793fe8e 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging;