Permalink
Browse files

Initial commit for Voldemort backed stack (VStack) and indexed linked…

… list (VLinkedPagedList)
  • Loading branch information...
1 parent e491023 commit e0899dae4d0acf9fbc93b4bfd0a02f636545028d Jason Ko committed Sep 16, 2011
Showing with 2,274 additions and 0 deletions.
  1. +2 −0 .classpath
  2. +189 −0 contrib/collections/src/java/voldemort/collections/AddNodeAction.java
  3. +115 −0 contrib/collections/src/java/voldemort/collections/MappedListIterator.java
  4. +16 −0 contrib/collections/src/java/voldemort/collections/Mapping.java
  5. +67 −0 contrib/collections/src/java/voldemort/collections/UpdateElementById.java
  6. +55 −0 contrib/collections/src/java/voldemort/collections/UpdatePageIndex.java
  7. +33 −0 contrib/collections/src/java/voldemort/collections/VLinkedPagedKey.java
  8. +226 −0 contrib/collections/src/java/voldemort/collections/VLinkedPagedList.java
  9. +207 −0 contrib/collections/src/java/voldemort/collections/VLinkedPagedListIterator.java
  10. +265 −0 contrib/collections/src/java/voldemort/collections/VListIterator.java
  11. +94 −0 contrib/collections/src/java/voldemort/collections/VListIteratorValues.java
  12. +34 −0 contrib/collections/src/java/voldemort/collections/VListKey.java
  13. +72 −0 contrib/collections/src/java/voldemort/collections/VListNode.java
  14. +70 −0 contrib/collections/src/java/voldemort/collections/VPageIndexEntry.java
  15. +354 −0 contrib/collections/src/java/voldemort/collections/VStack.java
  16. +12 −0 contrib/collections/src/java/voldemort/utils/Identifiable.java
  17. +33 −0 contrib/collections/src/java/voldemort/utils/Identified.java
  18. +260 −0 contrib/collections/test/voldemort/collections/TestVLinkedPagedList.java
  19. +170 −0 contrib/collections/test/voldemort/collections/TestVStack.java
