Author: genman
Date: 2008-12-05 19:27:51 -0500 (Fri, 05 Dec 2008)
New Revision: 7256
Added:
core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2.java
core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2Config.java
core/trunk/src/test/java/org/jboss/cache/loader/JdbmCacheLoader2Test.java
Modified:
core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoaderConfig.java
Log:
JBCACHE-1440 - Preliminary implementation; need to come up with some performance tests
comparing this with the old
Added: core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2.java
(rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2.java 2008-12-06
00:27:51 UTC (rev 7256)
@@ -0,0 +1,248 @@
+/*
+ * 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.loader.jdbm;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jdbm.helper.Tuple;
+import jdbm.helper.TupleBrowser;
+import net.jcip.annotations.ThreadSafe;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Modification;
+import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
+
+/**
+ * Optimized version of the {@link JdbmCacheLoader} implementation which is better
+ * for storing data under a single node. Speed is improved.
+ * <p/>
+ * Data is stored using an FQN to Map association, where the depth is prefixed to the
FQN:
+ * <pre>
+ * 0/ = NodeData
+ * 1/node1 = Node Data
+ * 1/node2 = Node Data
+ * 2/node2/node3 = Node Data
+ * 2/node2/node4 = Node Data
+ * </pre>
+ * <p/>
+ * Browse operations lock the entire tree; eventually the JDBM team plans to fix this.
+ *
+ * @author Elias Ross
+ * @version $Id: JdbmCacheLoader.java 7086 2008-11-05 18:39:35Z genman $
+ */
+@ThreadSafe
+public class JdbmCacheLoader2 extends JdbmCacheLoader
+{
+ private static final Log log = LogFactory.getLog(JdbmCacheLoader2.class);
+ private static final boolean trace = log.isTraceEnabled();
+
+ /**
+ * Max number of dummy parent nodes to cache.
+ */
+ private static final int PARENT_CACHE_SIZE = 100;
+
+ /**
+ * Empty parent nodes whose existence is cached.
+ * Empty parents are required to ensure {@link #getChildrenNames(Fqn)}
+ * and recursive {@link #remove(Fqn)} work correctly.
+ */
+ private Set<Fqn> parents = Collections.synchronizedSet(new
HashSet<Fqn>());
+
+ @Override
+ JdbmCacheLoader2Config createConfig(IndividualCacheLoaderConfig base)
+ {
+ return new JdbmCacheLoader2Config(base);
+ }
+
+ /**
+ * Adds a depth number to the start of the FQN.
+ */
+ private Fqn withDepth(Fqn name) {
+ return withDepth(name, name.size());
+ }
+
+ /**
+ * Adds a depth number to the start of the FQN.
+ */
+ private Fqn withDepth(Fqn name, int depth) {
+ Fqn n = Fqn.fromElements(depth);
+ return Fqn.fromRelativeList(n, name.peekElements());
+ }
+
+ @Override
+ Set<Object> getChildrenNames0(Fqn name) throws IOException
+ {
+ Fqn name2 = withDepth(name, name.size() + 1);
+ TupleBrowser browser = tree.browse(name2);
+ Tuple t = new Tuple();
+
+ Set<Object> set = new HashSet<Object>();
+
+ while (browser.getNext(t))
+ {
+ Fqn fqn = (Fqn) t.getKey();
+ if (!fqn.isChildOf(name2))
+ {
+ break;
+ }
+ set.add(fqn.getLastElement());
+ }
+
+ if (set.isEmpty())
+ {
+ return null;
+ }
+
+ return Collections.unmodifiableSet(set);
+ }
+
+ @Override
+ public Map get(Fqn name)
+ throws Exception
+ {
+ checkOpen();
+ checkNonNull(name, "name");
+
+ return (Map) tree.find(withDepth(name));
+ }
+
+ @Override
+ public boolean exists(Fqn name) throws IOException
+ {
+ return tree.find(withDepth(name)) != null;
+ }
+
+ @Override
+ Object put0(Fqn name, Object key, Object value) throws Exception
+ {
+ checkNonNull(name, "name");
+ ensureParent(name);
+ Fqn dname = withDepth(name);
+ Map map = (Map) tree.find(dname);
+ Object oldValue = null;
+ if (map != null) {
+ oldValue = map.put(key, value);
+ tree.insert(dname, map, true);
+ } else {
+ map = new HashMap();
+ map.put(key, value);
+ tree.insert(dname, map, false);
+ }
+ return oldValue;
+ }
+
+ @Override
+ void put0(Fqn name, Map<?, ?> values) throws IOException
+ {
+ if (trace)
+ {
+ log.trace("put " + name + " values=" + values);
+ }
+ ensureParent(name);
+ Fqn dname = withDepth(name);
+ if (values == null)
+ values = emptyMap();
+ else
+ values = new HashMap(values);
+ tree.insert(dname, values, true);
+ }
+
+ private Map emptyMap() {
+ return new HashMap(0);
+ }
+
+ /**
+ * Ensures a parent node exists.
+ * Calls recursively to initialize parents as necessary.
+ */
+ private void ensureParent(Fqn name) throws IOException
+ {
+ if (name.size() <= 1)
+ return;
+ Fqn parent = name.getParent();
+ if (parents.contains(parent))
+ return;
+ if (!exists(parent))
+ put0(parent, emptyMap());
+ parents.add(parent);
+ if (parents.size() > PARENT_CACHE_SIZE)
+ {
+ parents.clear();
+ }
+ }
+
+ @Override
+ void erase0(Fqn name, boolean prune)
+ throws IOException
+ {
+ if (trace)
+ {
+ log.trace("erase " + name + " prune=" + prune);
+ }
+ if (!prune) {
+ put0(name, emptyMap());
+ return;
+ }
+ Set children = getChildrenNames(name);
+ if (children != null)
+ {
+ log.trace("remove children: " + children);
+ for (Object child : children)
+ {
+ erase0(Fqn.fromRelativeElements(name, child), true);
+ }
+ }
+ parents.remove(name);
+ try
+ {
+ tree.remove(withDepth(name));
+ }
+ catch (IllegalArgumentException e)
+ {
+ log.trace("remove non-existant key? " + e);
+ }
+ }
+
+ @Override
+ Object eraseKey0(Fqn name, Object key)
+ throws IOException
+ {
+ Fqn dname = withDepth(name);
+ Map map = (Map) tree.find(dname);
+ Object oldValue = null;
+ if (map != null) {
+ oldValue = map.remove(key);
+ tree.insert(dname, map, true);
+ }
+ return oldValue;
+ }
+
+}
Added: core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2Config.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2Config.java
(rev 0)
+++
core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoader2Config.java 2008-12-06
00:27:51 UTC (rev 7256)
@@ -0,0 +1,58 @@
+/*
+ * 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.loader.jdbm;
+
+import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
+
+/**
+ * Configuration for {@link JdbmCacheLoader2}.
+ *
+ * @author Elias Ross
+ */
+public class JdbmCacheLoader2Config extends JdbmCacheLoaderConfig
+{
+
+ private static final long serialVersionUID = 8905490360516820352L;
+
+ /**
+ * Constructs a new JdbmCacheLoader2Config.
+ */
+ public JdbmCacheLoader2Config()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new JdbmCacheLoader2Config.
+ */
+ public JdbmCacheLoader2Config(IndividualCacheLoaderConfig base)
+ {
+ super(base);
+ }
+
+ @Override
+ void setClassName()
+ {
+ setClassName(JdbmCacheLoader2.class.getName());
+ }
+
+}
\ No newline at end of file
Modified: core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoaderConfig.java
===================================================================
---
core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoaderConfig.java 2008-12-06
00:03:37 UTC (rev 7255)
+++
core/trunk/src/main/java/org/jboss/cache/loader/jdbm/JdbmCacheLoaderConfig.java 2008-12-06
00:27:51 UTC (rev 7256)
@@ -31,9 +31,14 @@
private static final long serialVersionUID = 4626734068542420865L;
private String location;
-
+
public JdbmCacheLoaderConfig()
{
+ setClassName();
+ }
+
+ void setClassName()
+ {
setClassName(JdbmCacheLoader.class.getName());
}
@@ -44,7 +49,7 @@
*/
JdbmCacheLoaderConfig(IndividualCacheLoaderConfig base)
{
- setClassName(JdbmCacheLoader.class.getName());
+ setClassName();
populateFromBaseConfig(base);
}
Added: core/trunk/src/test/java/org/jboss/cache/loader/JdbmCacheLoader2Test.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/loader/JdbmCacheLoader2Test.java
(rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/loader/JdbmCacheLoader2Test.java 2008-12-06
00:27:51 UTC (rev 7256)
@@ -0,0 +1,38 @@
+package org.jboss.cache.loader;
+
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.Test;
+
+/**
+ * Tests {@link org.jboss.cache.loader.jdbm.JdbmCacheLoader2}.
+ *
+ * @author Elias Ross
+ * @version $Id: JdbmCacheLoaderTest.java 6905 2008-10-13 09:35:27Z dpospisi(a)redhat.com
$
+ */
+@Test (groups = {"functional"})
+public class JdbmCacheLoader2Test extends CacheLoaderTestsBase
+{
+ @Override
+ protected void configureCache() throws Exception
+ {
+ CacheSPI<Object, Object> cache = cacheTL.get();
+ String tmpDir = System.getProperty("java.io.tmpdir", "/tmp");
+ String threadId = Thread.currentThread().getName();
+ String tmpCLLoc = tmpDir + "/JBossCache-JdbmCacheLoader2Test-" +
threadId;
+
cache.getConfiguration().setCacheLoaderConfig(getSingleCacheLoaderConfig("",
"org.jboss.cache.loader.jdbm.JdbmCacheLoader",
+ "location=" + tmpCLLoc, false, true, false));
+ TestingUtil.recursiveFileRemove(tmpCLLoc);
+ }
+
+ @Override
+ public void testCacheLoaderThreadSafety() throws Exception
+ {
+ }
+
+ @Override
+ public void testCacheLoaderThreadSafetyMultipleFqns() throws Exception
+ {
+ }
+
+}