liquibase.lockservice.LockService Maven / Gradle / Ivy
package liquibase.lockservice;
import liquibase.database.Database;
import liquibase.exception.DatabaseException;
import liquibase.exception.LockException;
import liquibase.executor.Executor;
import liquibase.executor.ExecutorService;
import liquibase.logging.LogFactory;
import liquibase.statement.SqlStatement;
import liquibase.statement.core.LockDatabaseChangeLogStatement;
import liquibase.statement.core.SelectFromDatabaseChangeLogLockStatement;
import liquibase.statement.core.UnlockDatabaseChangeLogStatement;
import liquibase.statement.core.RawSqlStatement;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class LockService {
private Database database;
private boolean hasChangeLogLock = false;
private long changeLogLockWaitTime = 1000 * 60 * 5; //default to 5 mins
private long changeLogLocRecheckTime = 1000 * 10; //default to every 10 seconds
private static Map instances = new ConcurrentHashMap();
private LockService(Database database) {
this.database = database;
}
public static LockService getInstance(Database database) {
if (!instances.containsKey(database)) {
instances.put(database, new LockService(database));
}
return instances.get(database);
}
public void setChangeLogLockWaitTime(long changeLogLockWaitTime) {
this.changeLogLockWaitTime = changeLogLockWaitTime;
}
public void setChangeLogLockRecheckTime(long changeLogLocRecheckTime) {
this.changeLogLocRecheckTime = changeLogLocRecheckTime;
}
public boolean hasChangeLogLock() {
return hasChangeLogLock;
}
public void waitForLock() throws LockException {
boolean locked = false;
long timeToGiveUp = new Date().getTime() + changeLogLockWaitTime;
while (!locked && new Date().getTime() < timeToGiveUp) {
locked = acquireLock();
if (!locked) {
LogFactory.getLogger().info("Waiting for changelog lock....");
try {
Thread.sleep(changeLogLocRecheckTime);
} catch (InterruptedException e) {
;
}
}
}
if (!locked) {
DatabaseChangeLogLock[] locks = listLocks();
String lockedBy;
if (locks.length > 0) {
DatabaseChangeLogLock lock = locks[0];
lockedBy = lock.getLockedBy() + " since " + DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(lock.getLockGranted());
} else {
lockedBy = "UNKNOWN";
}
throw new LockException("Could not acquire change log lock. Currently locked by " + lockedBy);
}
}
public boolean acquireLock() throws LockException {
if (hasChangeLogLock) {
return true;
}
Executor executor = ExecutorService.getInstance().getExecutor(database);
try {
database.rollback();
database.checkDatabaseChangeLogLockTable();
Boolean locked = (Boolean) ExecutorService.getInstance().getExecutor(database).queryForObject(new SelectFromDatabaseChangeLogLockStatement("LOCKED"), Boolean.class);
if (locked) {
return false;
} else {
executor.comment("Lock Database");
int rowsUpdated = executor.update(new LockDatabaseChangeLogStatement());
if (rowsUpdated > 1) {
throw new LockException("Did not update change log lock correctly");
}
if (rowsUpdated == 0)
{
// another node was faster
return false;
}
database.commit();
LogFactory.getLogger().info("Successfully acquired change log lock");
hasChangeLogLock = true;
database.setCanCacheLiquibaseTableInfo(true);
return true;
}
} catch (Exception e) {
throw new LockException(e);
} finally {
try {
database.rollback();
} catch (DatabaseException e) {
;
}
}
}
public void releaseLock() throws LockException {
Executor executor = ExecutorService.getInstance().getExecutor(database);
try {
if (database.hasDatabaseChangeLogLockTable()) {
executor.comment("Release Database Lock");
database.rollback();
int updatedRows = executor.update(new UnlockDatabaseChangeLogStatement());
if (updatedRows != 1) {
throw new LockException("Did not update change log lock correctly.\n\n" + updatedRows + " rows were updated instead of the expected 1 row using executor " + executor.getClass().getName()+" there are "+executor.queryForInt(new RawSqlStatement("select count(*) from "+database.getDatabaseChangeLogLockTableName()))+" rows in the table");
}
database.commit();
hasChangeLogLock = false;
instances.remove(this.database);
database.setCanCacheLiquibaseTableInfo(false);
LogFactory.getLogger().info("Successfully released change log lock");
}
} catch (Exception e) {
throw new LockException(e);
} finally {
try {
database.rollback();
} catch (DatabaseException e) {
;
}
}
}
public DatabaseChangeLogLock[] listLocks() throws LockException {
try {
if (!database.hasDatabaseChangeLogLockTable()) {
return new DatabaseChangeLogLock[0];
}
List allLocks = new ArrayList();
SqlStatement sqlStatement = new SelectFromDatabaseChangeLogLockStatement("ID", "LOCKED", "LOCKGRANTED", "LOCKEDBY");
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy