diff --git a/src/Evolve/Dialect/Cassandra/CassandraCluster.cs b/src/Evolve/Dialect/Cassandra/CassandraCluster.cs index c2245a3c..0936131a 100644 --- a/src/Evolve/Dialect/Cassandra/CassandraCluster.cs +++ b/src/Evolve/Dialect/Cassandra/CassandraCluster.cs @@ -39,7 +39,7 @@ public override IEvolveMetadata GetMetadataTable(string schema, string tableName /// Will check for a predefined keyspace and table to see if there is a lock. /// Otherwise, always returns true, because the lock is granted at table level. /// - public override bool TryAcquireApplicationLock() + public override bool TryAcquireApplicationLock(object? lockId = null) { string clusterLockKeyspaceName = "cluster_lock"; string clusterLockTableName = "lock"; @@ -54,6 +54,9 @@ public override bool TryAcquireApplicationLock() clusterLockTableName = clusterLock!.GetValue("defaultClusterLockTable", clusterLockTableName)!; } + // Input parameter overrides both the above variants + clusterLockTableName = lockId?.ToString() ?? clusterLockTableName; + try { return WrappedConnection.QueryForLong($"select count(locked) from {clusterLockKeyspaceName}.{clusterLockTableName}") == 0; @@ -71,7 +74,7 @@ public override bool TryAcquireApplicationLock() /// /// Returns always true, because the lock is released at table level. /// - public override bool ReleaseApplicationLock() => true; + public override bool ReleaseApplicationLock(object? lockId = null) => true; public override SqlStatementBuilderBase SqlStatementBuilder { get; } = new CqlStatementBuilder(); } diff --git a/src/Evolve/Dialect/CockroachDB/CockroachDBCluster.cs b/src/Evolve/Dialect/CockroachDB/CockroachDBCluster.cs index 6da3a87f..f7526168 100644 --- a/src/Evolve/Dialect/CockroachDB/CockroachDBCluster.cs +++ b/src/Evolve/Dialect/CockroachDB/CockroachDBCluster.cs @@ -21,8 +21,8 @@ public CockroachDBCluster(WrappedConnection wrappedConnection) : base(wrappedCon public override Schema GetSchema(string schemaName) => new CockroachDBDatabase(schemaName, WrappedConnection); - public override bool TryAcquireApplicationLock() => true; + public override bool TryAcquireApplicationLock(object? lockId = null) => true; - public override bool ReleaseApplicationLock() => true; + public override bool ReleaseApplicationLock(object? lockId = null) => true; } } \ No newline at end of file diff --git a/src/Evolve/Dialect/DatabaseHelper.cs b/src/Evolve/Dialect/DatabaseHelper.cs index 19bb8d8e..887e15d7 100644 --- a/src/Evolve/Dialect/DatabaseHelper.cs +++ b/src/Evolve/Dialect/DatabaseHelper.cs @@ -28,9 +28,9 @@ protected DatabaseHelper(WrappedConnection wrappedConnection) public abstract IEvolveMetadata GetMetadataTable(string schema, string tableName); - public abstract bool TryAcquireApplicationLock(); + public abstract bool TryAcquireApplicationLock(object? lockId = null); - public abstract bool ReleaseApplicationLock(); + public abstract bool ReleaseApplicationLock(object? lockId = null); public void Dispose() { diff --git a/src/Evolve/Dialect/MySQL/MySQLDatabase.cs b/src/Evolve/Dialect/MySQL/MySQLDatabase.cs index 80b5d8c0..2198d07b 100644 --- a/src/Evolve/Dialect/MySQL/MySQLDatabase.cs +++ b/src/Evolve/Dialect/MySQL/MySQLDatabase.cs @@ -24,8 +24,8 @@ public MySQLDatabase(WrappedConnection wrappedConnection) : base(wrappedConnecti public override Schema GetSchema(string schemaName) => new MySQLSchema(schemaName, WrappedConnection); - public override bool TryAcquireApplicationLock() => WrappedConnection.QueryForLong($"SELECT GET_LOCK('{LOCK_ID}', 0);") == 1; + public override bool TryAcquireApplicationLock(object? lockId = null) => WrappedConnection.QueryForLong($"SELECT GET_LOCK('{lockId?? LOCK_ID}', 0);") == 1; - public override bool ReleaseApplicationLock() => WrappedConnection.QueryForLong($"SELECT RELEASE_LOCK('{LOCK_ID}');") == 1; + public override bool ReleaseApplicationLock(object? lockId = null) => WrappedConnection.QueryForLong($"SELECT RELEASE_LOCK('{lockId ?? LOCK_ID}');") == 1; } } diff --git a/src/Evolve/Dialect/PostgreSQL/PostgreSQLDatabase.cs b/src/Evolve/Dialect/PostgreSQL/PostgreSQLDatabase.cs index 0570b133..2c7d9276 100644 --- a/src/Evolve/Dialect/PostgreSQL/PostgreSQLDatabase.cs +++ b/src/Evolve/Dialect/PostgreSQL/PostgreSQLDatabase.cs @@ -23,9 +23,9 @@ public PostgreSQLDatabase(WrappedConnection wrappedConnection) : base(wrappedCon public override Schema GetSchema(string schemaName) => new PostgreSQLSchema(schemaName, WrappedConnection); - public override bool TryAcquireApplicationLock() => WrappedConnection.QueryForBool($"SELECT pg_try_advisory_lock({LOCK_ID})"); + public override bool TryAcquireApplicationLock(object? lockId = null) => WrappedConnection.QueryForBool($"SELECT pg_try_advisory_lock({lockId ?? LOCK_ID})"); - public override bool ReleaseApplicationLock() => WrappedConnection.QueryForBool($"SELECT pg_advisory_unlock({LOCK_ID})"); + public override bool ReleaseApplicationLock(object? lockId = null) => WrappedConnection.QueryForBool($"SELECT pg_advisory_unlock({lockId ?? LOCK_ID})"); private string CleanSchemaName(string schemaName) { diff --git a/src/Evolve/Dialect/SQLServer/SQLServerDatabase.cs b/src/Evolve/Dialect/SQLServer/SQLServerDatabase.cs index 9679dc5a..14c02e91 100644 --- a/src/Evolve/Dialect/SQLServer/SQLServerDatabase.cs +++ b/src/Evolve/Dialect/SQLServer/SQLServerDatabase.cs @@ -23,7 +23,7 @@ public SQLServerDatabase(WrappedConnection wrappedConnection) : base(wrappedConn public override Schema GetSchema(string schemaName) => new SQLServerSchema(schemaName, WrappedConnection); - public override bool TryAcquireApplicationLock() + public override bool TryAcquireApplicationLock(object? lockId = null) { return WrappedConnection.ExecuteDbCommand("sp_getapplock", cmd => { @@ -37,7 +37,7 @@ public override bool TryAcquireApplicationLock() var inParam1 = cmd.CreateParameter(); inParam1.ParameterName = "@Resource"; - inParam1.Value = LOCK_ID; + inParam1.Value = lockId ?? LOCK_ID; inParam1.DbType = DbType.String; inParam1.Direction = ParameterDirection.Input; cmd.Parameters.Add(inParam1); @@ -70,7 +70,7 @@ public override bool TryAcquireApplicationLock() }) >= 0; } - public override bool ReleaseApplicationLock() + public override bool ReleaseApplicationLock(object? lockId = null) { return WrappedConnection.ExecuteDbCommand("sp_releaseapplock", cmd => { @@ -84,7 +84,7 @@ public override bool ReleaseApplicationLock() var inParam1 = cmd.CreateParameter(); inParam1.ParameterName = "@Resource"; - inParam1.Value = LOCK_ID; + inParam1.Value = lockId ?? LOCK_ID; inParam1.DbType = DbType.String; inParam1.Direction = ParameterDirection.Input; cmd.Parameters.Add(inParam1); diff --git a/src/Evolve/Dialect/SQLite/SQLiteDatabase.cs b/src/Evolve/Dialect/SQLite/SQLiteDatabase.cs index 4af9bd74..ac14a847 100644 --- a/src/Evolve/Dialect/SQLite/SQLiteDatabase.cs +++ b/src/Evolve/Dialect/SQLite/SQLiteDatabase.cs @@ -26,12 +26,12 @@ public SQLiteDatabase(WrappedConnection wrappedConnection) : base(wrappedConnect /// Not supported in SQLite. /// /// Always true - public override bool TryAcquireApplicationLock() => true; + public override bool TryAcquireApplicationLock(object? lockId = null) => true; /// /// Not supported in SQLite. /// /// Always true - public override bool ReleaseApplicationLock() => true; + public override bool ReleaseApplicationLock(object? lockId = null) => true; } } diff --git a/src/Evolve/Evolve.cs b/src/Evolve/Evolve.cs index 64510adb..bfd80153 100644 --- a/src/Evolve/Evolve.cs +++ b/src/Evolve/Evolve.cs @@ -77,6 +77,7 @@ public string MetadataTableSchema public bool RetryRepeatableMigrationsUntilNoError { get; set; } public TransactionKind TransactionMode { get; set; } = TransactionKind.CommitEach; public bool SkipNextMigrations { get; set; } = false; + public object? ApplicationLockId { get; set; } = null; private IMigrationLoader? _migrationLoader; public IMigrationLoader MigrationLoader @@ -772,7 +773,7 @@ private void InternalExecuteCommand(Action commandAction) if (EnableClusterMode) { var metadata = db.GetMetadataTable(MetadataTableSchema, MetadataTableName); - if (!db.ReleaseApplicationLock() || !metadata.ReleaseLock()) + if (!db.ReleaseApplicationLock(ApplicationLockId) || !metadata.ReleaseLock()) { _log("Error trying to release Evolve lock."); } @@ -881,7 +882,7 @@ private void WaitForApplicationLock(DatabaseHelper db) { while (true) { - if (db.TryAcquireApplicationLock()) + if (db.TryAcquireApplicationLock(ApplicationLockId)) { break; } diff --git a/test/Evolve.Tests/Integration/PostgreSQL/Scenario010.cs b/test/Evolve.Tests/Integration/PostgreSQL/Scenario010.cs new file mode 100644 index 00000000..d9a4a9c3 --- /dev/null +++ b/test/Evolve.Tests/Integration/PostgreSQL/Scenario010.cs @@ -0,0 +1,20 @@ +using EvolveDb.Tests.Infrastructure; +using Xunit; +using Xunit.Abstractions; + +namespace EvolveDb.Tests.Integration.PostgreSql +{ + [Collection("PostgreSql collection")] + public class Scenario010 : Scenario + { + public Scenario010(PostgreSqlFixture dbContainer, ITestOutputHelper output) : base(dbContainer, output) {} + + [Fact] + [Category(Test.PostgreSQL, Test.Sceanario)] + public void Scenario_lockIdSpecific() + { + Evolve.ApplicationLockId = 27893423; + Evolve.Migrate(); + } + } +}