[infinispan-commits] Infinispan SVN: r869 - in trunk/cachestore/jdbm/src: test/java/org/infinispan/loaders/jdbm and 1 other directory.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Mon Sep 28 06:50:57 EDT 2009
Author: galder.zamarreno at jboss.com
Date: 2009-09-28 06:50:57 -0400 (Mon, 28 Sep 2009)
New Revision: 869
Modified:
trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStore.java
trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStoreConfig.java
trunk/cachestore/jdbm/src/test/java/org/infinispan/loaders/jdbm/JdbmCacheStoreTest.java
Log:
Additions to expiry trees are now done in the eviction thread based on queued up entries, so removed corresponding TODO.
Modified: trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStore.java
===================================================================
--- trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStore.java 2009-09-28 09:57:26 UTC (rev 868)
+++ trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStore.java 2009-09-28 10:50:57 UTC (rev 869)
@@ -37,6 +37,8 @@
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
/**
* A persistent <code>CacheLoader</code> based on the JDBM project. See http://jdbm.sourceforge.net/ . Does not support
@@ -48,6 +50,7 @@
* (key,"m") == meta and (key,"v") == value.
*
* @author Elias Ross
+ * @author Galder Zamarreño
*/
@ThreadSafe
public class JdbmCacheStore extends AbstractCacheStore {
@@ -59,7 +62,7 @@
private static final String EXPIRY = "Expiry";
private final String DATE = "HH:mm:ss.SSS";
- private final Object expiryLock = new Object();
+ private BlockingQueue<ExpiryEntry> expiryEntryQueue;
private JdbmCacheStoreConfig config;
private RecordManager recman;
@@ -85,6 +88,8 @@
locationStr = System.getProperty("java.io.tmpdir");
config.setLocation(locationStr);
}
+
+ expiryEntryQueue = new LinkedBlockingQueue<ExpiryEntry>(config.getExpiryQueueSize());
// JBCACHE-1448 db name parsing fix courtesy of Ciro Cavani
/* Parse config string. */
@@ -275,24 +280,12 @@
}
Long at = new Long(expiry);
Object key = entry.getKey();
- if (trace)
- log.trace("at " + new SimpleDateFormat(DATE).format(new Date(at)) + " expire " + key);
- // TODO could store expiry entries in a separate thread; would remove this
- // lock as well
- synchronized (expiryLock) {
- Object existing = expiryTree.insert(at, key, false);
- if (existing != null) {
- // in the case of collision make the key a List ...
- if (existing instanceof List) {
- ((List) existing).add(key);
- expiryTree.insert(at, existing, true);
- } else {
- List<Object> al = new ArrayList<Object>(2);
- al.add(existing);
- al.add(key);
- expiryTree.insert(at, al, true);
- }
- }
+ if (trace) log.trace("at " + new SimpleDateFormat(DATE).format(new Date(at)) + " expire " + key);
+
+ try {
+ expiryEntryQueue.put(new ExpiryEntry(at, key));
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // Restore interruption status
}
}
@@ -356,26 +349,44 @@
* @throws ClassNotFoundException
*/
private void purgeInternal0() throws Exception {
+ // Drain queue and update expiry tree
+ List<ExpiryEntry> entries = new ArrayList<ExpiryEntry>();
+ expiryEntryQueue.drainTo(entries);
+ for (ExpiryEntry entry : entries) {
+ Object existing = expiryTree.insert(entry.expiry, entry.key, false);
+ if (existing != null) {
+ // in the case of collision make the key a List ...
+ if (existing instanceof List) {
+ ((List) existing).add(entry.key);
+ expiryTree.insert(entry.expiry, existing, true);
+ } else {
+ List<Object> al = new ArrayList<Object>(2);
+ al.add(existing);
+ al.add(entry.key);
+ expiryTree.insert(entry.expiry, al, true);
+ }
+ }
+ }
+
+ // Browse the expiry and remove accordingly
TupleBrowser browse = expiryTree.browse();
Tuple tuple = new Tuple();
List<Long> times = new ArrayList<Long>();
List<Object> keys = new ArrayList<Object>();
- synchronized (expiryLock) {
- while (browse.getNext(tuple)) {
- Long time = (Long) tuple.getKey();
- if (time > System.currentTimeMillis())
- break;
- times.add(time);
- Object key = tuple.getValue();
- if (key instanceof List)
- keys.addAll((List) key);
- else
- keys.add(key);
- }
- for (Long time : times) {
- expiryTree.remove(time);
- }
+ while (browse.getNext(tuple)) {
+ Long time = (Long) tuple.getKey();
+ if (time > System.currentTimeMillis())
+ break;
+ times.add(time);
+ Object key = tuple.getValue();
+ if (key instanceof List)
+ keys.addAll((List) key);
+ else
+ keys.add(key);
}
+ for (Long time : times) {
+ expiryTree.remove(time);
+ }
if (!keys.isEmpty())
log.debug("purge (up to) " + keys.size() + " entries");
@@ -484,4 +495,14 @@
return size;
}
}
+
+ private final class ExpiryEntry {
+ private final Long expiry;
+ private final Object key;
+
+ private ExpiryEntry(long expiry, Object key) {
+ this.expiry = new Long(expiry);
+ this.key = key;
+ }
+ }
}
\ No newline at end of file
Modified: trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStoreConfig.java
===================================================================
--- trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStoreConfig.java 2009-09-28 09:57:26 UTC (rev 868)
+++ trunk/cachestore/jdbm/src/main/java/org/infinispan/loaders/jdbm/JdbmCacheStoreConfig.java 2009-09-28 10:50:57 UTC (rev 869)
@@ -3,67 +3,79 @@
import java.util.Comparator;
import org.infinispan.CacheException;
+import org.infinispan.config.Dynamic;
import org.infinispan.loaders.LockSupportCacheStoreConfig;
-import org.infinispan.marshall.Marshaller;
import org.infinispan.util.Util;
/**
* Configures {@link JdbmCacheStore}.
- * <p/>
- * <ul>
- * <li><tt>location</tt> - a location on disk where the store can write internal
- * files.</li>
- * <li><tt>comparatorClassName</tt> - comparator class used to sort the keys
- * by the cache loader. This should only need to be set when using keys that
- * do not have a natural ordering.
- * </ul>
*
* @author Elias Ross
+ * @author Galder Zamarreño
* @since 4.0
*/
public class JdbmCacheStoreConfig extends LockSupportCacheStoreConfig {
- private static final long serialVersionUID = 1L;
-
- String location = "jdbm";
- String comparatorClassName = NaturalComparator.class.getName();
+ /** The serialVersionUID */
+ private static final long serialVersionUID = -3686035269816837880L;
+ /**
+ * @configRef desc="A location on disk where the store can write internal files"
+ */
+ String location = "jdbm";
+ /**
+ * @configRef desc="Comparator class used to sort the keys by the cache loader.
+ * This should only need to be set when using keys that do not have a natural ordering."
+ */
+ String comparatorClassName = NaturalComparator.class.getName();
+
+ /**
+ * @configRef desc="Whenever a new entry is stored, an expiry entry is created and added
+ * to the a queue that is later consumed by the eviction thread. This parameter sets the size
+ * of this queue."
+ */
+ @Dynamic
+ int expiryQueueSize = 10000;
- public JdbmCacheStoreConfig() {
- setCacheLoaderClassName(JdbmCacheStore.class.getName());
- }
+ public JdbmCacheStoreConfig() {
+ setCacheLoaderClassName(JdbmCacheStore.class.getName());
+ }
- public String getLocation() {
- return location;
- }
+ public String getLocation() {
+ return location;
+ }
- public void setLocation(String location) {
- testImmutability("location");
- this.location = location;
- }
+ public void setLocation(String location) {
+ testImmutability("location");
+ this.location = location;
+ }
- /**
- * Returns comparatorClassName.
- */
- public String getComparatorClassName() {
- return comparatorClassName;
- }
+ public String getComparatorClassName() {
+ return comparatorClassName;
+ }
- /**
- * Sets comparatorClassName.
- */
- public void setComparatorClassName(String comparatorClassName) {
- this.comparatorClassName = comparatorClassName;
- }
+ public void setComparatorClassName(String comparatorClassName) {
+ testImmutability("comparatorClassName");
+ this.comparatorClassName = comparatorClassName;
+ }
- /**
- * Returns a new comparator instance based on {@link #setComparatorClassName(String)}.
- */
- public Comparator createComparator() {
- try {
- return (Comparator) Util.getInstance(comparatorClassName);
- } catch (Exception e) {
- throw new CacheException(e);
- }
- }
+ public int getExpiryQueueSize() {
+ return expiryQueueSize;
+ }
+ public void setExpiryQueueSize(int expiryQueueSize) {
+ testImmutability("expiryQueueSize");
+ this.expiryQueueSize = expiryQueueSize;
+ }
+
+ /**
+ * Returns a new comparator instance based on {@link #setComparatorClassName(String)}.
+ */
+ public Comparator createComparator() {
+ try {
+ return (Comparator) Util.getInstance(comparatorClassName);
+ } catch (Exception e) {
+ throw new CacheException(e);
+ }
+ }
+
}
Modified: trunk/cachestore/jdbm/src/test/java/org/infinispan/loaders/jdbm/JdbmCacheStoreTest.java
===================================================================
--- trunk/cachestore/jdbm/src/test/java/org/infinispan/loaders/jdbm/JdbmCacheStoreTest.java 2009-09-28 09:57:26 UTC (rev 868)
+++ trunk/cachestore/jdbm/src/test/java/org/infinispan/loaders/jdbm/JdbmCacheStoreTest.java 2009-09-28 10:50:57 UTC (rev 869)
@@ -70,7 +70,41 @@
assert fcs.load("k2") == null;
assert fcs.load("k3") == null;
}
+
+ public void testStopStartDoesntNukeValues() throws InterruptedException, CacheLoaderException {
+ assert !cs.containsKey("k1");
+ assert !cs.containsKey("k2");
+ long lifespan = 1;
+ long idle = 1;
+ InternalCacheEntry se1 = InternalEntryFactory.create("k1", "v1", lifespan);
+ InternalCacheEntry se2 = InternalEntryFactory.create("k2", "v2");
+ InternalCacheEntry se3 = InternalEntryFactory.create("k3", "v3", -1, idle);
+ InternalCacheEntry se4 = InternalEntryFactory.create("k4", "v4", lifespan, idle);
+
+ cs.store(se1);
+ cs.store(se2);
+ cs.store(se3);
+ cs.store(se4);
+ Thread.sleep(100);
+ // Force a purge expired so that expiry tree is updated
+ cs.purgeExpired();
+ cs.stop();
+ cs.start();
+ assert se1.isExpired();
+ assert cs.load("k1") == null;
+ assert !cs.containsKey("k1");
+ assert cs.load("k2") != null;
+ assert cs.containsKey("k2");
+ assert cs.load("k2").getValue().equals("v2");
+ assert se3.isExpired();
+ assert cs.load("k3") == null;
+ assert !cs.containsKey("k3");
+ assert se3.isExpired();
+ assert cs.load("k3") == null;
+ assert !cs.containsKey("k3");
+ }
+
public void testIterator() throws Exception {
InternalCacheEntry k1 = InternalEntryFactory.create("k1", "v1");
InternalCacheEntry k2 = InternalEntryFactory.create("k2", "v2");
More information about the infinispan-commits
mailing list