[jboss-cvs] JBossCache/src-50/org/jboss/cache/pojo/collection ...
Elias Ross
genman at noderunner.net
Mon Nov 6 18:32:16 EST 2006
User: genman
Date: 06/11/06 18:32:16
Modified: src-50/org/jboss/cache/pojo/collection
CachedListImpl.java CachedSetImpl.java
Added: src-50/org/jboss/cache/pojo/collection IntegerCache.java
Log:
JBCACHE-485 - Set.contains() remove() and add() O(1) ops now
Revision Changes Path
1.11 +13 -13 JBossCache/src-50/org/jboss/cache/pojo/collection/CachedListImpl.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: CachedListImpl.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src-50/org/jboss/cache/pojo/collection/CachedListImpl.java,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- CachedListImpl.java 10 Oct 2006 08:08:23 -0000 1.10
+++ CachedListImpl.java 6 Nov 2006 23:32:16 -0000 1.11
@@ -69,7 +69,7 @@
checkIndex();
try
{
- return Null.toNullValue(pCache_.getObject(AopUtil.constructFqn(getFqn(), Integer.toString(index))));
+ return Null.toNullValue(pCache_.getObject(AopUtil.constructFqn(getFqn(), IntegerCache.toString(index))));
} catch (Exception e)
{
throw new RuntimeException(e);
@@ -108,7 +108,7 @@
if (index != 0)
checkIndex(); // Since index can be size().
return Null.toNullValue(pCache_.attach(AopUtil.constructFqn(getFqn(),
- Integer.toString(index)), Null.toNullObject(element)));
+ IntegerCache.toString(index)), Null.toNullObject(element)));
} catch (Exception e)
{
throw new RuntimeException(e);
@@ -123,10 +123,10 @@
checkIndex(); // Since index can be size().
for (int i = size(); i > index; i--)
{
- Object obj = pCache_.detach(AopUtil.constructFqn(getFqn(), Integer.toString(i - 1)));
- pCache_.attach(AopUtil.constructFqn(getFqn(), Integer.toString(i)), obj);
+ Object obj = pCache_.detach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(i - 1)));
+ pCache_.attach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(i)), obj);
}
- pCache_.attach(AopUtil.constructFqn(getFqn(), Integer.toString(index)), Null.toNullObject(element));
+ pCache_.attach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(index)), Null.toNullObject(element));
} catch (Exception e)
{
throw new RuntimeException(e);
@@ -181,15 +181,15 @@
checkIndex();
// Object result = cache.removeObject(((Fqn) fqn.clone()).add(new Integer(index)));
int size = size();
- Object result = Null.toNullValue(pCache_.detach(AopUtil.constructFqn(getFqn(), Integer.toString(index))));
+ Object result = Null.toNullValue(pCache_.detach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(index))));
if (size == (index + 1))
{
return result; // We are the last one.
}
for (int i = index; i < size - 1; i++)
{
- Object obj = pCache_.detach(AopUtil.constructFqn(getFqn(), Integer.toString(i + 1)));
- pCache_.attach(AopUtil.constructFqn(getFqn(), Integer.toString(i)), obj);
+ Object obj = pCache_.detach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(i + 1)));
+ pCache_.attach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(i)), obj);
}
return result;
} catch (Exception e)
@@ -225,7 +225,7 @@
try
{
- return Null.toNullValue(pCache_.getObject(AopUtil.constructFqn(getFqn(), Integer.toString(++current))));
+ return Null.toNullValue(pCache_.getObject(AopUtil.constructFqn(getFqn(), IntegerCache.toString(++current))));
} catch (Exception e)
{
throw new RuntimeException(e);
@@ -244,16 +244,16 @@
if (current < (size - 1))
{
// Need to reshuffle the items.
- Object last = pCache_.detach(AopUtil.constructFqn(getFqn(), Integer.toString(current)));
+ Object last = pCache_.detach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(current)));
for (int i = current + 1; i < size; i++)
{
- last = pCache_.detach(AopUtil.constructFqn(getFqn(), Integer.toString(i)));
- pCache_.attach(AopUtil.constructFqn(getFqn(), Integer.toString(i - 1)), last);
+ last = pCache_.detach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(i)));
+ pCache_.attach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(i - 1)), last);
}
} else
{ // we are the last index.
// Need to move back the cursor.
- pCache_.detach(AopUtil.constructFqn(getFqn(), Integer.toString(current)));
+ pCache_.detach(AopUtil.constructFqn(getFqn(), IntegerCache.toString(current)));
}
current--;
size--;
1.10 +120 -120 JBossCache/src-50/org/jboss/cache/pojo/collection/CachedSetImpl.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: CachedSetImpl.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src-50/org/jboss/cache/pojo/collection/CachedSetImpl.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- CachedSetImpl.java 13 Oct 2006 10:24:46 -0000 1.9
+++ CachedSetImpl.java 6 Nov 2006 23:32:16 -0000 1.10
@@ -25,10 +25,14 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
-import java.util.LinkedList;
+import java.util.ArrayList;
/**
- * Set that uses cache as a underlying backend store
+ * Set implementation that uses a cache as an underlying backend store.
+ * Set data is stored in children nodes named based on the attached Object's hash code
+ * in hexidecimal string form.
+ * If there are conflicts between two Objects with the same hash code, then a
+ * counter (upper 32 bits of 64) is used.
*
* @author Ben Wang
* @author Scott Marlow
@@ -52,100 +56,132 @@
private Node getNode()
{
- try
- {
return CacheApiUtil.getDataNode(cache_, getFqn());
- } catch (Exception e)
- {
- throw new RuntimeException(e);
- }
}
private Fqn getFqn()
{
- // Need this since fqn can be reset.
+ // Cannot cache this as this can be reset
return interceptor_.getFqn();
}
- // implementation of the java.util.Set interface
- public int size()
+ // java.util.Set implementation
+
+ public boolean add(Object o)
{
- Node node = getNode();
- if (node == null)
+ o = Null.toNullObject(o);
+ int hashCode = o.hashCode();
+ int size = size();
+ for (int i = 0; i < size + 1; i++)
+ {
+ Object key = toLong(hashCode, i);
+ Object o2 = getNoUnmask(key);
+ if (o2 == null)
{
- return 0;
+ putNoMask(key, o);
+ return true;
}
-
- Collection<Node> children = node.getChildren();
- return children == null ? 0 : children.size();
+ if (o.equals(o2))
+ return false;
}
-
- public Iterator iterator()
- {
- return new IteratorImpl(keySet());
+ // should never reach here
+ throw new CacheException();
}
+ public void clear()
+ {
+ Node node = getNode();
+ if (node == null)
+ return;
- public boolean add(Object o)
+ Collection<Node> children = node.getChildren();
+ for (Node n : children)
{
- Collection keys = keySet();
+ pCache_.detach(n.getFqn());
+ }
+ }
- // This could be done with 'contains(o)' but it would invoke 'keySet()'
- // twice
- for (Iterator iter = new IteratorImpl(keys); iter.hasNext();)
- if (iter.next() == o)
+ public boolean contains(Object o)
+ {
+ o = Null.toNullObject(o);
+ int hashCode = o.hashCode();
+ int size = size();
+ for (int i = 0; i < size; i++)
+ {
+ Object key = toLong(hashCode, i);
+ Object o2 = getNoUnmask(key);
+ if (o2 == null)
return false;
-
- // Search for an available key. This is a fast operation as the key set
- // is already available. Start with the size of the key set and go
- // up as this will be the fastest way to find an unused key. Gaps
- // in the keys don't matter, as this is a Set not a List
- int key = keys.size();
- String keyString;
- while (keys.contains((keyString = Integer.toString(key))))
- key++;
-
- pCache_.attach(AopUtil.constructFqn(getFqn(), keyString), Null.toNullObject(o));
+ if (o.equals(o2))
return true;
}
+ return false;
+ }
- public boolean contains(Object o)
+ public Iterator iterator()
{
- Iterator iter = iterator();
- if (o == null)
+ Node node = getNode();
+ if (node == null)
+ return Collections.EMPTY_SET.iterator();
+ return new IteratorImpl(node);
+ }
+
+ public boolean remove(Object o)
{
- while (iter.hasNext())
+ o = Null.toNullObject(o);
+ int hashCode = o.hashCode();
+ int size = size();
+ boolean removed = false;
+ Object oldkey = null;
+ for (int i = 0; i < size; i++)
{
- if (iter.next() == null)
+ Object key = toLong(hashCode, i);
+ Object o2 = getNoUnmask(key);
+ if (o2 == null)
+ break;
+ if (removed)
{
- return true;
- }
+ // move o2 to old key
+ pCache_.detach(AopUtil.constructFqn(getFqn(), key));
+ pCache_.attach(AopUtil.constructFqn(getFqn(), oldkey), o2);
}
- } else
- {
- while (iter.hasNext())
- {
- if (o.equals(iter.next()))
+ if (o.equals(o2))
{
- return true;
+ pCache_.detach(AopUtil.constructFqn(getFqn(), key));
+ removed = true;
}
+ oldkey = key;
}
+ return removed;
}
- return false;
+
+ public int size()
+ {
+ Node node = getNode();
+ if (node == null)
+ return 0;
+
+ return node.getChildren().size();
}
+ /**
+ * Return a long with "count" as the high 32 bits.
+ * TODO should be able to use java.lang.Long, but some CacheLoader don't
+ * support non-String keys
+ */
+ private String toLong(long hashCode, long count) {
+ long key = (hashCode & 0xFFFFL) | (count << 32);
+ return Long.toHexString(key);
+ }
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- for (Iterator it = iterator(); it.hasNext();)
+ private Object putNoMask(Object key, Object pojo)
{
- Object key = it.next();
- buf.append("[").append(key).append("]");
- if (it.hasNext()) buf.append(", ");
+ return pCache_.putObject(AopUtil.constructFqn(getFqn(), key), pojo);
}
- return buf.toString();
+ private Object getNoUnmask(Object key)
+ {
+ return pCache_.getObject(AopUtil.constructFqn(getFqn(), key));
}
public int hashCode()
@@ -158,18 +194,14 @@
public boolean equals(Object o)
{
- if (o == null)
- return false;
-
if (o == this)
return true;
try
{
- Set set = (Set) o;
-
- return (set.size() == keySet().size() && this.containsAll(set));
- } catch (ClassCastException e)
+ return super.equals(o);
+ }
+ catch (ClassCastException e)
{
return false;
}
@@ -179,37 +211,17 @@
}
}
- private Collection keySet()
- {
- Node node = getNode();
-
- // TODO Not efficient here!!
- if (node != null)
- {
- Collection<Node> children = node.getChildren();
- if (children == null) return null;
-
- LinkedList keys = new LinkedList();
- for(Node n : children)
- {
- keys.add(n.getFqn().getLast());
- }
-
- return keys;
- }
-
- return Collections.EMPTY_SET;
- }
-
private class IteratorImpl implements Iterator
{
- private Iterator iterator;
+ private Iterator<Node> iterator;
- private Object key;
+ private Node node;
+ private Object o;
- private IteratorImpl(Collection keys)
+ private IteratorImpl(Node node)
{
- iterator = keys.iterator();
+ Collection<Node> children = node.getChildren();
+ iterator = children.iterator();
}
public boolean hasNext()
@@ -219,30 +231,18 @@
public Object next()
{
- // (Brian) Removed Jussi's call to iterator.hasNext() followed by
- // an NSOE if false. That approach was slightly more efficient if
- // hasNext() were false, but in the vast majority of cases iterators
- // are used correctly and it was an extra step.
-
- this.key = iterator.next();
-
- try
- {
- return Null.toNullValue(pCache_.getObject(AopUtil.constructFqn(getFqn(), this.key)));
- } catch (CacheException e)
- {
- throw new RuntimeException(e);
- }
+ node = iterator.next();
+ o = Null.toNullValue(pCache_.getObject(node.getFqn()));
+ return o;
}
public void remove() throws IllegalStateException
{
- if (this.key == null)
+ if (node == null)
{
throw new IllegalStateException();
}
-
- pCache_.detach(AopUtil.constructFqn(getFqn(), this.key));
+ CachedSetImpl.this.remove(o);
}
}
1.1 date: 2006/11/06 23:32:16; author: genman; state: Exp;JBossCache/src-50/org/jboss/cache/pojo/collection/IntegerCache.java
Index: IntegerCache.java
===================================================================
package org.jboss.cache.pojo.collection;
/**
* Cache of integers in String format from 0-99.
*/
public class IntegerCache
{
private IntegerCache() {}
private static final String values[] = new String[100];
static
{
for (int i = 0; i < values.length; i++)
values[i] = Integer.toString(i).intern();
}
public static String toString(int i)
{
if (i >= 0 && i < values.length)
return values[i];
return Integer.toString(i);
}
}
More information about the jboss-cvs-commits
mailing list