[jboss-cvs] JBossCache/src/org/jboss/cache/lock ...

Jimmy Wilson jawilson at redhat.com
Sun Jun 24 16:26:17 EDT 2007


  User: jawilson
  Date: 07/06/24 16:26:17

  Added:       src/org/jboss/cache/lock  Tag: Branch_JBossCache_1_4_0
                        StripedLock.java
  Log:
  Fix for [JBCACHE-1103].  Cache Loaders need to control locking when needed, not their interceptor counterpart.
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.5.2.2   +162 -0    JBossCache/src/org/jboss/cache/lock/StripedLock.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: StripedLock.java
  ===================================================================
  RCS file: StripedLock.java
  diff -N StripedLock.java
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ StripedLock.java	24 Jun 2007 20:26:16 -0000	1.5.2.2
  @@ -0,0 +1,162 @@
  +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 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
  + * {@link org.jboss.cache.loader.CacheLoader} implemtations thread safe.
  + * <p/>
  + * Backed by a set of {@link java.util.concurrent.locks.ReentrantReadWriteLock} instances, and using the {@link org.jboss.cache.Fqn}
  + * hashcodes to determine buckets.
  + * <p/>
  + * Since buckets are used, it doesn't matter that the Fqn in question is not removed from the lock map when no longer in
  + * use, since the Fqn is not referenced in this class.  Rather, the hash code is used.
  + * <p/>
  + *
  + * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
  + * @since 2.0.0
  + */
  + at ThreadSafe
  +public class StripedLock
  +{
  +   private static final int DEFAULT_CONCURRENCY = 20;
  +   private int lockSegmentMask;
  +   private int lockSegmentShift;
  +
  +   ReentrantReadWriteLock[] sharedLocks;
  +   private Log log = LogFactory.getLog(StripedLock.class);
  +
  +   /**
  +    * This constructor just calls {@link #StripedLock(int)} with a default concurrency value of 20.
  +    */
  +   public StripedLock()
  +   {
  +      this(DEFAULT_CONCURRENCY);
  +   }
  +
  +   /**
  +    * Creates a new StripedLock which uses a certain number of shared locks across all elements that need to be locked.
  +    *
  +    * @param concurrency number of threads expected to use this class concurrently.
  +    */
  +   public StripedLock(int concurrency)
  +   {
  +      int tempLockSegShift = 0;
  +      int numLocks = 1;
  +      while (numLocks < concurrency)
  +      {
  +         ++tempLockSegShift;
  +         numLocks <<= 1;
  +      }
  +      lockSegmentShift = 32 - tempLockSegShift;
  +      lockSegmentMask = numLocks - 1;
  +
  +      sharedLocks = new ReentrantReadWriteLock[numLocks];
  +
  +      for (int i = 0; i < numLocks; i++) sharedLocks[i] = new ReentrantReadWriteLock();
  +   }
  +
  +   /**
  +    * Blocks until a lock is acquired.
  +    *
  +    * @param fqn       the Fqn to lock on
  +    * @param exclusive if true, a write (exclusive) lock is attempted, otherwise a read (shared) lock is used.
  +    */
  +   public void acquireLock(Fqn fqn, boolean exclusive)
  +   {
  +      ReentrantReadWriteLock lock = getLock(fqn);
  +
  +      if (exclusive)
  +      {
  +         // allow for reentrancy
  +         lock.writeLock().lock();
  +      }
  +      else
  +         lock.readLock().lock();
  +   }
  +
  +   /**
  +    * Releases a lock the caller may be holding. This method is idempotent.
  +    *
  +    * @param fqn the Fqn to release
  +    */
  +   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?
  +         }
  +      }
  +   }
  +
  +   ReentrantReadWriteLock getLock(Object o)
  +   {
  +      return sharedLocks[hashToIndex(o)];
  +   }
  +
  +   int hashToIndex(Object o)
  +   {
  +      return (hash(o) >>> 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 x the object serving as a key
  +    * @return the hash code
  +    */
  +   int hash(Object x)
  +   {
  +      int h = x.toString().hashCode();
  +      h += ~(h << 9);
  +      h ^= (h >>> 14);
  +      h += (h << 4);
  +      h ^= (h >>> 10);
  +      return h;
  +   }
  +
  +   /**
  +    * Releases locks on all fqns passed in.  Makes multiple calls to {@link #releaseLock(org.jboss.cache.Fqn)}.  This method is idempotent.
  +    *
  +    * @param fqns list of fqns
  +    * @see #releaseLock(org.jboss.cache.Fqn)
  +    */
  +   public void releaseAllLocks(List<Fqn> fqns)
  +   {
  +      for (Fqn f : fqns) releaseLock(f);
  +   }
  +
  +   /**
  +    * Acquires locks on all fqns passed in.  Makes multiple calls to {@link #acquireLock(org.jboss.cache.Fqn,boolean)}
  +    *
  +    * @param fqns      list of fqns
  +    * @param exclusive whether locks are exclusive.
  +    * @see #acquireLock(org.jboss.cache.Fqn,boolean)
  +    */
  +   public void acquireAllLocks(List<Fqn> fqns, boolean exclusive)
  +   {
  +      for (Fqn f : fqns) acquireLock(f, exclusive);
  +   }
  +}
  
  
  



More information about the jboss-cvs-commits mailing list