Skip to content

Commit 39085b9

Browse files
authored
Add DB locking for container APIs (#15870)
1 parent e9cfcf4 commit 39085b9

File tree

8 files changed

+64
-6
lines changed

8 files changed

+64
-6
lines changed

src/Umbraco.Core/Services/ContentTypeContainerService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Umbraco.Cms.Core.Models;
44
using Umbraco.Cms.Core.Persistence.Repositories;
55
using Umbraco.Cms.Core.Scoping;
6+
using Umbraco.Cms.Core.Services.Locking;
67

78
namespace Umbraco.Cms.Core.Services;
89

@@ -23,4 +24,8 @@ public ContentTypeContainerService(
2324
protected override Guid ContainedObjectType => Constants.ObjectTypes.DocumentType;
2425

2526
protected override UmbracoObjectTypes ContainerObjectType => UmbracoObjectTypes.DocumentTypeContainer;
27+
28+
protected override int[] ReadLockIds => ContentTypeLocks.ReadLockIds;
29+
30+
protected override int[] WriteLockIds => ContentTypeLocks.WriteLockIds;
2631
}

src/Umbraco.Core/Services/ContentTypeService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Umbraco.Cms.Core.Persistence.Repositories;
99
using Umbraco.Cms.Core.Scoping;
1010
using Umbraco.Cms.Core.Services.Changes;
11+
using Umbraco.Cms.Core.Services.Locking;
1112
using Umbraco.Cms.Core.Services.OperationStatus;
1213

1314
namespace Umbraco.Cms.Core.Services;
@@ -64,10 +65,9 @@ public ContentTypeService(
6465
StaticServiceProvider.Instance.GetRequiredService<IUserIdKeyResolver>())
6566
{ }
6667

67-
// beware! order is important to avoid deadlocks
68-
protected override int[] ReadLockIds { get; } = { Constants.Locks.ContentTypes };
68+
protected override int[] ReadLockIds => ContentTypeLocks.ReadLockIds;
6969

70-
protected override int[] WriteLockIds { get; } = { Constants.Locks.ContentTree, Constants.Locks.ContentTypes };
70+
protected override int[] WriteLockIds => ContentTypeLocks.WriteLockIds;
7171

7272
protected override Guid ContainedObjectType => Constants.ObjectTypes.DocumentType;
7373

src/Umbraco.Core/Services/DataTypeContainerService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,10 @@ public DataTypeContainerService(
2323
protected override Guid ContainedObjectType => Constants.ObjectTypes.DataType;
2424

2525
protected override UmbracoObjectTypes ContainerObjectType => UmbracoObjectTypes.DataTypeContainer;
26+
27+
// data types do not have read/write locks (yet)
28+
protected override int[] ReadLockIds => [];
29+
30+
// data types do not have read/write locks (yet)
31+
protected override int[] WriteLockIds => [];
2632
}

src/Umbraco.Core/Services/EntityTypeContainerService.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ internal abstract class EntityTypeContainerService<TTreeEntity, TEntityContainer
2222

2323
protected abstract UmbracoObjectTypes ContainerObjectType { get; }
2424

25+
protected abstract int[] ReadLockIds { get; }
26+
27+
protected abstract int[] WriteLockIds { get; }
28+
2529
protected EntityTypeContainerService(
2630
ICoreScopeProvider provider,
2731
ILoggerFactory loggerFactory,
@@ -42,6 +46,7 @@ protected EntityTypeContainerService(
4246
public async Task<EntityContainer?> GetAsync(Guid id)
4347
{
4448
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
49+
ReadLock(scope);
4550
return await Task.FromResult(_entityContainerRepository.Get(id));
4651
}
4752

@@ -134,6 +139,7 @@ protected EntityTypeContainerService(
134139
public async Task<Attempt<EntityContainer?, EntityContainerOperationStatus>> DeleteAsync(Guid id, Guid userKey)
135140
{
136141
using ICoreScope scope = ScopeProvider.CreateCoreScope();
142+
WriteLock(scope);
137143

138144
EntityContainer? container = _entityContainerRepository.Get(id);
139145
if (container == null)
@@ -178,6 +184,7 @@ protected EntityTypeContainerService(
178184
}
179185

180186
using ICoreScope scope = ScopeProvider.CreateCoreScope();
187+
WriteLock(scope);
181188

182189
EntityContainerOperationStatus operationValidationStatus = operationValidation();
183190
if (operationValidationStatus != EntityContainerOperationStatus.Success)
@@ -212,9 +219,26 @@ protected EntityTypeContainerService(
212219
}
213220

214221
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
222+
ReadLock(scope);
215223
return _entityContainerRepository.Get(treeEntity.ParentId);
216224
}
217225

218226
private void Audit(AuditType type, int userId, int objectId)
219227
=> _auditRepository.Save(new AuditItem(objectId, type, userId, ContainerObjectType.GetName()));
228+
229+
private void ReadLock(ICoreScope scope)
230+
{
231+
if (ReadLockIds.Any())
232+
{
233+
scope.ReadLock(ReadLockIds);
234+
}
235+
}
236+
237+
private void WriteLock(ICoreScope scope)
238+
{
239+
if (WriteLockIds.Any())
240+
{
241+
scope.WriteLock(WriteLockIds);
242+
}
243+
}
220244
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Umbraco.Cms.Core.Services.Locking;
2+
3+
internal static class ContentTypeLocks
4+
{
5+
// beware! order is important to avoid deadlocks
6+
internal static int[] ReadLockIds { get; } = { Constants.Locks.ContentTypes };
7+
8+
internal static int[] WriteLockIds { get; } = { Constants.Locks.ContentTree, Constants.Locks.ContentTypes };
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Umbraco.Cms.Core.Services.Locking;
2+
3+
internal static class MediaTypeLocks
4+
{
5+
// beware! order is important to avoid deadlocks
6+
internal static int[] ReadLockIds { get; } = { Constants.Locks.MediaTypes };
7+
8+
internal static int[] WriteLockIds { get; } = { Constants.Locks.MediaTree, Constants.Locks.MediaTypes };
9+
}

src/Umbraco.Core/Services/MediaTypeContainerService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Umbraco.Cms.Core.Models;
44
using Umbraco.Cms.Core.Persistence.Repositories;
55
using Umbraco.Cms.Core.Scoping;
6+
using Umbraco.Cms.Core.Services.Locking;
67

78
namespace Umbraco.Cms.Core.Services;
89

@@ -23,4 +24,8 @@ public MediaTypeContainerService(
2324
protected override Guid ContainedObjectType => Constants.ObjectTypes.MediaType;
2425

2526
protected override UmbracoObjectTypes ContainerObjectType => UmbracoObjectTypes.MediaTypeContainer;
27+
28+
protected override int[] ReadLockIds => MediaTypeLocks.ReadLockIds;
29+
30+
protected override int[] WriteLockIds => MediaTypeLocks.WriteLockIds;
2631
}

src/Umbraco.Core/Services/MediaTypeService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Umbraco.Cms.Core.Persistence.Repositories;
88
using Umbraco.Cms.Core.Scoping;
99
using Umbraco.Cms.Core.Services.Changes;
10+
using Umbraco.Cms.Core.Services.Locking;
1011

1112
namespace Umbraco.Cms.Core.Services;
1213

@@ -60,10 +61,9 @@ public MediaTypeService(
6061
}
6162

6263

63-
// beware! order is important to avoid deadlocks
64-
protected override int[] ReadLockIds { get; } = { Constants.Locks.MediaTypes };
64+
protected override int[] ReadLockIds => MediaTypeLocks.ReadLockIds;
6565

66-
protected override int[] WriteLockIds { get; } = { Constants.Locks.MediaTree, Constants.Locks.MediaTypes };
66+
protected override int[] WriteLockIds => MediaTypeLocks.WriteLockIds;
6767

6868
protected override Guid ContainedObjectType => Constants.ObjectTypes.MediaType;
6969

0 commit comments

Comments
 (0)