[jbosscache-commits] JBoss Cache SVN: r6788 - in core/trunk/src/main/java/org/jboss/cache: util/concurrent/locks and 1 other directory.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Thu Sep 25 10:29:11 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-09-25 10:29:10 -0400 (Thu, 25 Sep 2008)
New Revision: 6788

Added:
   core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/UpgradableLock.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/lock/StripedLock.java
Log:
JBCACHE-1410:  JDBCCacheLoader may attempt to create a node entry in the DB twice

Modified: core/trunk/src/main/java/org/jboss/cache/lock/StripedLock.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/StripedLock.java	2008-09-25 14:27:07 UTC (rev 6787)
+++ core/trunk/src/main/java/org/jboss/cache/lock/StripedLock.java	2008-09-25 14:29:10 UTC (rev 6788)
@@ -22,12 +22,10 @@
 package org.jboss.cache.lock;
 
 import net.jcip.annotations.ThreadSafe;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.util.concurrent.locks.UpgradableLock;
 
 import java.util.List;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * A simple implementation of lock striping, using Fqns as the keys to lock on, primarily used to help make
@@ -50,8 +48,7 @@
    private final int lockSegmentMask;
    private final int lockSegmentShift;
 
-   final ReentrantReadWriteLock[] sharedLocks;
-   private final Log log = LogFactory.getLog(StripedLock.class);
+   final UpgradableLock[] sharedLocks;
 
    /**
     * This constructor just calls {@link #StripedLock(int)} with a default concurrency value of 20.
@@ -78,9 +75,9 @@
       lockSegmentShift = 32 - tempLockSegShift;
       lockSegmentMask = numLocks - 1;
 
-      sharedLocks = new ReentrantReadWriteLock[numLocks];
+      sharedLocks = new UpgradableLock[numLocks];
 
-      for (int i = 0; i < numLocks; i++) sharedLocks[i] = new ReentrantReadWriteLock();
+      for (int i = 0; i < numLocks; i++) sharedLocks[i] = new UpgradableLock();
    }
 
    /**
@@ -91,15 +88,16 @@
     */
    public void acquireLock(Fqn fqn, boolean exclusive)
    {
-      ReentrantReadWriteLock lock = getLock(fqn);
+      UpgradableLock lock = getLock(fqn);
 
       if (exclusive)
       {
-         // allow for reentrancy
-         lock.writeLock().lock();
+         lock.acquireWriteLockWithUpgrade();
       }
       else
+      {
          lock.readLock().lock();
+      }
    }
 
    /**
@@ -109,28 +107,11 @@
     */
    public void releaseLock(Fqn fqn)
    {
-      ReentrantReadWriteLock lock = getLock(fqn);
-      if (lock.isWriteLockedByCurrentThread())
-      {
-         lock.writeLock().unlock();
-         // check that we still don't have a stale WL
-//         if (lock.isWriteLockedByCurrentThread() && log.isWarnEnabled())
-//            log.warn("Write lock still exists on Fqn " + fqn + " for current thread.  Perhaps this was write-locked more than once?");
-      }
-      else
-      {
-         try
-         {
-            lock.readLock().unlock();
-         }
-         catch (IllegalMonitorStateException imse)
-         {
-            // perhaps the RL was already released earlier?
-         }
-      }
+      UpgradableLock lock = getLock(fqn);
+      lock.unlock();
    }
 
-   final ReentrantReadWriteLock getLock(Object o)
+   final UpgradableLock getLock(Object o)
    {
       return sharedLocks[hashToIndex(o)];
    }

Added: core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/UpgradableLock.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/UpgradableLock.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/concurrent/locks/UpgradableLock.java	2008-09-25 14:29:10 UTC (rev 6788)
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt 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 org.jboss.cache.util.concurrent.ConcurrentHashSet;
+
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * A {@link java.util.concurrent.locks.ReentrantReadWriteLock} with support for acquiring write locks when the current
+ * thread already has a read lock.  Also supports releasing such write locks and re-acquiring read locks in the process.
+ */
+public class UpgradableLock extends ReentrantReadWriteLock
+{
+   private final Set<Thread> upgraders = new ConcurrentHashSet<Thread>();
+
+   /**
+    * Attempts to upgrade a read lock to a write lock.  If no read locks are held, a write lock is simply attempted.
+    */
+   public void acquireWriteLockWithUpgrade()
+   {
+      boolean upgradeNeeded = true;
+      try
+      {
+         readLock().unlock();
+      }
+      catch (IllegalMonitorStateException imse)
+      {
+         // read lock was never held; no upgrading needed.
+         upgradeNeeded = false;
+      }
+
+      if (upgradeNeeded) upgraders.add(Thread.currentThread());
+
+      writeLock().lock();
+   }
+
+   /**
+    * Unlocks any locks held by the current thread.  If a write lock is held, it is released.  If a read lock is held
+    * it is released.  This method supports reentrant locks so unlocking repeatedly may release >1 write lock.  It
+    * also supports upgraded locks, i.e., read locks that were upgraded to write locks.
+    */
+   public void unlock()
+   {
+      if (isWriteLockedByCurrentThread())
+      {
+         writeLock().unlock();
+         Thread current;
+         if (!isWriteLockedByCurrentThread() && upgraders.contains((current = Thread.currentThread())))
+         {
+            // re-acquire the RL.
+            readLock().lock();
+            upgraders.remove(current);
+         }
+      }
+      else
+      {
+         try
+         {
+            readLock().unlock();
+         }
+         catch (IllegalMonitorStateException imse)
+         {
+            // perhaps the RL was already released earlier?
+         }
+      }
+   }
+}




More information about the jbosscache-commits mailing list