JBoss Cache SVN: r6471 - in core/trunk/src: test/java/org/jboss/cache/util and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 11:55:10 -0400 (Thu, 31 Jul 2008)
New Revision: 6471
Added:
core/trunk/src/main/java/org/jboss/cache/util/Caches.java
core/trunk/src/test/java/org/jboss/cache/util/CachesTest.java
Log:
Preliminary support for JBCACHE-941
Added: core/trunk/src/main/java/org/jboss/cache/util/Caches.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/Caches.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/Caches.java 2008-07-31 15:55:10 UTC (rev 6471)
@@ -0,0 +1,816 @@
+package org.jboss.cache.util;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.cache.loader.CacheLoader;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Adaptors for {@link Cache} classes, such as {@link Node}.
+ * This is useful for integration of JBoss Cache into existing applications.
+ * <p/>
+ * Example use:
+ * <pre>
+ * Cache c = ...;
+ * Map m = Caches.asMap(c);
+ * m.put("a", "b"); // null
+ * m.containsKey("a"); // true
+ * m.remove("a"); // "b"
+ * </pre>
+ */
+public class Caches
+{
+
+ private Caches()
+ {
+ }
+
+ /**
+ * Returns a {@link Map} from the root node.
+ *
+ * @see #asMap(Node)
+ */
+ public static Map asMap(Cache cache)
+ {
+ if (cache == null)
+ throw new NullPointerException("cache");
+ return asMap(cache.getRoot());
+ }
+
+ /**
+ * Returns a {@link Map}, where map keys are named children of the given Node,
+ * and values are kept under a single key for this node.
+ * The map may be safely concurrently modified through this Map or externally,
+ * and its contents reflect the cache state and
+ * existing data of the Node.
+ * This means that {@link ConcurrentModificationException} is never thrown
+ * and all methods are thread safe.
+ * <p/>
+ * The map is not serializable.
+ * <p/>
+ * Usage note: As a single node is used for every key, it is most efficient to store
+ * data for a single entity (e.g. Person) in a single object.
+ * <p/>
+ * Also, when using a {@link CacheLoader} for storage, keys used must be valid as
+ * part of the {@link Fqn} used in calls. Generally speaking, simple string values are
+ * preferred.
+ */
+ public static Map asMap(Node node)
+ {
+ return new MapNode(node);
+ }
+
+ /**
+ * Returns a {@link Map}, where map data is put and returned directly from a single Node.
+ * This method is "simple" as data is kept under a single node.
+ * Note that storing all data in a single Node can be inefficient when using persistence,
+ * replication, or transactions.
+ * The map may be safely concurrently modified through this Map or externally.
+ * This means that {@link ConcurrentModificationException} is never thrown
+ * and all methods are thread safe.
+ * <p/>
+ * The methods {@link Map#entrySet} and {@link Map#values} and {@link Map#keySet}
+ * do not allow for modification of the Node.
+ * Further all these methods return a collection which is a snapshot (copy)
+ * of the data at time of calling. This may be very inefficient.
+ * <p/>
+ * The map is not serializable.
+ */
+ public static Map asSimpleMap(Node node)
+ {
+ return new SimpleMapNode(node);
+ }
+
+ /**
+ * Returns a {@link Set}, where set entries are data entries of the given Node.
+ * This method is "simple" as data is kept under a single node.
+ * <p/>
+ * Note that storing all data in a single Node can be inefficient when using persistence,
+ * replication, or transactions.
+ * The set may be safely concurrently modified through this Map or externally.
+ * This means that {@link ConcurrentModificationException} is never thrown
+ * and all methods are thread safe.
+ * <p/>
+ * The set is not serializable.
+ */
+ public static Set asSimpleSet(Node node)
+ {
+ return new SimpleSetNode(node);
+ }
+
+ /**
+ * Returns a {@link Map}, where map entries are partitioned into
+ * children nodes, within a cache node.
+ * The default child selector divides the data into 16 child nodes based on hash code.
+ * Note that for large data sets, the number of child nodes should be increased.
+ *
+ * @param node node to cache under
+ */
+ public static Map asPartitionedMap(Node node)
+ {
+ return new PartitionedMapNode(node, HashKeySelector.DEFAULT);
+ }
+
+ /**
+ * Returns a {@link Map}, where map entries are partitioned
+ * into children, within a cache node, by key hash code.
+ * <p/>
+ * The map is not serializable.
+ * <p/>
+ * Usage note: This is a performance (and size) compromise between {@link #asMap(Node)}
+ * and {@link #asSimpleMap(Node)}. For applications using a {@link org.jboss.cache.loader.CacheLoader},
+ * {@link #asMap(Node)} is a better choice.
+ * <p/>
+ *
+ * @param node node to cache under
+ * @param ss selector strategy that chooses a segment based on key
+ */
+ public static Map asPartitionedMap(Node node, ChildSelector ss)
+ {
+ return new PartitionedMapNode(node, ss);
+ }
+
+ /**
+ * Returns a {@link Map}, where map entries are partitioned into child nodes,
+ * within the cache root, by key hash code.
+ *
+ * @param cache cache to use
+ * @return
+ */
+ public static Map asPartitionedMap(Cache cache)
+ {
+ return asPartitionedMap(cache.getRoot());
+ }
+
+ /**
+ * Returns a segment ({@link Node#getChild(Object) child node name})
+ * to use based on the characteristics of a key.
+ * <p/>
+ * Here is an example class which selects a child based on a person's department:
+ * <pre>
+ * public static class DepartmentSelector implements ChildSelector<Person>
+ * {
+ * <p/>
+ * public Object childName(Person key)
+ * {
+ * return key.getDepartment();
+ * }
+ * <p/>
+ * }
+ * </pre>
+ *
+ * @
+ */
+ public interface ChildSelector<T>
+ {
+ /**
+ * Returns a child node name for a key.
+ *
+ * @param key for calls to {@link Map#put}, {@link Map#get} etc.
+ * @return node name
+ */
+ Object childName(T key);
+ }
+
+ /**
+ * Class that returns a child name to use based on the hash code of a key.
+ */
+ public static class HashKeySelector implements ChildSelector
+ {
+
+ static ChildSelector DEFAULT = new HashKeySelector(16);
+
+ protected int segments;
+
+ /**
+ * Constructs with N segments, where N must be a power of 2.
+ */
+ public HashKeySelector(int segments)
+ {
+ this.segments = segments;
+ if (Integer.bitCount(segments) != 1)
+ throw new IllegalArgumentException();
+ if (segments <= 0)
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Computes an improved hash code from an object's hash code.
+ */
+ protected int hashCode(int i)
+ {
+ i ^= i >>> 20 ^ i >>> 12;
+ return i ^ i >>> 7 ^ i >>> 4;
+ }
+
+ /**
+ * Returns the segment for this key, in the inclusive range 0 to {@link #segments} - 1.
+ */
+ protected int segmentFor(Object key)
+ {
+ if (key == null)
+ return 0;
+ int hc = key.hashCode();
+ return hashCode(hc) & (segments - 1);
+ }
+
+ /**
+ * Returns the node name for this segment.
+ */
+ protected Object childName(int segment)
+ {
+ return "" + segment;//IntegerCache.toString(segment);
+ }
+
+ /**
+ * Returns the node name for this key.
+ * By default, returns a String containing the segment.
+ */
+ public Object childName(Object key)
+ {
+ return childName(segmentFor(key));
+ }
+
+ public String toString()
+ {
+ return super.toString() + " segments=" + segments;
+ }
+
+ }
+
+ static class MapNode extends AbstractMap
+ {
+
+ public static final String KEY = "K";
+
+ private Node node;
+
+ public MapNode(Node node)
+ {
+ if (node == null)
+ throw new NullPointerException("node");
+ this.node = node;
+ }
+
+ @Override
+ public Set entrySet()
+ {
+ return new AbstractSet()
+ {
+
+ @Override
+ public Iterator iterator()
+ {
+ final Iterator<Node> i = set().iterator();
+ return new Iterator()
+ {
+
+ Object name;
+
+ boolean next = false;
+
+ public boolean hasNext()
+ {
+ return i.hasNext();
+ }
+
+ public Object next()
+ {
+ Node n = i.next();
+ this.name = n.getFqn().getLastElement();
+ this.next = true;
+ Object key = n.get(KEY);
+ return new SimpleEntry(name, key);
+ }
+
+ public void remove()
+ {
+ if (!next)
+ throw new IllegalStateException();
+ node.removeChild(name);
+ }
+
+ public String toString()
+ {
+ return "Itr name=" + name;
+ }
+
+ };
+ }
+
+ private Set<Node> set()
+ {
+ return node.getChildren();
+ }
+
+ @Override
+ public int size()
+ {
+ return set().size();
+ }
+
+ };
+ }
+
+ @Override
+ public void clear()
+ {
+ for (Object o : node.getChildrenNames())
+ node.removeChild(o);
+ }
+
+ @Override
+ public boolean containsKey(Object arg0)
+ {
+ return node.getChild(arg0) != null;
+ }
+
+ @Override
+ public Object get(Object arg0)
+ {
+ Node child = node.getChild(arg0);
+ if (child == null)
+ return null;
+ return child.get(KEY);
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return node.getChildrenNames().isEmpty();
+ }
+
+ @Override
+ public Set keySet()
+ {
+
+ return new AbstractSet()
+ {
+
+ private Set set()
+ {
+ return node.getChildrenNames();
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ final Iterator i = set().iterator();
+ return new Iterator()
+ {
+
+ Object child;
+
+ public boolean hasNext()
+ {
+ return i.hasNext();
+ }
+
+ public Object next()
+ {
+ child = i.next();
+ return child;
+ }
+
+ public void remove()
+ {
+ if (child == null)
+ throw new IllegalStateException();
+ node.removeChild(child);
+ // since set is read-only, invalidate
+ }
+
+ };
+ }
+
+ @Override
+ public boolean remove(Object key)
+ {
+ return node.removeChild(key);
+ }
+
+ @Override
+ public int size()
+ {
+ return set().size();
+ }
+
+ };
+
+ }
+
+ @Override
+ public Object put(Object arg0, Object arg1)
+ {
+ return node.addChild(Fqn.fromElements(arg0)).put(KEY, arg1);
+ }
+
+ @Override
+ public Object remove(Object arg0)
+ {
+ Node child = node.getChild(arg0);
+ if (child == null)
+ return null;
+ Object o = child.remove(KEY);
+ node.removeChild(arg0);
+ return o;
+ }
+
+ @Override
+ public int size()
+ {
+ return node.getChildrenNames().size();
+ }
+
+ }
+
+ static class SimpleMapNode extends AbstractMap implements java.util.Map
+ {
+
+ private Node node;
+
+ public SimpleMapNode(Node node)
+ {
+ if (node == null)
+ throw new NullPointerException("node");
+ this.node = node;
+ }
+
+ @Override
+ public void clear()
+ {
+ node.clearData();
+ }
+
+ @Override
+ public boolean containsKey(Object key)
+ {
+ return node.getKeys().contains(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value)
+ {
+ return node.getData().containsValue(value);
+ }
+
+ /**
+ * getData returns a snapshot of the data.
+ */
+ public Set entrySet()
+ {
+ return node.getData().entrySet();
+ }
+
+ @Override
+ public Object get(Object key)
+ {
+ return node.get(key);
+ }
+
+ @Override
+ public Set keySet()
+ {
+ return node.getKeys();
+ }
+
+ @Override
+ public Object put(Object key, Object value)
+ {
+ return node.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map map)
+ {
+ node.putAll(map);
+ }
+
+ @Override
+ public Object remove(Object key)
+ {
+ return node.remove(key);
+ }
+
+ @Override
+ public int size()
+ {
+ return node.dataSize();
+ }
+
+ }
+
+ static class SimpleSetNode extends AbstractSet implements java.util.Set
+ {
+
+ private Node node;
+
+ private static final String VALUE = "V";
+
+ public SimpleSetNode(Node node)
+ {
+ if (node == null)
+ throw new NullPointerException("node");
+ this.node = node;
+ }
+
+ @Override
+ public void clear()
+ {
+ node.clearData();
+ }
+
+ @Override
+ public boolean contains(Object key)
+ {
+ return node.getKeys().contains(key);
+ }
+
+ @Override
+ public boolean remove(Object key)
+ {
+ return node.remove(key) != null;
+ }
+
+ @Override
+ public int size()
+ {
+ return node.dataSize();
+ }
+
+ @Override
+ public boolean add(Object arg0)
+ {
+ return node.put(arg0, VALUE) == null;
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ final Iterator i = node.getKeys().iterator();
+ return new Iterator()
+ {
+ Object key;
+
+ boolean next = false;
+
+ public boolean hasNext()
+ {
+ return i.hasNext();
+ }
+
+ public Object next()
+ {
+ key = i.next();
+ next = true;
+ return key;
+ }
+
+ public void remove()
+ {
+ if (!next)
+ throw new IllegalStateException();
+ node.remove(key);
+ }
+
+ };
+ }
+
+ }
+
+ static class PartitionedMapNode extends AbstractMap
+ {
+
+ private Node node;
+
+ private ChildSelector selector;
+
+ public PartitionedMapNode(Node node, ChildSelector selector)
+ {
+ this.node = node;
+ this.selector = selector;
+ }
+
+ @Override
+ public Set entrySet()
+ {
+ return new AbstractSet<Map.Entry>()
+ {
+
+ Iterator<Node> ci = node.getChildren().iterator();
+
+ @Override
+ public Iterator<Entry> iterator()
+ {
+ return new Iterator<Entry>()
+ {
+
+ Iterator ni;
+
+ {
+ nextChild();
+ findNext();
+ }
+
+ private void nextChild()
+ {
+ ni = new SimpleMapNode(ci.next()).entrySet().iterator();
+ }
+
+ private void findNext()
+ {
+ while (!ni.hasNext())
+ {
+ if (!ci.hasNext())
+ return;
+ nextChild();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return ni.hasNext();
+ }
+
+ public Entry next()
+ {
+ Entry n = (Entry) ni.next();
+ findNext();
+ return n;
+ }
+
+ public void remove()
+ {
+ ni.remove();
+ }
+
+ };
+ }
+
+ @Override
+ public int size()
+ {
+ return PartitionedMapNode.this.size();
+ }
+
+ };
+ }
+
+ @Override
+ public Set keySet()
+ {
+ return new AbstractSet<Map.Entry>()
+ {
+
+ @Override
+ public Iterator<Entry> iterator()
+ {
+ return PartitionedMapNode.super.keySet().iterator();
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ boolean key = PartitionedMapNode.this.containsKey(o);
+ PartitionedMapNode.this.remove(o);
+ return key;
+ }
+
+ @Override
+ public boolean contains(Object o)
+ {
+ return PartitionedMapNode.this.containsKey(o);
+ }
+
+ @Override
+ public int size()
+ {
+ return PartitionedMapNode.super.keySet().size();
+ }
+
+ };
+ }
+
+ @Override
+ public void clear()
+ {
+ for (Object o : node.getChildrenNames())
+ node.getChild(o).clearData();
+ }
+
+ private Node nodeFor(Object o)
+ {
+ return node.getChild(selector.childName(o));
+ }
+
+ @Override
+ public boolean containsKey(Object o)
+ {
+ Node n = nodeFor(o);
+ if (n == null) return false;
+ return n.getKeys().contains(o);
+ }
+
+ @Override
+ public Object get(Object o)
+ {
+ Node n = nodeFor(o);
+ if (n == null) return null;
+ return n.get(o);
+ }
+
+ public Object put(Object key, Object value)
+ {
+ Object name = selector.childName(key);
+ Node n = node.getChild(name);
+ if (n == null)
+ n = node.addChild(Fqn.fromElements(name));
+ return n.put(key, value);
+ }
+
+ public Object remove(Object o)
+ {
+ Node n = nodeFor(o);
+ return n.remove(o);
+ }
+
+ public int size()
+ {
+ int size = 0;
+ for (Object o : node.getChildrenNames())
+ {
+ Node child = node.getChild(o);
+ size += child.dataSize();
+ }
+ return size;
+ }
+
+ }
+
+ public static class SimpleEntry<K, V> implements Entry<K, V>
+ {
+ K key;
+ V value;
+
+ public SimpleEntry(K key, V value)
+ {
+ this.key = key;
+ this.value = value;
+ }
+
+ public SimpleEntry(Entry<K, V> e)
+ {
+ this.key = e.getKey();
+ this.value = e.getValue();
+ }
+
+ public K getKey()
+ {
+ return key;
+ }
+
+ public V getValue()
+ {
+ return value;
+ }
+
+ public V setValue(V value)
+ {
+ V oldValue = this.value;
+ this.value = value;
+ return oldValue;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof Map.Entry))
+ return false;
+ Map.Entry e = (Map.Entry) o;
+ return eq(key, e.getKey()) && eq(value, e.getValue());
+ }
+
+ public int hashCode()
+ {
+ return ((key == null) ? 0 : key.hashCode()) ^
+ ((value == null) ? 0 : value.hashCode());
+ }
+
+ public String toString()
+ {
+ return key + "=" + value;
+ }
+
+ private static boolean eq(Object o1, Object o2)
+ {
+ return (o1 == null ? o2 == null : o1.equals(o2));
+ }
+ }
+}
Added: core/trunk/src/test/java/org/jboss/cache/util/CachesTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/util/CachesTest.java (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/util/CachesTest.java 2008-07-31 15:55:10 UTC (rev 6471)
@@ -0,0 +1,212 @@
+package org.jboss.cache.util;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.Node;
+import org.jboss.cache.util.Caches.ChildSelector;
+import org.jboss.cache.util.Caches.SimpleEntry;
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests {@link Caches}.
+ */
+@Test(groups = "functional")
+public class CachesTest
+{
+ String a = "a";
+
+ String b = "b";
+
+ String c = "c";
+
+ Cache<Object, Object> cache = new DefaultCacheFactory<Object, Object>().createCache();
+
+ public void testSegment()
+ {
+ Map<Object, Object> m = Caches.asPartitionedMap(cache);
+ // m.put(a, b);
+ testMap(m);
+ m.clear();
+ int c = 100;
+ for (int i = 0; i < c; i++)
+ {
+ m.put(Integer.toHexString(i), "foo " + i);
+ }
+ for (int i = 0; i < c; i++)
+ {
+ assertEquals("foo " + i, m.get(Integer.toHexString(i)));
+ }
+ System.out.println(CachePrinter.printCacheDetails(cache));
+ }
+
+ public void testAsMap()
+ {
+ Map<Object, Object> m = Caches.asMap(cache);
+ testMap(m);
+ for (Node n : cache.getRoot().getChildren())
+ {
+ assertEquals("/a", n.getFqn().toString());
+ assertEquals(c, n.get("K"));
+ }
+ m.clear();
+
+ m.put(a, a);
+ testCollectionRemove(m.keySet());
+ m.put(a, a);
+ testCollectionRemove(m.values());
+ m.put(a, a);
+ testCollectionRemove(m.entrySet());
+ }
+
+ private void testCollectionRemove(Collection c)
+ {
+ Iterator i;
+ i = c.iterator();
+ assertEquals(true, i.hasNext());
+ try
+ {
+ i.remove();
+ fail("no next");
+ }
+ catch (IllegalStateException e)
+ {
+ }
+ i.next();
+ i.remove();
+ assertEquals(false, i.hasNext());
+ assertEquals("C " + c, 0, c.size());
+ }
+
+ public void testAsSimpleSet()
+ {
+ Set s = Caches.asSimpleSet(cache.getRoot());
+ testSet(s);
+ }
+
+ private void testSet(Set s)
+ {
+ assertEquals(0, s.size());
+ assertEquals(true, s.add(a));
+ assertEquals(false, s.add(a));
+ assertEquals(1, s.size());
+ assertEquals("[a]", s.toString());
+ assertEquals(true, s.contains(a));
+ assertEquals(true, s.remove(a));
+ assertEquals(false, s.remove(a));
+ assertEquals(false, s.contains(a));
+ s.add(b);
+ s.clear();
+ assertEquals(false, s.contains(b));
+ s.add(c);
+ Iterator i = s.iterator();
+ s.add(a);
+ s.remove(a); // stable iterator
+ assertTrue(i.hasNext());
+ assertEquals(c, i.next());
+ i.remove();
+ assertEquals(false, i.hasNext());
+ assertEquals(0, s.size());
+ assertEquals(true, s.isEmpty());
+ }
+
+ private void testMap(Map m)
+ {
+ assertEquals(null, m.put(a, b));
+ assertEquals(b, m.put(a, c));
+ assertEquals("{a=c}", m.toString());
+ assertEquals(1, m.size());
+ assertEquals("a", m.keySet().iterator().next());
+ assertEquals(true, m.containsKey(a));
+ assertEquals(true, m.containsValue(c));
+ assertEquals(false, m.containsValue(b));
+ assertEquals(c, m.remove(a));
+ assertEquals(null, m.remove(a));
+ assertEquals(0, m.size());
+ assertEquals(false, m.keySet().iterator().hasNext());
+ m.put(c, a);
+ assertEquals(1, m.keySet().size());
+ assertEquals(1, m.entrySet().size());
+ assertEquals(1, m.values().size());
+ Iterator i = m.keySet().iterator();
+ m.put(b, b);
+ m.remove(b); // stable iterator
+ assertEquals(true, i.hasNext());
+ assertEquals(c, i.next());
+ assertEquals(false, i.hasNext());
+
+ assertEquals(true, m.keySet().contains(c));
+ assertEquals(true, m.entrySet().contains(new SimpleEntry(c, a)));
+ assertEquals(true, m.values().contains(a));
+ assertEquals(false, m.keySet().contains(a));
+ assertEquals(false, m.entrySet().contains(new SimpleEntry(a, c)));
+ assertEquals(false, m.values().contains(c));
+ assertEquals(false, m.isEmpty());
+ m.clear();
+ assertEquals(0, m.size());
+ m.put(a, a);
+ m.clear();
+ assertEquals(0, m.size());
+ assertEquals(true, m.isEmpty());
+ }
+
+ public void testAsSimpleMap()
+ {
+ Map m = Caches.asSimpleMap(cache.getRoot());
+ testMap(m);
+ }
+
+ public void testSelector()
+ {
+ Map m = Caches.asPartitionedMap(cache.getRoot(), new DepartmentSelector());
+ Person f = new Person("Fred", a);
+ Person g = new Person("George", b);
+ Person h = new Person("Harry", b);
+ // associate person with a number
+ m.put(f, 42);
+ m.put(g, 69);
+ m.put(h, 21);
+ assertEquals(42, m.get(f));
+ assertEquals(69, m.get(g));
+ System.out.println(CachePrinter.printCacheDetails(cache));
+ }
+
+ public static class Person
+ {
+ String name;
+
+ String department;
+
+ public Person(String name, String department)
+ {
+ super();
+ this.name = name;
+ this.department = department;
+ }
+
+ public String getDepartment()
+ {
+ return department;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+ }
+
+ public static class DepartmentSelector implements ChildSelector<Person>
+ {
+
+ public Object childName(Person key)
+ {
+ return key.getDepartment();
+ }
+
+ }
+}
16 years, 5 months
JBoss Cache SVN: r6470 - core/trunk/src/main/java/org/jboss/cache.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 11:51:47 -0400 (Thu, 31 Jul 2008)
New Revision: 6470
Modified:
core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
Log:
Unnecessary volatile flag
Modified: core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNode.java 2008-07-31 15:37:28 UTC (rev 6469)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNode.java 2008-07-31 15:51:47 UTC (rev 6470)
@@ -21,7 +21,7 @@
*/
public abstract class AbstractNode<K, V>
{
- protected volatile ConcurrentMap children; // purposefully NOT genericized yet, since UnversionedNode and PessimisticUnversionedNode will both store different types.
+ protected ConcurrentMap children; // purposefully NOT genericized yet, since UnversionedNode and PessimisticUnversionedNode will both store different types.
protected Fqn fqn;
/**
16 years, 5 months
JBoss Cache SVN: r6469 - in core/trunk/src/main/java/org/jboss/cache: transaction and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 11:37:28 -0400 (Thu, 31 Jul 2008)
New Revision: 6469
Modified:
core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
core/trunk/src/main/java/org/jboss/cache/invocation/MVCCInvocationContext.java
core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java
Log:
Better tuned collections
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-31 15:22:36 UTC (rev 6468)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-31 15:37:28 UTC (rev 6469)
@@ -131,7 +131,7 @@
else
{
// no need to worry about concurrency here - a context is only valid for a single thread.
- if (invocationLocks == null) invocationLocks = new LinkedHashSet(5);
+ if (invocationLocks == null) invocationLocks = new LinkedHashSet(4);
invocationLocks.addAll(locks);
}
}
@@ -147,7 +147,7 @@
else
{
// no need to worry about concurrency here - a context is only valid for a single thread.
- if (invocationLocks == null) invocationLocks = new LinkedHashSet(5);
+ if (invocationLocks == null) invocationLocks = new LinkedHashSet(4);
invocationLocks.add(lock);
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/MVCCInvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/MVCCInvocationContext.java 2008-07-31 15:22:36 UTC (rev 6468)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/MVCCInvocationContext.java 2008-07-31 15:37:28 UTC (rev 6469)
@@ -16,7 +16,7 @@
*/
public class MVCCInvocationContext extends AbstractInvocationContext
{
- private final Map<Fqn, NodeSPI> lookedUpNodes = new HashMap<Fqn, NodeSPI>();
+ private final Map<Fqn, NodeSPI> lookedUpNodes = new HashMap<Fqn, NodeSPI>(4);
private MVCCTransactionContext mvccTCtx;
@Override
Modified: core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java 2008-07-31 15:22:36 UTC (rev 6468)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java 2008-07-31 15:37:28 UTC (rev 6469)
@@ -17,7 +17,7 @@
*/
public class MVCCTransactionContext extends AbstractTransactionContext
{
- private final Map<Fqn, NodeSPI> lookedUpNodes = new HashMap<Fqn, NodeSPI>();
+ private final Map<Fqn, NodeSPI> lookedUpNodes = new HashMap<Fqn, NodeSPI>(8);
public MVCCTransactionContext(Transaction tx) throws SystemException, RollbackException
{
16 years, 5 months
JBoss Cache SVN: r6468 - in core/tags/2.2.0.CR7: src/main/java/org/jboss/cache and 1 other directory.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 11:22:36 -0400 (Thu, 31 Jul 2008)
New Revision: 6468
Modified:
core/tags/2.2.0.CR7/pom.xml
core/tags/2.2.0.CR7/src/main/java/org/jboss/cache/Version.java
Log:
Updated versions
Modified: core/tags/2.2.0.CR7/pom.xml
===================================================================
--- core/tags/2.2.0.CR7/pom.xml 2008-07-31 15:20:20 UTC (rev 6467)
+++ core/tags/2.2.0.CR7/pom.xml 2008-07-31 15:22:36 UTC (rev 6468)
@@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
- <jbosscache-core-version>2.2.0-SNAPSHOT</jbosscache-core-version>
+ <jbosscache-core-version>2.2.0.CR7</jbosscache-core-version>
<!-- By default only run tests in the "unit" group -->
<defaultTestGroup>unit</defaultTestGroup>
<!-- By default only generate Javadocs when we install the module. -->
@@ -412,7 +412,7 @@
<activeByDefault>false</activeByDefault>
</activation>
<properties>
- <jbosscache-core-version>2.2.0-SNAPSHOT-JBossAS</jbosscache-core-version>
+ <jbosscache-core-version>2.2.0.CR7-JBossAS</jbosscache-core-version>
<defaultTestGroup>functional,unit</defaultTestGroup>
</properties>
<dependencies>
Modified: core/tags/2.2.0.CR7/src/main/java/org/jboss/cache/Version.java
===================================================================
--- core/tags/2.2.0.CR7/src/main/java/org/jboss/cache/Version.java 2008-07-31 15:20:20 UTC (rev 6467)
+++ core/tags/2.2.0.CR7/src/main/java/org/jboss/cache/Version.java 2008-07-31 15:22:36 UTC (rev 6468)
@@ -11,10 +11,10 @@
@Immutable
public class Version
{
- public static final String version = "2.2.0-SNAPSHOT";
+ public static final String version = "2.2.0.CR7";
public static final String codename = "Poblano";
//public static final String cvs = "$Id: Version.java 4592 2007-10-10 16:44:36Z manik.surtani(a)jboss.com $";
- static final byte[] version_id = {'0', '2', '2', '0', 'S'};
+ static final byte[] version_id = {'0', '2', '2', '0', 'C', '7'};
private static final int MAJOR_SHIFT = 11;
private static final int MINOR_SHIFT = 6;
16 years, 5 months
JBoss Cache SVN: r6467 - core/tags.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 11:20:20 -0400 (Thu, 31 Jul 2008)
New Revision: 6467
Added:
core/tags/2.2.0.CR7/
Log:
Tagging CR7
Copied: core/tags/2.2.0.CR7 (from rev 6466, core/branches/2.2.X)
16 years, 5 months
JBoss Cache SVN: r6466 - core/trunk/src/main/java/org/jboss/cache.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 11:18:30 -0400 (Thu, 31 Jul 2008)
New Revision: 6466
Modified:
core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
Log:
comments
Modified: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2008-07-31 15:01:05 UTC (rev 6465)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2008-07-31 15:18:30 UTC (rev 6466)
@@ -281,9 +281,6 @@
channel.setOpt(Channel.AUTO_GETSTATE, fetchState);
channel.setOpt(Channel.BLOCK, true);
- // always use the InactiveRegionAwareRpcDispatcher - exceptions due to regions not being active should not propagate to remote
- // nodes as errors. - Manik
- // but only if we are using region based marshalling?!??
if (configuration.isUseRegionBasedMarshalling())
{
rpcDispatcher = new InactiveRegionAwareRpcDispatcher(channel, messageListener, new MembershipListenerAdaptor(),
16 years, 5 months
JBoss Cache SVN: r6465 - core/trunk/src/main/java/org/jboss/cache/invocation.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 11:01:05 -0400 (Thu, 31 Jul 2008)
New Revision: 6465
Modified:
core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
Log:
Using a peek to keep legacy code happy
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java 2008-07-31 14:54:13 UTC (rev 6464)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java 2008-07-31 15:01:05 UTC (rev 6465)
@@ -35,6 +35,7 @@
import org.jboss.cache.config.Option;
import org.jboss.cache.factories.annotations.Inject;
import org.jboss.cache.factories.annotations.NonVolatile;
+import org.jboss.cache.factories.annotations.Start;
import org.jboss.cache.interceptors.base.CommandInterceptor;
import org.jboss.cache.loader.CacheLoaderManager;
import org.jboss.cache.marshall.Marshaller;
@@ -78,6 +79,7 @@
private DataContainer dataContainer;
private CommandsFactory commandsFactory;
private MVCCNodeHelper mvccHelper;
+ private boolean usingMvcc;
@Inject
public void initialize(StateTransferManager stateTransferManager, CacheLoaderManager cacheLoaderManager, Notifier notifier,
@@ -99,8 +101,15 @@
this.mvccHelper = mvccHelper;
}
+ @Start
+ private void setNodeLockingScheme()
+ {
+ usingMvcc = configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC;
+ }
+
private void reset()
{
+ this.usingMvcc = false;
this.stateTransferManager = null;
this.cacheLoaderManager = null;
this.transactionManager = null;
@@ -230,10 +239,17 @@
public boolean exists(Fqn fqn)
{
- InvocationContext ctx = invocationContextContainer.get();
- cacheStatusCheck(ctx);
- ExistsCommand command = commandsFactory.buildExistsNodeCommand(fqn);
- return (Boolean) invoker.invoke(ctx, command);
+ if (usingMvcc)
+ {
+ InvocationContext ctx = invocationContextContainer.get();
+ cacheStatusCheck(ctx);
+ ExistsCommand command = commandsFactory.buildExistsNodeCommand(fqn);
+ return (Boolean) invoker.invoke(ctx, command);
+ }
+ else
+ {
+ return peek(fqn, false) != null;
+ }
}
public Notifier getNotifier()
@@ -257,7 +273,7 @@
public NodeSPI<K, V> peek(Fqn fqn, boolean includeDeletedNodes, boolean includeInvalidNodes)
{
// TODO: clean this up somehow! Anyway, this method should NOT be used outside of testing frameworks.
- return (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+ return (usingMvcc)
? mvccPeek(fqn)
: (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes, includeInvalidNodes);
}
@@ -266,7 +282,7 @@
public NodeSPI<K, V> peek(Fqn fqn, boolean includeDeletedNodes)
{
// TODO: clean this up somehow! Anyway, this method should NOT be used outside of testing frameworks.
- return (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+ return (usingMvcc)
? mvccPeek(fqn)
: (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes);
}
16 years, 5 months
JBoss Cache SVN: r6464 - core/trunk/src/main/java/org/jboss/cache/invocation.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 10:54:13 -0400 (Thu, 31 Jul 2008)
New Revision: 6464
Modified:
core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
Log:
TODOs
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-31 14:52:03 UTC (rev 6463)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-31 14:54:13 UTC (rev 6464)
@@ -323,6 +323,7 @@
public long getLockAcquisitionTimeout(long timeout)
{
+ // TODO: this stuff really doesn't belong here. Put it somewhere else.
if (getOptionOverrides() != null
&& getOptionOverrides().getLockAcquisitionTimeout() >= 0)
{
@@ -347,11 +348,13 @@
public boolean isValidTransaction()
{
+ // ought to move to the transaction context
return transaction != null && TransactionTable.isValid(transaction);
}
public void throwIfNeeded(Throwable e) throws Throwable
{
+ // TODO: this stuff really doesn't belong here. Put it somewhere else.
Option optionOverride = getOptionOverrides();
boolean shouldRethtrow = optionOverride == null || !optionOverride.isFailSilently();
if (!shouldRethtrow)
16 years, 5 months
JBoss Cache SVN: r6463 - core/trunk/src/main/java/org/jboss/cache/transaction.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 10:52:03 -0400 (Thu, 31 Jul 2008)
New Revision: 6463
Added:
core/trunk/src/main/java/org/jboss/cache/transaction/AbstractTransactionContext.java
Log:
Refactored the way modification lists are managed in the transaction context
Added: core/trunk/src/main/java/org/jboss/cache/transaction/AbstractTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/AbstractTransactionContext.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/AbstractTransactionContext.java 2008-07-31 14:52:03 UTC (rev 6463)
@@ -0,0 +1,263 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache.transaction;
+
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.commands.WriteCommand;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
+import org.jboss.cache.util.ImmutableListCopy;
+
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * An abstract transaction context
+ */
+public abstract class AbstractTransactionContext implements TransactionContext
+{
+
+ /**
+ * Local transaction
+ */
+ private Transaction ltx = null;
+ private Option option;
+ private OrderedSynchronizationHandler orderedSynchronizationHandler;
+
+ private boolean forceAsyncReplication = false;
+ private boolean forceSyncReplication = false;
+
+ /**
+ * List<ReversibleCommand> of modifications ({@link org.jboss.cache.commands.WriteCommand}). They will be replicated on TX commit
+ */
+ private List<WriteCommand> modificationList;
+ /**
+ * A list of modifications that have been encountered with a LOCAL mode option. These will be removed from the modification list during replication.
+ */
+ private List<WriteCommand> localModifications;
+
+ /**
+ * LinkedHashSet of locks acquired by the transaction. We use a LinkedHashSet because we need efficient Set semantics
+ * but also need guaranteed ordering for use by lock release code (see JBCCACHE-874).
+ * <p/>
+ * This needs to be unchecked since we support both MVCC (Fqns held here) or legacy Opt/Pess locking (NodeLocks held here).
+ * once we drop support for opt/pess locks we can genericise this to contain Fqns. - Manik Surtani, June 2008
+ */
+ private LinkedHashSet transactionLocks;
+
+ /**
+ * A list of dummy uninitialised nodes created by the cache loader interceptor to load data for a
+ * given node in this tx.
+ */
+ private List<Fqn> dummyNodesCreatedByCacheLoader;
+
+ /**
+ * List<Fqn> of nodes that have been removed by the transaction
+ */
+ private List<Fqn> removedNodes = null;
+
+ public AbstractTransactionContext(Transaction tx) throws SystemException, RollbackException
+ {
+ ltx = tx;
+ orderedSynchronizationHandler = new OrderedSynchronizationHandler(tx);
+ }
+
+ public void addModification(WriteCommand command)
+ {
+ if (command == null) return;
+ if (modificationList == null) modificationList = new LinkedList<WriteCommand>();
+ modificationList.add(command);
+ }
+
+ public List<WriteCommand> getModifications()
+ {
+ if (modificationList == null) return Collections.emptyList();
+ return modificationList;
+ }
+
+ public void addLocalModification(WriteCommand command)
+ {
+ if (command == null) throw new NullPointerException("Command is null!");
+ if (localModifications == null) localModifications = new LinkedList<WriteCommand>();
+ localModifications.add(command);
+ }
+
+ public List<WriteCommand> getLocalModifications()
+ {
+ if (localModifications == null) return Collections.emptyList();
+ return localModifications;
+ }
+
+
+ public void addRemovedNode(Fqn fqn)
+ {
+ if (fqn == null) throw new NullPointerException("Fqn is null!");
+ if (removedNodes == null) removedNodes = new LinkedList<Fqn>();
+ removedNodes.add(fqn);
+ }
+
+ public List<Fqn> getRemovedNodes()
+ {
+ if (removedNodes == null) return Collections.emptyList();
+ return new ArrayList<Fqn>(removedNodes);
+ }
+
+ public void setTransaction(Transaction tx)
+ {
+ ltx = tx;
+ }
+
+ public Transaction getTransaction()
+ {
+ return ltx;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void addLock(Object lock)
+ {
+ // no need to worry about concurrency here - a context is only valid for a single thread.
+ if (transactionLocks == null) transactionLocks = new LinkedHashSet(5);
+ transactionLocks.add(lock);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void removeLock(Object lock)
+ {
+ // no need to worry about concurrency here - a context is only valid for a single thread.
+ if (transactionLocks != null) transactionLocks.remove(lock);
+ }
+
+ public void clearLocks()
+ {
+ if (transactionLocks != null) transactionLocks.clear();
+ }
+
+ public boolean hasLock(Object lock)
+ {
+ return transactionLocks != null && transactionLocks.contains(lock);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void addAllLocks(List newLocks)
+ {
+ // no need to worry about concurrency here - a context is only valid for a single thread.
+ if (transactionLocks == null) transactionLocks = new LinkedHashSet(5);
+ transactionLocks.addAll(newLocks);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getLocks()
+ {
+ return transactionLocks == null || transactionLocks.isEmpty() ? Collections.emptyList() : new ImmutableListCopy(transactionLocks);
+ }
+
+
+ public boolean isForceAsyncReplication()
+ {
+ return forceAsyncReplication;
+ }
+
+ public void setForceAsyncReplication(boolean forceAsyncReplication)
+ {
+ this.forceAsyncReplication = forceAsyncReplication;
+ if (forceAsyncReplication)
+ {
+ forceSyncReplication = false;
+ }
+ }
+
+ public boolean isForceSyncReplication()
+ {
+ return forceSyncReplication;
+ }
+
+ public void setForceSyncReplication(boolean forceSyncReplication)
+ {
+ this.forceSyncReplication = forceSyncReplication;
+ if (forceSyncReplication)
+ {
+ forceAsyncReplication = false;
+ }
+ }
+
+ /**
+ * Returns debug information about this transaction.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("TransactionEntry\nmodificationList: ").append(modificationList);
+ return sb.toString();
+ }
+
+ public void addDummyNodeCreatedByCacheLoader(Fqn fqn)
+ {
+ if (dummyNodesCreatedByCacheLoader == null)
+ dummyNodesCreatedByCacheLoader = new LinkedList<Fqn>();
+ dummyNodesCreatedByCacheLoader.add(fqn);
+ }
+
+ public List<Fqn> getDummyNodesCreatedByCacheLoader()
+ {
+ if (dummyNodesCreatedByCacheLoader == null) return Collections.emptyList();
+ return dummyNodesCreatedByCacheLoader;
+ }
+
+ public void setOption(Option o)
+ {
+ this.option = o;
+ }
+
+ public Option getOption()
+ {
+ return this.option;
+ }
+
+ public OrderedSynchronizationHandler getOrderedSynchronizationHandler()
+ {
+ return orderedSynchronizationHandler;
+ }
+
+ public void setOrderedSynchronizationHandler(OrderedSynchronizationHandler orderedSynchronizationHandler)
+ {
+ this.orderedSynchronizationHandler = orderedSynchronizationHandler;
+ }
+
+ public boolean hasModifications()
+ {
+ return modificationList != null && !modificationList.isEmpty();
+ }
+
+ public boolean hasLocalModifications()
+ {
+ return localModifications != null && !localModifications.isEmpty();
+ }
+
+ public boolean hasAnyModifications()
+ {
+ return hasModifications() || hasLocalModifications();
+ }
+
+ public void reset()
+ {
+ orderedSynchronizationHandler = null;
+ modificationList = null;
+ localModifications = null;
+ option = null;
+ if (transactionLocks != null) transactionLocks.clear();
+ if (dummyNodesCreatedByCacheLoader != null) dummyNodesCreatedByCacheLoader.clear();
+ if (removedNodes != null) removedNodes.clear();
+ }
+}
16 years, 5 months
JBoss Cache SVN: r6462 - in core/trunk/src/main/java/org/jboss/cache: interceptors and 3 other directories.
by jbosscache-commits@lists.jboss.org
Author: manik.surtani(a)jboss.com
Date: 2008-07-31 10:50:35 -0400 (Thu, 31 Jul 2008)
New Revision: 6462
Modified:
core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/interceptors/BaseRpcInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java
core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java
core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
core/trunk/src/main/java/org/jboss/cache/invocation/InvocationContext.java
core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java
core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
core/trunk/src/main/java/org/jboss/cache/transaction/TransactionContext.java
Log:
Refactored the way modification lists are managed in the transaction context
Modified: core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -169,7 +169,7 @@
if (gtx != null)
{
CreateNodeCommand createNodeCommand = commandsFactory.buildCreateNodeCommand(childFqn);
- ctx.getTransactionContext().addModification(createNodeCommand);
+ ctx.getTransactionContext().addLocalModification(createNodeCommand);
}
if (notify) cache.getNotifier().notifyNodeCreated(childFqn, false, ctx);
}
Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -322,7 +322,7 @@
if (ctx.getTransactionContext() != null)
{
CreateNodeCommand createNodeCommand = commandsFactory.buildCreateNodeCommand(childFqn);
- ctx.getTransactionContext().addModification(createNodeCommand);
+ ctx.getTransactionContext().addLocalModification(createNodeCommand);
}
// notify if we actually created a new child
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/BaseRpcInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/BaseRpcInterceptor.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/BaseRpcInterceptor.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -162,7 +162,7 @@
protected boolean skipReplicationOfTransactionMethod(InvocationContext ctx)
{
GlobalTransaction gtx = ctx.getGlobalTransaction();
- return ctx.getTransaction() == null || gtx == null || gtx.isRemote() || ctx.getOptionOverrides().isCacheModeLocal() || !ctx.isTxHasMods();
+ return ctx.getTransaction() == null || gtx == null || gtx.isRemote() || ctx.getOptionOverrides().isCacheModeLocal() || !ctx.getTransactionContext().hasModifications();
}
/**
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -100,7 +100,7 @@
{
if (inTransaction())
{
- if (ctx.isTxHasMods())
+ if (ctx.getTransactionContext().hasAnyModifications())
{
// this is a commit call.
GlobalTransaction gtx = command.getGlobalTransaction();
@@ -154,7 +154,7 @@
if (inTransaction())
{
if (trace) log.trace("transactional so don't put stuff in the cloader yet.");
- if (ctx.isTxHasMods())
+ if (ctx.getTransactionContext().hasAnyModifications())
{
GlobalTransaction gtx = command.getGlobalTransaction();
// this is a rollback method
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -39,6 +39,7 @@
import org.jboss.cache.lock.LockUtil;
import org.jboss.cache.lock.PessimisticNodeBasedLockManager;
import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.transaction.PessimisticTransactionContext;
import org.jboss.cache.transaction.TransactionContext;
import java.util.ArrayList;
@@ -159,7 +160,7 @@
}
// 1. Revert the modifications by running the undo-op list in reverse. This *cannot* throw any exceptions !
- undoOperations(transactionContext);
+ undoOperations((PessimisticTransactionContext) transactionContext);
}
if (trace)
{
@@ -170,9 +171,9 @@
return retVal;
}
- private void undoOperations(TransactionContext transactionContext)
+ private void undoOperations(PessimisticTransactionContext transactionContext)
{
- List<WriteCommand> modificationList = transactionContext.getModifications();
+ List<WriteCommand> modificationList = transactionContext.getAllModifications();
if (modificationList.isEmpty())
{
Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -19,7 +19,6 @@
import org.jboss.cache.commands.tx.PrepareCommand;
import org.jboss.cache.commands.tx.RollbackCommand;
import org.jboss.cache.commands.write.ClearDataCommand;
-import org.jboss.cache.commands.write.CreateNodeCommand;
import org.jboss.cache.commands.write.InvalidateCommand;
import org.jboss.cache.commands.write.PutDataMapCommand;
import org.jboss.cache.commands.write.PutKeyValueCommand;
@@ -45,7 +44,6 @@
import javax.transaction.Transaction;
import java.util.Collections;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -560,8 +558,6 @@
*/
protected void runCommitPhase(InvocationContext ctx, GlobalTransaction gtx, List modifications, boolean onePhaseCommit)
{
- // set the hasMods flag in the invocation ctx. This should not be replicated, just used locally by the interceptors.
- ctx.setTxHasMods(modifications != null && modifications.size() > 0);
try
{
VisitableCommand commitCommand = onePhaseCommit ? buildPrepareCommand(gtx, modifications, true) : commandsFactory.buildCommitCommand(gtx);
@@ -603,12 +599,10 @@
/**
* creates a rollback()
*/
- protected void runRollbackPhase(InvocationContext ctx, GlobalTransaction gtx, Transaction tx, List<WriteCommand> modifications)
+ protected void runRollbackPhase(InvocationContext ctx, GlobalTransaction gtx, Transaction tx)
{
try
{
- ctx.setTxHasMods(modifications != null && modifications.size() > 0);
-
// JBCACHE-457
VisitableCommand rollbackCommand = commandsFactory.buildRollbackCommand(gtx);
if (trace) log.trace(" running rollback for " + gtx);
@@ -629,25 +623,6 @@
}
}
- /**
- * An optimisation of commands to be broadcast in a prepare call, which involves removing of unnecessary commands
- * as well as the "aggregation" of commands that can be aggregated.
- *
- * @param mods list of modifications
- * @return compacted list of modifications
- */
- private List<WriteCommand> compact(List<WriteCommand> mods)
- {
- // TODO: 3.0.0: Make this more sophisticated, so it aggregates multiple puts on the same node, puts followed by a remove, etc.
- // for now this just removes the redundant CreateNodeCommands from the list.
- List<WriteCommand> newList = new LinkedList<WriteCommand>();
- for (WriteCommand cmd : mods)
- {
- if (!(cmd instanceof CreateNodeCommand)) newList.add(cmd);
- }
- return newList;
- }
-
private boolean isOnePhaseCommit()
{
if (!configuration.getCacheMode().isSynchronous() && !optimistic)
@@ -680,8 +655,6 @@
{
VisitableCommand originalCommand = ctx.getCommand();
ctx.setCommand(prepareCommand);
- // set the hasMods flag in the invocation ctx. This should not be replicated, just used locally by the interceptors.
- ctx.setTxHasMods(modifications != null && modifications.size() > 0);
try
{
result = invokeNextInterceptor(ctx, prepareCommand);
@@ -976,7 +949,7 @@
case Status.STATUS_MARKED_ROLLBACK:
case Status.STATUS_ROLLEDBACK:
log.debug("Running rollback phase");
- runRollbackPhase(ctx, gtx, tx, modifications);
+ runRollbackPhase(ctx, gtx, tx);
log.debug("Finished rollback phase");
break;
@@ -1077,6 +1050,10 @@
modifications = Collections.emptyList();
return;
}
+ else
+ {
+ modifications = transactionContext.getModifications();
+ }
// set any transaction wide options as current for this thread, caching original options that would then be reset
originalOptions = ctx.getOptionOverrides();
@@ -1091,7 +1068,6 @@
case Status.STATUS_ACTIVE:
case Status.STATUS_PREPARING:
// run a prepare call.
- modifications = compact(modifications);
Object result = isOnePhaseCommit() ? null : runPreparePhase(ctx, gtx, modifications);
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -38,7 +38,6 @@
private Option optionOverrides;
// defaults to true.
private boolean originLocal = true;
- private boolean txHasMods;
private boolean localRollbackOnly;
@Deprecated
private MethodCall methodCall;
@@ -214,20 +213,9 @@
", transactionContext=" + transactionContext +
", optionOverrides=" + optionOverrides +
", originLocal=" + originLocal +
- ", txHasMods=" + txHasMods +
'}';
}
- public boolean isTxHasMods()
- {
- return txHasMods;
- }
-
- public void setTxHasMods(boolean b)
- {
- txHasMods = b;
- }
-
public boolean isLocalRollbackOnly()
{
return localRollbackOnly;
@@ -239,7 +227,6 @@
globalTransaction = null;
optionOverrides = null;
originLocal = true;
- txHasMods = false;
invocationLocks = null;
methodCall = null;
command = null;
@@ -256,7 +243,6 @@
copy.originLocal = originLocal;
copy.transaction = transaction;
copy.transactionContext = transactionContext;
- copy.txHasMods = txHasMods;
}
public void setState(InvocationContext template)
@@ -271,7 +257,6 @@
this.setOptionOverrides(template.getOptionOverrides());
this.setOriginLocal(template.isOriginLocal());
this.setTransaction(template.getTransaction());
- this.setTxHasMods(template.isTxHasMods());
}
@Override
@@ -284,7 +269,6 @@
if (localRollbackOnly != that.localRollbackOnly) return false;
if (originLocal != that.originLocal) return false;
- if (txHasMods != that.txHasMods) return false;
if (globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null)
{
return false;
@@ -306,7 +290,6 @@
result = 29 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
result = 29 * result + (optionOverrides != null ? optionOverrides.hashCode() : 0);
result = 29 * result + (originLocal ? 1 : 0);
- result = 29 * result + (txHasMods ? 1 : 0);
result = 29 * result + (localRollbackOnly ? 1 : 0);
return result;
}
Modified: core/trunk/src/main/java/org/jboss/cache/invocation/InvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/InvocationContext.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/InvocationContext.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -229,18 +229,6 @@
void setOriginLocal(boolean originLocal);
/**
- * @return true if the current transaction has any modifications, false otherwise.
- */
- boolean isTxHasMods();
-
- /**
- * Sets whether modifications have been detected on the current transaction.
- *
- * @param b flag to set
- */
- void setTxHasMods(boolean b);
-
- /**
* @return true if the current transaction is set to rollback only.
*/
boolean isLocalRollbackOnly();
@@ -324,6 +312,5 @@
* @param throwable throwable to throw
* @throws Throwable if allowed to throw one.
*/
- void throwIfNeeded(Throwable throwable
- ) throws Throwable;
+ void throwIfNeeded(Throwable throwable) throws Throwable;
}
Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -120,7 +120,7 @@
if ((tctx = ctx.getTransactionContext()) != null)
{
CreateNodeCommand createNodeCommand = commandsFactory.buildCreateNodeCommand(fqn);
- tctx.addModification(createNodeCommand);
+ tctx.addLocalModification(createNodeCommand);
}
// notify if we actually created a new child
Modified: core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/MVCCTransactionContext.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -15,7 +15,7 @@
* @author Manik Surtani (<a href="mailto:manik@jboss.org">manik(a)jboss.org</a>)
* @since 3.0
*/
-public class MVCCTransactionContext extends PessimisticTransactionContext
+public class MVCCTransactionContext extends AbstractTransactionContext
{
private final Map<Fqn, NodeSPI> lookedUpNodes = new HashMap<Fqn, NodeSPI>();
Modified: core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -7,20 +7,12 @@
package org.jboss.cache.transaction;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.Fqn;
import org.jboss.cache.commands.WriteCommand;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
-import org.jboss.cache.util.ImmutableListCopy;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
@@ -41,236 +33,43 @@
* @deprecated will be removed along with optimistic and pessimistic locking.
*/
@Deprecated
-public class PessimisticTransactionContext implements TransactionContext
+public class PessimisticTransactionContext extends AbstractTransactionContext
{
+ private List<WriteCommand> allModifications;
- private static final Log log = LogFactory.getLog(PessimisticTransactionContext.class);
-
- /**
- * Local transaction
- */
- private Transaction ltx = null;
- private Option option;
- private OrderedSynchronizationHandler orderedSynchronizationHandler;
-
- private boolean forceAsyncReplication = false;
- private boolean forceSyncReplication = false;
-
- /**
- * List<ReversibleCommand> of modifications ({@link org.jboss.cache.commands.WriteCommand}). They will be replicated on TX commit
- */
- private List<WriteCommand> modificationList;
- /**
- * A list of modifications that have been encountered with a LOCAL mode option. These will be removed from the modification list during replication.
- */
- private List<WriteCommand> localModifications;
-
- /**
- * LinkedHashSet of locks acquired by the transaction. We use a LinkedHashSet because we need efficient Set semantics
- * but also need guaranteed ordering for use by lock release code (see JBCCACHE-874).
- * <p/>
- * This needs to be unchecked since we support both MVCC (Fqns held here) or legacy Opt/Pess locking (NodeLocks held here).
- * once we drop support for opt/pess locks we can genericise this to contain Fqns. - Manik Surtani, June 2008
- */
- private LinkedHashSet transactionLocks;
-
- /**
- * A list of dummy uninitialised nodes created by the cache loader interceptor to load data for a
- * given node in this tx.
- */
- private List<Fqn> dummyNodesCreatedByCacheLoader;
-
- /**
- * List<Fqn> of nodes that have been removed by the transaction
- */
- private List<Fqn> removedNodes = null;
-
public PessimisticTransactionContext(Transaction tx) throws SystemException, RollbackException
{
- ltx = tx;
- orderedSynchronizationHandler = new OrderedSynchronizationHandler(tx);
+ super(tx);
}
- public void addModification(WriteCommand command)
+ @Override
+ public void addLocalModification(WriteCommand command)
{
if (command == null) return;
- if (modificationList == null) modificationList = new LinkedList<WriteCommand>();
- modificationList.add(command);
+ super.addLocalModification(command);
+ if (allModifications == null) allModifications = new LinkedList<WriteCommand>();
+ allModifications.add(command);
}
- public List<WriteCommand> getModifications()
- {
- if (modificationList == null) return Collections.emptyList();
- return modificationList;
- }
-
- public void addLocalModification(WriteCommand command)
- {
- if (command == null) throw new NullPointerException("Command is null!");
- if (localModifications == null) localModifications = new LinkedList<WriteCommand>();
- localModifications.add(command);
- }
-
- public List<WriteCommand> getLocalModifications()
- {
- if (localModifications == null) return Collections.emptyList();
- return localModifications;
- }
-
-
- public void addRemovedNode(Fqn fqn)
- {
- if (fqn == null) throw new NullPointerException("Fqn is null!");
- if (removedNodes == null) removedNodes = new LinkedList<Fqn>();
- removedNodes.add(fqn);
- }
-
- public List<Fqn> getRemovedNodes()
- {
- if (removedNodes == null) return Collections.emptyList();
- return new ArrayList<Fqn>(removedNodes);
- }
-
- public void setTransaction(Transaction tx)
- {
- ltx = tx;
- }
-
- public Transaction getTransaction()
- {
- return ltx;
- }
-
- @SuppressWarnings("unchecked")
- public void addLock(Object lock)
- {
- // no need to worry about concurrency here - a context is only valid for a single thread.
- if (transactionLocks == null) transactionLocks = new LinkedHashSet(5);
- transactionLocks.add(lock);
- }
-
- @SuppressWarnings("unchecked")
- public void removeLock(Object lock)
- {
- // no need to worry about concurrency here - a context is only valid for a single thread.
- if (transactionLocks != null) transactionLocks.remove(lock);
- }
-
- public void clearLocks()
- {
- if (transactionLocks != null) transactionLocks.clear();
- }
-
- public boolean hasLock(Object lock)
- {
- return transactionLocks != null && transactionLocks.contains(lock);
- }
-
- @SuppressWarnings("unchecked")
- public void addAllLocks(List newLocks)
- {
- // no need to worry about concurrency here - a context is only valid for a single thread.
- if (transactionLocks == null) transactionLocks = new LinkedHashSet(5);
- transactionLocks.addAll(newLocks);
- }
-
- @SuppressWarnings("unchecked")
- public List getLocks()
- {
- return transactionLocks == null || transactionLocks.isEmpty() ? Collections.emptyList() : new ImmutableListCopy(transactionLocks);
- }
-
-
- public boolean isForceAsyncReplication()
- {
- return forceAsyncReplication;
- }
-
- public void setForceAsyncReplication(boolean forceAsyncReplication)
- {
- this.forceAsyncReplication = forceAsyncReplication;
- if (forceAsyncReplication)
- {
- forceSyncReplication = false;
- }
- }
-
- public boolean isForceSyncReplication()
- {
- return forceSyncReplication;
- }
-
- public void setForceSyncReplication(boolean forceSyncReplication)
- {
- this.forceSyncReplication = forceSyncReplication;
- if (forceSyncReplication)
- {
- forceAsyncReplication = false;
- }
- }
-
- /**
- * Returns debug information about this transaction.
- */
@Override
- public String toString()
+ public void addModification(WriteCommand command)
{
- StringBuilder sb = new StringBuilder();
- sb.append("TransactionEntry\nmodificationList: ").append(modificationList);
- return sb.toString();
+ if (command == null) return;
+ super.addModification(command);
+ if (allModifications == null) allModifications = new LinkedList<WriteCommand>();
+ allModifications.add(command);
}
- public void addDummyNodeCreatedByCacheLoader(Fqn fqn)
+ public List<WriteCommand> getAllModifications()
{
- if (dummyNodesCreatedByCacheLoader == null)
- dummyNodesCreatedByCacheLoader = new LinkedList<Fqn>();
- dummyNodesCreatedByCacheLoader.add(fqn);
+ if (allModifications == null) return Collections.emptyList();
+ return allModifications;
}
- public List<Fqn> getDummyNodesCreatedByCacheLoader()
- {
- if (dummyNodesCreatedByCacheLoader == null) return Collections.emptyList();
- return dummyNodesCreatedByCacheLoader;
- }
-
- public void setOption(Option o)
- {
- this.option = o;
- }
-
- public Option getOption()
- {
- return this.option;
- }
-
- public OrderedSynchronizationHandler getOrderedSynchronizationHandler()
- {
- return orderedSynchronizationHandler;
- }
-
- public void setOrderedSynchronizationHandler(OrderedSynchronizationHandler orderedSynchronizationHandler)
- {
- this.orderedSynchronizationHandler = orderedSynchronizationHandler;
- }
-
- public boolean hasModifications()
- {
- return modificationList != null && !modificationList.isEmpty();
- }
-
- public boolean hasLocalModifications()
- {
- return localModifications != null && !localModifications.isEmpty();
- }
-
+ @Override
public void reset()
{
- orderedSynchronizationHandler = null;
- if (modificationList != null) modificationList = null;
- if (localModifications != null) localModifications = null;
- option = null;
- if (transactionLocks != null) transactionLocks.clear();
- if (dummyNodesCreatedByCacheLoader != null) dummyNodesCreatedByCacheLoader.clear();
- if (removedNodes != null) removedNodes.clear();
+ super.reset();
+ allModifications = null;
}
}
Modified: core/trunk/src/main/java/org/jboss/cache/transaction/TransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/TransactionContext.java 2008-07-31 14:12:50 UTC (rev 6461)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/TransactionContext.java 2008-07-31 14:50:35 UTC (rev 6462)
@@ -241,7 +241,7 @@
void setOrderedSynchronizationHandler(OrderedSynchronizationHandler orderedSynchronizationHandler);
/**
- * @return true if modifications were registered to either modificationList or to class loader modifications list.
+ * @return true if modifications were registered.
*/
boolean hasModifications();
@@ -251,6 +251,11 @@
boolean hasLocalModifications();
/**
+ * @return true if either there are modifications or local modifications that are not for replicating.
+ */
+ boolean hasAnyModifications();
+
+ /**
* Cleans up internal state, freeing up references.
*/
void reset();
16 years, 5 months