package mil.nga.giat.geowave.adapter.vector.plugin.lock;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import mil.nga.giat.geowave.adapter.vector.plugin.GeoWavePluginConfig;
/**
* Single GeoServer lock support. In a clustered model, do not use.
*
*
*
*/
public class MemoryLockManager extends
AbstractLockingManagement
{
private final static Logger LOGGER = LoggerFactory.getLogger(MemoryLockManager.class);
private static final Map<String, Map<String, AuthorizedLock>> LOCKS = new HashMap<String, Map<String, AuthorizedLock>>();
private final Map<String, AuthorizedLock> locks;
public MemoryLockManager(
String instanceName ) {
Map<String, AuthorizedLock> lockSet;
synchronized (LOCKS) {
lockSet = LOCKS.get(instanceName);
if (lockSet == null) {
lockSet = new HashMap<String, AuthorizedLock>();
LOCKS.put(
instanceName,
lockSet);
}
}
locks = lockSet;
}
public MemoryLockManager(
GeoWavePluginConfig pluginConfig ) {
this(
pluginConfig.getName());
}
@Override
public void releaseAll(
AuthorizedLock lock ) {
ArrayList<AuthorizedLock> toRelease = new ArrayList<AuthorizedLock>();
synchronized (locks) {
Iterator<Entry<String, AuthorizedLock>> it = locks.entrySet().iterator();
while (it.hasNext()) {
Entry<String, AuthorizedLock> entry = it.next();
if (entry.getValue().equals(
lock) || entry.getValue().isAuthorized(
lock)) {
toRelease.add(entry.getValue());
it.remove();
}
}
}
for (AuthorizedLock lockToRelease : toRelease)
lockToRelease.invalidate();
}
/**
* Release all locks associated with a transaction. Occurs on commit and
* rollback
*
* @param lock
*/
@Override
public void resetAll(
AuthorizedLock lock ) {
ArrayList<AuthorizedLock> toRelease = new ArrayList<AuthorizedLock>();
synchronized (locks) {
Iterator<Entry<String, AuthorizedLock>> it = locks.entrySet().iterator();
while (it.hasNext()) {
Entry<String, AuthorizedLock> entry = it.next();
if (entry.getValue().equals(
lock) || entry.getValue().isAuthorized(
lock)) {
toRelease.add(entry.getValue());
}
}
}
for (AuthorizedLock lockToRelease : toRelease)
lockToRelease.resetExpireTime();
}
@SuppressFBWarnings(value = {
"MWN_MISMATCHED_WAIT"
}, justification = "incorrect flag; lock held (in synchronized block)")
@Override
public void lock(
AuthorizedLock lock,
String featureID ) {
AuthorizedLock featureLock = null;
synchronized (locks) {
featureLock = locks.get(featureID);
if (featureLock == null || featureLock.isStale()) {
featureLock = lock;
locks.put(
featureID,
lock);
return;
}
else if (featureLock.isAuthorized(lock)) {
return;
}
}
// want to loop until this 'lock' is the 'winning' lock.
while (featureLock != lock) {
// at this point, some other transaction may have the lock
synchronized (featureLock) {
// check if stale, which occurs when the transaction is
// completed.
while (!featureLock.isStale())
try {
// only wait a little, because the feature lock could be
// stale
// flagged as mismatched wait...but this is correct
featureLock.wait(Math.min(
5000,
featureLock.getExpireTime() - System.currentTimeMillis()));
}
catch (InterruptedException ex) {}
catch (Exception e) {
LOGGER.error(
"Memory lock manager filed to wait for lock release. Will cycle till lock is stale.",
e);
}
}
synchronized (locks) {
featureLock = locks.get(featureID);
// did this code win the race to get the lock for the feature
// ID?
if (featureLock == null || featureLock.isStale()) {
locks.put(
featureID,
lock);
featureLock = lock;
}
}
}
}
@Override
public boolean exists(
String authID ) {
synchronized (locks) {
Iterator<Entry<String, AuthorizedLock>> it = locks.entrySet().iterator();
while (it.hasNext()) {
Entry<String, AuthorizedLock> entry = it.next();
if (entry.getValue().isAuthorized(
authID) || !entry.getValue().isStale()) return true;
}
}
return false;
}
@Override
public void unlock(
AuthorizedLock lock,
String featureID ) {
AuthorizedLock featureLock = null;
boolean notify = false;
synchronized (locks) {
featureLock = locks.get(featureID);
if (featureLock != null && featureLock.isAuthorized(lock)) {
locks.remove(featureID);
notify = true;
}
}
if (notify) {
featureLock.invalidate();
}
}
}