Author: manik.surtani(a)jboss.com
Date: 2009-03-18 07:36:28 -0400 (Wed, 18 Mar 2009)
New Revision: 7909
Added:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/AbstractSharedLockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantSharedLockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementLockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementOwnableReentrantLockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementReentrantLockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantSharedLockContainer.java
core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockPerFqnTest.java
Removed:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockContainer.java
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantLockContainer.java
Modified:
core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java
core/trunk/src/main/java/org/jboss/cache/config/Configuration.java
core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java
core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java
core/trunk/src/main/resources/schema/jbosscache-config-3.1.xsd
Log:
JBCACHE-1494 - Lock-per-Fqn option in addition to lock striping, for MVCC
Modified: core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml
===================================================================
---
core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml 2009-03-18
09:45:27 UTC (rev 7908)
+++
core/trunk/src/main/docbook/userguide/en/modules/configuration_reference.xml 2009-03-18
11:36:28 UTC (rev 7909)
@@ -23,6 +23,7 @@
lockAcquisitionTimeout="20000"
nodeLockingScheme="mvcc"
writeSkewCheck="false"
+ useLockStriping="true"
concurrencyLevel="500"/>
<!--
@@ -477,6 +478,19 @@
is <literal>mvcc</literal> and
<literal>isolationLevel</literal> is
<literal>REPEATABLE_READ</literal>.
See the <link linkend="mvcc.writeskew">section on write
skews</link> for a more detailed discussion.</entry>
</row>
+ <row>
+ <entry><emphasis
role="bold">useLockStriping</emphasis></entry>
+ <entry>useLockStriping</entry>
+ <entry>true, false</entry>
+ <entry>true</entry>
+
+ <entry>Specifies whether lock striping is used. Only used if
<literal>nodeLockingScheme</literal>
+ is <literal>mvcc</literal>. Lock striping usually offers
greater performance and better memory usage,
+ although in certain cases deadlocks may occur where several Fqns map
to the same shared lock. This
+ can be mitigated by increasing your concurrency level, though the
only concrete solution is to
+ disable lock striping altogether.
+ </entry>
+ </row>
<row>
<entry><emphasis
role="bold">concurrencyLevel</emphasis></entry>
<entry>concurrencyLevel</entry>
@@ -484,7 +498,8 @@
<entry>500</entry>
<entry>Specifies the number of shared locks to use for write
locks acquired. Only used if <literal>nodeLockingScheme</literal>
- is <literal>mvcc</literal>. See the <link
linkend="mvcc.impl">section on JBoss Cache's MVCC
implementation</link> for a more detailed discussion.</entry>
+ is <literal>mvcc</literal>, and is ignored if
<literal>useLockStriping</literal> is <literal>false</literal>.
+ See the <link linkend="mvcc.impl">section on JBoss
Cache's MVCC implementation</link> for a more detailed
discussion.</entry>
</row>
</tbody>
</tgroup>
Modified: core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java 2009-03-18 09:45:27
UTC (rev 7908)
+++ core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java 2009-03-18 11:36:28
UTC (rev 7909)
@@ -43,7 +43,7 @@
import org.jboss.cache.jmx.annotations.ManagedOperation;
import org.jboss.cache.lock.LockManager;
import org.jboss.cache.util.concurrent.locks.LockContainer;
-import org.jboss.cache.util.concurrent.locks.ReentrantLockContainer;
+import org.jboss.cache.util.concurrent.locks.ReentrantSharedLockContainer;
import org.jgroups.Address;
import java.util.ArrayList;
@@ -77,7 +77,7 @@
private EvictionConfig evictionConfig;
private final EvictionTimerTask evictionTimerTask = new EvictionTimerTask();
- private final LockContainer<Fqn> regionLocks = new
ReentrantLockContainer<Fqn>(4);
+ private final LockContainer<Fqn> regionLocks = new
ReentrantSharedLockContainer<Fqn>(4);
protected Configuration configuration;
protected RPCManager rpcManager;
protected LockManager lockManager;
@@ -93,12 +93,12 @@
protected final void lock(Fqn fqn)
{
- regionLocks.getLock(fqn).lock();
+ regionLocks.acquireLock(fqn);
}
protected final void unlock(Fqn fqn)
{
- regionLocks.getLock(fqn).unlock();
+ regionLocks.releaseLock(fqn);
}
@Inject
Modified: core/trunk/src/main/java/org/jboss/cache/config/Configuration.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/config/Configuration.java 2009-03-18 09:45:27
UTC (rev 7908)
+++ core/trunk/src/main/java/org/jboss/cache/config/Configuration.java 2009-03-18 11:36:28
UTC (rev 7909)
@@ -44,12 +44,7 @@
public class Configuration extends ConfigurationComponent
{
private static final long serialVersionUID = 5553791890144997466L;
-
- private Marshaller marshaller;
-
private transient JGroupsStackParser jGroupsStackParser = new JGroupsStackParser();
- private boolean invocationBatchingEnabled;
- private URL jgroupsConfigFile;
/**
* Behavior of the JVM shutdown hook registered by the cache
@@ -228,6 +223,10 @@
private int listenerAsyncQueueSize = 50000;
private int serializationExecutorPoolSize = 0;
private int serializationExecutorQueueSize = 50000;
+ private Marshaller marshaller;
+ private boolean invocationBatchingEnabled;
+ private boolean useLockStriping = true;
+ private URL jgroupsConfigFile;
@Start(priority = 1)
void correctIsolationLevels()
@@ -267,12 +266,23 @@
return writeSkewCheck;
}
+ public boolean isUseLockStriping()
+ {
+ return useLockStriping;
+ }
+
public void setWriteSkewCheck(boolean writeSkewCheck)
{
testImmutability("writeSkewCheck");
this.writeSkewCheck = writeSkewCheck;
}
+ public void setUseLockStriping(boolean useLockStriping)
+ {
+ testImmutability("useLockStriping");
+ this.useLockStriping = useLockStriping;
+ }
+
public int getConcurrencyLevel()
{
return concurrencyLevel;
Modified:
core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java 2009-03-18
09:45:27 UTC (rev 7908)
+++
core/trunk/src/main/java/org/jboss/cache/config/parsing/XmlConfigurationParser.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -395,19 +395,20 @@
private void configureLocking(Element element)
{
- String isolationLevel = getAttributeValue(element, "isolationLevel");
- if (existsAttribute(isolationLevel))
config.setIsolationLevel(IsolationLevel.valueOf(isolationLevel));
- String lockParentForChildInsertRemove = getAttributeValue(element,
"lockParentForChildInsertRemove");
- if (existsAttribute(lockParentForChildInsertRemove))
-
config.setLockParentForChildInsertRemove(getBoolean(lockParentForChildInsertRemove));
- String lockAcquisitionTimeout = getAttributeValue(element,
"lockAcquisitionTimeout");
- if (existsAttribute(lockAcquisitionTimeout))
config.setLockAcquisitionTimeout(getLong(lockAcquisitionTimeout));
- String nodeLockingScheme = getAttributeValue(element,
"nodeLockingScheme");
- if (existsAttribute(nodeLockingScheme))
config.setNodeLockingScheme(nodeLockingScheme);
- String writeSkewCheck = getAttributeValue(element, "writeSkewCheck");
- if (existsAttribute(writeSkewCheck))
config.setWriteSkewCheck(getBoolean(writeSkewCheck));
- String concurrencyLevel = getAttributeValue(element,
"concurrencyLevel");
- if (existsAttribute(concurrencyLevel))
config.setConcurrencyLevel(getInt(concurrencyLevel));
+ String tmp = getAttributeValue(element, "isolationLevel");
+ if (existsAttribute(tmp)) config.setIsolationLevel(IsolationLevel.valueOf(tmp));
+ tmp = getAttributeValue(element, "lockParentForChildInsertRemove");
+ if (existsAttribute(tmp))
config.setLockParentForChildInsertRemove(getBoolean(tmp));
+ tmp = getAttributeValue(element, "lockAcquisitionTimeout");
+ if (existsAttribute(tmp)) config.setLockAcquisitionTimeout(getLong(tmp));
+ tmp = getAttributeValue(element, "nodeLockingScheme");
+ if (existsAttribute(tmp)) config.setNodeLockingScheme(tmp);
+ tmp = getAttributeValue(element, "writeSkewCheck");
+ if (existsAttribute(tmp)) config.setWriteSkewCheck(getBoolean(tmp));
+ tmp = getAttributeValue(element, "useLockStriping");
+ if (existsAttribute(tmp)) config.setUseLockStriping(getBoolean(tmp));
+ tmp = getAttributeValue(element, "concurrencyLevel");
+ if (existsAttribute(tmp)) config.setConcurrencyLevel(getInt(tmp));
}
private Element getSingleElement(String elementName)
Modified: core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java 2009-03-18 09:45:27
UTC (rev 7908)
+++ core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java 2009-03-18 11:36:28
UTC (rev 7909)
@@ -34,12 +34,13 @@
import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.invocation.InvocationContextContainer;
import org.jboss.cache.jmx.annotations.ManagedAttribute;
-import org.jboss.cache.jmx.annotations.ManagedOperation;
import static org.jboss.cache.lock.LockType.READ;
import org.jboss.cache.util.concurrent.locks.LockContainer;
import org.jboss.cache.util.concurrent.locks.OwnableReentrantLock;
-import org.jboss.cache.util.concurrent.locks.OwnableReentrantLockContainer;
-import org.jboss.cache.util.concurrent.locks.ReentrantLockContainer;
+import org.jboss.cache.util.concurrent.locks.OwnableReentrantSharedLockContainer;
+import org.jboss.cache.util.concurrent.locks.ReentrantSharedLockContainer;
+import org.jboss.cache.util.concurrent.locks.PerElementReentrantLockContainer;
+import org.jboss.cache.util.concurrent.locks.PerElementOwnableReentrantLockContainer;
import javax.transaction.TransactionManager;
import java.util.Collection;
@@ -92,7 +93,10 @@
@Start
public void startLockManager()
{
- lockContainer = transactionManager == null ? new
ReentrantLockContainer<Fqn>(configuration.getConcurrencyLevel()) : new
OwnableReentrantLockContainer<Fqn>(configuration.getConcurrencyLevel(),
invocationContextContainer);
+ lockContainer =
+ configuration.isUseLockStriping() ?
+ transactionManager == null ? new
ReentrantSharedLockContainer<Fqn>(configuration.getConcurrencyLevel()) : new
OwnableReentrantSharedLockContainer<Fqn>(configuration.getConcurrencyLevel(),
invocationContextContainer) :
+ transactionManager == null ? new
PerElementReentrantLockContainer<Fqn>() : new
PerElementOwnableReentrantLockContainer<Fqn>(invocationContextContainer);
}
@Start
@@ -106,8 +110,7 @@
if (lockType == READ) return true; // we don't support read locks. TODO:
enforce this with an assertion
if (trace) log.trace("Attempting to lock " + fqn);
- Lock lock = lockContainer.getLock(fqn);
- return lock.tryLock(lockAcquisitionTimeout, MILLISECONDS);
+ return lockContainer.acquireLock(fqn, lockAcquisitionTimeout, MILLISECONDS);
}
public boolean lock(Fqn fqn, LockType lockType, Object owner, long timeoutMillis)
throws InterruptedException
@@ -115,8 +118,7 @@
if (lockType == READ) return true; // we don't support read locks. TODO:
enforce this with an assertion
if (trace) log.trace("Attempting to lock " + fqn);
- Lock lock = lockContainer.getLock(fqn);
- return lock.tryLock(timeoutMillis, MILLISECONDS);
+ return lockContainer.acquireLock(fqn, lockAcquisitionTimeout, MILLISECONDS);
}
public boolean lockAndRecord(Fqn fqn, LockType lockType, InvocationContext ctx) throws
InterruptedException
@@ -124,8 +126,7 @@
if (lockType == READ) return true; // we don't support read locks. TODO:
enforce this with an assertion
if (trace) log.trace("Attempting to lock " + fqn);
- Lock lock = lockContainer.getLock(fqn);
- if (lock.tryLock(ctx.getLockAcquisitionTimeout(lockAcquisitionTimeout),
MILLISECONDS))
+ if (lockContainer.acquireLock(fqn, lockAcquisitionTimeout, MILLISECONDS))
{
ctx.addLock(fqn);
return true;
@@ -138,10 +139,9 @@
public void unlock(Fqn fqn, Object owner)
{
if (trace) log.trace("Attempting to unlock " + fqn);
- Lock lock = lockContainer.getLock(fqn);
try
{
- lock.unlock();
+ lockContainer.releaseLock(fqn);
}
catch (IllegalMonitorStateException imse)
{
@@ -163,7 +163,7 @@
if (trace) log.trace("Attempting to unlock " + f);
try
{
- lockContainer.getLock(f).unlock();
+ lockContainer.releaseLock(f);
}
catch (IllegalMonitorStateException imse)
{
@@ -336,10 +336,4 @@
{
return lockContainer.size() - lockContainer.getNumLocksHeld();
}
-
- @ManagedOperation(description = "Tests the spreading of locks across Fqns. For a
given (String based) Fqn, this method returns the index in the lock array that it maps
to.")
- public int testHashing(String fqn)
- {
- return lockContainer.hashToIndex(Fqn.fromString(fqn));
- }
}
Copied:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/AbstractSharedLockContainer.java
(from rev 7906,
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java)
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/AbstractSharedLockContainer.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/AbstractSharedLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,102 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.cache.util.concurrent.locks;
+
+import net.jcip.annotations.ThreadSafe;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A container for locks. Used with lock striping.
+ *
+ * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik
AT jboss DOT org</a>)
+ * @since 3.0
+ */
+@ThreadSafe
+public abstract class AbstractSharedLockContainer<E> implements
LockContainer<E>
+{
+ private int lockSegmentMask;
+ private int lockSegmentShift;
+
+
+ protected int calculateNumberOfSegments(int concurrencyLevel)
+ {
+ int tempLockSegShift = 0;
+ int numLocks = 1;
+ while (numLocks < concurrencyLevel)
+ {
+ ++tempLockSegShift;
+ numLocks <<= 1;
+ }
+ lockSegmentShift = 32 - tempLockSegShift;
+ lockSegmentMask = numLocks - 1;
+ return numLocks;
+ }
+
+ final int hashToIndex(E object)
+ {
+ return (hash(object) >>> lockSegmentShift) & lockSegmentMask;
+ }
+
+ /**
+ * Returns a hash code for non-null Object x.
+ * Uses the same hash code spreader as most other java.util hash tables, except that
this uses the string representation
+ * of the object passed in.
+ *
+ * @param object the object serving as a key
+ * @return the hash code
+ */
+ final int hash(E object)
+ {
+ // Spread bits to regularize both segment and index locations,
+ // using variant of single-word Wang/Jenkins hash.
+ int h = object.hashCode();
+ h += (h << 15) ^ 0xffffcd7d;
+ h ^= (h >>> 10);
+ h += (h << 3);
+ h ^= (h >>> 6);
+ h += (h << 2) + (h << 14);
+ h = h ^ (h >>> 16);
+ return h;
+ }
+
+ protected abstract void initLocks(int numLocks);
+
+ public void acquireLock(E object)
+ {
+ Lock lock = getLock(object);
+ lock.lock();
+ }
+
+ public boolean acquireLock(E object, long timeout, TimeUnit unit) throws
InterruptedException
+ {
+ Lock lock = getLock(object);
+ return lock.tryLock(timeout, unit);
+ }
+
+ public void releaseLock(E object)
+ {
+ Lock lock = getLock(object);
+ lock.unlock();
+ }
+}
Property changes on:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/AbstractSharedLockContainer.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Deleted:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java 2009-03-18
09:45:27 UTC (rev 7908)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -1,116 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.cache.util.concurrent.locks;
-
-import net.jcip.annotations.ThreadSafe;
-
-import java.util.concurrent.locks.Lock;
-
-/**
- * A container for locks. Used with lock striping.
- *
- * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik
AT jboss DOT org</a>)
- * @since 3.0
- */
-@ThreadSafe
-public abstract class LockContainer<E>
-{
- private int lockSegmentMask;
- private int lockSegmentShift;
-
-
- protected int calculateNumberOfSegments(int concurrencyLevel)
- {
- int tempLockSegShift = 0;
- int numLocks = 1;
- while (numLocks < concurrencyLevel)
- {
- ++tempLockSegShift;
- numLocks <<= 1;
- }
- lockSegmentShift = 32 - tempLockSegShift;
- lockSegmentMask = numLocks - 1;
- return numLocks;
- }
-
- public final int hashToIndex(E object)
- {
- return (hash(object) >>> lockSegmentShift) & lockSegmentMask;
- }
-
- /**
- * Returns a hash code for non-null Object x.
- * Uses the same hash code spreader as most other java.util hash tables, except that
this uses the string representation
- * of the object passed in.
- *
- * @param object the object serving as a key
- * @return the hash code
- */
- final int hash(E object)
- {
- // Spread bits to regularize both segment and index locations,
- // using variant of single-word Wang/Jenkins hash.
- int h = object.hashCode();
- h += (h << 15) ^ 0xffffcd7d;
- h ^= (h >>> 10);
- h += (h << 3);
- h ^= (h >>> 6);
- h += (h << 2) + (h << 14);
- h = h ^ (h >>> 16);
- return h;
- }
-
- protected abstract void initLocks(int numLocks);
-
- /**
- * Tests if a give owner owns a lock on a specified object.
- *
- * @param object object to check
- * @param owner owner to test
- * @return true if owner owns lock, false otherwise
- */
- public abstract boolean ownsLock(E object, Object owner);
-
- /**
- * @param object object
- * @return true if an object is locked, false otherwise
- */
- public abstract boolean isLocked(E object);
-
- /**
- * @param object object
- * @return the lock for a specific object
- */
- public abstract Lock getLock(E object);
-
- /**
- * @return number of locks held
- */
- public abstract int getNumLocksHeld();
-
- /**
- * Clears all locks held and re-initialises stripes.
- */
- public abstract void reset();
-
- public abstract int size();
-}
Added: core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/LockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,52 @@
+package org.jboss.cache.util.concurrent.locks;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * A container for locks
+ *
+ * @author Manik Surtani
+ * @since 3.1.0
+ */
+public interface LockContainer<E>
+{
+ /**
+ * Tests if a give owner owns a lock on a specified object.
+ *
+ * @param object object to check
+ * @param owner owner to test
+ * @return true if owner owns lock, false otherwise
+ */
+ boolean ownsLock(E object, Object owner);
+
+ /**
+ * @param object object
+ * @return true if an object is locked, false otherwise
+ */
+ boolean isLocked(E object);
+
+ /**
+ * @param object object
+ * @return the lock for a specific object
+ */
+ Lock getLock(E object);
+
+ /**
+ * @return number of locks held
+ */
+ int getNumLocksHeld();
+
+ /**
+ * Clears all locks held and re-initialises stripes.
+ */
+ void reset();
+
+ int size();
+
+ void acquireLock(E object);
+
+ boolean acquireLock(E object, long timeout, TimeUnit unit) throws
InterruptedException;
+
+ void releaseLock(E object);
+}
Deleted:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockContainer.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockContainer.java 2009-03-18
09:45:27 UTC (rev 7908)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -1,101 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.cache.util.concurrent.locks;
-
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.invocation.InvocationContextContainer;
-
-import java.util.Arrays;
-
-/**
- * A LockContainer that holds {@link
org.jboss.cache.util.concurrent.locks.OwnableReentrantLock}s.
- *
- * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik
AT jboss DOT org</a>)
- * @see org.jboss.cache.util.concurrent.locks.ReentrantLockContainer
- * @see org.jboss.cache.util.concurrent.locks.OwnableReentrantLock
- * @since 3.0
- */
-@ThreadSafe
-public class OwnableReentrantLockContainer<E> extends LockContainer<E>
-{
- OwnableReentrantLock[] sharedLocks;
- InvocationContextContainer icc;
-
- /**
- * Creates a new LockContainer which uses a certain number of shared locks across all
elements that need to be locked.
- *
- * @param concurrencyLevel concurrency level for number of stripes to create. Stripes
are created in powers of two, with a minimum of concurrencyLevel created.
- * @param icc invocation context container to use
- */
- public OwnableReentrantLockContainer(int concurrencyLevel, InvocationContextContainer
icc)
- {
- this.icc = icc;
- initLocks(calculateNumberOfSegments(concurrencyLevel));
- }
-
- protected void initLocks(int numLocks)
- {
- sharedLocks = new OwnableReentrantLock[numLocks];
- for (int i = 0; i < numLocks; i++) sharedLocks[i] = new
OwnableReentrantLock(icc);
- }
-
- public final OwnableReentrantLock getLock(E object)
- {
- return sharedLocks[hashToIndex(object)];
- }
-
- public final boolean ownsLock(E object, Object owner)
- {
- OwnableReentrantLock lock = getLock(object);
- return owner.equals(lock.getOwner());
- }
-
- public final boolean isLocked(E object)
- {
- OwnableReentrantLock lock = getLock(object);
- return lock.isLocked();
- }
-
- public final int getNumLocksHeld()
- {
- int i = 0;
- for (OwnableReentrantLock l : sharedLocks) if (l.isLocked()) i++;
- return i;
- }
-
- public String toString()
- {
- return "OwnableReentrantLockContainer{" +
- "sharedLocks=" + (sharedLocks == null ? null :
Arrays.asList(sharedLocks)) +
- '}';
- }
-
- public void reset()
- {
- initLocks(sharedLocks.length);
- }
-
- public int size()
- {
- return sharedLocks.length;
- }
-}
Copied:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantSharedLockContainer.java
(from rev 7906,
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantLockContainer.java)
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantSharedLockContainer.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantSharedLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.cache.util.concurrent.locks;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.invocation.InvocationContextContainer;
+
+import java.util.Arrays;
+
+/**
+ * A LockContainer that holds {@link
org.jboss.cache.util.concurrent.locks.OwnableReentrantLock}s.
+ *
+ * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik
AT jboss DOT org</a>)
+ * @see ReentrantSharedLockContainer
+ * @see org.jboss.cache.util.concurrent.locks.OwnableReentrantLock
+ * @since 3.0
+ */
+@ThreadSafe
+public class OwnableReentrantSharedLockContainer<E> extends
AbstractSharedLockContainer<E>
+{
+ OwnableReentrantLock[] sharedLocks;
+ InvocationContextContainer icc;
+
+ /**
+ * Creates a new LockContainer which uses a certain number of shared locks across all
elements that need to be locked.
+ *
+ * @param concurrencyLevel concurrency level for number of stripes to create. Stripes
are created in powers of two, with a minimum of concurrencyLevel created.
+ * @param icc invocation context container to use
+ */
+ public OwnableReentrantSharedLockContainer(int concurrencyLevel,
InvocationContextContainer icc)
+ {
+ this.icc = icc;
+ initLocks(calculateNumberOfSegments(concurrencyLevel));
+ }
+
+ protected void initLocks(int numLocks)
+ {
+ sharedLocks = new OwnableReentrantLock[numLocks];
+ for (int i = 0; i < numLocks; i++) sharedLocks[i] = new
OwnableReentrantLock(icc);
+ }
+
+ public final OwnableReentrantLock getLock(E object)
+ {
+ return sharedLocks[hashToIndex(object)];
+ }
+
+ public final boolean ownsLock(E object, Object owner)
+ {
+ OwnableReentrantLock lock = getLock(object);
+ return owner.equals(lock.getOwner());
+ }
+
+ public final boolean isLocked(E object)
+ {
+ OwnableReentrantLock lock = getLock(object);
+ return lock.isLocked();
+ }
+
+ public final int getNumLocksHeld()
+ {
+ int i = 0;
+ for (OwnableReentrantLock l : sharedLocks) if (l.isLocked()) i++;
+ return i;
+ }
+
+ public String toString()
+ {
+ return "OwnableReentrantSharedLockContainer{" +
+ "sharedLocks=" + (sharedLocks == null ? null :
Arrays.asList(sharedLocks)) +
+ '}';
+ }
+
+ public void reset()
+ {
+ initLocks(sharedLocks.length);
+ }
+
+ public int size()
+ {
+ return sharedLocks.length;
+ }
+}
Property changes on:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/OwnableReentrantSharedLockContainer.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementLockContainer.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementLockContainer.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,87 @@
+package org.jboss.cache.util.concurrent.locks;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * A lock container that maintains a new lock per element
+ *
+ * @author Manik Surtani
+ * @since 3.1.0
+ */
+public abstract class PerElementLockContainer<E> implements LockContainer<E>
+{
+ ConcurrentMap<E, Lock> locks = new ConcurrentHashMap<E, Lock>();
+
+ protected abstract Lock newLock();
+
+ public Lock getLock(E object)
+ {
+ Lock l = newLock();
+ Lock tmp = locks.putIfAbsent(object, l);
+ if (tmp != null) l = tmp;
+ return l;
+ }
+
+ public int getNumLocksHeld()
+ {
+ return locks.size();
+ }
+
+ public void reset()
+ {
+ for (Lock l: locks.values())
+ {
+ try
+ {
+ l.unlock();
+ }
+ catch (Exception e)
+ {
+ // no-op
+ }
+ }
+ locks.clear();
+ }
+
+ public int size()
+ {
+ return locks.size();
+ }
+
+ public void acquireLock(E object)
+ {
+ Lock l = getLock(object);
+ l.lock();
+ // now check that the lock is still valid...
+ if (l != locks.get(object))
+ {
+ // we acquired the wrong lock!
+ l.unlock();
+ acquireLock(object);
+ }
+ }
+
+ public boolean acquireLock(E object, long timeout, TimeUnit unit) throws
InterruptedException
+ {
+ Lock l = getLock(object);
+ boolean result = l.tryLock(timeout, unit);
+
+ // now check that the lock is still valid...
+ if (result && l != locks.get(object))
+ {
+ // we acquired the wrong lock!
+ l.unlock();
+ result = acquireLock(object, timeout, unit);
+ }
+ return result;
+ }
+
+ public void releaseLock(E object)
+ {
+ Lock l = locks.remove(object);
+ if (l != null) l.unlock();
+ }
+}
Added:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementOwnableReentrantLockContainer.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementOwnableReentrantLockContainer.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementOwnableReentrantLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,43 @@
+package org.jboss.cache.util.concurrent.locks;
+
+import org.jboss.cache.invocation.InvocationContextContainer;
+
+import java.util.concurrent.locks.Lock;
+
+/**
+ * Per element container for {@link
org.jboss.cache.util.concurrent.locks.OwnableReentrantLock}s
+ *
+ * @author Manik Surtani
+ * @since 3.1.0
+ */
+public class PerElementOwnableReentrantLockContainer<E> extends
PerElementLockContainer<E>
+{
+ private InvocationContextContainer icc;
+
+ public PerElementOwnableReentrantLockContainer(InvocationContextContainer icc)
+ {
+ this.icc = icc;
+ }
+
+ public boolean ownsLock(E object, Object owner)
+ {
+ OwnableReentrantLock l = getLockFromMap(object);
+ return l != null && owner.equals(l.getOwner());
+ }
+
+ public boolean isLocked(E object)
+ {
+ OwnableReentrantLock l = getLockFromMap(object);
+ return l != null && l.isLocked();
+ }
+
+ private OwnableReentrantLock getLockFromMap(E key)
+ {
+ return (OwnableReentrantLock) locks.get(key);
+ }
+
+ protected final Lock newLock()
+ {
+ return new OwnableReentrantLock(icc);
+ }
+}
Added:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementReentrantLockContainer.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementReentrantLockContainer.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/PerElementReentrantLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,35 @@
+package org.jboss.cache.util.concurrent.locks;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Per-element container for {@link java.util.concurrent.locks.ReentrantLock}s
+ *
+ * @author Manik Surtani
+ * @since 3.1.0
+ */
+public class PerElementReentrantLockContainer<E> extends
PerElementLockContainer<E>
+{
+ public boolean ownsLock(E object, Object owner)
+ {
+ ReentrantLock l = getLockFromMap(object);
+ return l != null && l.isHeldByCurrentThread();
+ }
+
+ public boolean isLocked(E object)
+ {
+ ReentrantLock l = getLockFromMap(object);
+ return l != null && l.isLocked();
+ }
+
+ private ReentrantLock getLockFromMap(E key)
+ {
+ return (ReentrantLock) locks.get(key);
+ }
+
+ protected final Lock newLock()
+ {
+ return new ReentrantLock();
+ }
+}
Deleted:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantLockContainer.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantLockContainer.java 2009-03-18
09:45:27 UTC (rev 7908)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -1,97 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
-package org.jboss.cache.util.concurrent.locks;
-
-import net.jcip.annotations.ThreadSafe;
-
-import java.util.Arrays;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * A LockContainer that holds ReentrantLocks
- *
- * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik
AT jboss DOT org</a>)
- * @see org.jboss.cache.util.concurrent.locks.OwnableReentrantLockContainer
- * @since 3.0
- */
-@ThreadSafe
-public class ReentrantLockContainer<E> extends LockContainer<E>
-{
- ReentrantLock[] sharedLocks;
-
- /**
- * Creates a new LockContainer which uses a certain number of shared locks across all
elements that need to be locked.
- *
- * @param concurrencyLevel concurrency level for number of stripes to create. Stripes
are created in powers of two, with a minimum of concurrencyLevel created.
- */
- public ReentrantLockContainer(int concurrencyLevel)
- {
- initLocks(calculateNumberOfSegments(concurrencyLevel));
- }
-
- protected void initLocks(int numLocks)
- {
- sharedLocks = new ReentrantLock[numLocks];
- for (int i = 0; i < numLocks; i++) sharedLocks[i] = new ReentrantLock();
- }
-
- public final ReentrantLock getLock(E object)
- {
- return sharedLocks[hashToIndex(object)];
- }
-
- public final int getNumLocksHeld()
- {
- int i = 0;
- for (ReentrantLock l : sharedLocks) if (l.isLocked()) i++;
- return i;
- }
-
- public final boolean ownsLock(E object, Object owner)
- {
- ReentrantLock lock = getLock(object);
- return lock.isHeldByCurrentThread();
- }
-
- public final boolean isLocked(E object)
- {
- ReentrantLock lock = getLock(object);
- return lock.isLocked();
- }
-
- public String toString()
- {
- return "ReentrantLockContainer{" +
- "sharedLocks=" + (sharedLocks == null ? null :
Arrays.asList(sharedLocks)) +
- '}';
- }
-
- public void reset()
- {
- initLocks(sharedLocks.length);
- }
-
- public int size()
- {
- return sharedLocks.length;
- }
-}
Copied:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantSharedLockContainer.java
(from rev 7906,
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantLockContainer.java)
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantSharedLockContainer.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantSharedLockContainer.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,97 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.cache.util.concurrent.locks;
+
+import net.jcip.annotations.ThreadSafe;
+
+import java.util.Arrays;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * A LockContainer that holds ReentrantLocks
+ *
+ * @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik
AT jboss DOT org</a>)
+ * @see OwnableReentrantSharedLockContainer
+ * @since 3.0
+ */
+@ThreadSafe
+public class ReentrantSharedLockContainer<E> extends
AbstractSharedLockContainer<E>
+{
+ ReentrantLock[] sharedLocks;
+
+ /**
+ * Creates a new LockContainer which uses a certain number of shared locks across all
elements that need to be locked.
+ *
+ * @param concurrencyLevel concurrency level for number of stripes to create. Stripes
are created in powers of two, with a minimum of concurrencyLevel created.
+ */
+ public ReentrantSharedLockContainer(int concurrencyLevel)
+ {
+ initLocks(calculateNumberOfSegments(concurrencyLevel));
+ }
+
+ protected void initLocks(int numLocks)
+ {
+ sharedLocks = new ReentrantLock[numLocks];
+ for (int i = 0; i < numLocks; i++) sharedLocks[i] = new ReentrantLock();
+ }
+
+ public final ReentrantLock getLock(E object)
+ {
+ return sharedLocks[hashToIndex(object)];
+ }
+
+ public final int getNumLocksHeld()
+ {
+ int i = 0;
+ for (ReentrantLock l : sharedLocks) if (l.isLocked()) i++;
+ return i;
+ }
+
+ public final boolean ownsLock(E object, Object owner)
+ {
+ ReentrantLock lock = getLock(object);
+ return lock.isHeldByCurrentThread();
+ }
+
+ public final boolean isLocked(E object)
+ {
+ ReentrantLock lock = getLock(object);
+ return lock.isLocked();
+ }
+
+ public String toString()
+ {
+ return "ReentrantSharedLockContainer{" +
+ "sharedLocks=" + (sharedLocks == null ? null :
Arrays.asList(sharedLocks)) +
+ '}';
+ }
+
+ public void reset()
+ {
+ initLocks(sharedLocks.length);
+ }
+
+ public int size()
+ {
+ return sharedLocks.length;
+ }
+}
Property changes on:
core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/ReentrantSharedLockContainer.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: core/trunk/src/main/resources/schema/jbosscache-config-3.1.xsd
===================================================================
--- core/trunk/src/main/resources/schema/jbosscache-config-3.1.xsd 2009-03-18 09:45:27 UTC
(rev 7908)
+++ core/trunk/src/main/resources/schema/jbosscache-config-3.1.xsd 2009-03-18 11:36:28 UTC
(rev 7909)
@@ -86,6 +86,7 @@
</xs:simpleType>
</xs:attribute>
<xs:attribute name="writeSkewCheck"
type="tns:booleanType"/>
+ <xs:attribute name="useLockStriping"
type="tns:booleanType"/>
<xs:attribute name="concurrencyLevel"
type="xs:integer"/>
</xs:complexType>
Added: core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockPerFqnTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockPerFqnTest.java
(rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/LockPerFqnTest.java 2009-03-18
11:36:28 UTC (rev 7909)
@@ -0,0 +1,105 @@
+package org.jboss.cache.api.mvcc;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.invocation.InvocationContextContainer;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.util.TestingUtil;
+import org.jboss.cache.util.concurrent.locks.PerElementLockContainer;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+@Test(groups = "functional", sequential = true, testName =
"api.mvcc.LockPerFqnTest")
+public class LockPerFqnTest
+{
+ Cache cache;
+
+ @BeforeMethod
+ public void setUp()
+ {
+ Configuration cfg = new Configuration();
+ cfg.setUseLockStriping(false);
+ cfg.setNodeLockingScheme(Configuration.NodeLockingScheme.MVCC);
+ cache = new DefaultCacheFactory().createCache(cfg);
+ }
+
+ @AfterMethod
+ public void tearDown()
+ {
+ TestingUtil.killCaches(cache);
+ }
+
+ public void testLocksCleanedUp()
+ {
+ cache.put("/a/b/c", "k", "v");
+ cache.put("/a/b/d", "k", "v");
+ assertNoLocks();
+ }
+
+ public void testLocksConcurrency() throws Exception
+ {
+ final int NUM_THREADS = 10;
+ final CountDownLatch l = new CountDownLatch(1);
+ final int numLoops = 1000;
+ final List<Exception> exceptions = new LinkedList<Exception>();
+
+ Thread[] t = new Thread[NUM_THREADS];
+ for (int i=0; i<NUM_THREADS; i++) t[i] = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ l.await();
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ for (int i=0; i<numLoops; i++)
+ {
+ try
+ {
+ switch (i % 2)
+ {
+ case 0:
+ cache.put("/a/fqn" + i, "k", "v");
+ break;
+ case 1:
+ cache.removeNode("/a/fqn" + i);
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ exceptions.add(e);
+ }
+ }
+ }
+ };
+
+ for (Thread th: t) th.start();
+ l.countDown();
+ for (Thread th: t) th.join();
+
+ if (!exceptions.isEmpty()) throw exceptions.get(0);
+ assertNoLocks();
+ }
+
+ private void assertNoLocks()
+ {
+ LockManager lm = TestingUtil.extractLockManager(cache);
+ LockAssert.assertNoLocks(
+ lm,
TestingUtil.extractComponentRegistry(cache).getComponent(InvocationContextContainer.class)
+ );
+
+ PerElementLockContainer lc = (PerElementLockContainer) TestingUtil.extractField(lm,
"lockContainer");
+ assert lc.size() == 0;
+ }
+}