Commit 5f9af5a8 authored by Pete Matern's avatar Pete Matern Committed by pete

Reworked LocalLockFactory to use a wrapper around the actual ReentrantLock so...

Reworked LocalLockFactory to use a wrapper around the actual ReentrantLock so we can avoid using a cleanup thread.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@8326 b35dd754-fafc-0310-a699-88a17e54d16e
parent c9d224fb
...@@ -17,8 +17,10 @@ import java.lang.ref.WeakReference; ...@@ -17,8 +17,10 @@ import java.lang.ref.WeakReference;
import java.util.Map; import java.util.Map;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
/** /**
* LockFactory to be used when not running in cluster mode. The locks returned by this * LockFactory to be used when not running in cluster mode. The locks returned by this
...@@ -28,45 +30,107 @@ import java.util.concurrent.locks.ReentrantLock; ...@@ -28,45 +30,107 @@ import java.util.concurrent.locks.ReentrantLock;
*/ */
public class LocalLockFactory implements LockFactory { public class LocalLockFactory implements LockFactory {
private TimerTask maintenanceTask; private Map<Object, ReentrantLock> locks = new ConcurrentHashMap<Object, ReentrantLock>();
private Map<Object, WeakReference<Lock>> locks = new ConcurrentHashMap<Object, WeakReference<Lock>>(); private Map<Object, Integer> counts = new ConcurrentHashMap<Object, Integer>();
public Lock getLock(Object key) { public Lock getLock(Object key) {
WeakReference<Lock> lockRef;
Lock lock;
Object lockKey = key; Object lockKey = key;
if (key instanceof String) { if (key instanceof String) {
lockKey = ((String) key).intern(); lockKey = ((String) key).intern();
} }
synchronized (lockKey) {
lockRef = locks.get(key); return new LocalLock(lockKey);
lock = lockRef != null ? lockRef.get() : null; }
if (lockRef == null || lock == null) {
lock = new ReentrantLock(true); private void acquireLock(Object key) {
lockRef = new WeakReference<Lock>(lock); ReentrantLock lock;
locks.put(key, lockRef); synchronized (key) {
lock = lookupLockForAcquire(key);
}
lock.lock();
}
private void releaseLock(Object key) {
ReentrantLock lock;
synchronized (key) {
lock = lookupLockForRelease(key);
if (lock.getHoldCount() <= 1 && !counts.containsKey(key)) {
locks.remove(key);
}
}
lock.unlock();
}
private ReentrantLock lookupLockForAcquire(Object key) {
ReentrantLock lock = locks.get(key);
if (lock == null) {
lock = new ReentrantLock();
locks.put(key, lock);
}
Integer count = counts.get(key);
if (count == null) {
counts.put(key, 1);
}
else {
counts.put(key, ++count);
}
return lock;
}
private ReentrantLock lookupLockForRelease(Object key) {
ReentrantLock lock = locks.get(key);
if (lock == null) {
throw new IllegalStateException("No lock found for object " + key);
}
Integer count = counts.get(key);
if (count == null) {
throw new IllegalStateException("No count found for object " + key);
}
if (count == 1) {
counts.remove(key);
} }
else {
counts.put(key, --count);
} }
return lock; return lock;
} }
public void start() {
// Remove entries in the locks Map that are no longer used private class LocalLock implements Lock {
maintenanceTask = new TimerTask() { private final Object key;
public void run() {
for (Map.Entry<Object, WeakReference<Lock>> entry : locks.entrySet()) { LocalLock(Object key) {
if (entry.getValue().get() == null) { this.key = key;
locks.remove(entry.getKey());
} }
public void lock(){
acquireLock(key);
} }
public void unlock() {
releaseLock(key);
}
public void lockInterruptibly(){
throw new UnsupportedOperationException();
}
public Condition newCondition(){
throw new UnsupportedOperationException();
}
public boolean tryLock() {
throw new UnsupportedOperationException();
} }
};
TaskEngine.getInstance().scheduleAtFixedRate(maintenanceTask, 30000, 60000); public boolean tryLock(long time, TimeUnit unit) {
throw new UnsupportedOperationException();
} }
public void shutdown() {
TaskEngine.getInstance().cancelScheduledTask(maintenanceTask);
// Clean up existing locks
locks.clear();
} }
} }
...@@ -29,16 +29,4 @@ public interface LockFactory { ...@@ -29,16 +29,4 @@ public interface LockFactory {
* @return an existing lock on the specified key or creates a new one if none was found. * @return an existing lock on the specified key or creates a new one if none was found.
*/ */
Lock getLock(Object key); Lock getLock(Object key);
/**
* Message sent when a new factory is set to the {@link org.jivesoftware.util.lock.LockManager}.
* Implementors could start maintenance tasks.
*/
void start();
/**
* Message sent when an already used factory by {@link org.jivesoftware.util.lock.LockManager}
* is replaced by another factory. Implementors should stop maintenance tasks.
*/
void shutdown();
} }
...@@ -44,15 +44,7 @@ public class LockManager { ...@@ -44,15 +44,7 @@ public class LockManager {
* @param lockFactory the new lock factory to use for creating new Locks. * @param lockFactory the new lock factory to use for creating new Locks.
*/ */
public static void setLockFactory(LockFactory lockFactory) { public static void setLockFactory(LockFactory lockFactory) {
// Shutdown old factory
if (LockManager.lockFactory != null) {
LockManager.lockFactory.shutdown();
}
LockManager.lockFactory = lockFactory; LockManager.lockFactory = lockFactory;
// Start new factory
if (LockManager.lockFactory != null) {
LockManager.lockFactory.start();
}
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment