Index: core/src/main/java/org/infinispan/util/concurrent/locks/containers/ReentrantPerEntryLockContainer.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP <+>/*\n * JBoss, Home of Professional Open Source\n * Copyright 2009 Red Hat Inc. and/or its affiliates and other\n * contributors as indicated by the @author tags. All rights reserved.\n * See the copyright.txt in the distribution for a full listing of\n * individual contributors.\n *\n * This is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as\n * published by the Free Software Foundation; either version 2.1 of\n * the License, or (at your option) any later version.\n *\n * This software is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this software; if not, write to the Free\n * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA\n * 02110-1301 USA, or see the FSF site: http://www.fsf.org.\n */\npackage org.infinispan.util.concurrent.locks.containers;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * A per-entry lock container for ReentrantLocks\n *\n * @author Manik Surtani\n * @since 4.0\n */\npublic class ReentrantPerEntryLockContainer extends AbstractPerEntryLockContainer {\n\n public ReentrantPerEntryLockContainer(int concurrencyLevel) {\n super(concurrencyLevel);\n }\n\n @Override\n protected ReentrantLock newLock() {\n return new ReentrantLock();\n }\n\n @Override\n public boolean ownsLock(Object key, Object ignored) {\n ReentrantLock l = getLockFromMap(key);\n return l != null && l.isHeldByCurrentThread();\n }\n\n @Override\n public boolean isLocked(Object key) {\n ReentrantLock l = getLockFromMap(key);\n return l != null && l.isLocked();\n }\n\n private ReentrantLock getLockFromMap(Object key) {\n return locks.get(key);\n }\n\n @Override\n protected void unlock(ReentrantLock l, Object unused) {\n l.unlock();\n }\n\n @Override\n protected boolean tryLock(ReentrantLock lock, long timeout, TimeUnit unit, Object unused) throws InterruptedException {\n return lock.tryLock(timeout, unit);\n }\n}\n =================================================================== --- core/src/main/java/org/infinispan/util/concurrent/locks/containers/ReentrantPerEntryLockContainer.java (date 1342591130000) +++ core/src/main/java/org/infinispan/util/concurrent/locks/containers/ReentrantPerEntryLockContainer.java (revision ) @@ -67,4 +67,19 @@ protected boolean tryLock(ReentrantLock lock, long timeout, TimeUnit unit, Object unused) throws InterruptedException { return lock.tryLock(timeout, unit); } + + @Override + public void releaseLock(Object lockOwner, Object key) { + ReentrantLock l = locks.get(key); + if (l != null) { + if (!l.isHeldByCurrentThread()) + throw new IllegalStateException("Lock for [" + key + "] not held by current thread " + Thread.currentThread()); + while (l.isHeldByCurrentThread()) + unlock(l, lockOwner); + if (!l.hasQueuedThreads()) + locks.remove(key); + } + else + throw new IllegalStateException("No lock for [" + key + ']'); + } } Index: core/src/main/java/org/infinispan/util/concurrent/locks/OwnableReentrantLock.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP <+>/*\n * JBoss, Home of Professional Open Source\n * Copyright 2009 Red Hat Inc. and/or its affiliates and other\n * contributors as indicated by the @author tags. All rights reserved.\n * See the copyright.txt in the distribution for a full listing of\n * individual contributors.\n *\n * This is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as\n * published by the Free Software Foundation; either version 2.1 of\n * the License, or (at your option) any later version.\n *\n * This software is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this software; if not, write to the Free\n * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA\n * 02110-1301 USA, or see the FSF site: http://www.fsf.org.\n */\npackage org.infinispan.util.concurrent.locks;\n\nimport net.jcip.annotations.ThreadSafe;\nimport org.infinispan.transaction.xa.GlobalTransaction;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.AbstractQueuedSynchronizer;\nimport java.util.concurrent.locks.Lock;\n\n/**\n * A lock that supports reentrancy based on owner (and not on current thread). For this to work, the lock needs to be\n * constructed with a reference to the {@link org.infinispan.context.InvocationContextContainer}, so it is able to\n * determine whether the caller's \"owner\" reference is the current thread or a {@link\n * org.infinispan.transaction.xa.GlobalTransaction} instance.\n *

\n * This makes this lock implementation very closely tied to Infinispan internals, but it provides for a very clean,\n * efficient and moreover familiar interface to work with, since it implements {@link java.util.concurrent.locks.Lock}.\n *

\n * For the sake of performance, this lock only supports nonfair queueing.\n *

\n *\n * @author Manik Surtani (manik@jboss.org)\n * @since 4.0\n */\n@ThreadSafe\npublic class OwnableReentrantLock extends AbstractQueuedSynchronizer implements Lock {\n\n private static final long serialVersionUID = 4932974734462848792L;\n private transient Object owner;\n private final ThreadLocal requestorOnStack = new ThreadLocal();\n\n /**\n * @return a GlobalTransaction instance if the current call is participating in a transaction, or the current thread\n * otherwise.\n */\n protected final Object currentRequestor() {\n Object cr = requestorOnStack.get();\n if (cr == null) throw new IllegalStateException(\"Should never get to this state!\");\n return cr;\n }\n\n private void setCurrentRequestor(Object requestor) {\n requestorOnStack.set(requestor);\n }\n\n public void unsetCurrentRequestor() {\n requestorOnStack.remove();\n }\n\n @Override\n public void lock() {\n throw new UnsupportedOperationException();\n }\n\n @Override\n public void unlock() {\n throw new UnsupportedOperationException();\n }\n\n public void lock(GlobalTransaction requestor) {\n setCurrentRequestor(requestor);\n try {\n if (compareAndSetState(0, 1))\n owner = requestor;\n else\n acquire(1);\n } finally {\n unsetCurrentRequestor();\n }\n }\n\n @Override\n public void lockInterruptibly() throws InterruptedException {\n acquireInterruptibly(1);\n }\n\n @Override\n public boolean tryLock() {\n return tryAcquire(1);\n }\n\n @Override\n public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {\n throw new UnsupportedOperationException(\"Should never get here\");\n }\n\n public boolean tryLock(Object requestor, long time, TimeUnit unit) throws InterruptedException {\n setCurrentRequestor(requestor);\n try {\n return tryAcquireNanos(1, unit.toNanos(time));\n } finally {\n unsetCurrentRequestor();\n }\n }\n\n public void unlock(Object requestor) {\n setCurrentRequestor(requestor);\n try {\n release(1);\n } catch (IllegalMonitorStateException imse) {\n // ignore?\n } finally {\n unsetCurrentRequestor();\n }\n }\n\n @Override\n public ConditionObject newCondition() {\n throw new UnsupportedOperationException(\"Not supported in this implementation!\");\n }\n\n @Override\n protected final boolean tryAcquire(int acquires) {\n final Object current = currentRequestor();\n int c = getState();\n if (c == 0) {\n if (compareAndSetState(0, acquires)) {\n owner = current;\n return true;\n }\n } else if (current.equals(owner)) {\n setState(c + acquires);\n return true;\n }\n return false;\n }\n\n @Override\n protected final boolean tryRelease(int releases) {\n int c = getState() - releases;\n if (!currentRequestor().equals(owner)) {\n //throw new IllegalMonitorStateException(this.toString());\n // lets be quiet about this\n return false;\n }\n boolean free = false;\n if (c == 0) {\n free = true;\n owner = null;\n }\n setState(c);\n return free;\n }\n\n @Override\n protected final boolean isHeldExclusively() {\n return getState() != 0 && currentRequestor().equals(owner);\n }\n\n /**\n * @return the owner of the lock, or null if it is currently unlocked.\n */\n public final Object getOwner() {\n int c = getState();\n Object o = owner;\n return (c == 0) ? null : o;\n }\n\n /**\n * @return the hold count of the current lock, or 0 if it is not locked.\n */\n public final int getHoldCount(Object requestor) {\n int c = getState();\n Object o = owner;\n return (requestor.equals(o)) ? c : 0;\n }\n\n /**\n * @return true if the lock is locked, false otherwise\n */\n public final boolean isLocked() {\n return getState() != 0;\n }\n\n /**\n * Reconstitute this lock instance from a stream, resetting the lock to an unlocked state.\n *\n * @param s the stream\n */\n private void readObject(java.io.ObjectInputStream s)\n throws java.io.IOException, ClassNotFoundException {\n s.defaultReadObject();\n setState(0); // reset to unlocked state\n }\n\n /**\n * Returns a string identifying this lock, as well as its lock state. The state, in brackets, includes either the\n * String "Unlocked" or the String "Locked by" followed by the String representation of the lock\n * owner.\n *\n * @return a string identifying this lock, as well as its lock state.\n */\n public String toString() {\n Object owner = getOwner();\n return super.toString() + ((owner == null) ?\n \"[Unlocked]\" :\n \"[Locked by \" + owner + \"]\");\n }\n}\n =================================================================== --- core/src/main/java/org/infinispan/util/concurrent/locks/OwnableReentrantLock.java (date 1342591130000) +++ core/src/main/java/org/infinispan/util/concurrent/locks/OwnableReentrantLock.java (revision ) @@ -126,7 +126,20 @@ } } + public void unlockAll(Object requestor) { + setCurrentRequestor(requestor); + try { + while (!release(1)) { + // loop unless all locks are released + } + } catch (IllegalMonitorStateException imse) { + // ignore? + } finally { + unsetCurrentRequestor(); + } + } + - @Override + @Override public ConditionObject newCondition() { throw new UnsupportedOperationException("Not supported in this implementation!"); } Index: core/src/main/java/org/infinispan/util/concurrent/locks/containers/OwnableReentrantPerEntryLockContainer.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP <+>/*\n * JBoss, Home of Professional Open Source\n * Copyright 2009 Red Hat Inc. and/or its affiliates and other\n * contributors as indicated by the @author tags. All rights reserved.\n * See the copyright.txt in the distribution for a full listing of\n * individual contributors.\n *\n * This is free software; you can redistribute it and/or modify it\n * under the terms of the GNU Lesser General Public License as\n * published by the Free Software Foundation; either version 2.1 of\n * the License, or (at your option) any later version.\n *\n * This software is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this software; if not, write to the Free\n * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA\n * 02110-1301 USA, or see the FSF site: http://www.fsf.org.\n */\npackage org.infinispan.util.concurrent.locks.containers;\n\nimport org.infinispan.util.concurrent.locks.OwnableReentrantLock;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * A per-entry lock container for OwnableReentrantLocks\n *\n * @author Manik Surtani\n * @since 4.0\n */\npublic class OwnableReentrantPerEntryLockContainer extends AbstractPerEntryLockContainer {\n\n public OwnableReentrantPerEntryLockContainer(int concurrencyLevel) {\n super(concurrencyLevel);\n }\n\n @Override\n protected OwnableReentrantLock newLock() {\n return new OwnableReentrantLock();\n }\n\n @Override\n public boolean ownsLock(Object key, Object owner) {\n OwnableReentrantLock l = getLockFromMap(key);\n return l != null && owner.equals(l.getOwner());\n }\n\n @Override\n public boolean isLocked(Object key) {\n OwnableReentrantLock l = getLockFromMap(key);\n return l != null && l.isLocked();\n }\n\n private OwnableReentrantLock getLockFromMap(Object key) {\n return locks.get(key);\n }\n\n @Override\n protected boolean tryLock(OwnableReentrantLock lock, long timeout, TimeUnit unit, Object lockOwner) throws InterruptedException {\n return lock.tryLock(lockOwner, timeout, unit);\n }\n\n @Override\n protected void unlock(OwnableReentrantLock l, Object owner) {\n l.unlock(owner);\n }\n}\n =================================================================== --- core/src/main/java/org/infinispan/util/concurrent/locks/containers/OwnableReentrantPerEntryLockContainer.java (date 1342591130000) +++ core/src/main/java/org/infinispan/util/concurrent/locks/containers/OwnableReentrantPerEntryLockContainer.java (revision ) @@ -68,4 +68,20 @@ protected void unlock(OwnableReentrantLock l, Object owner) { l.unlock(owner); } + + @Override + public void releaseLock(Object lockOwner, Object key) { + OwnableReentrantLock l = locks.get(key); + if (l != null) { + if (lockOwner.equals(l.getOwner())) { + l.unlockAll(lockOwner); + if (!l.hasQueuedThreads()) + locks.remove(key); + } + else + throw new IllegalStateException("Lock for [" + key + "] not held by current owner " + l.getOwner()); + } + else + throw new IllegalStateException("No lock for [" + key + ']'); + } }