/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.sa.engine.lock;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.google.common.collect.Maps;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
/**
* This is a helper class that is constructed for each execution, allowing locks to be acquired and released.
*
* @author jonnymiller
*/
public class ExecutionLockManager {
private static final Logger LOG = Logger.getLogger(ExecutionLockManager.class);
private CoordinatorClient coordinator;
private Map<String, LockState> locks = Maps.newLinkedHashMap();
public ExecutionLockManager(CoordinatorClient coordinator) {
this.coordinator = coordinator;
}
public Set<String> getLocks() {
return locks.keySet();
}
/**
* Acquires a named lock.
*
* @param name
* the name of the lock.
* @return true if the lock was acquired.
*/
public boolean acquireLock(String name) {
LockState state = getLock(name);
return acquireLock(name, state);
}
/**
* Releases the named lock.
*
* @param name
* the name of the lock.
*/
public void releaseLock(String name) {
LockState state = getLock(name);
releaseLock(name, state);
}
/**
* Destroys any held locks that may be remaining.
*/
public void destroyLocks() {
for (Map.Entry<String, LockState> entry : locks.entrySet()) {
String name = entry.getKey();
LockState state = entry.getValue();
// Release as many locks as were acquired.
int acquiredCount = state.count;
for (int i = 0; i < acquiredCount; i++) {
releaseLock(name, state);
}
}
}
protected LockState getLock(String name) {
LockState state = locks.get(name);
if (state == null) {
state = new LockState();
state.lock = coordinator.getLock(name);
locks.put(name, state);
}
return state;
}
protected boolean acquireLock(String name, LockState state) {
try {
state.lock.acquire();
state.count++;
LOG.debug("Acquired lock '" + name + "'");
return true;
} catch (Exception e) {
LOG.error("Error acquiring lock '" + name + "'", e);
return false;
}
}
protected void releaseLock(String name, LockState state) {
try {
if (state != null) {
state.lock.release();
if (state.count > 0) {
state.count--;
}
else {
LOG.warn("Release called on lock '" + name + "' which does not appear to have been acquired");
}
}
} catch (Exception e) {
LOG.error("Error releasing lock '" + name + "'", e);
}
}
private static class LockState {
private InterProcessLock lock;
private int count;
}
}