diff --git a/src/Umbraco.Cms.Persistence.EFCore/Locking/SqlServerEFCoreDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.EFCore/Locking/SqlServerEFCoreDistributedLockingMechanism.cs index 4652c513a3..38cdeef114 100644 --- a/src/Umbraco.Cms.Persistence.EFCore/Locking/SqlServerEFCoreDistributedLockingMechanism.cs +++ b/src/Umbraco.Cms.Persistence.EFCore/Locking/SqlServerEFCoreDistributedLockingMechanism.cs @@ -16,8 +16,8 @@ namespace Umbraco.Cms.Persistence.EFCore.Locking; internal class SqlServerEFCoreDistributedLockingMechanism : IDistributedLockingMechanism where T : DbContext { - private readonly IOptionsMonitor _connectionStrings; - private readonly IOptionsMonitor _globalSettings; + private ConnectionStrings _connectionStrings; + private GlobalSettings _globalSettings; private readonly ILogger> _logger; private readonly Lazy> _scopeAccessor; // Hooray it's a circular dependency. @@ -32,27 +32,29 @@ internal class SqlServerEFCoreDistributedLockingMechanism : IDistributedLocki { _logger = logger; _scopeAccessor = scopeAccessor; - _globalSettings = globalSettings; - _connectionStrings = connectionStrings; + _globalSettings = globalSettings.CurrentValue; + _connectionStrings = connectionStrings.CurrentValue; + globalSettings.OnChange(x=>_globalSettings = x); + connectionStrings.OnChange(x=>_connectionStrings = x); } public bool HasActiveRelatedScope => _scopeAccessor.Value.AmbientScope is not null; /// - public bool Enabled => _connectionStrings.CurrentValue.IsConnectionStringConfigured() && - string.Equals(_connectionStrings.CurrentValue.ProviderName, "Microsoft.Data.SqlClient", StringComparison.InvariantCultureIgnoreCase) && _scopeAccessor.Value.AmbientScope is not null; + public bool Enabled => _connectionStrings.IsConnectionStringConfigured() && + string.Equals(_connectionStrings.ProviderName, "Microsoft.Data.SqlClient", StringComparison.InvariantCultureIgnoreCase) && _scopeAccessor.Value.AmbientScope is not null; /// public IDistributedLock ReadLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingReadLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingReadLockDefaultTimeout; return new SqlServerDistributedLock(this, lockId, DistributedLockType.ReadLock, obtainLockTimeout.Value); } /// public IDistributedLock WriteLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingWriteLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingWriteLockDefaultTimeout; return new SqlServerDistributedLock(this, lockId, DistributedLockType.WriteLock, obtainLockTimeout.Value); } @@ -168,9 +170,7 @@ internal class SqlServerEFCoreDistributedLockingMechanism : IDistributedLocki "A transaction with minimum ReadCommitted isolation level is required."); } - await dbContext.Database.ExecuteSqlRawAsync($"SET LOCK_TIMEOUT {(int)_timeout.TotalMilliseconds};"); - - var rowsAffected = await dbContext.Database.ExecuteSqlAsync(@$"UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id={LockId}"); + var rowsAffected = await dbContext.Database.ExecuteSqlAsync(@$"SET LOCK_TIMEOUT {(int)_timeout.TotalMilliseconds};UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id={LockId}"); if (rowsAffected == 0) { diff --git a/src/Umbraco.Cms.Persistence.EFCore/Locking/SqliteEFCoreDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.EFCore/Locking/SqliteEFCoreDistributedLockingMechanism.cs index 8d92ec0e03..23b3d8d410 100644 --- a/src/Umbraco.Cms.Persistence.EFCore/Locking/SqliteEFCoreDistributedLockingMechanism.cs +++ b/src/Umbraco.Cms.Persistence.EFCore/Locking/SqliteEFCoreDistributedLockingMechanism.cs @@ -16,8 +16,8 @@ namespace Umbraco.Cms.Persistence.EFCore.Locking; internal class SqliteEFCoreDistributedLockingMechanism : IDistributedLockingMechanism where T : DbContext { - private readonly IOptionsMonitor _connectionStrings; - private readonly IOptionsMonitor _globalSettings; + private ConnectionStrings _connectionStrings; + private GlobalSettings _globalSettings; private readonly ILogger> _logger; private readonly Lazy> _efCoreScopeAccessor; @@ -29,27 +29,29 @@ internal class SqliteEFCoreDistributedLockingMechanism : IDistributedLockingM { _logger = logger; _efCoreScopeAccessor = efCoreScopeAccessor; - _connectionStrings = connectionStrings; - _globalSettings = globalSettings; + _globalSettings = globalSettings.CurrentValue; + _connectionStrings = connectionStrings.CurrentValue; + globalSettings.OnChange(x=>_globalSettings = x); + connectionStrings.OnChange(x=>_connectionStrings = x); } public bool HasActiveRelatedScope => _efCoreScopeAccessor.Value.AmbientScope is not null; /// - public bool Enabled => _connectionStrings.CurrentValue.IsConnectionStringConfigured() && - string.Equals(_connectionStrings.CurrentValue.ProviderName, "Microsoft.Data.Sqlite", StringComparison.InvariantCultureIgnoreCase) && _efCoreScopeAccessor.Value.AmbientScope is not null; + public bool Enabled => _connectionStrings.IsConnectionStringConfigured() && + string.Equals(_connectionStrings.ProviderName, "Microsoft.Data.Sqlite", StringComparison.InvariantCultureIgnoreCase) && _efCoreScopeAccessor.Value.AmbientScope is not null; // With journal_mode=wal we can always read a snapshot. public IDistributedLock ReadLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingReadLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingReadLockDefaultTimeout; return new SqliteDistributedLock(this, lockId, DistributedLockType.ReadLock, obtainLockTimeout.Value); } // With journal_mode=wal only a single write transaction can exist at a time. public IDistributedLock WriteLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingWriteLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingWriteLockDefaultTimeout; return new SqliteDistributedLock(this, lockId, DistributedLockType.WriteLock, obtainLockTimeout.Value); } diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs index 77975e8f31..a7f183e57a 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs @@ -17,8 +17,8 @@ namespace Umbraco.Cms.Persistence.SqlServer.Services; /// public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism { - private readonly IOptionsMonitor _connectionStrings; - private readonly IOptionsMonitor _globalSettings; + private ConnectionStrings _connectionStrings; + private GlobalSettings _globalSettings; private readonly ILogger _logger; private readonly Lazy _scopeAccessor; // Hooray it's a circular dependency. @@ -33,25 +33,28 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism { _logger = logger; _scopeAccessor = scopeAccessor; - _globalSettings = globalSettings; - _connectionStrings = connectionStrings; + _globalSettings = globalSettings.CurrentValue; + _connectionStrings = connectionStrings.CurrentValue; + globalSettings.OnChange(x => _globalSettings = x); + connectionStrings.OnChange(x => _connectionStrings = x); + } /// - public bool Enabled => _connectionStrings.CurrentValue.IsConnectionStringConfigured() && - string.Equals(_connectionStrings.CurrentValue.ProviderName,Constants.ProviderName, StringComparison.InvariantCultureIgnoreCase); + public bool Enabled => _connectionStrings.IsConnectionStringConfigured() && + string.Equals(_connectionStrings.ProviderName,Constants.ProviderName, StringComparison.InvariantCultureIgnoreCase); /// public IDistributedLock ReadLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingReadLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingReadLockDefaultTimeout; return new SqlServerDistributedLock(this, lockId, DistributedLockType.ReadLock, obtainLockTimeout.Value); } /// public IDistributedLock WriteLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingWriteLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingWriteLockDefaultTimeout; return new SqlServerDistributedLock(this, lockId, DistributedLockType.WriteLock, obtainLockTimeout.Value); } diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs index 54e30d6fa6..f43a1eff05 100644 --- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs +++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs @@ -16,8 +16,8 @@ namespace Umbraco.Cms.Persistence.Sqlite.Services; public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism { - private readonly IOptionsMonitor _connectionStrings; - private readonly IOptionsMonitor _globalSettings; + private ConnectionStrings _connectionStrings; + private GlobalSettings _globalSettings; private readonly ILogger _logger; private readonly Lazy _scopeAccessor; @@ -29,25 +29,27 @@ public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism { _logger = logger; _scopeAccessor = scopeAccessor; - _connectionStrings = connectionStrings; - _globalSettings = globalSettings; + _connectionStrings = connectionStrings.CurrentValue; + _globalSettings = globalSettings.CurrentValue; + globalSettings.OnChange(x=>_globalSettings = x); + connectionStrings.OnChange(x=>_connectionStrings = x); } /// - public bool Enabled => _connectionStrings.CurrentValue.IsConnectionStringConfigured() && - string.Equals(_connectionStrings.CurrentValue.ProviderName, Constants.ProviderName, StringComparison.InvariantCultureIgnoreCase); + public bool Enabled => _connectionStrings.IsConnectionStringConfigured() && + string.Equals(_connectionStrings.ProviderName, Constants.ProviderName, StringComparison.InvariantCultureIgnoreCase); // With journal_mode=wal we can always read a snapshot. public IDistributedLock ReadLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingReadLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingReadLockDefaultTimeout; return new SqliteDistributedLock(this, lockId, DistributedLockType.ReadLock, obtainLockTimeout.Value); } // With journal_mode=wal only a single write transaction can exist at a time. public IDistributedLock WriteLock(int lockId, TimeSpan? obtainLockTimeout = null) { - obtainLockTimeout ??= _globalSettings.CurrentValue.DistributedLockingWriteLockDefaultTimeout; + obtainLockTimeout ??= _globalSettings.DistributedLockingWriteLockDefaultTimeout; return new SqliteDistributedLock(this, lockId, DistributedLockType.WriteLock, obtainLockTimeout.Value); }