[jbosscache-commits] JBoss Cache SVN: r7909 - in core/trunk/src: main/java/org/jboss/cache and 6 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Wed Mar 18 07:36:28 EDT 2009


Author: manik.surtani at 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
+ */
+ at 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
- */
- at 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
- */
- at 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
+ */
+ at 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
- */
- at 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
+ */
+ at 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;
+
+ at 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;
+   }
+}




More information about the jbosscache-commits mailing list