Skip to content

Commit

Permalink
Merge pull request #108 from denyskonakhevych/LB-2097
Browse files Browse the repository at this point in the history
LB-2097: Lock acquisition concurrency issue
  • Loading branch information
nvoxland authored May 24, 2022
2 parents f722c71 + 1675d8e commit 8843c75
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
import liquibase.statement.core.LockDatabaseChangeLogStatement;
import liquibase.statement.core.RawSqlStatement;
import liquibase.statement.core.UnlockDatabaseChangeLogStatement;
import liquibase.util.NetUtil;

import java.net.SocketException;
import java.net.UnknownHostException;
import java.sql.SQLException;
import java.sql.Statement;

Expand Down Expand Up @@ -51,17 +54,16 @@ public boolean acquireLock() throws LockException {
super.init();


boolean locked = executor.queryForInt(
new RawSqlStatement("SELECT COUNT(*) FROM " + getChangeLogLockTableName() + " where " +
"locked = TRUE ALLOW FILTERING")
) > 0;

if (locked) {
if (isLocked(executor)) {
return false;
} else {

executor.comment("Lock Database");
int rowsUpdated = executor.update(new LockDatabaseChangeLogStatement());
if (rowsUpdated == -1 && !isLockedByCurrentInstance(executor)) {
// another node was faster
return false;
}
if ((rowsUpdated == -1) && (database instanceof MSSQLDatabase)) {

Scope.getCurrentScope().getLog(this.getClass()).info("Database did not return a proper row count (Might have NOCOUNT enabled)");
Expand Down Expand Up @@ -178,8 +180,27 @@ public boolean isDatabaseChangeLogLockTableInitialized(final boolean tableJustCr
return isDatabaseChangeLogLockTableInitialized;
}

private boolean isLocked(Executor executor) throws DatabaseException {
return executor.queryForInt(
new RawSqlStatement("SELECT COUNT(*) FROM " + database.getDefaultCatalogName() + "." + getChangeLogLockTableName() + " where " +
"locked = TRUE ALLOW FILTERING")
) > 0;
}

private boolean isLockedByCurrentInstance(Executor executor) throws DatabaseException {
try {
final String lockedBy = NetUtil.getLocalHostName() + " (" + NetUtil.getLocalHostAddress() + ")";
return executor.queryForInt(
new RawSqlStatement("SELECT COUNT(*) FROM " + database.getDefaultCatalogName() + "." + getChangeLogLockTableName() + " where " +
"LOCKED = TRUE AND LOCKEDBY = '" + lockedBy + "' ALLOW FILTERING")
) > 0;
} catch (SocketException | UnknownHostException e) {
throw new UnexpectedLiquibaseException(e);
}
}

private String getChangeLogLockTableName() {
if(database.getLiquibaseCatalogName() != null) {
if (database.getLiquibaseCatalogName() != null) {
return database.getLiquibaseCatalogName() + "." + database.getDatabaseChangeLogLockTableName();
} else {
return database.getDatabaseChangeLogLockTableName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public boolean supports(LockDatabaseChangeLogStatement statement, Database datab
public Sql[] generateSql(LockDatabaseChangeLogStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
RawSqlStatement updateStatement = new RawSqlStatement("UPDATE " +
database.escapeTableName(database.getLiquibaseCatalogName(), database.getLiquibaseSchemaName(), database.getDatabaseChangeLogLockTableName()) +
" SET LOCKED = TRUE, LOCKEDBY = '" + hostname + " (" + hostaddress + ")" + "', LOCKGRANTED = " + System.currentTimeMillis() + " WHERE ID = 1");
" SET LOCKED = TRUE, LOCKEDBY = '" + hostname + " (" + hostaddress + ")" + "', LOCKGRANTED = " + System.currentTimeMillis() + " WHERE ID = 1 IF LOCKED = FALSE");
return SqlGeneratorFactory.getInstance().generateSql(updateStatement, database);
}

Expand Down

0 comments on commit 8843c75

Please sign in to comment.