[jbosscache-commits] JBoss Cache SVN: r6969 - in core/branches/flat/src/main/java/org/jboss/starobrno: lock and 1 other directory.
jbosscache-commits at lists.jboss.org
jbosscache-commits at lists.jboss.org
Wed Oct 15 21:00:50 EDT 2008
Author: jason.greene at jboss.com
Date: 2008-10-15 21:00:50 -0400 (Wed, 15 Oct 2008)
New Revision: 6969
Added:
core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoader.java
core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoaderConfig.java
core/branches/flat/src/main/java/org/jboss/starobrno/lock/StripedLock.java
Modified:
core/branches/flat/src/main/java/org/jboss/starobrno/loader/CacheLoader.java
Log:
Port FileCacheLoader
Modified: core/branches/flat/src/main/java/org/jboss/starobrno/loader/CacheLoader.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/loader/CacheLoader.java 2008-10-16 00:50:31 UTC (rev 6968)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/loader/CacheLoader.java 2008-10-16 01:00:50 UTC (rev 6969)
@@ -118,13 +118,6 @@
V put(Object key, V value) ;
/**
- * Removes the given key and value from the attributes of the given node.
- * Does nothing if the node doesn't exist
- * Returns the removed value.
- */
- V remove(Object key, V value);
-
- /**
* Removes everything from this cache-loader
*/
void clear();
@@ -134,7 +127,7 @@
*
* @param fqn the {@link Fqn} of the node
*/
- void remove(Object key);
+ V remove(Object key);
/**
* Retrieves all entries stored in this cache loader
Added: core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoader.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoader.java (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoader.java 2008-10-16 01:00:50 UTC (rev 6969)
@@ -0,0 +1,495 @@
+/*
+ * 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.starobrno.loader;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.jcip.annotations.ThreadSafe;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.starobrno.CacheException;
+import org.jboss.starobrno.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
+import org.jboss.starobrno.lock.StripedLock;
+import org.jboss.starobrno.marshall.EntryData;
+import org.jboss.util.stream.MarshalledValueInputStream;
+
+/**
+ * Simple file-based CacheLoader implementation. Nodes are directories, attributes of a node is a file in the directory
+ * <p/>
+ * The FileCacheLoader has some severe limitations which restrict its use in a production
+ * environment, or if used in such an environment, it should be used with due care and sufficient
+ * understanding of these limitations.
+ * <ul>
+ * <li>Due to the way the FileCacheLoader represents a tree structure on disk (directories and files) traversal is inefficient for deep trees.</li>
+ * <li>Usage on shared filesystems like NFS, Windows shares, etc. should be avoided as these do not implement proper file locking and can cause data corruption.</li>
+ * <li>Usage with an isolation level of NONE can cause corrupt writes as multiple threads attempt to write to the same file.</li>
+ * <li>File systems are inherently not transactional, so when attempting to use your cache in a transactional context, failures when writing to the file (which happens during the commit phase) cannot be recovered.</li>
+ * </ul>
+ * <p/>
+ * As a rule of thumb, it is recommended that the FileCacheLoader not be used in a highly concurrent,
+ * transactional or stressful environment, and its use is restricted to testing.
+ * <p/>
+ * In terms of concurrency, file systems are notoriously inconsistent in their implementations of concurrent locks. To get around
+ * this and to meet the <b>thread safety</b> contracts set out in {@link CacheLoader}, this implementation uses a {@link org.jboss.cache.lock.StripedLock}
+ *
+ * @author Bela Ban
+ * @author <a href="mailto:galder.zamarreno at jboss.com">Galder Zamarreno</a>
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
+ * @version $Id: FileCacheLoader.java 6885 2008-10-08 16:28:04Z manik.surtani at jboss.com $
+ */
+ at ThreadSafe
+public class FileCacheLoader<K,V> extends AbstractCacheLoader<K,V>
+{
+ File root = null;
+ String rootPath = null;
+ Log log = LogFactory.getLog(getClass());
+
+ protected final StripedLock lock = new StripedLock();
+
+ private FileCacheLoaderConfig config;
+
+ /**
+ * For full path, check '*' '<' '>' '|' '"' '?' Regex: [\*<>|"?]
+ */
+ public static final Pattern PATH_PATTERN = Pattern.compile("[\\*<>|\"?]");
+
+ /**
+ * For fqn, check '*' '<' '>' '|' '"' '?' and also '\' '/' and ':'
+ */
+ public static final Pattern KEY_PATTERN = Pattern.compile("[\\\\\\/:*<>|\"?]");
+ private static boolean isOldWindows;
+
+ static
+ {
+ float osVersion = -1;
+ try
+ {
+ osVersion = Float.parseFloat(System.getProperty("os.version").trim());
+ }
+ catch (Exception e)
+ {
+ // ignore
+ }
+ // 4.x is windows NT/2000 and 5.x is XP.
+ isOldWindows = System.getProperty("os.name").toLowerCase().startsWith("windows") && osVersion < 4;
+ }
+
+ public void setConfig(IndividualCacheLoaderConfig base)
+ {
+ if (base instanceof FileCacheLoaderConfig)
+ {
+ this.config = (FileCacheLoaderConfig) base;
+ }
+ else if (base != null)
+ {
+ this.config = new FileCacheLoaderConfig(base);
+ }
+
+ String location = this.config != null ? this.config.getLocation() : null;
+ if (location != null && location.length() > 0)
+ {
+ root = new File(location);
+ rootPath = root.getAbsolutePath() + File.separator;
+ }
+ }
+
+ public IndividualCacheLoaderConfig getConfig()
+ {
+ return config;
+ }
+
+ @Override
+ public void create()
+ {
+ if (root == null)
+ {
+ String tmpLocation = System.getProperty("java.io.tmpdir", "C:\\tmp");
+ root = new File(tmpLocation);
+ rootPath = root.getAbsolutePath() + File.separator;
+ }
+ if (!root.exists())
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("Creating cache loader location " + root);
+ }
+
+ if (config.isCheckCharacterPortability())
+ {
+ /* Before creating the root, check whether the path is character portable. Anything that comes after is part
+ of the fqn which is inspected later. */
+ isCharacterPortableLocation(root.getAbsolutePath());
+ }
+
+ boolean created = root.mkdirs();
+ if (!created)
+ {
+ throw new CacheException("Unable to create cache loader location " + root);
+ }
+ }
+
+ if (!root.isDirectory())
+ {
+ throw new CacheException("Cache loader location [" + root + "] is not a directory!");
+ }
+ }
+
+ public V get(Object key)
+ {
+ lock(key);
+ try
+ {
+ try
+ {
+ return loadValue(key);
+ }
+ catch (Exception e)
+ {
+ throw new CacheException(e);
+ }
+ }
+ finally
+ {
+ unlock(key);
+ }
+ }
+
+ public boolean exists(Object key)
+ {
+ lock(key);
+ try
+ {
+ return getFile(key, false).exists();
+ }
+ catch (IOException e)
+ {
+ throw new CacheException(e);
+ }
+ finally
+ {
+ unlock(key);
+ }
+ }
+
+ public V put(Object key, V value)
+ {
+ lock(key);
+ try
+ {
+ V retval;
+ try
+ {
+ retval = loadValue(key);
+ storeValue(key, value);
+ return retval;
+ }
+ catch (Exception e)
+ {
+ throw new CacheException(e);
+ }
+ }
+ finally
+ {
+ unlock(key);
+ }
+ }
+
+ public V remove(Object key)
+ {
+ lock(key);
+ try
+ {
+ V retval;
+ try
+ {
+ File file = getFile(key, false);
+ if (! file.exists())
+ return null;
+
+ retval = loadValue(key);
+ file.delete();
+ return retval;
+ }
+ catch (Exception e)
+ {
+ throw new CacheException(e);
+ }
+ }
+ finally
+ {
+ unlock(key);
+ }
+ }
+
+ private void unlock(Object key)
+ {
+ lock.releaseLock(key.toString());
+ }
+
+ private void lock(Object key)
+ {
+ lock.acquireLock(key.toString(), true);
+ }
+
+ private File getDirectory(Object key, boolean create) throws IOException
+ {
+ File f = new File(getFullPath(key));
+ if (!f.exists())
+ {
+ if (create)
+ {
+ boolean make = f.mkdirs();
+ if (!make)
+ throw new IOException("Unable to mkdirs " + f);
+ }
+ }
+ return f;
+ }
+
+ private String getFullPath(Object key)
+ {
+ return rootPath;
+ }
+
+ private void safeClose(Closeable closeable)
+ {
+ if (closeable == null)
+ return;
+
+ try
+ {
+ closeable.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+
+ private V loadValue(Object key) throws Exception
+ {
+ File child = getFile(key, false);
+ if (!child.exists())
+ return null;
+
+ return loadValue(child);
+ }
+
+ private V loadValue(File file) throws Exception
+ {
+ FileInputStream fileIn = null;
+ ObjectInputStream input = null;
+
+ try
+ {
+ fileIn = new FileInputStream(file);
+ input = new MarshalledValueInputStream(fileIn);
+ return (V) getMarshaller().objectFromObjectStream(input);
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ return null;
+ }
+ finally
+ {
+ safeClose(input);
+ safeClose(fileIn);
+ }
+ }
+
+ private EntryData<K, V> loadEntry(File file) throws Exception
+ {
+ FileInputStream fileIn = null;
+ ObjectInputStream input = null;
+
+ try
+ {
+ fileIn = new FileInputStream(file);
+ input = new MarshalledValueInputStream(fileIn);
+ V value = (V) getMarshaller().objectFromObjectStream(input);
+ K key = (K) getMarshaller().objectFromObjectStream(input);
+ return new EntryData<K,V>(key, value);
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ return null;
+ }
+ finally
+ {
+ safeClose(input);
+ safeClose(fileIn);
+ }
+ }
+
+ private File getFile(Object key, boolean create) throws IOException
+ {
+ File directory = getDirectory(key, create);
+ File child = new File(directory, key.toString());
+ if (create && !child.exists())
+ {
+ if (config.isCheckCharacterPortability())
+ {
+ /* Check whether the entire file path (root + fqn + data file name), is length portable */
+ isLengthPortablePath(child.getAbsolutePath());
+ /* Check whether the fqn tree we're trying to store could contain non portable characters */
+ isCharacterPortableKey(key);
+ }
+
+ if (!child.createNewFile())
+ {
+ throw new IOException("Unable to create file: " + child);
+ }
+ }
+
+ return child;
+ }
+
+ protected void storeValue(Object key, Object value) throws Exception
+ {
+ File child = getFile(key, true);
+
+ FileOutputStream fileOut = null;
+ ObjectOutputStream output = null;
+ try
+ {
+ fileOut = new FileOutputStream(child);
+ output = new ObjectOutputStream(fileOut);
+ getMarshaller().objectToObjectStream(value, output);
+ getMarshaller().objectToObjectStream(key, output); // For getAllEntries
+ }
+ finally
+ {
+ safeClose(output);
+ safeClose(fileOut);
+ }
+ }
+
+ protected boolean isCharacterPortableLocation(String fileAbsolutePath)
+ {
+ Matcher matcher = PATH_PATTERN.matcher(fileAbsolutePath);
+ if (matcher.find())
+ {
+ log.warn("Cache loader location ( " + fileAbsolutePath + " ) contains one of these characters: '*' '<' '>' '|' '\"' '?'");
+ log.warn("Directories containing these characters are illegal in some operative systems and could lead to portability issues");
+ return false;
+ }
+
+ return true;
+ }
+
+ protected boolean isCharacterPortableKey(Object key)
+ {
+ // getFullPath converts Object to String via toString(), so we do too
+ Matcher matcher = KEY_PATTERN.matcher(key.toString());
+ if (matcher.find())
+ {
+ log.warn("The key.toString() contains one of these characters: '*' '<' '>' '|' '\"' '?' '\\' '/' ':' ");
+ log.warn("Directories containing these characters are illegal in some operating systems and could lead to portability issues");
+ return false;
+ }
+
+ return true;
+ }
+
+ protected boolean isLengthPortablePath(String absoluteFqnPath)
+ {
+
+ if (isOldWindows && absoluteFqnPath.length() > 255)
+ {
+ log.warn("The full absolute path to the fqn that you are trying to store is bigger than 255 characters, this could lead to problems on certain Windows systems: " + absoluteFqnPath);
+ return false;
+ }
+
+ return true;
+ }
+
+ public void clear()
+ {
+ File directory = new File(rootPath);
+ if (! directory.exists())
+ return;
+
+ File[] files = directory.listFiles();
+ if (files != null)
+ {
+ for (File file : files)
+ {
+ try
+ {
+ lock(file.getName());
+ if (file.exists())
+ file.delete();
+ }
+ finally
+ {
+ unlock(file.getName());
+ }
+ }
+ }
+ }
+
+ public List<EntryData<K, V>> getAllEntries()
+ {
+ List<EntryData<K,V>> entries = new LinkedList<EntryData<K,V>>();
+ File directory = new File(rootPath);
+ if (! directory.exists())
+ return entries;
+
+ File[] files = directory.listFiles();
+ if (files != null)
+ {
+ for (File file : files)
+ {
+ try
+ {
+ lock(file.getName());
+ if (file.exists())
+ {
+ EntryData<K,V> entry = loadEntry(file);
+ if (entry != null)
+ entries.add(entry);
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ finally
+ {
+ unlock(file.getName());
+ }
+ }
+ }
+
+ return entries;
+ }
+}
Property changes on: core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoader.java
___________________________________________________________________
Name: svn:executable
+ *
Added: core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoaderConfig.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoaderConfig.java (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/loader/FileCacheLoaderConfig.java 2008-10-16 01:00:50 UTC (rev 6969)
@@ -0,0 +1,111 @@
+/*
+ * 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.starobrno.loader;
+
+import org.jboss.cache.util.Util;
+import org.jboss.starobrno.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
+import org.jboss.starobrno.config.Dynamic;
+
+import java.util.Properties;
+
+public class FileCacheLoaderConfig extends IndividualCacheLoaderConfig
+{
+ private static final long serialVersionUID = 4626734068542420865L;
+
+ private String location;
+ @Dynamic
+ private boolean checkCharacterPortability = true;
+
+ public FileCacheLoaderConfig()
+ {
+ setClassName(FileCacheLoader.class.getName());
+ }
+
+ /**
+ * For use by {@link FileCacheLoader}.
+ *
+ * @param base generic config object created by XML parsing.
+ */
+ FileCacheLoaderConfig(IndividualCacheLoaderConfig base)
+ {
+ setClassName(FileCacheLoader.class.getName());
+ populateFromBaseConfig(base);
+ }
+
+ public String getLocation()
+ {
+ return location;
+ }
+
+ public void setLocation(String location)
+ {
+ testImmutability("location");
+ this.location = location;
+ }
+
+ public boolean isCheckCharacterPortability()
+ {
+ return checkCharacterPortability;
+ }
+
+ public void setCheckCharacterPortability(boolean checkCharacterPortability)
+ {
+ testImmutability("check.character.portability");
+ this.checkCharacterPortability = checkCharacterPortability;
+ }
+
+ @Override
+ public void setProperties(Properties props)
+ {
+ super.setProperties(props);
+
+ if (props != null)
+ {
+ setLocation(props.getProperty("location"));
+ String prop = props.getProperty("check.character.portability");
+ setCheckCharacterPortability((prop == null || Boolean.valueOf(prop)));
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof FileCacheLoaderConfig && equalsExcludingProperties(obj))
+ {
+ return Util.safeEquals(location, ((FileCacheLoaderConfig) obj).location);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return 31 * hashCodeExcludingProperties() + (location == null ? 0 : location.hashCode());
+ }
+
+ @Override
+ public FileCacheLoaderConfig clone() throws CloneNotSupportedException
+ {
+ return (FileCacheLoaderConfig) super.clone();
+ }
+
+}
\ No newline at end of file
Added: core/branches/flat/src/main/java/org/jboss/starobrno/lock/StripedLock.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/lock/StripedLock.java (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/lock/StripedLock.java 2008-10-16 01:00:50 UTC (rev 6969)
@@ -0,0 +1,168 @@
+/*
+ * 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.starobrno.lock;
+
+import net.jcip.annotations.ThreadSafe;
+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 final int lockSegmentMask;
+ private final int lockSegmentShift;
+
+ final ReentrantReadWriteLock[] sharedLocks;
+
+ /**
+ * 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(Object key, boolean exclusive)
+ {
+ ReentrantReadWriteLock lock = getLock(key);
+
+ if (exclusive)
+ {
+ 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(Object key)
+ {
+ ReentrantReadWriteLock lock = getLock(key);
+ if (lock.isWriteLockedByCurrentThread())
+ {
+ lock.writeLock().unlock();
+ }
+ else
+ {
+ lock.readLock().unlock();
+ }
+ }
+
+ final ReentrantReadWriteLock getLock(Object o)
+ {
+ return sharedLocks[hashToIndex(o)];
+ }
+
+ final 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
+ */
+ final int hash(Object x)
+ {
+ int h = x.hashCode();
+ h ^= (h >>> 20) ^ (h >>> 12);
+ return h ^ (h >>> 7) ^ (h >>> 4);
+ }
+
+ /**
+ * 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<Object> keys)
+ {
+ for (Object k : keys) releaseLock(k);
+ }
+
+ /**
+ * 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<Object> keys, boolean exclusive)
+ {
+ for (Object k : keys) acquireLock(k, exclusive);
+ }
+}
More information about the jbosscache-commits
mailing list