View
@@ -12,6 +12,8 @@
<classpathentry kind="src" path="example/java"/>
<classpathentry kind="src" path="contrib/krati/src/java"/>
<classpathentry kind="src" path="contrib/krati/test"/>
+ <classpathentry kind="src" path="contrib/collections/src/java"/>
+ <classpathentry kind="src" path="contrib/collections/test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/catalina-ant.jar"/>
<classpathentry kind="lib" path="lib/commons-codec-1.3.jar"/>
@@ -0,0 +1,189 @@
+package voldemort.collections;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import voldemort.client.StoreClient;
+import voldemort.client.UpdateAction;
+import voldemort.versioning.ObsoleteVersionException;
+import voldemort.versioning.Versioned;
+
+/**
+ * @author jko
+ *
+ * Adds a node E to the front of the list identified by K. Inserts the node to the front
+ * of the list, with id 0, and then modifies the pointers for the first node and next
+ * node accordingly.
+ *
+ * @param <E> the type of the value
+ * @param <K> the type of the key identifying the list
+ */
+public class AddNodeAction<K, E> extends UpdateAction<Map<String, Object>, Map<String, Object>>
+{
+ private final K _key;
+ private final E _value;
+
+ @SuppressWarnings("unchecked")
+ private StoreClient<Map<String, Object>, Map<String, Object>> _storeClient = null;
+ private Map<Integer, Map<String, Object>> _rollback = new HashMap<Integer, Map<String, Object>>();
+
+ public AddNodeAction(K key, E value)
+ {
+ _key = key;
+ _value = value;
+ }
+
+ @Override
+ public void rollback()
+ {
+ if (_storeClient == null)
+ return;
+
+ for (Entry<Integer, Map<String, Object>> entry : _rollback.entrySet())
+ {
+ VListKey<K> key = new VListKey<K>(_key, entry.getKey());
+ _storeClient.put(key.mapValue(), entry.getValue());
+ }
+ }
+
+ /**
+ * @throws ObsoleteVersionException if a concurrent modification (remove or another add)
+ * has not completed modifying the structure.
+ * @throws ArrayIndexOutOfBoundsException if no more ids left to identify object
+ */
+ @Override
+ public void update(StoreClient<Map<String, Object>, Map<String, Object>> storeClient)
+ {
+ _storeClient = storeClient;
+ VListKey<K> newKey = new VListKey<K>(_key, 0);
+ Versioned<Map<String, Object>> firstNodeMap = storeClient.get(newKey.mapValue());
+ // adding first node of the list
+ if (firstNodeMap == null)
+ {
+ Versioned<Map<String, Object>> newNode =
+ new Versioned<Map<String, Object>>((new VListNode<E>(_value, 0, VStack.NULL_ID,
+ VStack.NULL_ID, true)).mapValue());
+ // throws ObsoleteVersionException if another process has created a new node already
+ storeClient.put(newKey.mapValue(), newNode);
+ }
+ else // add to front of list
+ {
+ Versioned<VListNode<E>> firstNode =
+ new Versioned<VListNode<E>>(VListNode.<E>valueOf(firstNodeMap.getValue()),
+ firstNodeMap.getVersion());
+
+ if (! firstNode.getValue().isStable())
+ {
+ throw new ObsoleteVersionException("cannot add when list node is not stable");
+ }
+
+ // set stable flag to false
+ Map<String, Object> tmpMap = new HashMap<String, Object>(firstNodeMap.getValue());
+ tmpMap.put(VListNode.STABLE, false);
+ storeClient.put(newKey.mapValue(),
+ new Versioned<Map<String, Object>>(tmpMap, firstNodeMap.getVersion()));
+ _rollback.put(0, firstNodeMap.getValue());
+
+ int newId;
+ int nextId = firstNode.getValue().getNextId();
+ newId = (nextId == VStack.NULL_ID) ? 1 : nextId + 1;
+ if (newId == Integer.MAX_VALUE)
+ throw new ArrayIndexOutOfBoundsException(newId + " out of bounds");
+
+ Versioned<VListNode<E>> nextNode = null;
+ VListKey<K> nextKey = new VListKey<K>(_key, nextId);
+ if (nextId != VStack.NULL_ID)
+ {
+ Versioned<Map<String, Object>> nextNodeMap = storeClient.get(nextKey.mapValue());
+ if (nextNodeMap == null)
+ throw new ObsoleteVersionException("possible concurrent modification");
+ nextNode = new Versioned<VListNode<E>>(VListNode.<E>valueOf(nextNodeMap.getValue()),
+ nextNodeMap.getVersion());
+ if (! nextNode.getValue().isStable())
+ {
+ throw new ObsoleteVersionException("cannot add when list node is not stable");
+ }
+
+ // set stable flag to false
+ tmpMap = new HashMap<String, Object>(nextNode.getValue().mapValue());
+ tmpMap.put(VListNode.STABLE, false);
+ storeClient.put(nextKey.mapValue(),
+ new Versioned<Map<String, Object>>(tmpMap, nextNode.getVersion()));
+ _rollback.put(nextId, nextNode.getValue().mapValue());
+ }
+
+ // insert new node
+ Map<String, Object> newNode =
+ (new VListNode<E>(_value, 0, VStack.NULL_ID, newId, true)).mapValue();
+ // don't need to specify versioned because node is already "locked"
+ storeClient.put(newKey.mapValue(), newNode);
+
+ // move first node to next index
+ VListKey<K> firstKey = new VListKey<K>(_key, newId);
+ firstNode = new Versioned<VListNode<E>>(new VListNode<E>(firstNode.getValue().getValue(),
+ newId, 0, firstNode.getValue().getNextId(), true));
+ // don't need to specify versioned because node is already "locked"
+ storeClient.put(firstKey.mapValue(),
+ firstNode.getValue().mapValue());
+
+ // redefine previous pointer on next node
+ if (nextNode != null)
+ {
+ if (! storeClient.applyUpdate(new UpdateNextNode<K, E>(nextNode, nextKey, newId)))
+ throw new ObsoleteVersionException("unable to update node");
+ }
+ }
+ }
+
+ /**
+ * Updates a the previous pointer of a node specified by key to a newId.
+ *
+ * @param <K>
+ * @param <E>
+ */
+ private static class UpdateNextNode<K, E>
+ extends UpdateAction<Map<String, Object>, Map<String, Object>>
+ {
+ private final VListKey<K> _key;
+ private final int _newId;
+
+ private Versioned<VListNode<E>> _listNode;
+ private int numCalls = 0;
+
+ /**
+ * @param listNode
+ * @param key
+ * @param newId
+ */
+ public UpdateNextNode(Versioned<VListNode<E>> listNode, VListKey<K> key, int newId)
+ {
+ _listNode = listNode;
+ _key = key;
+ _newId = newId;
+ }
+
+ @Override
+ public void update(StoreClient<Map<String, Object>, Map<String, Object>> storeClient)
+ {
+ if (numCalls > 0)
+ {
+ // TODO jko maybe delete this if unnecessary
+ Versioned<Map<String, Object>> nextNodeMap = storeClient.get(_key.mapValue());
+ if (nextNodeMap == null)
+ throw new ObsoleteVersionException("possible concurrent modification");
+ _listNode = new Versioned<VListNode<E>>(VListNode.<E>valueOf(nextNodeMap.getValue()),
+ nextNodeMap.getVersion());
+ }
+
+ VListNode<E> nodeValue = _listNode.getValue();
+ _listNode.setObject(new VListNode<E>(nodeValue.getValue(), nodeValue.getId(),
+ _newId, nodeValue.getNextId(), true));
+ Map<String, Object> nextNodeMap = _listNode.getValue().mapValue();
+ storeClient.put(_key.mapValue(), nextNodeMap);
+
+ numCalls++;
+ }
+
+ }
+}
@@ -0,0 +1,115 @@
+package voldemort.collections;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * @author jko
+ *
+ * Analogous to ListIterator, except for us with a map-backed list. The
+ * main difference is that these lists are not indexed by sequential
+ * number, but instead referred to by an id whose order has nothing to
+ * do with the position of the element in the list.
+ *
+ * @param <K> the type of the key used by the underlying map
+ * @param <E> the type of the elements being stored
+ */
+public interface MappedListIterator<K, E> extends Iterator<E> {
+
+ /**
+ * Inserts the specified element into the list (optional operation).
+ */
+ void add(E e);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Iterator#hasNext()
+ */
+ boolean hasNext();
+
+ /**
+ * Returns true if this list iterator has more elements when traversing the
+ * list in the reverse direction. (In other words, returns true if previous
+ * would return an element rather than throwing an exception.)
+ *
+ * @return true if the list iterator has more elements when traversing the
+ * list in the reverse direction
+ */
+ boolean hasPrevious();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Iterator#next()
+ */
+ E next();
+
+ /**
+ * Returns the id associated with the next element in the list, or null if
+ * the list iterator is at the end of the list.
+ *
+ * @return the id associated with the next element in the list
+ */
+ K nextId();
+
+ /**
+ * Returns the previous element in the list. This method may be called
+ * repeatedly to iterate through the list backwards, or intermixed with
+ * calls to next to go back and forth. (Note that alternating calls to next
+ * and previous will return the same element repeatedly.)
+ *
+ * @return the previous element in the list
+ *
+ * @throws NoSuchElementException - if the iteration has no previous
+ * element.
+ */
+ E previous();
+
+ /**
+ * Returns the id associated with the previous element in the list, or null
+ * if the list iterator is at the beginning of the list.
+ *
+ * @return the id associated with the previous element in the list
+ */
+ K previousId();
+
+ /**
+ * Returns the id for the last element that was returned by next or
+ * previous.
+ *
+ * @return the id for the last element that was returned by next or previous
+ * @throws IllegalStateException if neither next nor previous has been
+ * called, or remove or add has been called after the last call to
+ * next or previous
+ */
+ K lastId();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Iterator#remove()
+ */
+ void remove();
+
+ /**
+ * Replaces the last element returned by next or previous with the specified
+ * element (optional operation). This call can be made only if neither
+ * ListIterator.remove nor ListIterator.add have been called after the last
+ * call to next or previous.
+ *
+ * @param e the element with which to replace the last element returned by
+ * next or previous.
+ *
+ * @throws UnsupportedOperationException if the set operation is not
+ * supported by this list iterator.
+ * @throws ClassCastException if the class of the specified element prevents
+ * it from being added to this list.
+ * @throws IllegalArgumentException if some aspect of the specified element
+ * prevents it from being added to this list.
+ * @throws IllegalStateException if neither next nor previous have been
+ * called, or remove or add have been called after the last call to
+ * next or previous.
+ */
+ void set(E e);
+}
@@ -0,0 +1,16 @@
+package voldemort.collections;
+
+import java.util.Map;
+
+/**
+ * Interface that allows an object to expose a Map view of itself.
+ *
+ * @author jko
+ *
+ * @param <K> Map key type
+ * @param <E> Map value type
+ */
+public interface Mapping<K, E>
+{
+ Map<K, E> asMap();
+}
@@ -0,0 +1,67 @@
+package voldemort.collections;
+
+import java.util.Map;
+
+import voldemort.client.StoreClient;
+import voldemort.client.UpdateAction;
+import voldemort.versioning.ObsoleteVersionException;
+import voldemort.versioning.Version;
+import voldemort.versioning.Versioned;
+
+/**
+ * @author jko
+ *
+ * Put the given value to the appropriate id in the stack, using the version of the current
+ * list node identified by that id.
+ *
+ * @param id
+ * @param element element to set
+ * @return element that was replaced by the new element
+ */
+public class UpdateElementById<K, E> extends UpdateAction<Map<String, Object>, Map<String, Object>>
+{
+ private final VListKey<K> _key;
+ private final E _element;
+ private final Version _version;
+ private E _result = null;
+
+ public UpdateElementById(VListKey<K> key, E element)
+ {
+ _key = key;
+ _element = element;
+ _version = null;
+ }
+
+ public UpdateElementById(VListKey<K> key, Versioned<E> element)
+ {
+ _key = key;
+ _element = element.getValue();
+ _version = element.getVersion();
+ }
+
+ @Override
+ public void update(StoreClient<Map<String, Object>, Map<String, Object>> storeClient)
+ {
+ Versioned<Map<String, Object>> nodeMap = storeClient.get(_key.mapValue());
+ if (nodeMap == null)
+ throw new IndexOutOfBoundsException("invalid id " + _key.getId());
+ Version version = (_version != null) ? _version : nodeMap.getVersion();
+ VListNode<E> listNode = VListNode.valueOf(nodeMap.getValue());
+ if (! listNode.isStable())
+ {
+ throw new ObsoleteVersionException("node " + _key.getId() + " not stable.");
+ }
+ _result = listNode.getValue();
+ VListNode<E> newNode = new VListNode<E>(_element, listNode.getId(), listNode.getPreviousId(),
+ listNode.getNextId(), true);
+ storeClient.put(_key.mapValue(),
+ new Versioned<Map<String, Object>>(newNode.mapValue(), version));
+
+ }
+
+ public E getResult()
+ {
+ return _result;
+ }
+
+}
Oops, something went wrong.

0 comments on commit e0899da

Please sign in to comment.