Skip to content

Commit 58c6e65

Browse files
Merge branch 'v8/8.8' into v8/8.9
2 parents ca098e8 + d5d7d31 commit 58c6e65

File tree

7 files changed

+81
-37
lines changed

7 files changed

+81
-37
lines changed

src/Umbraco.Core/Runtime/MainDom.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,16 @@ private bool Acquire()
144144

145145
_logger.Info<MainDom>("Acquiring.");
146146

147-
// Get the lock
148-
var acquired = _mainDomLock.AcquireLockAsync(LockTimeoutMilliseconds).GetAwaiter().GetResult();
147+
// Get the lock
148+
var acquired = false;
149+
try
150+
{
151+
acquired = _mainDomLock.AcquireLockAsync(LockTimeoutMilliseconds).GetAwaiter().GetResult();
152+
}
153+
catch (Exception ex)
154+
{
155+
_logger.Error<MainDom>(ex, "Error while acquiring");
156+
}
149157

150158
if (!acquired)
151159
{

src/Umbraco.Core/Runtime/SqlMainDomLock.cs

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using NPoco;
2+
using System;
23
using System.Data;
34
using System.Data.SqlClient;
45
using System.Diagnostics;
@@ -49,19 +50,23 @@ public async Task<bool> AcquireLockAsync(int millisecondsTimeout)
4950
}
5051

5152
if (!(_dbFactory.SqlContext.SqlSyntax is SqlServerSyntaxProvider sqlServerSyntaxProvider))
53+
{
5254
throw new NotSupportedException("SqlMainDomLock is only supported for Sql Server");
55+
}
5356

5457
_sqlServerSyntax = sqlServerSyntaxProvider;
5558

5659
_logger.Debug<SqlMainDomLock>("Acquiring lock...");
5760

5861
var tempId = Guid.NewGuid().ToString();
5962

60-
using var db = _dbFactory.CreateDatabase();
61-
using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
63+
IUmbracoDatabase db = null;
6264

6365
try
6466
{
67+
db = _dbFactory.CreateDatabase();
68+
db.BeginTransaction(IsolationLevel.ReadCommitted);
69+
6570
try
6671
{
6772
// wait to get a write lock
@@ -102,7 +107,8 @@ public async Task<bool> AcquireLockAsync(int millisecondsTimeout)
102107
}
103108
finally
104109
{
105-
transaction.Complete();
110+
db?.CompleteTransaction();
111+
db?.Dispose();
106112
}
107113

108114

@@ -161,11 +167,11 @@ private void ListeningLoop()
161167
// new MainDom will just take over.
162168
if (_cancellationTokenSource.IsCancellationRequested)
163169
return;
164-
165-
using var db = _dbFactory.CreateDatabase();
166-
using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
170+
IUmbracoDatabase db = null;
167171
try
168172
{
173+
db = _dbFactory.CreateDatabase();
174+
db.BeginTransaction(IsolationLevel.ReadCommitted);
169175
// get a read lock
170176
_sqlServerSyntax.ReadLock(db, Constants.Locks.MainDom);
171177

@@ -189,7 +195,8 @@ private void ListeningLoop()
189195
}
190196
finally
191197
{
192-
transaction.Complete();
198+
db?.CompleteTransaction();
199+
db?.Dispose();
193200
}
194201
}
195202

@@ -208,34 +215,47 @@ private Task<bool> WaitForExistingAsync(string tempId, int millisecondsTimeout)
208215

209216
return Task.Run(() =>
210217
{
211-
using var db = _dbFactory.CreateDatabase();
212-
213-
var watch = new Stopwatch();
214-
watch.Start();
215-
while (true)
218+
try
216219
{
217-
// poll very often, we need to take over as fast as we can
218-
// local testing shows the actual query to be executed from client/server is approx 300ms but would change depending on environment/IO
219-
Thread.Sleep(1000);
220-
221-
var acquired = TryAcquire(db, tempId, updatedTempId);
222-
if (acquired.HasValue)
223-
return acquired.Value;
220+
using var db = _dbFactory.CreateDatabase();
224221

225-
if (watch.ElapsedMilliseconds >= millisecondsTimeout)
222+
var watch = new Stopwatch();
223+
watch.Start();
224+
while (true)
226225
{
227-
return AcquireWhenMaxWaitTimeElapsed(db);
226+
// poll very often, we need to take over as fast as we can
227+
// local testing shows the actual query to be executed from client/server is approx 300ms but would change depending on environment/IO
228+
Thread.Sleep(1000);
229+
230+
var acquired = TryAcquire(db, tempId, updatedTempId);
231+
if (acquired.HasValue)
232+
return acquired.Value;
233+
234+
if (watch.ElapsedMilliseconds >= millisecondsTimeout)
235+
{
236+
return AcquireWhenMaxWaitTimeElapsed(db);
237+
}
228238
}
229239
}
240+
catch (Exception ex)
241+
{
242+
_logger.Error<SqlMainDomLock>(ex, "An error occurred trying to acquire and waiting for existing SqlMainDomLock to shutdown");
243+
return false;
244+
}
245+
230246
}, _cancellationTokenSource.Token);
231247
}
232248

233249
private bool? TryAcquire(IUmbracoDatabase db, string tempId, string updatedTempId)
234250
{
235-
using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
251+
// Creates a separate transaction to the DB instance so we aren't allocating tons of new DB instances for each transaction
252+
// since this is executed in a tight loop
253+
254+
ITransaction transaction = null;
236255

237256
try
238257
{
258+
transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
239259
// get a read lock
240260
_sqlServerSyntax.ReadLock(db, Constants.Locks.MainDom);
241261

@@ -281,14 +301,18 @@ private Task<bool> WaitForExistingAsync(string tempId, int millisecondsTimeout)
281301
}
282302
finally
283303
{
284-
transaction.Complete();
304+
transaction?.Complete();
305+
transaction?.Dispose();
285306
}
286307

287308
return null; // continue
288309
}
289310

290311
private bool AcquireWhenMaxWaitTimeElapsed(IUmbracoDatabase db)
291312
{
313+
// Creates a separate transaction to the DB instance so we aren't allocating tons of new DB instances for each transaction
314+
// since this is executed in a tight loop
315+
292316
// if the timeout has elapsed, it either means that the other main dom is taking too long to shutdown,
293317
// or it could mean that the previous appdomain was terminated and didn't clear out the main dom SQL row
294318
// and it's just been left as an orphan row.
@@ -298,10 +322,12 @@ private bool AcquireWhenMaxWaitTimeElapsed(IUmbracoDatabase db)
298322

299323
_logger.Debug<SqlMainDomLock>("Timeout elapsed, assuming orphan row, acquiring MainDom.");
300324

301-
using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
325+
ITransaction transaction = null;
302326

303327
try
304328
{
329+
transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
330+
305331
_sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom);
306332

307333
// so now we update the row with our appdomain id
@@ -324,7 +350,8 @@ private bool AcquireWhenMaxWaitTimeElapsed(IUmbracoDatabase db)
324350
}
325351
finally
326352
{
327-
transaction.Complete();
353+
transaction?.Complete();
354+
transaction?.Dispose();
328355
}
329356
}
330357

@@ -375,11 +402,12 @@ protected virtual void Dispose(bool disposing)
375402

376403
if (_dbFactory.Configured)
377404
{
378-
using var db = _dbFactory.CreateDatabase();
379-
using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted);
380-
405+
IUmbracoDatabase db = null;
381406
try
382407
{
408+
db = _dbFactory.CreateDatabase();
409+
db.BeginTransaction(IsolationLevel.ReadCommitted);
410+
383411
// get a write lock
384412
_sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom);
385413

@@ -406,7 +434,15 @@ protected virtual void Dispose(bool disposing)
406434
}
407435
finally
408436
{
409-
transaction.Complete();
437+
try
438+
{
439+
db?.CompleteTransaction();
440+
db?.Dispose();
441+
}
442+
catch (Exception ex)
443+
{
444+
_logger.Error<SqlMainDomLock>(ex, "Unexpected error during dispose when completing transaction.");
445+
}
410446
}
411447
}
412448
}

src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div>
22
<ng-form name="tabbedContentForm">
3-
<div class="umb-group-panel" retrive-dom-element="registerPropertyGroup(element[0], attributes.appAnchor)" data-app-anchor="{{group.id}}" data-element="group-{{group.alias}}" ng-repeat="group in content.tabs track by group.label">
3+
<div class="umb-group-panel" retrive-dom-element="registerPropertyGroup(element[0], attributes.appAnchor)" data-app-anchor="{{group.id}}" data-element="group-{{group.alias}}" ng-repeat="group in content.tabs track by group.id">
44

55
<div class="umb-group-panel__header">
66
<div id="group-{{group.id}}">{{ group.label }}</div>

src/Umbraco.Web.UI.Client/src/views/components/elementeditor/umb-element-editor-content.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<ng-form name="elementTypeContentForm">
33
<div class="umb-group-panel"
44
data-element="group-{{group.alias}}"
5-
ng-repeat="group in vm.model.variants[0].tabs track by group.label">
5+
ng-repeat="group in vm.model.variants[0].tabs track by group.id">
66

77
<div class="umb-group-panel__header">
88
<div id="group-{{group.id}}">{{ group.label }}</div>

src/Umbraco.Web.UI.Client/src/views/components/member/umb-member-node-info.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div class="umb-package-details">
22
<div class="umb-package-details__main-content">
33

4-
<umb-box data-element="node-info-membership" ng-repeat="group in node.tabs| filter: {properties:{view:'readonlyvalue'}} track by group.label">
4+
<umb-box data-element="node-info-membership" ng-repeat="group in node.tabs| filter: {properties:{view:'readonlyvalue'}} track by group.id">
55

66
<div class="umb-group-panel__header">
77
<div>{{ group.label }}</div>

src/Umbraco.Web.UI.Client/src/views/media/apps/content/content.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="form-horizontal" ng-controller="Umbraco.Editors.Media.Apps.ContentController as vm">
2-
<div class="umb-group-panel" data-element="group-{{group.alias}}" ng-repeat="group in content.tabs | filter: { hide : '!' + true } track by group.label">
2+
<div class="umb-group-panel" data-element="group-{{group.alias}}" ng-repeat="group in content.tabs | filter: { hide : '!' + true } track by group.id">
33

44
<div class="umb-group-panel__header">
55
<div>{{ group.label }}</div>

src/Umbraco.Web.UI.Client/src/views/member/apps/content/content.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div class="form-horizontal" ng-controller="Umbraco.Editors.Member.Apps.ContentController as vm">
22

3-
<div class="umb-group-panel" ng-repeat="group in content.tabs track by group.label">
3+
<div class="umb-group-panel" ng-repeat="group in content.tabs track by group.id">
44

55
<div class="umb-group-panel__header">
66
<div>{{ group.label }}</div>

0 commit comments

Comments
 (0)