*** empty log message ***
authornavid <navid>
Wed, 21 Jan 2009 20:00:15 +0000 (20:00 +0000)
committernavid <navid>
Wed, 21 Jan 2009 20:00:15 +0000 (20:00 +0000)
41 files changed:
Robust/Transactions/dstm2/src/dstm2/AtomicByteArray.java [new file with mode: 0644]
Robust/Transactions/dstm2/src/dstm2/AtomicIntArray.java [new file with mode: 0644]
Robust/Transactions/dstm2/src/dstm2/AtomicLongArray.java [new file with mode: 0644]
Robust/Transactions/dstm2/src/dstm2/util/ArrayList.java [new file with mode: 0644]
Robust/Transactions/dstm2/src/dstm2/util/HashMap.java [new file with mode: 0644]
Robust/Transactions/dstm2/src/dstm2/util/IntHashMap.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/license.txt [new file with mode: 0644]
Robust/Transactions/mytuplesoup/readme.txt [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/DualFileTable.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/HashedTable.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/IndexedTableReader.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/PagedIndex.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/PagedIndexTransactional.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Row.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/RowMatcher.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Table.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndex.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexEntry.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexNode.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexPage.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexPageTransactional.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStream.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStreamMerger.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Value.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Conditional.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/HeapSort.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/JavaSort.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Join.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/MergeSort.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/MergeSort2.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/QuickSort.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RadixSort.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RowBuffer.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Sort.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortComparator.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortRule.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/BasicTest.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelPerformanceTest.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelThread.java [new file with mode: 0644]
Robust/Transactions/mytuplesoup/tuplesoup.jar [new file with mode: 0644]
Robust/Transactions/origtuplesoup/tuplesoup/readme.txt [new file with mode: 0644]

diff --git a/Robust/Transactions/dstm2/src/dstm2/AtomicByteArray.java b/Robust/Transactions/dstm2/src/dstm2/AtomicByteArray.java
new file mode 100644 (file)
index 0000000..d81ec46
--- /dev/null
@@ -0,0 +1,181 @@
+package dstm2;
+
+/*
+ * AtomicArray.java
+ *
+ * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, California 95054, U.S.A.  All rights reserved.  
+ * 
+ * Sun Microsystems, Inc. has intellectual property rights relating to
+ * technology embodied in the product that is described in this
+ * document.  In particular, and without limitation, these
+ * intellectual property rights may include one or more of the
+ * U.S. patents listed at http://www.sun.com/patents and one or more
+ * additional patents or pending patent applications in the U.S. and
+ * in other countries.
+ * 
+ * U.S. Government Rights - Commercial software.
+ * Government users are subject to the Sun Microsystems, Inc. standard
+ * license agreement and applicable provisions of the FAR and its
+ * supplements.  Use is subject to license terms.  Sun, Sun
+ * Microsystems, the Sun logo and Java are trademarks or registered
+ * trademarks of Sun Microsystems, Inc. in the U.S. and other
+ * countries.  
+ * 
+ * This product is covered and controlled by U.S. Export Control laws
+ * and may be subject to the export or import laws in other countries.
+ * Nuclear, missile, chemical biological weapons or nuclear maritime
+ * end uses or end users, whether direct or indirect, are strictly
+ * prohibited.  Export or reexport to countries subject to
+ * U.S. embargo or to entities identified on U.S. export exclusion
+ * lists, including, but not limited to, the denied persons and
+ * specially designated nationals lists is strictly prohibited.
+ */
+
+
+
+import TransactionalIO.exceptions.AbortedException;
+import TransactionalIO.exceptions.PanicException;
+import dstm2.factory.ofree.ReadSet;
+import java.lang.reflect.Array;
+
+/**
+ * @author mph
+ */
+@atomic public class AtomicByteArray {
+  
+  private final Byte[] array;
+  private final Byte[] shadow;
+  private Transaction writer;
+  private ReadSet readers;
+  long version;
+  private final String FORMAT = "Unexpected transaction state: %s";
+  
+  /** Creates a new instance of AtomicArray */
+  public AtomicByteArray(Class _class, int capacity) {
+    array  = (Byte[]) Array.newInstance(_class, capacity);
+    shadow = (Byte[]) Array.newInstance(_class, capacity);
+    writer = Transaction.COMMITTED;
+    readers = new ReadSet();
+    version = 0;
+  }
+  
+  public Byte get(int i) {
+    Transaction me  = Thread.getTransaction();
+    Transaction other = null;
+    ContentionManager manager = Thread.getContentionManager();
+    while (true) {
+      synchronized (this) {
+        other = openRead(me);
+        if (other == null) {
+          return array[i];
+        }
+      }
+      manager.resolveConflict(me, other);
+    }
+  }
+  
+  public void set(int i, Byte value) {
+    Transaction me  = Thread.getTransaction();
+    Transaction other = null;
+    ContentionManager manager = Thread.getContentionManager();
+    while (true) {
+      synchronized (this) {
+        other = openWrite(me);
+        if (other == null) {
+          array[i] = value;
+          return;
+        }
+      }
+      manager.resolveConflict(me, other);
+    }
+  }
+  /**
+   * Tries to open object for reading. Returns reference to conflictin transaction, if one exists
+   **/
+  private Transaction openRead(Transaction me) {
+    // not in a transaction
+    if (me == null) {  // restore object if latest writer aborted
+      if (writer.isAborted()) {
+        restore();
+        version++;
+        writer = Transaction.COMMITTED;
+      }
+      return null;
+    }
+    // Am I still active?
+    if (!me.isActive()) {
+      throw new AbortedException();
+    }
+    // Have I already opened this object?
+    if (writer == me) {
+      return null;
+    }
+    switch (writer.getStatus()) {
+      case ACTIVE:
+        return writer;
+      case COMMITTED:
+        break;
+      case ABORTED:
+        restore();
+        version++;
+        break;
+      default:
+        throw new PanicException(FORMAT, writer.getStatus());
+    }
+    writer = Transaction.COMMITTED;
+    readers.add(me);
+    return null;
+  }
+  
+  /**
+   * Tries to open object for reading. Returns reference to conflicting transaction, if one exists
+   **/
+  public Transaction openWrite(Transaction me) {
+    // not in a transaction
+    if (me == null) {  // restore object if latest writer aborted
+      if (writer.isAborted()) {
+        restore();
+        version++;
+        writer = Transaction.COMMITTED;
+      }
+      return null;
+    }
+    if (!me.validate()) {
+      throw new AbortedException();
+    }
+    if (me == writer) {
+      return null;
+    }
+    for (Transaction reader : readers) {
+      if (reader.isActive() && reader != me) {
+        return reader;
+      }
+    }
+    readers.clear();
+    switch (writer.getStatus()) {
+      case ACTIVE:
+        return writer;
+      case COMMITTED:
+        backup();
+        version++;
+        break;
+      case ABORTED:
+        restore();
+        version++;
+        break;
+      default:
+        throw new PanicException(FORMAT, writer.getStatus());
+    }
+    writer = me;
+    return null;
+  }
+  
+  private void restore() {
+    System.arraycopy(shadow, 0, array, 0, array.length);
+  }
+  private void backup() {
+    System.arraycopy(array, 0, shadow, 0, array.length);
+  }
+  
+}
diff --git a/Robust/Transactions/dstm2/src/dstm2/AtomicIntArray.java b/Robust/Transactions/dstm2/src/dstm2/AtomicIntArray.java
new file mode 100644 (file)
index 0000000..b1741c5
--- /dev/null
@@ -0,0 +1,181 @@
+package dstm2;
+
+/*
+ * AtomicArray.java
+ *
+ * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, California 95054, U.S.A.  All rights reserved.  
+ * 
+ * Sun Microsystems, Inc. has intellectual property rights relating to
+ * technology embodied in the product that is described in this
+ * document.  In particular, and without limitation, these
+ * intellectual property rights may include one or more of the
+ * U.S. patents listed at http://www.sun.com/patents and one or more
+ * additional patents or pending patent applications in the U.S. and
+ * in other countries.
+ * 
+ * U.S. Government Rights - Commercial software.
+ * Government users are subject to the Sun Microsystems, Inc. standard
+ * license agreement and applicable provisions of the FAR and its
+ * supplements.  Use is subject to license terms.  Sun, Sun
+ * Microsystems, the Sun logo and Java are trademarks or registered
+ * trademarks of Sun Microsystems, Inc. in the U.S. and other
+ * countries.  
+ * 
+ * This product is covered and controlled by U.S. Export Control laws
+ * and may be subject to the export or import laws in other countries.
+ * Nuclear, missile, chemical biological weapons or nuclear maritime
+ * end uses or end users, whether direct or indirect, are strictly
+ * prohibited.  Export or reexport to countries subject to
+ * U.S. embargo or to entities identified on U.S. export exclusion
+ * lists, including, but not limited to, the denied persons and
+ * specially designated nationals lists is strictly prohibited.
+ */
+
+
+
+import TransactionalIO.exceptions.AbortedException;
+import TransactionalIO.exceptions.PanicException;
+import dstm2.factory.ofree.ReadSet;
+import java.lang.reflect.Array;
+
+/**
+ * @author mph
+ */
+@atomic public class AtomicIntArray {
+  
+  private final Integer[] array;
+  private final Integer[] shadow;
+  private Transaction writer;
+  private ReadSet readers;
+  long version;
+  private final String FORMAT = "Unexpected transaction state: %s";
+  
+  /** Creates a new instance of AtomicArray */
+  public AtomicIntArray(Class _class, int capacity) {
+    array  = (Integer[]) Array.newInstance(_class, capacity);
+    shadow = (Integer[]) Array.newInstance(_class, capacity);
+    writer = Transaction.COMMITTED;
+    readers = new ReadSet();
+    version = 0;
+  }
+  
+  public Integer get(int i) {
+    Transaction me  = Thread.getTransaction();
+    Transaction other = null;
+    ContentionManager manager = Thread.getContentionManager();
+    while (true) {
+      synchronized (this) {
+        other = openRead(me);
+        if (other == null) {
+          return array[i];
+        }
+      }
+      manager.resolveConflict(me, other);
+    }
+  }
+  
+  public void set(int i, Integer value) {
+    Transaction me  = Thread.getTransaction();
+    Transaction other = null;
+    ContentionManager manager = Thread.getContentionManager();
+    while (true) {
+      synchronized (this) {
+        other = openWrite(me);
+        if (other == null) {
+          array[i] = value;
+          return;
+        }
+      }
+      manager.resolveConflict(me, other);
+    }
+  }
+  /**
+   * Tries to open object for reading. Returns reference to conflictin transaction, if one exists
+   **/
+  private Transaction openRead(Transaction me) {
+    // not in a transaction
+    if (me == null) {  // restore object if latest writer aborted
+      if (writer.isAborted()) {
+        restore();
+        version++;
+        writer = Transaction.COMMITTED;
+      }
+      return null;
+    }
+    // Am I still active?
+    if (!me.isActive()) {
+      throw new AbortedException();
+    }
+    // Have I already opened this object?
+    if (writer == me) {
+      return null;
+    }
+    switch (writer.getStatus()) {
+      case ACTIVE:
+        return writer;
+      case COMMITTED:
+        break;
+      case ABORTED:
+        restore();
+        version++;
+        break;
+      default:
+        throw new PanicException(FORMAT, writer.getStatus());
+    }
+    writer = Transaction.COMMITTED;
+    readers.add(me);
+    return null;
+  }
+  
+  /**
+   * Tries to open object for reading. Returns reference to conflicting transaction, if one exists
+   **/
+  public Transaction openWrite(Transaction me) {
+    // not in a transaction
+    if (me == null) {  // restore object if latest writer aborted
+      if (writer.isAborted()) {
+        restore();
+        version++;
+        writer = Transaction.COMMITTED;
+      }
+      return null;
+    }
+    if (!me.validate()) {
+      throw new AbortedException();
+    }
+    if (me == writer) {
+      return null;
+    }
+    for (Transaction reader : readers) {
+      if (reader.isActive() && reader != me) {
+        return reader;
+      }
+    }
+    readers.clear();
+    switch (writer.getStatus()) {
+      case ACTIVE:
+        return writer;
+      case COMMITTED:
+        backup();
+        version++;
+        break;
+      case ABORTED:
+        restore();
+        version++;
+        break;
+      default:
+        throw new PanicException(FORMAT, writer.getStatus());
+    }
+    writer = me;
+    return null;
+  }
+  
+  private void restore() {
+    System.arraycopy(shadow, 0, array, 0, array.length);
+  }
+  private void backup() {
+    System.arraycopy(array, 0, shadow, 0, array.length);
+  }
+  
+}
diff --git a/Robust/Transactions/dstm2/src/dstm2/AtomicLongArray.java b/Robust/Transactions/dstm2/src/dstm2/AtomicLongArray.java
new file mode 100644 (file)
index 0000000..a321c25
--- /dev/null
@@ -0,0 +1,199 @@
+package dstm2;
+
+/*
+ * AtomicArray.java
+ *
+ * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, California 95054, U.S.A.  All rights reserved.  
+ * 
+ * Sun Microsystems, Inc. has intellectual property rights relating to
+ * technology embodied in the product that is described in this
+ * document.  In particular, and without limitation, these
+ * intellectual property rights may include one or more of the
+ * U.S. patents listed at http://www.sun.com/patents and one or more
+ * additional patents or pending patent applications in the U.S. and
+ * in other countries.
+ * 
+ * U.S. Government Rights - Commercial software.
+ * Government users are subject to the Sun Microsystems, Inc. standard
+ * license agreement and applicable provisions of the FAR and its
+ * supplements.  Use is subject to license terms.  Sun, Sun
+ * Microsystems, the Sun logo and Java are trademarks or registered
+ * trademarks of Sun Microsystems, Inc. in the U.S. and other
+ * countries.  
+ * 
+ * This product is covered and controlled by U.S. Export Control laws
+ * and may be subject to the export or import laws in other countries.
+ * Nuclear, missile, chemical biological weapons or nuclear maritime
+ * end uses or end users, whether direct or indirect, are strictly
+ * prohibited.  Export or reexport to countries subject to
+ * U.S. embargo or to entities identified on U.S. export exclusion
+ * lists, including, but not limited to, the denied persons and
+ * specially designated nationals lists is strictly prohibited.
+ */
+
+
+
+import TransactionalIO.exceptions.AbortedException;
+import TransactionalIO.exceptions.PanicException;
+import dstm2.factory.ofree.ReadSet;
+import java.lang.reflect.Array;
+
+/**
+ * @author mph
+ */
+@atomic public class AtomicLongArray {
+  
+  private final Long[] array;
+  private final Long[] shadow;
+  private Transaction writer;
+  private ReadSet readers;
+  long version;
+  private final String FORMAT = "Unexpected transaction state: %s";
+  
+  /** Creates a new instance of AtomicArray */
+  public AtomicLongArray(Class _class, int capacity) {
+    array  = (Long[]) Array.newInstance(_class, capacity);
+    shadow = (Long[]) Array.newInstance(_class, capacity);
+    writer = Transaction.COMMITTED;
+    readers = new ReadSet();
+    version = 0;
+  }
+  
+  public Long get(int i) {
+    Transaction me  = Thread.getTransaction();
+    Transaction other = null;
+    ContentionManager manager = Thread.getContentionManager();
+    while (true) {
+      synchronized (this) {
+        other = openRead(me);
+        if (other == null) {
+          return array[i];
+        }
+      }
+      manager.resolveConflict(me, other);
+    }
+  }
+  
+  public void set(int i, Long value) {
+    Transaction me  = Thread.getTransaction();
+    Transaction other = null;
+    ContentionManager manager = Thread.getContentionManager();
+    while (true) {
+      synchronized (this) {
+        other = openWrite(me);
+        if (other == null) {
+          array[i] = value;
+          return;
+        }
+      }
+      manager.resolveConflict(me, other);
+    }
+  }
+  
+  
+   public void set(long[] values) {
+    Transaction me  = Thread.getTransaction();
+    Transaction other = null;
+    ContentionManager manager = Thread.getContentionManager();
+    while (true) {
+      synchronized (this) {
+        other = openWrite(me);
+        if (other == null) {
+          for (int i=0; i<values.length; i++)  
+            array[i] = values[i];
+          return;
+        }
+      }
+      manager.resolveConflict(me, other);
+    }
+  }
+  /**
+   * Tries to open object for reading. Returns reference to conflictin transaction, if one exists
+   **/
+  private Transaction openRead(Transaction me) {
+    // not in a transaction
+    if (me == null) {  // restore object if latest writer aborted
+      if (writer.isAborted()) {
+        restore();
+        version++;
+        writer = Transaction.COMMITTED;
+      }
+      return null;
+    }
+    // Am I still active?
+    if (!me.isActive()) {
+      throw new AbortedException();
+    }
+    // Have I already opened this object?
+    if (writer == me) {
+      return null;
+    }
+    switch (writer.getStatus()) {
+      case ACTIVE:
+        return writer;
+      case COMMITTED:
+        break;
+      case ABORTED:
+        restore();
+        version++;
+        break;
+      default:
+        throw new PanicException(FORMAT, writer.getStatus());
+    }
+    writer = Transaction.COMMITTED;
+    readers.add(me);
+    return null;
+  }
+  
+  /**
+   * Tries to open object for reading. Returns reference to conflicting transaction, if one exists
+   **/
+  public Transaction openWrite(Transaction me) {
+    // not in a transaction
+    if (me == null) {  // restore object if latest writer aborted
+      if (writer.isAborted()) {
+        restore();
+        version++;
+        writer = Transaction.COMMITTED;
+      }
+      return null;
+    }
+    if (!me.validate()) {
+      throw new AbortedException();
+    }
+    if (me == writer) {
+      return null;
+    }
+    for (Transaction reader : readers) {
+      if (reader.isActive() && reader != me) {
+        return reader;
+      }
+    }
+    readers.clear();
+    switch (writer.getStatus()) {
+      case ACTIVE:
+        return writer;
+      case COMMITTED:
+        backup();
+        version++;
+        break;
+      case ABORTED:
+        restore();
+        version++;
+        break;
+      default:
+        throw new PanicException(FORMAT, writer.getStatus());
+    }
+    writer = me;
+    return null;
+  }
+  
+  private void restore() {
+    System.arraycopy(shadow, 0, array, 0, array.length);
+  }
+  private void backup() {
+    System.arraycopy(array, 0, shadow, 0, array.length);
+  }
+  
+}
diff --git a/Robust/Transactions/dstm2/src/dstm2/util/ArrayList.java b/Robust/Transactions/dstm2/src/dstm2/util/ArrayList.java
new file mode 100644 (file)
index 0000000..3d38afe
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package dstm2.util;
+
+import dstm2.AtomicArray;
+import dstm2.factory.Factory;
+import dstm2.Thread;
+import dstm2.atomic;
+import java.util.Arrays;
+
+
+/**
+ *
+ * @author navid
+ */
+
+public class ArrayList<V extends dstm2.AtomicSuperClass>{
+   transient volatile int modCount;
+    private volatile int size;
+    AtomicArray<entry<V>> elementData;
+    private Factory<entry> factory;
+
+    public ArrayList() {
+        this(10);
+    }
+    
+    public ArrayList(int initialCapacity) {
+        super ();
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "  + initialCapacity);
+       this .elementData = new AtomicArray<entry<V>>(entry.class,initialCapacity);
+    }
+    
+    
+      public void ensureCapacity(int minCapacity) {
+          modCount++;
+          int oldCapacity = elementData.size();
+          if (minCapacity > oldCapacity) {
+                //Object oldData[] = elementData;
+                int newCapacity = (oldCapacity * 3) / 2 + 1;
+                if (newCapacity < minCapacity)
+                    newCapacity = minCapacity;
+                // minCapacity is usually close to size, so this is a win:
+                AtomicArray<entry<V>> newar =  new AtomicArray<entry<V>>(entry.class, newCapacity);
+                for (int i=0; i<newCapacity; i++)
+                    newar.set(i, elementData.get(i));
+                elementData = newar;
+          }
+      }
+
+            /**
+            * Returns the number of elements in this list.
+             *
+             * @return the number of elements in this list
+             */
+     public int size() {
+        return size;
+     }
+     
+     public boolean add(V value) {
+        ensureCapacity(size + 1); // Increments modCount!
+        entry<V> e = factory.create();
+        e.setValue(value);
+        elementData.set(size, e);
+        size++;
+        return true;
+     }
+     
+     public V get(int index){
+         return elementData.get(index).getValue();
+     }
+     
+     
+      public V remove(int index) {
+        rangeCheck(index);
+        modCount++;
+        entry<V> oldValue = elementData.get(index);
+
+        int numMoved = size - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index + 1, elementData,
+        index, numMoved);
+        size--;
+        elementData.set(size, null); // Let gc do its work
+        return oldValue.getValue();
+    }
+      
+      private void rangeCheck(int index) {
+         if (index < 0 || index >= this .size)
+             throw new IndexOutOfBoundsException();
+     }
+      
+      public void clear() {
+           modCount++;
+            // Let gc do its work
+           for (int i = 0; i < size; i++)
+              elementData.set(i, null);
+           size = 0;
+     } 
+    
+     @atomic interface entry<V>{
+        V getValue();
+        void setValue(V val);
+    }
+    
+
+
+}
diff --git a/Robust/Transactions/dstm2/src/dstm2/util/HashMap.java b/Robust/Transactions/dstm2/src/dstm2/util/HashMap.java
new file mode 100644 (file)
index 0000000..df7c54e
--- /dev/null
@@ -0,0 +1,894 @@
+package dstm2.util;
+
+import java.io.IOException;
+import java.util.AbstractSet;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import dstm2.Thread;
+import dstm2.atomic;
+import dstm2.factory.Factory;
+
+public class HashMap<V extends dstm2.AtomicSuperClass> implements Iterable<V>{
+       
+    /**
+     * The default initial capacity - MUST be a power of two.
+     */
+    static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     **/
+    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The table, resized as necessary. Length MUST Always be a power of two.
+     */
+    //transient TEntry<V>[] table;
+    dstm2.AtomicArray<TEntry> table;
+    final private Factory<TEntry> factory;
+       
+    //transient Entry<K, V>[] table;
+
+    /**
+     * The number of key-value mappings contained in this identity hash map.
+     */
+    //transient int size;
+    
+    java.util.concurrent.atomic.AtomicInteger size;
+    
+    /*
+     * The capacity of the table
+     */
+    transient int capacity;
+  
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     * @serial
+     */
+    int threshold;
+  
+    /**
+     * The load factor for the hash table.
+     *
+     * @serial
+     */
+    final float loadFactor;
+
+    /**
+     * The number of times this HashMap has been structurally modified
+     * Structural modifications are those that change the number of mappings in
+     * the HashMap or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the HashMap fail-fast.  (See ConcurrentModificationException).
+     */
+    transient volatile int modCount;
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and load factor.
+     *
+     * @param  initialCapacity The initial capacity.
+     * @param  loadFactor      The load factor.
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive.
+     */
+    public HashMap(int initialCapacity, float loadFactor) {
+       size = new AtomicInteger(0);
+       factory = Thread.makeFactory(TEntry.class);
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal initial capacity: " +
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal load factor: " +
+                                               loadFactor);
+
+        // Find a power of 2 >= initialCapacity
+        int capacity = 1;
+        while (capacity < initialCapacity) 
+            capacity <<= 1;
+    
+        this.capacity = capacity;
+        this.loadFactor = loadFactor;
+        threshold = (int)(capacity * loadFactor);
+        table = new dstm2.AtomicArray<TEntry>(TEntry.class, capacity);
+//        for(int i = 0; i < capacity; i++) {
+//             table[i] = factory.create();
+//        }
+        //table = new Entry[capacity];
+        init();
+    }
+  
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity.
+     * @throws IllegalArgumentException if the initial capacity is negative.
+     */
+    public HashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public HashMap() {
+       this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new <tt>HashMap</tt> with the same mappings as the
+     * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
+     * default load factor (0.75) and an initial capacity sufficient to
+     * hold the mappings in the specified <tt>Map</tt>.
+     *
+     * @param   m the map whose mappings are to be placed in this map.
+     * @throws  NullPointerException if the specified map is null.
+     */
+    public HashMap(HashMap<? extends V> m) {
+        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
+                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
+        putAllForCreate(m);
+    }
+
+    // internal utilities
+
+    /**
+     * Initialization hook for subclasses. This method is called
+     * in all constructors and pseudo-constructors (clone, readObject)
+     * after HashMap has been initialized but before any entries have
+     * been inserted.  (In the absence of this method, readObject would
+     * require explicit knowledge of subclasses.)
+     */
+    void init() {
+    }
+    public dstm2.AtomicArray<TEntry> getBuckets() {
+       return table;
+    }
+    /**
+     * Value representing null keys inside tables.
+     */
+    static final Object NULL_KEY = new Object();
+
+    /**
+     * Returns internal representation for key. Use NULL_KEY if key is null.
+     */
+    static <T> T maskNull(T key) {
+        return key == null ? (T)NULL_KEY : key;
+    }
+
+    /**
+     * Returns key represented by specified internal representation.
+     */
+    static <T> T unmaskNull(T key) {
+        return (key == NULL_KEY ? null : key);
+    }
+
+    /**
+     * Whether to prefer the old supplemental hash function, for
+     * compatibility with broken applications that rely on the
+     * internal hashing order.
+     *
+     * Set to true only by hotspot when invoked via
+     * -XX:+UseNewHashFunction or -XX:+AggressiveOpts
+     */
+    private static final boolean useNewHash;
+    static { useNewHash = false; }
+
+    private static int oldHash(int h) {
+        h += ~(h << 9);
+        h ^=  (h >>> 14);
+        h +=  (h << 4);
+        h ^=  (h >>> 10);
+        return h;
+    }
+
+    private static int newHash(int h) {
+        // This function ensures that hashCodes that differ only by
+        // constant multiples at each bit position have a bounded
+        // number of collisions (approximately 8 at default load factor).
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Applies a supplemental hash function to a given hashCode, which
+     * defends against poor quality hash functions.  This is critical
+     * because HashMap uses power-of-two length hash tables, that
+     * otherwise encounter collisions for hashCodes that do not differ
+     * in lower bits.
+     */
+    public static int hash(int h) {
+       return useNewHash ? newHash(h) : oldHash(h);
+    }
+
+    static int hash(Object key) {
+       return hash(key.hashCode());
+    }
+
+    /** 
+     * Check for equality of non-null reference x and possibly-null y. 
+     */
+    static boolean eq(Object x, Object y) {
+        return x == y || x.equals(y);
+    }
+
+    /**
+     * Returns index for hash code h. 
+     */
+    public static int indexFor(int h, int length) {
+        return h & (length-1);
+    }
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map.
+     */
+    public int size() {
+        return size.get();
+    }
+  
+    /**
+     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     *
+     * @return <tt>true</tt> if this map contains no key-value mappings.
+     */
+    public boolean isEmpty() {
+        return size.get() == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped in this identity
+     * hash map, or <tt>null</tt> if the map contains no mapping for this key.
+     * A return value of <tt>null</tt> does not <i>necessarily</i> indicate
+     * that the map contains no mapping for the key; it is also possible that
+     * the map explicitly maps the key to <tt>null</tt>. The
+     * <tt>containsKey</tt> method may be used to distinguish these two cases.
+     *
+     * @param   key the key whose associated value is to be returned.
+     * @return  the value to which this map maps the specified key, or
+     *          <tt>null</tt> if the map contains no mapping for this key.
+     * @see #put(Object, Object)
+     */
+    public V get(int key) {
+//             if (key == null)
+//                 return getForNullKey();
+        int hash = hash(key);
+        for (TEntry<V> e = table.get(indexFor(hash, capacity));
+             e != null;
+             e = e.getNext()) {
+            Object k;
+            if (e.getHash() == hash)
+                return e.getValue();
+        }
+        return null;
+    }
+
+//    private V getForNullKey() {
+//        int hash = hash(NULL_KEY.hashCode());
+//        int i = indexFor(hash, capacity);
+//        TEntry<K,V> e = table[i];
+//        //Entry<K,V> e = table[i];
+//        while (true) {
+//            if (e == null)
+//                return null;
+//            if (e.getKey() == NULL_KEY)
+//                return e.getValue();
+//            e = e.getNext();
+//        }
+//    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param   key   The key whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     */
+    public boolean containsKey(int key) {
+        Object k = maskNull(key);
+        int hash = hash(k);
+        int i = indexFor(hash, capacity);
+        TEntry<V> e = table.get(i); 
+        while (e != null) {
+            if (e.getHash() == hash) 
+                return true;
+            e = e.getNext();
+        }
+        return false;
+    }
+
+    /**
+     * Returns the entry associated with the specified key in the
+     * HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    TEntry<V> getEntry(int key) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        TEntry<V> e = table.get(i); 
+        while (e != null && !(e.getHash() == hash))
+            e = e.getNext();
+        return e;
+    }
+  
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *        if there was no mapping for key.  A <tt>null</tt> return can
+     *        also indicate that the HashMap previously associated
+     *        <tt>null</tt> with the specified key.
+     */
+    public V put(int key, V value) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        for (TEntry<V> e = table.get(i); e != null; e = e.getNext()) {
+            if (e.getHash() == hash) {
+                V oldValue = e.getValue();
+                e.setValue(value);
+//                e.recordAccess(this);
+                return oldValue;
+            }
+        }
+        modCount++;
+        addEntry(hash, value, i);
+        return null;
+    }
+
+
+
+    /**
+     * This method is used instead of put by constructors and
+     * pseudoconstructors (clone, readObject).  It does not resize the table,
+     * check for comodification, etc.  It calls createEntry rather than
+     * addEntry.
+     */
+    private void putForCreate(int key, V value) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+
+        /**
+         * Look for preexisting entry for key.  This will never happen for
+         * clone or deserialize.  It will only happen for construction if the
+         * input Map is a sorted map whose ordering is inconsistent w/ equals.
+         */
+        for (TEntry<V> e = table.get(i); e != null; e = e.getNext()) {
+            if (e.getHash() == hash) {
+                e.setValue(value);
+                return;
+            }
+        }
+
+        createEntry(hash, value, i);
+    }
+
+    void putAllForCreate(HashMap<? extends V> m) {
+        for (Iterator<? extends HashMap.TEntry<? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
+            HashMap.TEntry<? extends V> e = i.next();
+            putForCreate(e.getHash(), e.getValue());
+        }
+    }
+
+    /**
+     * Rehashes the contents of this map into a new array with a
+     * larger capacity.  This method is called automatically when the
+     * number of keys in this map reaches its threshold.
+     *
+     * If current capacity is MAXIMUM_CAPACITY, this method does not
+     * resize the map, but sets threshold to Integer.MAX_VALUE.
+     * This has the effect of preventing future calls.
+     *
+     * @param newCapacity the new capacity, MUST be a power of two;
+     *        must be greater than current capacity unless current
+     *        capacity is MAXIMUM_CAPACITY (in which case value
+     *        is irrelevant).
+     */
+    void resize(int newCapacity) {
+        dstm2.AtomicArray<TEntry> oldTable = table;
+        int oldCapacity = capacity;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            threshold = Integer.MAX_VALUE;
+            return;
+        }
+
+        dstm2.AtomicArray<TEntry> newTable = new dstm2.AtomicArray<TEntry>(TEntry.class, newCapacity);
+        transfer(newTable, newCapacity);
+        table = newTable;
+        threshold = (int)(newCapacity * loadFactor);
+        capacity = newCapacity;
+    }
+
+    /** 
+     * Transfer all entries from current table to newTable.
+     */
+    void transfer(dstm2.AtomicArray<TEntry> newTable, int nc) {
+       dstm2.AtomicArray<TEntry> src = table;
+        int newCapacity = nc;
+        for (int j = 0; j < capacity; j++) {
+            TEntry<V> e = src.get(j);
+            if (e != null) {
+                src.set(j, null);
+                do {
+                    TEntry<V> next = e.getNext();
+                    int i = indexFor(e.getHash(), newCapacity);  
+                    e.setNext(newTable.get(i));
+                    newTable.set(i, e);
+                    e = next;
+                } while (e != null);
+            }
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map
+     * These mappings will replace any mappings that
+     * this map had for any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map.
+     * @throws NullPointerException if the specified map is null.
+     */
+    public void putAll(HashMap<? extends V> m) {
+        int numKeysToBeAdded = m.size();
+        if (numKeysToBeAdded == 0)
+            return;
+
+        /*
+         * Expand the map if the map if the number of mappings to be added
+         * is greater than or equal to threshold.  This is conservative; the
+         * obvious condition is (m.size() + size) >= threshold, but this
+         * condition could result in a map with twice the appropriate capacity,
+         * if the keys to be added overlap with the keys already in this map.
+         * By using the conservative calculation, we subject ourself
+         * to at most one extra resize.
+         */
+        if (numKeysToBeAdded > threshold) {
+            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
+            if (targetCapacity > MAXIMUM_CAPACITY)
+                targetCapacity = MAXIMUM_CAPACITY;
+            int newCapacity = capacity;
+            while (newCapacity < targetCapacity)
+                newCapacity <<= 1;
+            if (newCapacity > capacity)
+                resize(newCapacity);
+        }
+
+        for (Iterator<? extends HashMap.TEntry<? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) {
+            HashMap.TEntry<? extends V> e = i.next();
+            put(e.getHash(), e.getValue());
+        }
+    }
+  
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param  key key whose mapping is to be removed from the map.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *        if there was no mapping for key.  A <tt>null</tt> return can
+     *        also indicate that the map previously associated <tt>null</tt>
+     *        with the specified key.
+     */
+    public V remove(int key) {
+        TEntry<V> e = removeEntryForKey(key);
+        return (e == null ? null : e.getValue());
+    }
+
+    /**
+     * Removes and returns the entry associated with the specified key
+     * in the HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    TEntry<V> removeEntryForKey(int key) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        TEntry<V> prev = table.get(i);
+        TEntry<V> e = prev;
+
+        while (e != null) {
+            TEntry<V> next = e.getNext();
+            if (e.getHash() == hash) {
+                modCount++;
+                size.decrementAndGet();
+                if (prev == e) 
+                    table.set(i, next);
+                else
+                    prev.setNext(next);
+//                e.recordRemoval(this);
+                return e;
+            }
+            prev = e;
+            e = next;
+        }
+   
+        return e;
+    }
+
+    /**
+     * Special version of remove for EntrySet.
+     */
+    TEntry<V> removeMapping(TEntry<V> o) {
+
+        TEntry<V> entry = o;
+        int hash = hash(o.getHash());
+        int i = indexFor(hash, capacity);
+        TEntry<V> prev = table.get(i);
+        TEntry<V> e = prev;
+
+        while (e != null) {
+            TEntry<V> next = e.getNext();
+            if (e.getHash() == hash) {
+                modCount++;
+                size.decrementAndGet();
+                if (prev == e) 
+                       table.set(i,  next);
+                else
+                    prev.setNext(next);
+//                e.recordRemoval(this);
+                return e;
+            }
+            prev = e;
+            e = next;
+        }
+   
+        return e;
+    }
+
+    /**
+     * Removes all mappings from this map.
+     */
+    public void clear() {
+        modCount++;
+        dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity; i++) 
+               table.set(i, null);
+        size.set(0);
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested.
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value.
+     */
+    public boolean containsValue(Object value) {
+       if (value == null) 
+            return containsNullValue();
+
+       dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity; i++)
+            for (TEntry e = tab.get(i); e != null ; e = e.getNext())
+                if (value.equals(e.getValue()))
+                    return true;
+       return false;
+    }
+
+    /**
+     * Special-case code for containsValue with null argument
+     **/
+    private boolean containsNullValue() {
+       dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity ; i++)
+            for (TEntry e = tab.get(i) ; e != null ; e = e.getNext())
+                if (e.getValue() == null)
+                    return true;
+       return false;
+    }
+
+    @atomic public interface TEntry<V> {
+       int getHash();
+               V   getValue();
+       TEntry<V> getNext();
+       void setHash(int h);
+       void setValue(V v);
+       void setNext(TEntry<V> n);
+       
+    }
+    
+
+    /**
+     * Add a new entry with the specified key, value and hash code to
+     * the specified bucket.  It is the responsibility of this 
+     * method to resize the table if appropriate.
+     *
+     * Subclass overrides this to alter the behavior of put method.
+     */
+    void addEntry(int hash, V value, int bucketIndex) {
+       TEntry<V> e = table.get(bucketIndex);
+       TEntry<V> n = factory.create();
+        n.setHash(hash);
+        n.setValue(value);
+        n.setNext(e);
+       table.set(bucketIndex, n);
+        if (size.incrementAndGet() >= threshold) {
+               synchronized(this) {
+                       if(size.get() >= threshold)
+                               resize(2 * capacity);
+               }
+        }
+    }
+
+    /**
+     * Like addEntry except that this version is used when creating entries
+     * as part of Map construction or "pseudo-construction" (cloning,
+     * deserialization).  This version needn't worry about resizing the table.
+     *
+     * Subclass overrides this to alter the behavior of HashMap(Map),
+     * clone, and readObject.
+     */
+    void createEntry(int hash, V value, int bucketIndex) {
+       TEntry<V> e = table.get(bucketIndex);
+       TEntry<V> n = factory.create();
+        n.setHash(hash);
+        n.setValue(value);
+        n.setNext(e);
+       table.set(bucketIndex, n);
+        size.incrementAndGet();
+    }
+
+    private abstract class HashIterator<E> implements Iterator<E> {
+        TEntry<V> next;        // next entry to return
+        int expectedModCount;  // For fast-fail 
+        int index;             // current slot 
+        TEntry<V> current;     // current entry
+
+        HashIterator() {
+            expectedModCount = modCount;
+            dstm2.AtomicArray<TEntry> t = table;
+            int i = capacity;
+            TEntry<V> n = null;
+            if (size.get() != 0) { // advance to first entry
+                while (i > 0 && (n = t.get(--i)) == null)
+                    ;
+            }
+            next = n;
+            index = i;
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        TEntry<V> nextEntry() { 
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            TEntry<V> e = next;
+            if (e == null) 
+                throw new NoSuchElementException();
+                
+            TEntry<V> n = e.getNext();
+            dstm2.AtomicArray<TEntry> t = table;
+            int i = index;
+            while (n == null && i > 0)
+                n = t.get(--i);
+            index = i;
+            next = n;
+            return current = e;
+        }
+
+        public void remove() {
+            if (current == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            int k = current.getHash();
+            current = null;
+            HashMap.this.removeEntryForKey(k);
+            expectedModCount = modCount;
+        }
+
+    }
+
+    private class ValueIterator extends HashIterator<V> {
+        public V next() {
+            return nextEntry().getValue();
+        }
+    }
+
+    private class KeyIterator extends HashIterator<Integer> {
+        public Integer next() {
+            return nextEntry().getHash();
+        }
+    }
+
+//    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
+//        public Map.Entry<K,V> next() {
+//            return nextEntry();
+//        }
+//    }
+
+    // Subclass overrides these to alter behavior of views' iterator() method
+    public Iterator<Integer> newKeyIterator()   {
+        return new KeyIterator();
+    }
+    public Iterator<V> newValueIterator()   {
+        return new ValueIterator();
+    }
+//    Iterator<Map.Entry<K,V>> newEntryIterator()   {
+//        return new EntryIterator();
+//    }
+
+
+    // Views
+
+    private transient Set<HashMap.TEntry<V>> entrySet = null;
+
+
+
+    private class KeySet extends AbstractSet<Integer> {
+        public Iterator<Integer> iterator() {
+            return newKeyIterator();
+        }
+        public int size() {
+            return size.get();
+        }
+        public boolean contains(Integer o) {
+            return containsKey(o);
+        }
+        public boolean remove(Integer o) {
+            return HashMap.this.removeEntryForKey(o) != null;
+        }
+        public void clear() {
+            HashMap.this.clear();
+        }
+    }
+
+
+
+    /**
+     * Returns a collection view of the mappings contained in this map.  Each
+     * element in the returned collection is a <tt>Map.Entry</tt>.  The
+     * collection is backed by the map, so changes to the map are reflected in
+     * the collection, and vice-versa.  The collection supports element
+     * removal, which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
+     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a collection view of the mappings contained in this map.
+     * @see Map.Entry
+     */
+    public Set<HashMap.TEntry<V>> entrySet() {
+        Set<HashMap.TEntry<V>> es = entrySet;
+        return (es != null ? es : (entrySet = (Set<HashMap.TEntry<V>>) (Set) new EntrySet()));
+    }
+
+    private class EntrySet {//extends AbstractSet/*<Map.Entry<K,V>>*/ {
+//        public Iterator/*<Map.Entry<K,V>>*/ iterator() {
+//            return newEntryIterator();
+//        }
+        public boolean contains(HashMap.TEntry<V> o) {
+            HashMap.TEntry<V> e = (HashMap.TEntry<V>) o;
+            TEntry<V> candidate = getEntry(e.getHash());
+            return candidate != null && candidate.equals(e);
+        }
+        public boolean remove(HashMap.TEntry<V> o) {
+            return removeMapping(o) != null;
+        }
+        public int size() {
+            return size.get();
+        }
+        public void clear() {
+            HashMap.this.clear();
+        }
+    }
+
+    /**
+     * Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>capacity</i> of the HashMap (the length of the
+     *            bucket array) is emitted (int), followed  by the
+     *            <i>size</i> of the HashMap (the number of key-value
+     *            mappings), followed by the key (Object) and value (Object)
+     *            for each key-value mapping represented by the HashMap
+     *             The key-value mappings are emitted in the order that they
+     *             are returned by <tt>entrySet().iterator()</tt>.
+     * 
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws IOException
+    {
+       Iterator<HashMap.TEntry<V>> i = entrySet().iterator();
+
+       // Write out the threshold, loadfactor, and any hidden stuff
+       s.defaultWriteObject();
+
+       // Write out number of buckets
+       s.writeInt(capacity);
+
+       // Write out size (number of Mappings)
+       s.writeInt(size.get());
+
+        // Write out keys and values (alternating)
+       while (i.hasNext()) { 
+            HashMap.TEntry<V> e = i.next();
+            s.writeObject(e.getHash());
+            s.writeObject(e.getValue());
+        }
+    }
+
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /**
+     * Reconstitute the <tt>HashMap</tt> instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+       // Read in the threshold, loadfactor, and any hidden stuff
+       s.defaultReadObject();
+
+       // Read in number of buckets and allocate the bucket array;
+       int numBuckets = s.readInt();
+       table = new dstm2.AtomicArray(TEntry.class, numBuckets);
+
+        init();  // Give subclass a chance to do its thing.
+
+       // Read in size (number of Mappings)
+       int size = s.readInt();
+
+       // Read the keys and values, and put the mappings in the HashMap
+       for (int i=0; i<size; i++) {
+           int key = (Integer) s.readObject();
+           V value = (V) s.readObject();
+           putForCreate(key, value);
+       }
+    }
+
+    // These methods are used when serializing HashSets
+    int   capacity()     { return capacity; }
+    float loadFactor()   { return loadFactor;   }
+
+       public int getCapacity() {
+               return capacity;
+       }
+
+       
+         public Iterator<V> iterator() {
+           return new Iterator<V>() {
+             int tableIndex = 0;
+             public TEntry<V> cursor = table.get(tableIndex);
+             public boolean hasNext() {
+               return cursor != null;
+             }
+             public V next() {
+               TEntry<V> node = cursor;
+               cursor = cursor.getNext();
+               while(cursor==null) {
+                       tableIndex++;
+                       if(tableIndex < capacity) {
+                               cursor = table.get(tableIndex);
+                       }
+               }
+               return node.getValue();
+             }
+             public void remove() {
+               throw new UnsupportedOperationException();
+             }
+             
+           };
+         }
+}
diff --git a/Robust/Transactions/dstm2/src/dstm2/util/IntHashMap.java b/Robust/Transactions/dstm2/src/dstm2/util/IntHashMap.java
new file mode 100644 (file)
index 0000000..ffb67a4
--- /dev/null
@@ -0,0 +1,894 @@
+package dstm2.util;
+
+import java.io.IOException;
+import java.util.AbstractSet;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import dstm2.Thread;
+import dstm2.atomic;
+import dstm2.factory.Factory;
+
+public class IntHashMap implements Iterable<Integer>{
+       
+    /**
+     * The default initial capacity - MUST be a power of two.
+     */
+    static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     **/
+    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The table, resized as necessary. Length MUST Always be a power of two.
+     */
+    //transient TEntry<V>[] table;
+    dstm2.AtomicArray<TEntry> table;
+    final private Factory<TEntry> factory;
+       
+    //transient Entry<K, V>[] table;
+
+    /**
+     * The number of key-value mappings contained in this identity hash map.
+     */
+    //transient int size;
+    
+    java.util.concurrent.atomic.AtomicInteger size;
+    
+    /*
+     * The capacity of the table
+     */
+    transient int capacity;
+  
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     * @serial
+     */
+    int threshold;
+  
+    /**
+     * The load factor for the hash table.
+     *
+     * @serial
+     */
+    final float loadFactor;
+
+    /**
+     * The number of times this HashMap has been structurally modified
+     * Structural modifications are those that change the number of mappings in
+     * the HashMap or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the HashMap fail-fast.  (See ConcurrentModificationException).
+     */
+    transient volatile int modCount;
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and load factor.
+     *
+     * @param  initialCapacity The initial capacity.
+     * @param  loadFactor      The load factor.
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive.
+     */
+    public IntHashMap(int initialCapacity, float loadFactor) {
+       size = new AtomicInteger(0);
+       factory = Thread.makeFactory(TEntry.class);
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal initial capacity: " +
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal load factor: " +
+                                               loadFactor);
+
+        // Find a power of 2 >= initialCapacity
+        int capacity = 1;
+        while (capacity < initialCapacity) 
+            capacity <<= 1;
+    
+        this.capacity = capacity;
+        this.loadFactor = loadFactor;
+        threshold = (int)(capacity * loadFactor);
+        table = new dstm2.AtomicArray<TEntry>(TEntry.class, capacity);
+//        for(int i = 0; i < capacity; i++) {
+//             table[i] = factory.create();
+//        }
+        //table = new Entry[capacity];
+        init();
+    }
+  
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity.
+     * @throws IllegalArgumentException if the initial capacity is negative.
+     */
+    public IntHashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public IntHashMap() {
+       this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new <tt>HashMap</tt> with the same mappings as the
+     * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
+     * default load factor (0.75) and an initial capacity sufficient to
+     * hold the mappings in the specified <tt>Map</tt>.
+     *
+     * @param   m the map whose mappings are to be placed in this map.
+     * @throws  NullPointerException if the specified map is null.
+     */
+    public IntHashMap(IntHashMap m) {
+        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
+                      DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
+        putAllForCreate(m);
+    }
+
+    // internal utilities
+
+    /**
+     * Initialization hook for subclasses. This method is called
+     * in all constructors and pseudo-constructors (clone, readObject)
+     * after HashMap has been initialized but before any entries have
+     * been inserted.  (In the absence of this method, readObject would
+     * require explicit knowledge of subclasses.)
+     */
+    void init() {
+    }
+    public dstm2.AtomicArray<TEntry> getBuckets() {
+       return table;
+    }
+    /**
+     * Value representing null keys inside tables.
+     */
+    static final Object NULL_KEY = new Object();
+
+    /**
+     * Returns internal representation for key. Use NULL_KEY if key is null.
+     */
+    static <T> T maskNull(T key) {
+        return key == null ? (T)NULL_KEY : key;
+    }
+
+    /**
+     * Returns key represented by specified internal representation.
+     */
+    static <T> T unmaskNull(T key) {
+        return (key == NULL_KEY ? null : key);
+    }
+
+    /**
+     * Whether to prefer the old supplemental hash function, for
+     * compatibility with broken applications that rely on the
+     * internal hashing order.
+     *
+     * Set to true only by hotspot when invoked via
+     * -XX:+UseNewHashFunction or -XX:+AggressiveOpts
+     */
+    private static final boolean useNewHash;
+    static { useNewHash = false; }
+
+    private static int oldHash(int h) {
+        h += ~(h << 9);
+        h ^=  (h >>> 14);
+        h +=  (h << 4);
+        h ^=  (h >>> 10);
+        return h;
+    }
+
+    private static int newHash(int h) {
+        // This function ensures that hashCodes that differ only by
+        // constant multiples at each bit position have a bounded
+        // number of collisions (approximately 8 at default load factor).
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Applies a supplemental hash function to a given hashCode, which
+     * defends against poor quality hash functions.  This is critical
+     * because HashMap uses power-of-two length hash tables, that
+     * otherwise encounter collisions for hashCodes that do not differ
+     * in lower bits.
+     */
+    public static int hash(int h) {
+       return useNewHash ? newHash(h) : oldHash(h);
+    }
+
+    public static int hash(Object key) {
+       return hash(key.hashCode());
+    }
+
+    /** 
+     * Check for equality of non-null reference x and possibly-null y. 
+     */
+    static boolean eq(Object x, Object y) {
+        return x == y || x.equals(y);
+    }
+
+    /**
+     * Returns index for hash code h. 
+     */
+    public static int indexFor(int h, int length) {
+        return h & (length-1);
+    }
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map.
+     */
+    public int size() {
+        return size.get();
+    }
+  
+    /**
+     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     *
+     * @return <tt>true</tt> if this map contains no key-value mappings.
+     */
+    public boolean isEmpty() {
+        return size.get() == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped in this identity
+     * hash map, or <tt>null</tt> if the map contains no mapping for this key.
+     * A return value of <tt>null</tt> does not <i>necessarily</i> indicate
+     * that the map contains no mapping for the key; it is also possible that
+     * the map explicitly maps the key to <tt>null</tt>. The
+     * <tt>containsKey</tt> method may be used to distinguish these two cases.
+     *
+     * @param   key the key whose associated value is to be returned.
+     * @return  the value to which this map maps the specified key, or
+     *          <tt>null</tt> if the map contains no mapping for this key.
+     * @see #put(Object, Object)
+     */
+    public Integer get(int key) {
+//             if (key == null)
+//                 return getForNullKey();
+        int hash = hash(key);
+        for (TEntry e = table.get(indexFor(hash, capacity));
+             e != null;
+             e = e.getNext()) {
+            Object k;
+            if (e.getHash() == hash)
+                return e.getValue();
+        }
+        return null;
+    }
+
+//    private V getForNullKey() {
+//        int hash = hash(NULL_KEY.hashCode());
+//        int i = indexFor(hash, capacity);
+//        TEntry<K,V> e = table[i];
+//        //Entry<K,V> e = table[i];
+//        while (true) {
+//            if (e == null)
+//                return null;
+//            if (e.getKey() == NULL_KEY)
+//                return e.getValue();
+//            e = e.getNext();
+//        }
+//    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param   key   The key whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     */
+    public boolean containsKey(int key) {
+        Object k = maskNull(key);
+        int hash = hash(k);
+        int i = indexFor(hash, capacity);
+        TEntry e = table.get(i); 
+        while (e != null) {
+            if (e.getHash() == hash) 
+                return true;
+            e = e.getNext();
+        }
+        return false;
+    }
+
+    /**
+     * Returns the entry associated with the specified key in the
+     * HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    TEntry getEntry(int key) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        TEntry e = table.get(i); 
+        while (e != null && !(e.getHash() == hash))
+            e = e.getNext();
+        return e;
+    }
+  
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *        if there was no mapping for key.  A <tt>null</tt> return can
+     *        also indicate that the HashMap previously associated
+     *        <tt>null</tt> with the specified key.
+     */
+    public Integer put(int key, Integer value) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        for (TEntry e = table.get(i); e != null; e = e.getNext()) {
+            if (e.getHash() == hash) {
+                Integer oldValue = e.getValue();
+                e.setValue(value);
+//                e.recordAccess(this);
+                return oldValue;
+            }
+        }
+        modCount++;
+        addEntry(hash, value, i);
+        return null;
+    }
+
+
+
+    /**
+     * This method is used instead of put by constructors and
+     * pseudoconstructors (clone, readObject).  It does not resize the table,
+     * check for comodification, etc.  It calls createEntry rather than
+     * addEntry.
+     */
+    private void putForCreate(int key, Integer value) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+
+        /**
+         * Look for preexisting entry for key.  This will never happen for
+         * clone or deserialize.  It will only happen for construction if the
+         * input Map is a sorted map whose ordering is inconsistent w/ equals.
+         */
+        for (TEntry e = table.get(i); e != null; e = e.getNext()) {
+            if (e.getHash() == hash) {
+                e.setValue(value);
+                return;
+            }
+        }
+
+        createEntry(hash, value, i);
+    }
+
+    void putAllForCreate(IntHashMap m) {
+        for (Iterator<? extends IntHashMap.TEntry> i = m.entrySet().iterator(); i.hasNext(); ) {
+            IntHashMap.TEntry e = i.next();
+            putForCreate(e.getHash(), e.getValue());
+        }
+    }
+
+    /**
+     * Rehashes the contents of this map into a new array with a
+     * larger capacity.  This method is called automatically when the
+     * number of keys in this map reaches its threshold.
+     *
+     * If current capacity is MAXIMUM_CAPACITY, this method does not
+     * resize the map, but sets threshold to Integer.MAX_VALUE.
+     * This has the effect of preventing future calls.
+     *
+     * @param newCapacity the new capacity, MUST be a power of two;
+     *        must be greater than current capacity unless current
+     *        capacity is MAXIMUM_CAPACITY (in which case value
+     *        is irrelevant).
+     */
+    void resize(int newCapacity) {
+        dstm2.AtomicArray<TEntry> oldTable = table;
+        int oldCapacity = capacity;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            threshold = Integer.MAX_VALUE;
+            return;
+        }
+
+        dstm2.AtomicArray<TEntry> newTable = new dstm2.AtomicArray<TEntry>(TEntry.class, newCapacity);
+        transfer(newTable, newCapacity);
+        table = newTable;
+        threshold = (int)(newCapacity * loadFactor);
+        capacity = newCapacity;
+    }
+
+    /** 
+     * Transfer all entries from current table to newTable.
+     */
+    void transfer(dstm2.AtomicArray<TEntry> newTable, int nc) {
+       dstm2.AtomicArray<TEntry> src = table;
+        int newCapacity = nc;
+        for (int j = 0; j < capacity; j++) {
+            TEntry e = src.get(j);
+            if (e != null) {
+                src.set(j, null);
+                do {
+                    TEntry next = e.getNext();
+                    int i = indexFor(e.getHash(), newCapacity);  
+                    e.setNext(newTable.get(i));
+                    newTable.set(i, e);
+                    e = next;
+                } while (e != null);
+            }
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map
+     * These mappings will replace any mappings that
+     * this map had for any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map.
+     * @throws NullPointerException if the specified map is null.
+     */
+    public void putAll(IntHashMap m) {
+        int numKeysToBeAdded = m.size();
+        if (numKeysToBeAdded == 0)
+            return;
+
+        /*
+         * Expand the map if the map if the number of mappings to be added
+         * is greater than or equal to threshold.  This is conservative; the
+         * obvious condition is (m.size() + size) >= threshold, but this
+         * condition could result in a map with twice the appropriate capacity,
+         * if the keys to be added overlap with the keys already in this map.
+         * By using the conservative calculation, we subject ourself
+         * to at most one extra resize.
+         */
+        if (numKeysToBeAdded > threshold) {
+            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
+            if (targetCapacity > MAXIMUM_CAPACITY)
+                targetCapacity = MAXIMUM_CAPACITY;
+            int newCapacity = capacity;
+            while (newCapacity < targetCapacity)
+                newCapacity <<= 1;
+            if (newCapacity > capacity)
+                resize(newCapacity);
+        }
+
+        for (Iterator<? extends IntHashMap.TEntry> i = m.entrySet().iterator(); i.hasNext(); ) {
+            IntHashMap.TEntry e = i.next();
+            put(e.getHash(), e.getValue());
+        }
+    }
+  
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param  key key whose mapping is to be removed from the map.
+     * @return previous value associated with specified key, or <tt>null</tt>
+     *        if there was no mapping for key.  A <tt>null</tt> return can
+     *        also indicate that the map previously associated <tt>null</tt>
+     *        with the specified key.
+     */
+    public Integer remove(int key) {
+        TEntry e = removeEntryForKey(key);
+        return (e == null ? null : e.getValue());
+    }
+
+    /**
+     * Removes and returns the entry associated with the specified key
+     * in the HashMap.  Returns null if the HashMap contains no mapping
+     * for this key.
+     */
+    TEntry removeEntryForKey(int key) {
+        int hash = hash(key);
+        int i = indexFor(hash, capacity);
+        TEntry prev = table.get(i);
+        TEntry e = prev;
+
+        while (e != null) {
+            TEntry next = e.getNext();
+            if (e.getHash() == hash) {
+                modCount++;
+                size.decrementAndGet();
+                if (prev == e) 
+                    table.set(i, next);
+                else
+                    prev.setNext(next);
+//                e.recordRemoval(this);
+                return e;
+            }
+            prev = e;
+            e = next;
+        }
+   
+        return e;
+    }
+
+    /**
+     * Special version of remove for EntrySet.
+     */
+    TEntry removeMapping(TEntry o) {
+
+        TEntry entry = o;
+        int hash = hash(o.getHash());
+        int i = indexFor(hash, capacity);
+        TEntry prev = table.get(i);
+        TEntry e = prev;
+
+        while (e != null) {
+            TEntry next = e.getNext();
+            if (e.getHash() == hash) {
+                modCount++;
+                size.decrementAndGet();
+                if (prev == e) 
+                       table.set(i,  next);
+                else
+                    prev.setNext(next);
+//                e.recordRemoval(this);
+                return e;
+            }
+            prev = e;
+            e = next;
+        }
+   
+        return e;
+    }
+
+    /**
+     * Removes all mappings from this map.
+     */
+    public void clear() {
+        modCount++;
+        dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity; i++) 
+               table.set(i, null);
+        size.set(0);
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested.
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value.
+     */
+    public boolean containsValue(Object value) {
+       if (value == null) 
+            return containsNullValue();
+
+       dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity; i++)
+            for (TEntry e = tab.get(i); e != null ; e = e.getNext())
+                if (value.equals(e.getValue()))
+                    return true;
+       return false;
+    }
+
+    /**
+     * Special-case code for containsValue with null argument
+     **/
+    private boolean containsNullValue() {
+       dstm2.AtomicArray<TEntry> tab = table;
+        for (int i = 0; i < capacity ; i++)
+            for (TEntry e = tab.get(i) ; e != null ; e = e.getNext())
+                if (e.getValue() == null)
+                    return true;
+       return false;
+    }
+
+    @atomic public interface TEntry {
+       int getHash();
+       Integer getValue();
+       TEntry getNext();
+       void setHash(int h);
+       void setValue(Integer v);
+       void setNext(TEntry n);
+       
+    }
+    
+
+    /**
+     * Add a new entry with the specified key, value and hash code to
+     * the specified bucket.  It is the responsibility of this 
+     * method to resize the table if appropriate.
+     *
+     * Subclass overrides this to alter the behavior of put method.
+     */
+    void addEntry(int hash, Integer value, int bucketIndex) {
+       TEntry e = table.get(bucketIndex);
+       TEntry n = factory.create();
+        n.setHash(hash);
+        n.setValue(value);
+        n.setNext(e);
+       table.set(bucketIndex, n);
+        if (size.incrementAndGet() >= threshold) {
+               synchronized(this) {
+                       if(size.get() >= threshold)
+                               resize(2 * capacity);
+               }
+        }
+    }
+
+    /**
+     * Like addEntry except that this version is used when creating entries
+     * as part of Map construction or "pseudo-construction" (cloning,
+     * deserialization).  This version needn't worry about resizing the table.
+     *
+     * Subclass overrides this to alter the behavior of HashMap(Map),
+     * clone, and readObject.
+     */
+    void createEntry(int hash, Integer value, int bucketIndex) {
+       TEntry e = table.get(bucketIndex);
+       TEntry n = factory.create();
+        n.setHash(hash);
+        n.setValue(value);
+        n.setNext(e);
+       table.set(bucketIndex, n);
+        size.incrementAndGet();
+    }
+
+    private abstract class HashIterator<E> implements Iterator<E> {
+        TEntry next;   // next entry to return
+        int expectedModCount;  // For fast-fail 
+        int index;             // current slot 
+        TEntry current;        // current entry
+
+        HashIterator() {
+            expectedModCount = modCount;
+            dstm2.AtomicArray<TEntry> t = table;
+            int i = capacity;
+            TEntry n = null;
+            if (size.get() != 0) { // advance to first entry
+                while (i > 0 && (n = t.get(--i)) == null)
+                    ;
+            }
+            next = n;
+            index = i;
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        TEntry nextEntry() { 
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            TEntry e = next;
+            if (e == null) 
+                throw new NoSuchElementException();
+                
+            TEntry n = e.getNext();
+            dstm2.AtomicArray<TEntry> t = table;
+            int i = index;
+            while (n == null && i > 0)
+                n = t.get(--i);
+            index = i;
+            next = n;
+            return current = e;
+        }
+
+        public void remove() {
+            if (current == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            int k = current.getHash();
+            current = null;
+            IntHashMap.this.removeEntryForKey(k);
+            expectedModCount = modCount;
+        }
+
+    }
+
+    private class ValueIterator extends HashIterator<Integer> {
+        public Integer next() {
+            return nextEntry().getValue();
+        }
+    }
+
+    private class KeyIterator extends HashIterator<Integer> {
+        public Integer next() {
+            return nextEntry().getHash();
+        }
+    }
+
+//    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
+//        public Map.Entry<K,V> next() {
+//            return nextEntry();
+//        }
+//    }
+
+    // Subclass overrides these to alter behavior of views' iterator() method
+    public Iterator<Integer> newKeyIterator()   {
+        return new KeyIterator();
+    }
+    public Iterator<Integer> newValueIterator()   {
+        return new ValueIterator();
+    }
+//    Iterator<Map.Entry<K,V>> newEntryIterator()   {
+//        return new EntryIterator();
+//    }
+
+
+    // Views
+
+    private transient Set<IntHashMap.TEntry> entrySet = null;
+
+
+
+    private class KeySet extends AbstractSet<Integer> {
+        public Iterator<Integer> iterator() {
+            return newKeyIterator();
+        }
+        public int size() {
+            return size.get();
+        }
+        public boolean contains(Integer o) {
+            return containsKey(o);
+        }
+        public boolean remove(Integer o) {
+            return IntHashMap.this.removeEntryForKey(o) != null;
+        }
+        public void clear() {
+            IntHashMap.this.clear();
+        }
+    }
+
+
+
+    /**
+     * Returns a collection view of the mappings contained in this map.  Each
+     * element in the returned collection is a <tt>Map.Entry</tt>.  The
+     * collection is backed by the map, so changes to the map are reflected in
+     * the collection, and vice-versa.  The collection supports element
+     * removal, which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
+     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a collection view of the mappings contained in this map.
+     * @see Map.Entry
+     */
+    public Set<IntHashMap.TEntry> entrySet() {
+        Set<IntHashMap.TEntry> es = entrySet;
+        return (es != null ? es : (entrySet = (Set<IntHashMap.TEntry>) (Set) new EntrySet()));
+    }
+
+    private class EntrySet {//extends AbstractSet/*<Map.Entry<K,V>>*/ {
+//        public Iterator/*<Map.Entry<K,V>>*/ iterator() {
+//            return newEntryIterator();
+//        }
+        public boolean contains(IntHashMap.TEntry o) {
+            IntHashMap.TEntry e = (IntHashMap.TEntry) o;
+            TEntry candidate = getEntry(e.getHash());
+            return candidate != null && candidate.equals(e);
+        }
+        public boolean remove(IntHashMap.TEntry o) {
+            return removeMapping(o) != null;
+        }
+        public int size() {
+            return size.get();
+        }
+        public void clear() {
+            IntHashMap.this.clear();
+        }
+    }
+
+    /**
+     * Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>capacity</i> of the HashMap (the length of the
+     *            bucket array) is emitted (int), followed  by the
+     *            <i>size</i> of the HashMap (the number of key-value
+     *            mappings), followed by the key (Object) and value (Object)
+     *            for each key-value mapping represented by the HashMap
+     *             The key-value mappings are emitted in the order that they
+     *             are returned by <tt>entrySet().iterator()</tt>.
+     * 
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws IOException
+    {
+       Iterator<IntHashMap.TEntry> i = entrySet().iterator();
+
+       // Write out the threshold, loadfactor, and any hidden stuff
+       s.defaultWriteObject();
+
+       // Write out number of buckets
+       s.writeInt(capacity);
+
+       // Write out size (number of Mappings)
+       s.writeInt(size.get());
+
+        // Write out keys and values (alternating)
+       while (i.hasNext()) { 
+            IntHashMap.TEntry e = i.next();
+            s.writeObject(e.getHash());
+            s.writeObject(e.getValue());
+        }
+    }
+
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /**
+     * Reconstitute the <tt>HashMap</tt> instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+       // Read in the threshold, loadfactor, and any hidden stuff
+       s.defaultReadObject();
+
+       // Read in number of buckets and allocate the bucket array;
+       int numBuckets = s.readInt();
+       table = new dstm2.AtomicArray(TEntry.class, numBuckets);
+
+        init();  // Give subclass a chance to do its thing.
+
+       // Read in size (number of Mappings)
+       int size = s.readInt();
+
+       // Read the keys and values, and put the mappings in the HashMap
+       for (int i=0; i<size; i++) {
+           int key = (Integer) s.readObject();
+           Integer value = (Integer) s.readObject();
+           putForCreate(key, value);
+       }
+    }
+
+    // These methods are used when serializing HashSets
+    int   capacity()     { return capacity; }
+    float loadFactor()   { return loadFactor;   }
+
+       public int getCapacity() {
+               return capacity;
+       }
+
+       
+         public Iterator<Integer> iterator() {
+           return new Iterator<Integer>() {
+             int tableIndex = 0;
+             public TEntry cursor = table.get(tableIndex);
+             public boolean hasNext() {
+               return cursor != null;
+             }
+             public Integer next() {
+               TEntry node = cursor;
+               cursor = cursor.getNext();
+               while(cursor==null) {
+                       tableIndex++;
+                       if(tableIndex < capacity) {
+                               cursor = table.get(tableIndex);
+                       }
+               }
+               return node.getValue();
+             }
+             public void remove() {
+               throw new UnsupportedOperationException();
+             }
+             
+           };
+         }
+}
diff --git a/Robust/Transactions/mytuplesoup/license.txt b/Robust/Transactions/mytuplesoup/license.txt
new file mode 100644 (file)
index 0000000..60c816d
--- /dev/null
@@ -0,0 +1,28 @@
+Copyright (c) 2005, Solido Systems
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+Neither the name of Solido Systems nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/readme.txt b/Robust/Transactions/mytuplesoup/readme.txt
new file mode 100644 (file)
index 0000000..bf75b92
--- /dev/null
@@ -0,0 +1,26 @@
+Readme file for Tuplesoup v0.1.1 released by Kasper J. Jeppesen September 7, 2007.
+
+If you have any comments you can reach the developers of tuplesoup at kjj@solidosystems.com
+
+[ Introduction ]
+Tuplesoup is a small easy to use Java based framework for storing and retrieving simple hashes.
+The latest version of Tuplesoup is always available from http://sourceforge.net/projects/tuplesoup
+
+[ License ]
+Tuplesoup has been released as open source under the BSD license by Solido Systems. See the file license.txt for the full license.
+
+[ Documentation ]
+By an amazing combination of laziness and procrastination I have not yet created an actual site for Tuplesoup. However, you can find a some posts about the design and usage of tuplesoup on my tech blog http://syntacticsirup.blogspot.com/
+
+[ Installation ]
+The tuplesoup distribution contains a jar file which can be placed in your java extensions folder or added to your classpath. No further installation steps are necesary.
+
+[ Update ]
+There is currently no procedures needed to perform an update other than just replacing the jar file. However, you should always read the changelog for any update procedures necesary between the file formats of future releases.
+
+[ Changelog ]
+ * 0.1.2
+    - Made table an interface, instantiate DualFileTable to get the same behaviour as before
+    - Added HashedTable which provides better multi threaded performance for single row queries
+ * 0.1.1
+    - First public release
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/DualFileTable.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/DualFileTable.java
new file mode 100644 (file)
index 0000000..8bfbe14
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+import com.solidosystems.tuplesoup.filter.*;
+
+/**
+ * The table stores a group of rows.
+ * Every row must have a unique id within a table.
+ */
+public class DualFileTable implements Table{
+
+    
+    private int INDEXCACHESIZE=8192;
+     
+    private String filealock="filea-dummy";
+    private String fileblock="fileb-dummy";
+
+    private DataOutputStream fileastream=null;
+    private DataOutputStream filebstream=null;
+    private RandomAccessFile filearandom=null;
+    private RandomAccessFile filebrandom=null;
+    FileChannel fca=null;
+    FileChannel fcb=null;
+    private TableIndex index=null;
+     
+    private long fileaposition=0;
+    private long filebposition=0;
+     
+    private boolean rowswitch=true;
+     
+    private String title;
+    private String location;
+     
+    private TableIndexNode indexcachefirst;
+    private TableIndexNode indexcachelast;
+    private int indexcacheusage;
+    private Hashtable<String,TableIndexNode> indexcache;
+    
+    // Statistic counters
+    long stat_add=0;
+    long stat_update=0;
+    long stat_delete=0;
+    long stat_add_size=0;
+    long stat_update_size=0;
+    long stat_read_size=0;
+    long stat_read=0;
+    long stat_cache_hit=0;
+    long stat_cache_miss=0;
+    long stat_cache_drop=0;
+    
+    protected String statlock="stat-dummy";
+    
+    /**
+     * Return the current values of the statistic counters and reset them.
+     * The current counters are:
+     * <ul>
+     *   <li>stat_table_add
+     *   <li>stat_table_update
+     *   <li>stat_table_delete
+     *   <li>stat_table_add_size
+     *   <li>stat_table_update_size
+     *   <li>stat_table_read_size
+     *   <li>stat_table_read
+     *   <li>stat_table_cache_hit
+     *   <li>stat_table_cache_miss
+     *   <li>stat_table_cache_drop
+     * </ul>
+     * Furthermore, the index will be asked to deliver separate index specific counters
+     */
+    public Hashtable<String,Long> readStatistics(){
+        Hashtable<String,Long> hash=new Hashtable<String,Long>();
+        synchronized(statlock){
+            hash.put("stat_table_add",stat_add);
+            hash.put("stat_table_update",stat_update);
+            hash.put("stat_table_delete",stat_delete);
+            hash.put("stat_table_add_size",stat_add_size);
+            hash.put("stat_table_update_size",stat_update_size);
+            hash.put("stat_table_read_size",stat_read_size);
+            hash.put("stat_table_read",stat_read);
+            hash.put("stat_table_cache_hit",stat_cache_hit);
+            hash.put("stat_table_cache_miss",stat_cache_miss);
+            hash.put("stat_table_cache_drop",stat_cache_drop);
+            stat_add=0;
+            stat_update=0;
+            stat_delete=0;
+            stat_add_size=0;
+            stat_update_size=0;
+            stat_read_size=0;
+            stat_read=0;
+            stat_cache_hit=0;
+            stat_cache_miss=0;
+            stat_cache_drop=0;
+            Hashtable<String,Long> ihash=index.readStatistics();
+            hash.putAll(ihash);
+        }
+        return hash;
+    }
+    
+    /**
+     * Create a new table object with the default flat index model
+     */
+
+    
+    /**
+     * Create a new table object with a specific index model
+     */
+    public DualFileTable(String title,String location, int indextype) throws IOException{
+        this.title=title;
+        this.location=location;
+        if(!this.location.endsWith(File.separator))this.location+=File.separator;
+        switch(indextype){
+             case PAGED  : index=new PagedIndex(getFileName(INDEX));
+                break;
+           
+        }
+        indexcachefirst=null;
+        indexcachelast=null;
+        indexcacheusage=0;
+        indexcache=new Hashtable<String,TableIndexNode>();
+    }
+     
+    /**
+     * Set the maximal allowable size of the index cache.
+     */ 
+    public void setIndexCacheSize(int newsize){
+        INDEXCACHESIZE=newsize;
+    }
+    
+    /**
+     * Close all open file streams
+     */
+    public void close(){
+        try{
+            if(fileastream!=null)fileastream.close();
+            if(filebstream!=null)filebstream.close();
+            if(filearandom!=null)filearandom.close();
+            if(filebrandom!=null)filebrandom.close();
+            index.close();
+        }catch(Exception e){}
+    }
+    
+    /** 
+     * Returns the name of this table
+     */ 
+    public String getTitle(){
+         return title;
+    }
+    
+    /**
+     * Returns the location of this tables datafiles
+     */ 
+    public String getLocation(){
+         return location;
+    }
+     
+    protected String getFileName(int type){
+         switch(type){
+             case FILEB  :   return location+title+".a";
+             case FILEA  :   return location+title+".b";
+             case INDEX  :   return location+title+".index";
+         }
+         return null;
+    }
+    
+    /**
+     * Delete the files created by this table object.
+     * Be aware that this will delete any data stored in this table!
+     */ 
+    public void deleteFiles(){
+         try{
+             File ftest=new File(getFileName(FILEA));
+             ftest.delete();
+         }catch(Exception e){}
+         try{
+             File ftest=new File(getFileName(FILEB));
+             ftest.delete();
+         }catch(Exception e){}
+         try{
+             File ftest=new File(getFileName(INDEX));
+             ftest.delete();
+         }catch(Exception e){}
+    }
+     
+     private synchronized void openFile(int type) throws IOException{
+         switch(type){
+             case FILEA  : if(fileastream==null){
+                                fileastream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFileName(FILEA),true)));
+                                File ftest=new File(getFileName(FILEA));
+                                fileaposition=ftest.length();
+                           }
+                          break;
+             case FILEB  : if(filebstream==null){
+                                filebstream=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(getFileName(FILEB),true)));
+                                File ftest=new File(getFileName(FILEB));
+                                filebposition=ftest.length();
+                           }
+                          break;
+         }
+     }
+     
+    /**
+     * Adds a row of data to this table.
+     */
+    public void addRow(Row row) throws IOException{
+        // Distribute new rows between the two datafiles by using the rowswitch, but don't spend time synchronizing... this does not need to be acurate!
+        if(rowswitch){
+            addRowA(row);
+        }else{
+            addRowB(row);
+        }
+        rowswitch=!rowswitch;
+    }
+     
+     private void addCacheEntry(TableIndexEntry entry){
+         synchronized(indexcache){
+             if(indexcacheusage>INDEXCACHESIZE){
+                 // remove first entry
+                 TableIndexNode node=indexcachefirst;
+                 indexcache.remove(node.getData().getId());
+                 indexcacheusage--;
+                 synchronized(statlock){
+                     stat_cache_drop++;
+                 }
+                 indexcachefirst=node.getNext();
+                 if(indexcachefirst==null){
+                    indexcachelast=null;
+                 }else{
+                    indexcachefirst.setPrevious(null);
+                 }
+             }
+             TableIndexNode node=new TableIndexNode(indexcachelast,entry);
+             if(indexcachelast!=null){
+                 indexcachelast.setNext(node);
+             }
+             if(indexcachefirst==null){
+                 indexcachefirst=node;
+             }
+             indexcachelast=node;
+             indexcache.put(entry.getId(),node);
+             indexcacheusage++;
+        }
+     }
+     
+     private void addRowA(Row row) throws IOException{
+         synchronized(filealock){
+             openFile(FILEA);
+             int pre=fileastream.size();
+             row.writeToStream(fileastream);
+             int post=fileastream.size();
+             fileastream.flush();
+             synchronized(statlock){
+                  stat_add++;
+                  stat_add_size+=row.getSize();
+              }
+             index.addEntry(row.getId(),row.getSize(),FILEA,fileaposition);
+             if(INDEXCACHESIZE>0){
+                 TableIndexEntry entry=new TableIndexEntry(row.getId(),row.getSize(),FILEA,fileaposition);
+                 addCacheEntry(entry);
+             }
+             fileaposition+=Row.calcSize(pre,post);
+         }
+     }
+     private void addRowB(Row row) throws IOException{
+         synchronized(fileblock){
+             openFile(FILEB);
+             int pre=filebstream.size();
+             row.writeToStream(filebstream);
+             int post=filebstream.size();
+             filebstream.flush();
+             synchronized(statlock){
+                  stat_add++;
+                  stat_add_size+=row.getSize();
+              }
+             index.addEntry(row.getId(),row.getSize(),FILEB,filebposition);
+             if(INDEXCACHESIZE>0){
+                 TableIndexEntry entry=new TableIndexEntry(row.getId(),row.getSize(),FILEB,filebposition);
+                 addCacheEntry(entry);
+             }
+             filebposition+=Row.calcSize(pre,post);
+         }
+     }
+     
+
+     private void updateCacheEntry(TableIndexEntry entry){
+          synchronized(indexcache){
+              if(indexcache.containsKey(entry.getId())){
+                  TableIndexNode node=indexcache.get(entry.getId());
+                  node.setData(entry);
+                  if(node!=indexcachelast){
+                      if(node==indexcachefirst){
+                          indexcachefirst=node.getNext();
+                      }
+                      node.remove();
+                      indexcachelast.setNext(node);
+                      node.setPrevious(indexcachelast);
+                      node.setNext(null);
+                      indexcachelast=node;
+                  }
+              }else{
+                  addCacheEntry(entry);
+              }
+         }
+      }
+
+      private void removeCacheEntry(String id){
+          synchronized(indexcache){
+                if(indexcache.containsKey(id)){
+                    TableIndexNode node=indexcache.get(id);
+                    indexcache.remove(id);
+                    if(indexcacheusage==1){
+                        indexcachefirst=null;
+                        indexcachelast=null;
+                        indexcacheusage=0;
+                        return;
+                    }
+                    if(node==indexcachefirst){
+                        indexcachefirst=node.getNext();
+                        indexcachefirst.setPrevious(null);
+                    }else if(node==indexcachelast){
+                        indexcachelast=node.getPrevious();
+                        indexcachelast.setNext(null);
+                    }else{
+                        node.remove();
+                    }
+                    indexcacheusage--;
+                    synchronized(statlock){
+                         stat_cache_drop++;
+                    }
+                }
+          }
+      }
+
+      private TableIndexEntry getCacheEntry(String id){
+          synchronized(indexcache){
+              if(indexcache.containsKey(id)){
+                  TableIndexNode node=indexcache.get(id);
+                  if(node!=indexcachelast){
+                      if(node==indexcachefirst){
+                            indexcachefirst=node.getNext();
+                        }
+                        node.remove();
+                        indexcachelast.setNext(node);
+                        node.setPrevious(indexcachelast);
+                        node.setNext(null);
+                        indexcachelast=node;
+                  }
+                  synchronized(statlock){
+                       stat_cache_hit++;
+                   }
+                  return node.getData();
+              }
+          }
+          synchronized(statlock){
+               stat_cache_miss++;
+           }
+          return null;
+      }
+
+     /**
+      * Adds a row to this table if it doesn't already exist, if it does it updates the row instead.
+      * This method is much slower than directly using add or update, so only use it if you don't know wether or not the row already exists.
+      */
+     public void addOrUpdateRow(Row row) throws IOException{
+         Row tmprow=getRow(row.getId());
+         if(tmprow==null){
+             addRow(row);
+         }else{
+             updateRow(row);
+         }
+     }
+
+     /**
+      * Updates a row stored in this table.
+      */
+     public void updateRow(Row row) throws IOException{
+         TableIndexEntry entry=null;
+         // Handle index entry caching
+         if(INDEXCACHESIZE>0){
+             synchronized(indexcache){
+                 entry=getCacheEntry(row.getId());
+                 if(entry==null){
+                     entry=index.scanIndex(row.getId());
+                     addCacheEntry(entry);
+                 }
+             }
+         }else{
+             entry=index.scanIndex(row.getId());
+         }
+         if(entry.getRowSize()>=row.getSize()){
+            // Add to the existing location
+            switch(entry.getLocation()){
+                case FILEA  :synchronized(filealock){
+                                if(filearandom==null){
+                                    filearandom=new RandomAccessFile(getFileName(FILEA),"rw");
+                                    fca=filearandom.getChannel();
+                                }
+                                filearandom.seek(entry.getPosition());
+                                row.writeToFile(filearandom);
+                                
+                                fca.force(false);
+                            }
+                            break;
+                case FILEB :synchronized(fileblock){
+                                if(filebrandom==null){
+                                    filebrandom=new RandomAccessFile(getFileName(FILEB),"rw");
+                                    fcb=filebrandom.getChannel();
+                                }
+                                filebrandom.seek(entry.getPosition());
+                                row.writeToFile(filebrandom);
+                                
+                                fcb.force(false);
+                            }
+                    break;
+            }
+         }else{
+             if(rowswitch){
+                  updateRowA(row);
+              }else{
+                  updateRowB(row);
+              }
+              rowswitch=!rowswitch;
+         }
+         synchronized(statlock){
+              stat_update++;
+              stat_update_size+=row.getSize();
+         }
+     }
+     
+     private void updateRowA(Row row) throws IOException{
+         synchronized(filealock){
+              openFile(FILEA);
+              int pre=fileastream.size();
+              row.writeToStream(fileastream);
+              int post=fileastream.size();
+              fileastream.flush();
+              index.updateEntry(row.getId(),row.getSize(),FILEA,fileaposition);
+              
+              // Handle index entry caching
+              if(INDEXCACHESIZE>0){
+                  updateCacheEntry(new TableIndexEntry(row.getId(),row.getSize(),FILEA,fileaposition));
+              }
+              fileaposition+=Row.calcSize(pre,post);
+          }
+     }
+
+     private void updateRowB(Row row) throws IOException{
+         synchronized(fileblock){
+              openFile(FILEB);
+              int pre=filebstream.size();
+              row.writeToStream(filebstream);
+              int post=filebstream.size();
+              filebstream.flush();
+              index.updateEntry(row.getId(),row.getSize(),FILEB,filebposition);
+              // Handle index entry caching
+              // Handle index entry caching
+                if(INDEXCACHESIZE>0){
+                    updateCacheEntry(new TableIndexEntry(row.getId(),row.getSize(),FILEB,filebposition));
+                }
+                filebposition+=Row.calcSize(pre,post);
+          }
+     }
+
+     /**
+      * Marks a row as deleted in the index.
+      * Be aware that the space consumed by the row is not actually reclaimed.
+      */
+     public void deleteRow(Row row) throws IOException{
+          // Handle index entry caching
+          if(INDEXCACHESIZE>0){
+              removeCacheEntry(row.getId());
+          }
+          index.updateEntry(row.getId(),row.getSize(),DELETE,0);
+          synchronized(statlock){
+               stat_delete++;
+          }
+     }
+     
+     /**
+      * Returns a tuplestream containing the given list of rows
+      */
+     public TupleStream getRows(List<String> rows) throws IOException{
+         return new IndexedTableReader(this,index.scanIndex(rows));
+     }
+
+     /**
+      * Returns a tuplestream containing the rows matching the given rowmatcher
+      */
+     public TupleStream getRows(RowMatcher matcher) throws IOException{
+         return new IndexedTableReader(this,index.scanIndex(),matcher);
+     }
+     
+     /**
+      * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+      */
+     public TupleStream getRows(List<String> rows,RowMatcher matcher) throws IOException{
+          return new IndexedTableReader(this,index.scanIndex(rows),matcher);
+      }
+
+     /**
+      * Returns a tuplestream of all rows in this table.
+      */
+     public TupleStream getRows() throws IOException{
+         // return new TableReader(this);
+         return new IndexedTableReader(this,index.scanIndex());
+     }
+     
+     /**
+      * Returns a single row stored in this table.
+      * If the row does not exist in the table, null will be returned.
+      */
+     public Row getRow(String id) throws IOException{
+         TableIndexEntry entry=null;
+          // Handle index entry caching
+          if(INDEXCACHESIZE>0){
+              synchronized(indexcache){
+                  entry=getCacheEntry(id);
+                   if(entry==null){
+                       entry=index.scanIndex(id);
+                       if(entry!=null){
+                           addCacheEntry(entry);
+                       }
+                   }
+              }
+          }else{
+              entry=index.scanIndex(id);
+          }
+          if(entry!=null){
+              long dataoffset=0;
+              DataInputStream data=null;
+              if(entry.location==Table.FILEA){
+                  data=new DataInputStream(new BufferedInputStream(new FileInputStream(getFileName(Table.FILEA))));
+              }else if(entry.location==Table.FILEB){
+                  data=new DataInputStream(new BufferedInputStream(new FileInputStream(getFileName(Table.FILEB))));
+              }
+              if(data!=null){
+                  while(dataoffset!=entry.position){
+                      dataoffset+=data.skipBytes((int)(entry.position-dataoffset));
+                  }
+                  Row row=Row.readFromStream(data);
+                  data.close();
+                  synchronized(statlock){
+                       stat_read++;
+                       stat_read_size+=row.getSize();
+                  }
+                  return row;
+              }
+              
+          }
+          return null;
+     }
+ }
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/HashedTable.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/HashedTable.java
new file mode 100644 (file)
index 0000000..b7d1968
--- /dev/null
@@ -0,0 +1,225 @@
+
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+import com.solidosystems.tuplesoup.filter.*;
+
+/**
+ * The table stores a group of rows.
+ * Every row must have a unique id within a table.
+ */
+public class HashedTable implements Table{
+    private int TABLESETSIZE=16;
+    private List<Table> tableset;
+    private String title;
+    private String location;
+    
+
+    
+    /**
+     * Create a new table object with a specific index model
+     */
+    public HashedTable(String title,String location, int indextype) throws IOException{
+        this.title=title;
+        this.location=location;
+        tableset=new ArrayList<Table>();
+        for(int i=0;i<TABLESETSIZE;i++){
+            tableset.add(new DualFileTable(title+"_"+i,location,indextype));
+        }
+    }
+    
+    
+    public Hashtable<String,Long> readStatistics(){
+        Hashtable<String,Long> results=new Hashtable<String,Long>();
+        for(int i=0;i<TABLESETSIZE;i++){
+            Hashtable<String,Long> tmp=tableset.get(i).readStatistics();
+            Set<String> keys=tmp.keySet();
+            Iterator<String> it=keys.iterator();
+            while(it.hasNext()){
+                String key=it.next();
+                long value=tmp.get(key);
+                if(results.containsKey(key)){
+                    results.put(key,results.get(key)+value);
+                }else{
+                    results.put(key,value);
+                }
+            }
+        }
+        return results;
+    }
+    
+    /** 
+     * Returns the name of this table
+     */ 
+    public String getTitle(){
+         return title;
+    }
+    
+    /**
+     * Returns the location of this tables datafiles
+     */ 
+    public String getLocation(){
+         return location;
+    }
+    
+    /**
+     * Delete the files created by this table object.
+     * Be aware that this will delete any data stored in this table!
+     */ 
+    public void deleteFiles(){
+        for(int i=0;i<TABLESETSIZE;i++){
+            tableset.get(i).deleteFiles();
+        }
+    }
+    
+    public void close(){
+        for(int i=0;i<TABLESETSIZE;i++){
+            tableset.get(i).close();
+        }
+    }
+    
+    public void setIndexCacheSize(int size){
+        for(int i=0;i<TABLESETSIZE;i++){
+            tableset.get(i).setIndexCacheSize(size/TABLESETSIZE);
+        }
+    }
+    
+    private Table getTableForId(String id){
+        return tableset.get(id.hashCode() & (TABLESETSIZE-1));
+    }
+    
+    /**
+      * Returns a single row stored in this table.
+      * If the row does not exist in the table, null will be returned.
+      */
+     public Row getRow(String id) throws IOException{
+        Table tbl=getTableForId(id);
+        return tbl.getRow(id);
+     }
+    
+    /**
+      * Returns a tuplestream of all rows in this table.
+      */
+     public TupleStream getRows() throws IOException{
+        TupleStreamMerger merge=new TupleStreamMerger();
+        for(int i=0;i<TABLESETSIZE;i++){
+            merge.addStream(tableset.get(i).getRows());
+        }
+        return merge;
+     }
+     /**
+       * Returns a tuplestream containing the given list of rows
+       */
+      public TupleStream getRows(List<String> rows) throws IOException{
+          List<List<String>> listset=new ArrayList<List<String>>();
+          for(int i=0;i<TABLESETSIZE;i++){
+              listset.add(new ArrayList<String>());
+          }
+          for(int i=0;i<rows.size();i++){
+              String id=rows.get(i);
+              listset.get(id.hashCode() & TABLESETSIZE).add(id);
+          }
+          TupleStreamMerger merge=new TupleStreamMerger();
+          for(int i=0;i<TABLESETSIZE;i++){
+              if(listset.get(i).size()>0){
+                  merge.addStream(tableset.get(i).getRows(listset.get(i)));
+              }
+          }
+          return merge;
+      }
+
+      /**
+       * Returns a tuplestream containing the rows matching the given rowmatcher
+       */
+      public TupleStream getRows(RowMatcher matcher) throws IOException{
+          TupleStreamMerger merge=new TupleStreamMerger();
+          for(int i=0;i<TABLESETSIZE;i++){
+              merge.addStream(tableset.get(i).getRows(matcher));
+          }
+          return merge;
+      }  
+        
+      /**
+       * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+       */
+      public TupleStream getRows(List<String> rows,RowMatcher matcher) throws IOException{
+          List<List<String>> listset=new ArrayList<List<String>>();
+            for(int i=0;i<TABLESETSIZE;i++){
+                listset.add(new ArrayList<String>());
+            }
+            for(int i=0;i<rows.size();i++){
+                String id=rows.get(i);
+                listset.get(id.hashCode() & TABLESETSIZE).add(id);
+            }
+            TupleStreamMerger merge=new TupleStreamMerger();
+            for(int i=0;i<TABLESETSIZE;i++){
+                if(listset.get(i).size()>0){
+                    merge.addStream(tableset.get(i).getRows(listset.get(i),matcher));
+                }
+            }
+            return merge;
+      }
+      
+      /**
+        * Marks a row as deleted in the index.
+        * Be aware that the space consumed by the row is not actually reclaimed.
+        */
+       public void deleteRow(Row row) throws IOException{
+           getTableForId(row.getId()).deleteRow(row);
+       }
+       
+       /**
+        * Adds a row of data to this table.
+        */
+       public void addRow(Row row) throws IOException{
+           getTableForId(row.getId()).addRow(row);
+       }
+
+        /**
+         * Adds a row to this table if it doesn't already exist, if it does it updates the row instead.
+         * This method is much slower than directly using add or update, so only use it if you don't know wether or not the row already exists.
+         */
+        public void addOrUpdateRow(Row row) throws IOException{
+            getTableForId(row.getId()).addOrUpdateRow(row);
+        }
+
+        /**
+         * Updates a row stored in this table.
+         */
+        public void updateRow(Row row) throws IOException{
+            getTableForId(row.getId()).updateRow(row);
+        }
+}
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/IndexedTableReader.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/IndexedTableReader.java
new file mode 100644 (file)
index 0000000..0684c3b
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ package com.solidosystems.tuplesoup.core;
+ import com.solidosystems.tuplesoup.filter.*;
+ import java.io.*;
+ import java.util.*;
+
+public class IndexedTableReader extends TupleStream{
+    private DataInputStream fileastream=null;
+    private DataInputStream filebstream=null;
+    private long fileaposition=0;
+    private long filebposition=0;
+
+    private List<TableIndexEntry>fileaentries;
+    private List<TableIndexEntry>filebentries;
+    
+    private List<TableIndexEntry>entries;
+
+    private Hashtable<String,Row>fileabuffer;
+    private Hashtable<String,Row>filebbuffer;
+
+    private List<String>rows;
+    private int rowpointer;
+    private Row next=null;
+    
+    private DualFileTable table;
+    
+    private RowMatcher matcher=null;
+    
+    public IndexedTableReader(DualFileTable table,List<TableIndexEntry>entries) throws IOException{
+        this.table=table;
+        this.rows=rows;
+        rowpointer=0;
+        
+        this.entries=entries;
+        fileaentries=new ArrayList<TableIndexEntry>();
+        filebentries=new ArrayList<TableIndexEntry>();
+        
+        Iterator<TableIndexEntry> it=entries.iterator();
+        while(it.hasNext()){
+            TableIndexEntry entry=it.next();
+            // TODO: we really shouldn't get nulls here
+            if(entry!=null){
+                if(entry.location==Table.FILEA){
+                    fileaentries.add(entry);
+                }else if(entry.location==Table.FILEB){
+                    filebentries.add(entry);
+                }
+            }
+        }
+        
+        Collections.sort(fileaentries);
+        Collections.sort(filebentries);
+        
+        fileabuffer=new Hashtable<String,Row>();
+        filebbuffer=new Hashtable<String,Row>();
+        
+        readNext();   
+    }
+    
+    
+    public IndexedTableReader(DualFileTable table,List<TableIndexEntry>entries,RowMatcher matcher) throws IOException{
+        this.table=table;
+        this.rows=rows;
+        rowpointer=0;
+        this.matcher=matcher;
+        
+        this.entries=entries;
+        fileaentries=new ArrayList<TableIndexEntry>();
+        filebentries=new ArrayList<TableIndexEntry>();
+        
+        Iterator<TableIndexEntry> it=entries.iterator();
+        while(it.hasNext()){
+            TableIndexEntry entry=it.next();
+            // TODO: we really shouldn't get nulls here
+            if(entry!=null){
+                if(entry.location==Table.FILEA){
+                    fileaentries.add(entry);
+                }else if(entry.location==Table.FILEB){
+                    filebentries.add(entry);
+                }
+            }
+        }
+        
+        Collections.sort(fileaentries);
+        Collections.sort(filebentries);
+        
+        fileabuffer=new Hashtable<String,Row>();
+        filebbuffer=new Hashtable<String,Row>();
+        
+        readNext();   
+    }
+    
+    private void readNextFromFileA(TableIndexEntry entry) throws IOException{
+        if(fileabuffer.containsKey(entry.id)){
+            next=fileabuffer.remove(entry.id);
+            return;
+        }
+        while(true){
+            if(fileaentries.size()>0){
+                TableIndexEntry nextfilea=fileaentries.remove(0);
+                if(fileastream==null){
+                    fileastream=new DataInputStream(new BufferedInputStream(new FileInputStream(table.getFileName(Table.FILEA))));
+                    fileaposition=0;
+                }
+                if(fileaposition>nextfilea.position){
+                    // We have already read this entry... skip it
+                    // readNextFromFileA(entry);
+                    // return;
+                }else{
+                    while(fileaposition!=nextfilea.position){
+                        fileaposition+=fileastream.skipBytes((int)(nextfilea.position-fileaposition));
+                    }
+                    Row row=Row.readFromStream(fileastream);
+                    synchronized(table.statlock){
+                        table.stat_read_size+=row.getSize();
+                        table.stat_read++;
+                    }
+                    fileaposition+=row.getSize();
+                    if(row.getId().equals(entry.id)){
+                        next=row;
+                        return;
+                    }else{
+                        fileabuffer.put(row.getId(),row);
+                        // readNextFromFileA(entry);
+                    }
+                }
+            }else{
+                next=null;
+                return;
+            }
+        }
+    }
+    
+    private void readNextFromFileB(TableIndexEntry entry) throws IOException{
+        if(filebbuffer.containsKey(entry.id)){
+            next=filebbuffer.remove(entry.id);
+            return;
+        }
+        while(true){
+            if(filebentries.size()>0){
+                TableIndexEntry nextfileb=filebentries.remove(0);
+                if(filebstream==null){
+                    filebstream=new DataInputStream(new BufferedInputStream(new FileInputStream(table.getFileName(Table.FILEB))));
+                    filebposition=0;
+                }
+                if(filebposition>nextfileb.position){
+                    // We have already read this entry... skip it
+                    // readNextFromFileB(entry);
+                    // return;
+                }else{
+                    while(filebposition!=nextfileb.position){
+                        filebposition+=filebstream.skipBytes((int)(nextfileb.position-filebposition));
+                    }
+                    Row row=Row.readFromStream(filebstream);
+                    synchronized(table.statlock){
+                        table.stat_read_size+=row.getSize();
+                        table.stat_read++;
+                    }
+                    filebposition+=row.getSize();
+                    if(row.getId().equals(entry.id)){
+                        next=row;
+                        return;
+                    }else{
+                        filebbuffer.put(row.getId(),row);
+                        // readNextFromFileB(entry);
+                    }
+                }
+            }else{
+                next=null;
+                return;
+            }
+        }
+    }
+    
+    private void readNext() throws IOException{
+        if(entries.size()>rowpointer){
+            TableIndexEntry entry=entries.get(rowpointer++);
+            if(entry!=null){
+                   switch(entry.location){
+                    case Table.FILEA    : readNextFromFileA(entry);
+                                        // return;
+                                        break;
+                    case Table.FILEB : readNextFromFileB(entry);
+                                        // return;
+                                        break;
+                }
+                if(next!=null){
+                    if(matcher!=null){
+                        if(!matcher.matches(next)){
+                             readNext();
+                        }
+                    }
+                }
+                return;
+            }else{
+                readNext();
+                return;
+            }
+        }
+        try{
+            if(fileastream!=null)fileastream.close();
+        }catch(Exception e){}
+        try{
+            if(filebstream!=null)filebstream.close();
+        }catch(Exception e){}
+        next=null;
+    }
+    
+    public boolean hasNext(){
+        if(next!=null)return true;
+        return false;
+    }
+    
+    public Row next(){
+        try{
+            if(next!=null){
+                Row tmp=next;
+                readNext();
+                return tmp;
+            }
+        }catch(Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+    
+    public void remove(){
+        
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/PagedIndex.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/PagedIndex.java
new file mode 100644 (file)
index 0000000..f200fa9
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+
+public class PagedIndex implements TableIndex{
+    protected static final int INITIALPAGEHASH=1024;
+    protected static final int PAGESIZE=2048;
+    
+    private RandomAccessFile out=null;
+    private String filename;
+    private TableIndexPage[] root=null;
+    
+    private long stat_read=0;
+    private long stat_write=0;
+    protected long stat_create_page=0;
+    protected long stat_page_next=0;
+    protected long stat_page_branch=0;
+    public PagedIndex(String filename) throws IOException{
+        this.filename=filename;
+        File ftest=new File(filename);
+        if(!ftest.exists())ftest.createNewFile();
+        out=new RandomAccessFile(filename,"rw");
+        root=new TableIndexPage[INITIALPAGEHASH];
+        if(out.length()>0){
+            for(int i=0;i<INITIALPAGEHASH;i++){
+                root[i]=new TableIndexPage(this,out);
+                root[i].setFirst();
+                out.seek(root[i].getEndLocation());
+            }
+        }else{
+            for(int i=0;i<INITIALPAGEHASH;i++){
+                root[i]=TableIndexPage.createNewPage(this,out,PAGESIZE);
+                root[i].setFirst();
+            }
+        }
+    }
+    
+    public Hashtable<String,Long> readStatistics(){
+        Hashtable<String,Long> hash=new Hashtable<String,Long>();
+        hash.put("stat_index_read",stat_read);
+        hash.put("stat_index_write",stat_write);
+        hash.put("stat_index_create_page",stat_create_page);
+        hash.put("stat_index_page_next",stat_page_next);
+        hash.put("stat_index_page_branch",stat_page_branch);
+        stat_read=0;
+        stat_write=0;
+        stat_create_page=0;
+        stat_page_next=0;
+        stat_page_branch=0;
+        return hash;
+    }
+    
+    private int rootHash(String id){
+        return id.hashCode() & (INITIALPAGEHASH-1);
+    }
+    
+    private synchronized TableIndexPage getFirstFreePage(String id) throws IOException{
+        return root[rootHash(id)].getFirstFreePage(id,id.hashCode());
+    }
+    
+    private synchronized long getOffset(String id) throws IOException{
+        if(root==null)return -1;
+        return root[rootHash(id)].getOffset(id,id.hashCode());
+    }
+    
+    public synchronized void updateEntry(String id,int rowsize,int location,long position) throws IOException{
+        long offset=getOffset(id);
+        out.seek(offset);
+        TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+        entry.updateData(out);
+        stat_write++;
+    }
+    public synchronized void addEntry(String id,int rowsize,int location,long position) throws IOException{
+        TableIndexPage page=getFirstFreePage(id);
+        page.addEntry(id,rowsize,location,position);
+        stat_write++;
+    }
+    public synchronized TableIndexEntry scanIndex(String id) throws IOException{
+        if(root==null)return null;
+        return root[rootHash(id)].scanIndex(id,id.hashCode());
+    }
+    public synchronized List<TableIndexEntry> scanIndex(List<String> rows) throws IOException{
+        List<TableIndexEntry> lst=new ArrayList<TableIndexEntry>();
+        for(int i=0;i<rows.size();i++){
+            String id=rows.get(i);
+            TableIndexEntry entry=scanIndex(id);
+            if(entry!=null){
+                if(entry.getLocation()!=Table.DELETE)lst.add(entry);
+            }
+        }
+        return lst;
+    }
+    public synchronized List<TableIndexEntry> scanIndex() throws IOException{
+        ArrayList<TableIndexEntry> lst=new ArrayList<TableIndexEntry>();
+        for(int i=0;i<INITIALPAGEHASH;i++){
+            root[i].addEntriesToList(lst);
+        }
+        return lst;
+    }
+    public void close(){
+        try{
+            if(out!=null){
+                out.close();
+            }
+        }catch(Exception e){}
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/PagedIndexTransactional.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/PagedIndexTransactional.java
new file mode 100644 (file)
index 0000000..0a7e679
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.solidosystems.tuplesoup.core;
+
+/**
+ *
+ * @author navid
+ */
+public class PagedIndexTransactional {
+
+}
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Row.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Row.java
new file mode 100644 (file)
index 0000000..52b9bbf
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+
+/**
+ * Holds a row of data
+ */
+public class Row{
+     private String id;
+     private int size;
+     private Hashtable<String,Value> values;
+    
+     /**
+      * Creates a new empty row with the given row id.
+      */
+     public Row(String id){
+         this.id=id;
+         size=-1;
+         values=new Hashtable<String,Value>();
+     }
+     
+     /**
+      * Returns the number of keys in this row.
+      */
+     public int getKeyCount(){
+         return values.size();
+     }
+     
+     public Set<String> keySet(){
+         return values.keySet();
+     }
+     
+     /**
+      * Returns the actual size in bytes this row will take when written to a stream.
+      */
+     public int getSize(){
+         if(size==-1)recalcSize();
+         return size;
+     }
+
+     /**
+      * Returns a hashcode for this row. This hashcode will be based purely on the id of the row.
+      */
+     public int hashCode(){
+         return id.hashCode();
+     }
+     public boolean equals(Object obj){
+         try{
+             Row r=(Row)obj;
+             return r.id.equals(id);
+         }catch(Exception e){}
+         return false;
+     }
+     /**
+      * Returns the id of this row.
+      */
+     public String getId(){
+         return id;
+     }
+     /**
+      * Stores the given value for the given key.
+      */
+     public void put(String key,Value value){
+         size=-1;
+         values.put(key,value);
+     }
+     
+     /**
+      * Stores the given string wrapped in a value object for the given key.
+      */
+     public void put(String key,String value){
+         size=-1;
+         values.put(key,new Value(value));
+     }
+     
+     /**
+      * Stores the given int wrapped in a value object for the given key.
+      */
+     public void put(String key,int value){
+         size=-1;
+         values.put(key,new Value(value));
+     }
+     
+     /**
+      * Stores the given long wrapped in a value object for the given key.
+      */
+     public void put(String key,long value){
+         size=-1;
+         values.put(key,new Value(value));
+     }
+     
+     /**
+      * Stores the given float wrapped in a value object for the given key.
+      */
+     public void put(String key,float value){
+         size=-1;
+         values.put(key,new Value(value));
+     }
+     
+     /**
+      * Stores the given double wrapped in a value object for the given key.
+      */
+     public void put(String key,double value){
+         size=-1;
+         values.put(key,new Value(value));
+     }
+     
+     /**
+      * Stores the given boolean wrapped in a value object for the given key.
+      */
+     public void put(String key,boolean value){
+         size=-1;
+         values.put(key,new Value(value));
+     }
+     
+     /**
+      * Stores the given Date wrapped in a value object for the given key.
+      */
+     public void put(String key,Date value){
+         size=-1;
+         values.put(key,new Value(value));
+     }
+     
+     /**
+      * Returns the value stored for the current key, or a null value (not null) if the key does not exist.
+      */
+     public Value get(String key){
+         if(!values.containsKey(key))return new Value();
+         return values.get(key);
+     }
+     
+     /**
+      * Returns a string representation of the value stored for the current key.
+      * If the key does not exist, an empty string will be returned.
+      * See the documentation for Value to learn how the string value is generated.
+      */
+     public String getString(String key){
+         if(!values.containsKey(key))return "";
+         return values.get(key).getString();
+     }
+     
+     /**
+      * Returns an int representation of the value stored for the current key.
+      * If the key does not exist, 0 will be returned.
+      * See the documentation for Value to learn how the string value is generated.
+      */
+     public int getInt(String key){
+         if(!values.containsKey(key))return 0;
+          return values.get(key).getInt();
+     }
+     
+     /**
+      * Returns a long representation of the value stored for the current key.
+      * If the key does not exist, 0 will be returned.
+      * See the documentation for Value to learn how the string value is generated.
+      */
+     public long getLong(String key){
+         if(!values.containsKey(key))return 0;
+          return values.get(key).getLong();
+     }
+     
+     /**
+      * Returns a float representation of the value stored for the current key.
+      * If the key does not exist, 0 will be returned.
+      * See the documentation for Value to learn how the string value is generated.
+      */
+     public float getFloat(String key){
+         if(!values.containsKey(key))return 0f;
+          return values.get(key).getFloat();
+     }
+     
+     /**
+      * Returns a double representation of the value stored for the current key.
+      * If the key does not exist, 0 will be returned.
+      * See the documentation for Value to learn how the string value is generated.
+      */
+     public double getDouble(String key){
+         if(!values.containsKey(key))return 0d;
+          return values.get(key).getDouble();
+     }
+     
+     /**
+      * Returns a boolean representation of the value stored for the current key.
+      * If the key does not exist, false will be returned.
+      * See the documentation for Value to learn how the string value is generated.
+      */
+     public boolean getBoolean(String key){
+         if(!values.containsKey(key))return false;
+          return values.get(key).getBoolean();
+     }
+     
+     /**
+      * Returns a Date representation of the value stored for the current key.
+      * If the key does not exist, the date initialized with 0 will be returned.
+      * See the documentation for Value to learn how the string value is generated.
+      */
+     public Date getTimestamp(String key){
+         if(!values.containsKey(key))return new Date(0);
+          return values.get(key).getTimestamp();
+      }
+     /**
+      * Utility function to calculate the distance between ints, allowing for a single wraparound.
+      */
+     protected static int calcSize(int pre,int post){
+         if(post>pre)return post-pre;
+         return (Integer.MAX_VALUE-pre)+post;
+     }
+    
+     /**
+      * Recalculate the size of the row. Be aware that this method will actually write the full row to a buffer to calculate the size.
+      * Its a slow and memory consuming method to call!
+      */
+     private void recalcSize(){
+         try{
+             ByteArrayOutputStream bout=new ByteArrayOutputStream();
+             DataOutputStream dout=new DataOutputStream(bout);
+             writeToStream(dout);
+             size=bout.size();
+             dout.close();
+             bout.close();
+         }catch(Exception e){}
+     }
+    
+     /**
+      * Writes the contents of this row to the given RandomAccessFile
+      */
+     public void writeToFile(RandomAccessFile out) throws IOException{
+          long pre=out.getFilePointer();
+          
+          out.writeUTF(id);
+          
+          Set<String> keys=values.keySet();
+          out.writeInt(keys.size());
+          Iterator<String> it=keys.iterator();
+          while(it.hasNext()){
+              String key=it.next();
+             Value value=values.get(key);
+              out.writeUTF(key);
+              value.writeToFile(out);
+          }
+          long post=out.getFilePointer();
+          int size=(int)(post-pre);
+          this.size=size+4;
+          out.writeInt(this.size);
+      }
+      /**
+       * Writes the contents of this row to the given DataOutputStream.
+       */
+      public void writeToStream(DataOutputStream out) throws IOException{
+         int pre=out.size();
+         out.writeUTF(id);
+         Set<String> keys=values.keySet();
+         out.writeInt(keys.size());
+         Iterator<String> it=keys.iterator();
+         while(it.hasNext()){
+             String key=it.next();
+             Value value=values.get(key);
+             out.writeUTF(key);
+             value.writeToStream(out);
+         }
+         int post=out.size();
+         int size=calcSize(pre,post);
+         this.size=size+4;
+         out.writeInt(this.size);
+     }
+     /**
+      * Reads a full row from the given DataInputStream and returns it.
+      */
+     public static Row readFromStream(DataInputStream in) throws IOException{
+         String id=in.readUTF();
+         Row row=new Row(id);
+         int size=in.readInt();
+         for(int i=0;i<size;i++){
+             String key=in.readUTF();
+             Value value=Value.readFromStream(in);
+             row.put(key,value);
+         }
+         size=in.readInt();
+         row.size=size;
+         return row;
+     }
+     /**
+      * Returns a string representing this row formatted as the following example:
+      * (1732)=>{"name":string:"Kasper J. Jeppesen","age":int:31}
+      *
+      * @return a string representation of this row
+      */
+     public String toString(){
+         StringBuffer buf=new StringBuffer();
+         buf.append("("+id+")=>{");
+         Iterator<String> it=values.keySet().iterator();
+         boolean first=true;
+         while(it.hasNext()){
+             if(!first){
+                 buf.append(",");
+             }else{
+                 first=false;
+             }
+             String key=it.next();
+             buf.append("\"");
+             buf.append(key);
+             buf.append("\":");
+             Value value=values.get(key);
+             buf.append(value.getTypeName());
+             buf.append(":");
+             if(value.getType()==Value.STRING){
+                buf.append("\"");
+                // TODO: This string should be escaped properly
+                buf.append(value.getString());
+                buf.append("\"");
+             }else{
+                 buf.append(value.getString());
+             }
+         }
+         buf.append("}");
+         return buf.toString();
+     }
+     
+     /**
+      * Shorthand for calling toBasicXMLString("")
+      */
+     public String toBasicXMLString(){
+         return toBasicXMLString("");
+     }
+     
+     /**
+      * Creates an indentation of the given size and calls toBasicXMLString(String) with the indentation string as parameter.
+      */
+     public String toBasicXMLString(int indentation){
+         StringBuffer buf=new StringBuffer();
+         for(int i=0;i<indentation;i++){
+             buf.append(" ");
+         }
+         return toBasicXMLString(buf.toString());
+     }
+     
+     /**
+      * Creates a basic xml representation of the row as shown in the following sample:
+      * &lt;row id="1"&gt;
+      *   &lt;value name="foo" type="string"&gt;Bar&lt;/value&gt;
+      * &lt;/row&gt;
+      */
+     public String toBasicXMLString(String indentation){
+         StringBuffer buf=new StringBuffer();
+         buf.append(indentation);
+         buf.append("<row id=\""+id+"\">\n");
+         Iterator<String> it=values.keySet().iterator();
+         while(it.hasNext()){
+             String key=it.next();
+             Value value=values.get(key);
+             buf.append(indentation);
+             buf.append("   ");
+             buf.append(value.toBasicXMLString(key));
+             buf.append("\n");
+         }
+         buf.append(indentation);
+         buf.append("</row>\n");
+         return buf.toString();
+     }
+ }
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/RowMatcher.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/RowMatcher.java
new file mode 100644 (file)
index 0000000..1debd7b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ package com.solidosystems.tuplesoup.core;
+ import java.io.*;
+ import java.util.*;
+
+public class RowMatcher{
+    public final static int LESSTHAN=0;
+    public final static int EQUALS=1;
+    public final static int GREATERTHAN=2;
+    public final static int STARTSWITH=3;
+    public final static int ENDSWITH=4;
+    public final static int CONTAINS=5;
+    public final static int ISNULL=6;
+    
+    public final static int NOT=7;
+    public final static int OR=8;
+    public final static int AND=9;
+    public final static int XOR=10;
+    
+    private String key=null;
+    private Value value=null;
+    private int type=-1;
+    
+    private RowMatcher match1=null;
+    private RowMatcher match2=null;
+    
+    public RowMatcher(String key,int type,Value value){
+        this.key=key;
+        this.type=type;
+        this.value=value;
+    }
+    
+    public RowMatcher(String key,int type){
+        this.key=key;
+        this.type=type;
+    }
+    
+    public RowMatcher(RowMatcher match1,int type,RowMatcher match2){
+        this.match1=match1;
+        this.type=type;
+        this.match2=match2;
+    }
+    
+    public RowMatcher(int type,RowMatcher match1){
+        this.match1=match1;
+        this.type=type;
+    }
+
+    /**
+     * This method needs to be seriously optimized... especially the XOR method
+     */
+    public boolean matches(Row row){
+        if(value!=null){
+            Value compare=row.get(key);
+            switch(type){
+                case LESSTHAN   : return compare.lessThan(value);
+                case EQUALS     : return compare.equals(value);
+                case GREATERTHAN: return compare.greaterThan(value);
+                case STARTSWITH : return compare.startsWith(value);
+                case ENDSWITH   : return compare.endsWith(value);
+                case CONTAINS   : return compare.contains(value);
+            }
+        }else if(type==ISNULL){
+            Value compare=row.get(key);
+            return compare.isNull();
+        }else if((type==AND)||(type==OR)||(type==XOR)){
+            switch(type){
+                case AND        : return match1.matches(row)&&match2.matches(row);
+                case OR         : return match1.matches(row)||match2.matches(row);
+                case XOR        : return (match1.matches(row)||match2.matches(row))&&(!(match1.matches(row)&&match2.matches(row)));
+            }
+        }else if(type==NOT){
+            return !match1.matches(row);
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Table.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Table.java
new file mode 100644 (file)
index 0000000..5ff49fa
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+import java.io.*;
+import java.util.*;
+import java.nio.channels.*;
+import com.solidosystems.tuplesoup.filter.*;
+
+/**
+ * The table stores a group of rows.
+ * Every row must have a unique id within a table.
+ */
+public interface Table{
+    // Index type constants
+    public static final int MEMORY=0;
+    public static final int FLAT=1;
+    public static final int PAGED=2;
+     
+    // Row location constants
+    public static final int FILEA=0;
+    public static final int FILEB=1;
+    public static final int DELETE=2;
+    public static final int INDEX=3;
+     
+    /**
+     * Return the current values of the statistic counters and reset them.
+     * The current counters are:
+     * <ul>
+     *   <li>stat_table_add
+     *   <li>stat_table_update
+     *   <li>stat_table_delete
+     *   <li>stat_table_add_size
+     *   <li>stat_table_update_size
+     *   <li>stat_table_read_size
+     *   <li>stat_table_read
+     *   <li>stat_table_cache_hit
+     *   <li>stat_table_cache_miss
+     *   <li>stat_table_cache_drop
+     * </ul>
+     * Furthermore, the index will be asked to deliver separate index specific counters
+     */
+    public Hashtable<String,Long> readStatistics();
+
+    /**
+     * Set the maximal allowable size of the index cache.
+     */ 
+    public void setIndexCacheSize(int newsize);
+
+    /**
+     * Close all open file streams
+     */
+    public void close();
+
+    /** 
+     * Returns the name of this table
+     */ 
+    public String getTitle();
+    
+    /**
+     * Returns the location of this tables datafiles
+     */ 
+    public String getLocation();
+    
+    /**
+     * Delete the files created by this table object.
+     * Be aware that this will delete any data stored in this table!
+     */ 
+    public void deleteFiles();
+     
+    /**
+     * Adds a row of data to this table.
+     */
+    public void addRow(Row row) throws IOException;
+    
+     /**
+      * Adds a row to this table if it doesn't already exist, if it does it updates the row instead.
+      * This method is much slower than directly using add or update, so only use it if you don't know wether or not the row already exists.
+      */
+     public void addOrUpdateRow(Row row) throws IOException;
+     
+     /**
+      * Updates a row stored in this table.
+      */
+     public void updateRow(Row row) throws IOException;
+     
+     /**
+      * Marks a row as deleted in the index.
+      * Be aware that the space consumed by the row is not actually reclaimed.
+      */
+     public void deleteRow(Row row) throws IOException;
+     
+     /**
+      * Returns a tuplestream containing the given list of rows
+      */
+     public TupleStream getRows(List<String> rows) throws IOException;
+     
+     /**
+      * Returns a tuplestream containing the rows matching the given rowmatcher
+      */
+     public TupleStream getRows(RowMatcher matcher) throws IOException;
+     
+     /**
+      * Returns a tuplestream containing those rows in the given list that matches the given RowMatcher
+      */
+     public TupleStream getRows(List<String> rows,RowMatcher matcher) throws IOException;
+     
+     /**
+      * Returns a tuplestream of all rows in this table.
+      */
+     public TupleStream getRows() throws IOException;
+     
+     /**
+      * Returns a single row stored in this table.
+      * If the row does not exist in the table, null will be returned.
+      */
+     public Row getRow(String id) throws IOException;
+ }
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndex.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndex.java
new file mode 100644 (file)
index 0000000..ba8b76f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+import java.util.*;
+import java.io.*;
+
+public interface TableIndex{
+    public Hashtable<String,Long> readStatistics();
+    public void updateEntry(String id,int rowsize,int location,long position) throws IOException;
+    public void addEntry(String id,int rowsize,int location,long position) throws IOException;
+    public TableIndexEntry scanIndex(String id) throws IOException;
+    public List<TableIndexEntry> scanIndex(List<String> rows) throws IOException;
+    public List<TableIndexEntry> scanIndex() throws IOException;
+    public void close();
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexEntry.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexEntry.java
new file mode 100644 (file)
index 0000000..229d5f4
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+
+public class TableIndexEntry implements Comparable<TableIndexEntry>{
+    public String id;
+    public int location;
+    public long position;
+    private int size;
+    private int rowsize;
+    
+    public TableIndexEntry(String id,int rowsize,int location,long position){
+        this.id=id;
+        this.location=location;
+        this.position=position;
+        this.rowsize=rowsize;
+        size=-1;
+    }
+    public String getId(){
+        return id;
+    }
+    public void setPosition(long position){
+        this.position=position;
+    }
+    public long getPosition(){
+        return position;
+    }
+    public void setLocation(int location){
+        this.location=location;
+    }
+    public int getLocation(){
+        return location;
+    }
+    
+    public int getRowSize(){
+        return rowsize;
+    }
+    
+    public int compareTo(TableIndexEntry obj) throws ClassCastException{
+        TableIndexEntry ent=(TableIndexEntry)obj;
+        if(position<ent.position)return -1;
+        if(position==ent.position)return 0;
+        return 1;
+    }
+    
+    public boolean equals(Object obj){
+        try{
+            TableIndexEntry ent=(TableIndexEntry)obj;
+            if(ent.location==location){
+                if(ent.position==position){
+                    if(ent.id.equals(id)){
+                        return true;
+                    }
+                }
+            }
+        }catch(ClassCastException e){}
+        return false;
+    }
+    
+    public int getSize(){
+        if(size<0)calcSize();
+        return size;
+    }
+    public void setSize(int size){
+        this.size=size;
+    }
+    private void calcSize(){
+        try{
+            ByteArrayOutputStream bout=new ByteArrayOutputStream();
+            DataOutputStream dout=new DataOutputStream(bout);
+            dout.writeInt(id.hashCode());
+            dout.writeShort(id.length());
+            dout.writeChars(id);
+            dout.writeInt(rowsize);
+            dout.writeByte(location);
+            dout.writeLong(position);
+            setSize(bout.size());
+            dout.close();
+            bout.close();
+        }catch(Exception e){
+            e.printStackTrace();
+        }
+    }
+    
+    protected void writeData(RandomAccessFile out) throws IOException{
+        long pre=out.getFilePointer();
+        out.writeInt(id.hashCode());
+        out.writeShort(id.length());
+        out.writeChars(id);
+        out.writeInt(rowsize);
+        out.writeByte(location);
+        out.writeLong(position);
+        setSize((int)(out.getFilePointer()-pre));
+    }
+    protected void updateData(RandomAccessFile out) throws IOException{
+        long pre=out.getFilePointer();
+        out.skipBytes(4+2+id.length()*2);
+        out.writeInt(rowsize);
+        out.writeByte(location);
+        out.writeLong(position);
+        setSize((int)(out.getFilePointer()-pre));
+    }
+    protected void writeData(DataOutputStream out) throws IOException{
+        out.writeInt(id.hashCode());
+        out.writeShort(id.length());
+        out.writeChars(id);
+        out.writeInt(rowsize);
+        out.writeByte(location);
+        out.writeLong(position);
+    }
+    protected static TableIndexEntry readData(RandomAccessFile in) throws IOException{
+        long pre=in.getFilePointer();
+        in.readInt();
+        int num=in.readShort();
+        StringBuilder buf=new StringBuilder(num);
+        for(int i=0;i<num;i++){
+            buf.append(in.readChar());
+        }
+        String id=buf.toString();
+        int rowsize=in.readInt();
+        int location=in.readByte();
+        long position=in.readLong();
+        TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+        tmp.setSize((int)(in.getFilePointer()-pre));
+        return tmp;
+    }
+    
+    protected static TableIndexEntry readData(DataInputStream in) throws IOException{
+        in.readInt();
+        int num=in.readShort();
+        StringBuilder buf=new StringBuilder(num);
+        for(int i=0;i<num;i++){
+            buf.append(in.readChar());
+        }
+        String id=buf.toString();
+        int rowsize=in.readInt();
+        int location=in.readByte();
+        long position=in.readLong();
+        TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+        return tmp;
+    }
+    
+    protected static long scanForOffset(String id,DataInputStream in) throws IOException{
+        long offset=0;
+        int scanhash=id.hashCode();
+        try{
+            int datahash=in.readInt();
+            while(scanhash!=datahash){
+                int num=in.readShort();
+                in.skipBytes(1+4+8+num*2);
+                offset+=4+4+1+2+8+num*2;
+                datahash=in.readInt();
+            }
+            return offset;
+        }catch(EOFException e){}
+        return -1;
+    }
+    protected static TableIndexEntry lookForData(String id,DataInputStream in) throws IOException{
+        int scanhash=id.hashCode();
+        int datahash=in.readInt();
+        int num=in.readShort();
+        if(scanhash!=datahash){
+            in.skipBytes(4+1+8+num*2);
+            return null;
+        }
+        StringBuilder buf=new StringBuilder(num);
+        for(int i=0;i<num;i++){
+            buf.append(in.readChar());
+        }
+        String readid=buf.toString();
+        if(!readid.equals(id)){
+            in.skipBytes(4+1+8);
+            return null;
+        }
+        int rowsize=in.readInt();
+        int location=in.readByte();
+        long position=in.readLong();
+        TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+        return tmp;
+    }
+    protected static TableIndexEntry lookForData(String id,RandomAccessFile in) throws IOException{
+        int scanhash=id.hashCode();
+        int datahash=in.readInt();
+        int num=in.readShort();
+        if(scanhash!=datahash){
+            in.skipBytes(4+1+8+num*2);
+            return null;
+        }
+        StringBuilder buf=new StringBuilder(num);
+        for(int i=0;i<num;i++){
+            buf.append(in.readChar());
+        }
+        String readid=buf.toString();
+        if(!readid.equals(id)){
+            in.skipBytes(4+1+8);
+            return null;
+        }
+        int rowsize=in.readInt();
+        int location=in.readByte();
+        long position=in.readLong();
+        TableIndexEntry tmp=new TableIndexEntry(id,rowsize,location,position);
+        return tmp;
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexNode.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexNode.java
new file mode 100644 (file)
index 0000000..c093219
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+public class TableIndexNode{
+    private TableIndexNode previous;
+    private TableIndexEntry data;
+    private TableIndexNode next;
+    
+    public TableIndexNode(){
+        previous=null;
+        data=null;
+        next=null;
+    }
+    
+    public TableIndexNode(TableIndexEntry entry){
+        previous=null;
+        data=entry;
+        next=null;
+    }
+    public TableIndexNode(TableIndexNode prev,TableIndexEntry entry){
+        previous=prev;
+        data=entry;
+        next=null;
+    }
+    public TableIndexNode(TableIndexNode prev,TableIndexEntry entry,TableIndexNode nex){
+        previous=prev;
+        data=entry;
+        next=nex;
+    }
+    
+    public TableIndexEntry getData(){
+        return data;
+    }
+    public TableIndexNode getPrevious(){
+        return previous;
+    }
+    public TableIndexNode getNext(){
+        return next;
+    }
+    public void setNext(TableIndexNode node){
+        next=node;
+    }
+    public void setPrevious(TableIndexNode node){
+        previous=node;
+    }
+    public void setData(TableIndexEntry entry){
+        data=entry;
+    }
+    public void remove(){
+        if(previous!=null){
+            previous.setNext(next);
+        }
+        if(next!=null){
+            next.setPrevious(previous);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexPage.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexPage.java
new file mode 100644 (file)
index 0000000..3754921
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+
+public class TableIndexPage{
+    private final static int BASEOFFSET=4+8+8+4+4;
+    private RandomAccessFile file=null;
+    
+    private long location=-1;
+    private int size=-1;
+    private long next=-1;
+    private long lower=-1;
+    private int offset=0;
+    
+    private int starthash=-1;
+    private int endhash=-1;
+    private boolean first=false;
+    
+    private TableIndexPage nextpage=null;
+    private TableIndexPage lowerpage=null;
+    
+    private PagedIndex index=null;
+    
+    public TableIndexPage(PagedIndex index,RandomAccessFile file) throws IOException{
+        this.file=file;
+        this.index=index;
+        first=false;
+        location=file.getFilePointer();
+        size=file.readInt();
+        next=file.readLong();
+        lower=file.readLong();
+        offset=file.readInt();
+        endhash=file.readInt();
+        if(offset>0)starthash=file.readInt();
+    }
+    
+    public static TableIndexPage createNewPage(PagedIndex index,RandomAccessFile file,int size) throws IOException{
+        long pre=file.length();
+        file.setLength(file.length()+size+BASEOFFSET);
+        file.seek(pre);
+        file.writeInt(size);
+        file.writeLong(-1l);
+        file.writeLong(-1l);
+        file.writeInt(0);
+        file.writeInt(-1);
+        file.seek(pre);
+        index.stat_create_page++;
+        return new TableIndexPage(index,file);
+    }
+    
+    public void setFirst(){
+        first=true;
+    }
+    
+    public long getLocation(){
+        return location;
+    }
+    public long getEndLocation(){
+        return location+size+BASEOFFSET;
+    }
+    
+    public String toString(){
+        StringBuffer buf=new StringBuffer();
+        buf.append("{\n");
+        buf.append("  location  "+location+"\n");
+        buf.append("  size      "+size+"\n");
+        buf.append("  next      "+next+"\n");
+        buf.append("  lower     "+lower+"\n");
+        buf.append("  offset    "+offset+"\n");
+        buf.append("  starthash "+starthash+"\n");
+        buf.append("  endhash "+endhash+"\n");
+        buf.append("}\n");
+        return buf.toString();
+    }
+    
+    private void updateMeta() throws IOException{
+        file.seek(location);
+        file.writeInt(size);
+        file.writeLong(next);
+        file.writeLong(lower);
+        file.writeInt(offset);
+        file.writeInt(endhash);
+    }
+    
+    public void addEntriesToList(List<TableIndexEntry> lst) throws IOException{
+        if(lower>-1){
+            if(lowerpage==null){
+                file.seek(lower);
+                lowerpage=new TableIndexPage(index,file);
+            }
+            lowerpage.addEntriesToList(lst);
+        }
+        if(next>-1){
+            if(nextpage==null){
+                file.seek(next);
+                nextpage=new TableIndexPage(index,file);
+            }
+            nextpage.addEntriesToList(lst);
+        }
+        file.seek(location+BASEOFFSET);
+        long pre=file.getFilePointer();
+        while(file.getFilePointer()<pre+offset){
+            TableIndexEntry entry=TableIndexEntry.readData(file);
+            if(entry!=null){
+                if(entry.getLocation()!=Table.DELETE)lst.add(entry);
+            }
+        }
+    }
+    
+    public TableIndexEntry scanIndex(String id,int hashcode) throws IOException{
+        if(!first){
+            if(hashcode<starthash){
+                if(lower==-1)return null;
+                if(lowerpage==null){
+                    file.seek(lower);
+                    lowerpage=new TableIndexPage(index,file);
+                }
+                index.stat_page_branch++;
+                return lowerpage.scanIndex(id,hashcode);
+            }
+        }
+        if(hashcode>endhash){
+            if(next==-1)return null;
+            if(nextpage==null){
+                file.seek(next);
+                nextpage=new TableIndexPage(index,file);
+            }
+            index.stat_page_next++;
+            return nextpage.scanIndex(id,hashcode);
+        }
+        file.seek(location+BASEOFFSET);
+        long pre=file.getFilePointer();
+        while(file.getFilePointer()<pre+offset){
+            TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
+            if(entry!=null)return entry;
+        }
+        if(next==-1)return null;
+        if(nextpage==null){
+            file.seek(next);
+            nextpage=new TableIndexPage(index,file);
+        }
+        index.stat_page_next++;
+        return nextpage.scanIndex(id,hashcode);
+    }
+    protected long getOffset(String id,int hashcode) throws IOException{
+        if(!first){
+            if(hashcode<starthash){
+                if(lower==-1)return -1;
+                if(lowerpage==null){
+                    file.seek(lower);
+                    lowerpage=new TableIndexPage(index,file);
+                }
+                index.stat_page_branch++;
+                return lowerpage.getOffset(id,hashcode);
+            }
+        }
+        if(hashcode>endhash){
+            if(next==-1)return -1;
+            if(nextpage==null){
+                file.seek(next);
+                nextpage=new TableIndexPage(index,file);
+            }
+            index.stat_page_next++;
+            return nextpage.getOffset(id,hashcode);
+        }
+        file.seek(location+BASEOFFSET);
+        long pre=file.getFilePointer();
+        while(file.getFilePointer()<pre+offset){
+            long prescan=file.getFilePointer();
+            TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
+            if(entry!=null)return prescan;
+        }
+        if(next==-1)return -1;
+        if(nextpage==null){
+            file.seek(next);
+            nextpage=new TableIndexPage(index,file);
+        }
+        index.stat_page_next++;
+        return nextpage.getOffset(id,hashcode);
+    }
+    
+    protected TableIndexPage getFirstFreePage(String id,int hashcode) throws IOException{
+        // Is this an empty page?
+        if(offset==0){
+            return this;
+        }
+        // Is this hash lower than the starthash
+        if(!first){
+            if(hashcode<starthash){
+                if(lower==-1){
+                    lower=file.length();
+                    updateMeta();
+                    return createNewPage(index,file,PagedIndex.PAGESIZE);
+                }
+                if(lowerpage==null){
+                    file.seek(lower);
+                    lowerpage=new TableIndexPage(index,file);
+                }
+                index.stat_page_branch++;
+                return lowerpage.getFirstFreePage(id,hashcode);
+            }
+        }
+        // Do we have space in this page
+        if(size-offset>id.length()*2+4+4+8+1+2)return this;
+        // Check next
+        if(next==-1){
+            next=file.length();
+            updateMeta();
+            return createNewPage(index,file,PagedIndex.PAGESIZE);
+        }
+        if(nextpage==null){
+            file.seek(next);
+            nextpage=new TableIndexPage(index,file);
+        }
+        index.stat_page_next++;
+        return nextpage.getFirstFreePage(id,hashcode);
+    }
+    
+    public void addEntry(String id,int rowsize,int location,long position) throws IOException{
+        if(offset==0)starthash=id.hashCode();
+        file.seek(this.location+BASEOFFSET+offset);
+        TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+        entry.writeData(file);
+        offset+=entry.getSize();
+        if(id.hashCode()>endhash)endhash=id.hashCode();
+        updateMeta();
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexPageTransactional.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexPageTransactional.java
new file mode 100644 (file)
index 0000000..9385902
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+
+public class TableIndexPageTransactional{
+    public @atomic interface TableIndexPageTSInf{
+        Long getLocation();
+        Integer getSize();
+        Long getNext();
+        Long getLower();
+        Integer getOffset();
+        Integer getStarthash();
+        Integer getEndhash();
+        Boolean getFirst();
+        TableIndexPageTSInf getNextpage();
+        TableIndexPageTSInf getLowerpage();
+        
+     
+        void setLowerpage(TableIndexPageTSInf lowerpage);   
+        void setNextpage(TableIndexPageTSInf nextpage);
+        void setFirst(Boolean val);
+        void setEndhash();
+        void setStarthash();
+        void setOffset(Integer offset);
+        void setNext(Long next);
+        void setSize(Integer size);
+        void setLocation(Long location);
+        void setLower(Long val);
+    }
+    private final static int BASEOFFSET=4+8+8+4+4;
+    private RandomAccessFile file=null;
+    
+    private long location=-1;
+    private int size=-1;
+    private long next=-1;
+    private long lower=-1;
+    private int offset=0;
+    
+    private int starthash=-1;
+    private int endhash=-1;
+    private boolean first=false;
+    
+    private TableIndexPage nextpage=null;
+    private TableIndexPage lowerpage=null;
+    
+    private PagedIndex index=null;
+    
+    public TableIndexPageTransactional(PagedIndex index,RandomAccessFile file) throws IOException{
+        this.file=file;
+        this.index=index;
+        first=false;
+        location=file.getFilePointer();
+        size=file.readInt();
+        next=file.readLong();
+        lower=file.readLong();
+        offset=file.readInt();
+        endhash=file.readInt();
+        if(offset>0)starthash=file.readInt();
+    }
+    
+    public static TableIndexPage createNewPage(PagedIndex index,RandomAccessFile file,int size) throws IOException{
+        long pre=file.length();
+        file.setLength(file.length()+size+BASEOFFSET);
+        file.seek(pre);
+        file.writeInt(size);
+        file.writeLong(-1l);
+        file.writeLong(-1l);
+        file.writeInt(0);
+        file.writeInt(-1);
+        file.seek(pre);
+        index.stat_create_page++;
+        return new TableIndexPage(index,file);
+    }
+    
+    public void setFirst(){
+        first=true;
+    }
+    
+    public long getLocation(){
+        return location;
+    }
+    public long getEndLocation(){
+        return location+size+BASEOFFSET;
+    }
+    
+    public String toString(){
+        StringBuffer buf=new StringBuffer();
+        buf.append("{\n");
+        buf.append("  location  "+location+"\n");
+        buf.append("  size      "+size+"\n");
+        buf.append("  next      "+next+"\n");
+        buf.append("  lower     "+lower+"\n");
+        buf.append("  offset    "+offset+"\n");
+        buf.append("  starthash "+starthash+"\n");
+        buf.append("  endhash "+endhash+"\n");
+        buf.append("}\n");
+        return buf.toString();
+    }
+    
+    private void updateMeta() throws IOException{
+        file.seek(location);
+        file.writeInt(size);
+        file.writeLong(next);
+        file.writeLong(lower);
+        file.writeInt(offset);
+        file.writeInt(endhash);
+    }
+    
+    public void addEntriesToList(List<TableIndexEntry> lst) throws IOException{
+        if(lower>-1){
+            if(lowerpage==null){
+                file.seek(lower);
+                lowerpage=new TableIndexPage(index,file);
+            }
+            lowerpage.addEntriesToList(lst);
+        }
+        if(next>-1){
+            if(nextpage==null){
+                file.seek(next);
+                nextpage=new TableIndexPage(index,file);
+            }
+            nextpage.addEntriesToList(lst);
+        }
+        file.seek(location+BASEOFFSET);
+        long pre=file.getFilePointer();
+        while(file.getFilePointer()<pre+offset){
+            TableIndexEntry entry=TableIndexEntry.readData(file);
+            if(entry!=null){
+                if(entry.getLocation()!=Table.DELETE)lst.add(entry);
+            }
+        }
+    }
+    
+    public TableIndexEntry scanIndex(String id,int hashcode) throws IOException{
+        if(!first){
+            if(hashcode<starthash){
+                if(lower==-1)return null;
+                if(lowerpage==null){
+                    file.seek(lower);
+                    lowerpage=new TableIndexPage(index,file);
+                }
+                index.stat_page_branch++;
+                return lowerpage.scanIndex(id,hashcode);
+            }
+        }
+        if(hashcode>endhash){
+            if(next==-1)return null;
+            if(nextpage==null){
+                file.seek(next);
+                nextpage=new TableIndexPage(index,file);
+            }
+            index.stat_page_next++;
+            return nextpage.scanIndex(id,hashcode);
+        }
+        file.seek(location+BASEOFFSET);
+        long pre=file.getFilePointer();
+        while(file.getFilePointer()<pre+offset){
+            TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
+            if(entry!=null)return entry;
+        }
+        if(next==-1)return null;
+        if(nextpage==null){
+            file.seek(next);
+            nextpage=new TableIndexPage(index,file);
+        }
+        index.stat_page_next++;
+        return nextpage.scanIndex(id,hashcode);
+    }
+    protected long getOffset(String id,int hashcode) throws IOException{
+        if(!first){
+            if(hashcode<starthash){
+                if(lower==-1)return -1;
+                if(lowerpage==null){
+                    file.seek(lower);
+                    lowerpage=new TableIndexPage(index,file);
+                }
+                index.stat_page_branch++;
+                return lowerpage.getOffset(id,hashcode);
+            }
+        }
+        if(hashcode>endhash){
+            if(next==-1)return -1;
+            if(nextpage==null){
+                file.seek(next);
+                nextpage=new TableIndexPage(index,file);
+            }
+            index.stat_page_next++;
+            return nextpage.getOffset(id,hashcode);
+        }
+        file.seek(location+BASEOFFSET);
+        long pre=file.getFilePointer();
+        while(file.getFilePointer()<pre+offset){
+            long prescan=file.getFilePointer();
+            TableIndexEntry entry=TableIndexEntry.lookForData(id,file);
+            if(entry!=null)return prescan;
+        }
+        if(next==-1)return -1;
+        if(nextpage==null){
+            file.seek(next);
+            nextpage=new TableIndexPage(index,file);
+        }
+        index.stat_page_next++;
+        return nextpage.getOffset(id,hashcode);
+    }
+    
+    protected TableIndexPage getFirstFreePage(String id,int hashcode) throws IOException{
+        // Is this an empty page?
+        if(offset==0){
+            return this;
+        }
+        // Is this hash lower than the starthash
+        if(!first){
+            if(hashcode<starthash){
+                if(lower==-1){
+                    lower=file.length();
+                    updateMeta();
+                    return createNewPage(index,file,PagedIndex.PAGESIZE);
+                }
+                if(lowerpage==null){
+                    file.seek(lower);
+                    lowerpage=new TableIndexPage(index,file);
+                }
+                index.stat_page_branch++;
+                return lowerpage.getFirstFreePage(id,hashcode);
+            }
+        }
+        // Do we have space in this page
+        if(size-offset>id.length()*2+4+4+8+1+2)return this;
+        // Check next
+        if(next==-1){
+            next=file.length();
+            updateMeta();
+            return createNewPage(index,file,PagedIndex.PAGESIZE);
+        }
+        if(nextpage==null){
+            file.seek(next);
+            nextpage=new TableIndexPage(index,file);
+        }
+        index.stat_page_next++;
+        return nextpage.getFirstFreePage(id,hashcode);
+    }
+    
+    public void addEntry(String id,int rowsize,int location,long position) throws IOException{
+        if(offset==0)starthash=id.hashCode();
+        file.seek(this.location+BASEOFFSET+offset);
+        TableIndexEntry entry=new TableIndexEntry(id,rowsize,location,position);
+        entry.writeData(file);
+        offset+=entry.getSize();
+        if(id.hashCode()>endhash)endhash=id.hashCode();
+        updateMeta();
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStream.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStream.java
new file mode 100644 (file)
index 0000000..f6a7e81
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+
+public abstract class TupleStream{
+    public abstract boolean hasNext() throws IOException;
+    public abstract Row next() throws IOException;
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStreamMerger.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStreamMerger.java
new file mode 100644 (file)
index 0000000..8d71ce4
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.core;
+
+import java.io.*;
+import java.util.*;
+
+public class TupleStreamMerger extends TupleStream{
+    private List<TupleStream> streams;
+    private TupleStream current=null;
+    private Row next=null;
+    
+    public TupleStreamMerger(){
+        streams=new ArrayList<TupleStream>();
+    }
+    
+    public void addStream(TupleStream stream){
+        streams.add(stream);
+    }
+
+    public boolean hasNext() throws IOException{
+        if(next!=null)return true;
+        if(current==null){
+            if(streams.size()>0){
+                current=streams.remove(0);
+            }else return false;
+        }
+        if(current.hasNext()){
+            next=current.next();
+            return true;
+        }else{
+            current=null;
+            return hasNext();
+        }
+    }
+
+    public Row next() throws IOException{
+        if(next==null)hasNext();
+        Row tmp=next;
+        next=null;
+        return tmp;
+    }
+
+
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Value.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Value.java
new file mode 100644 (file)
index 0000000..0da4452
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ package com.solidosystems.tuplesoup.core;
+ import java.util.*;
+ import java.io.*;
+ /**
+  * The Value class holds a single data value.
+  * Current size estimate without string data: 8+4+4+8+8 = 32 bytes pr value in mem
+  */
+ public class Value{
+     public final static int NULL=0;
+     public final static int STRING=1;
+     public final static int INT=2;
+     public final static int LONG=3;
+     public final static int FLOAT=4;
+     public final static int DOUBLE=5;
+     public final static int BOOLEAN=6;
+     public final static int TIMESTAMP=7;
+     public final static int BINARY=8;
+
+     private byte type=NULL; // The type of the value being held
+     private String str_value=null;
+     private long int_value=0;
+     private double float_value=0.0;
+     private byte[] binary=null;
+
+     /**
+      * Returns the numerical type id for this value.
+      */
+     public int getType(){
+         return type;
+     }
+     
+     /**
+      * Returns the name this value's type.
+      */
+     public String getTypeName(){
+         switch(type){
+              case STRING     : return "string";
+              case INT        : return "int";
+              case LONG       : return "long";
+              case FLOAT      : return "float";
+              case DOUBLE     : return "double";
+              case BOOLEAN    : return "boolean";
+              case TIMESTAMP  : return "timestamp";
+              case BINARY     : return "binary";
+          }
+          return "null";
+     }
+
+     /**
+      * An implementation of the hashCode method as defined in java.lang.Object
+      * 
+      * @return a hash code value for this object
+      */
+     public int hashCode(){
+         int hash=0;
+         switch(type){
+             case STRING     : hash+=str_value.hashCode();
+             case INT        : hash+=(int)int_value;
+             case LONG       : hash+=(int)int_value;
+             case FLOAT      : hash+=(int)float_value;
+             case DOUBLE     : hash+=(int)float_value;
+             case BOOLEAN    : hash+=(int)int_value;
+             case TIMESTAMP  : hash+=(int)int_value;
+             case BINARY     : hash+=binary.hashCode();
+         }
+         return hash;
+     }
+
+     /**
+      * Returns true only if this Value has specifically been set to null.
+      *
+      * @return true if the data being held is null, false otherwise
+      */
+     public boolean isNull(){
+         return type==NULL;
+     }
+
+     /**
+      * Returns -1, 0 or 1 if this value is smaller, equal or larger than the value given as a parameter.
+      */
+     public int compareTo(Value value){
+         if(type==STRING){
+             return str_value.compareTo(value.getString());
+         }
+         if(lessThan(value))return -1;
+         if(greaterThan(value))return 1;
+         return 0;
+     }
+
+     /**
+      * Attempts to compare this Value to the value given as parameter and returns true if this value is less than the value given as a parameter.
+      * The types used for the comparison will always be based on the type of this Value based on the following rules.
+      * <ul>
+      *   <li>If this Value is a numeric type, then the other Value will be asked to deliver the same numeric type for the comparison.
+      *   <li>If this Value is a string, then both values will be asked to deliver a double value for the comparison.
+      *   <li>If this Value is a timestamp, then both values will be asked to deliver a long value for the comparison.
+      *   <li>If this Value is a boolean, false will be returned.
+      * </ul>
+      *
+      * @param value the value this value should be compared to
+      * @return true if this value is less than the value given as a parameter, false otherwise
+      */
+     public boolean lessThan(Value value){
+         switch(type){
+             case STRING     : return getDouble()<value.getDouble();
+             case INT        : return getInt()<value.getInt();
+             case LONG       : return getLong()<value.getLong();
+             case FLOAT      : return getFloat()<value.getFloat();
+             case DOUBLE     : return getDouble()<value.getDouble();
+             case TIMESTAMP  : return getLong()<value.getLong();
+         }
+         return false;
+     }
+
+     /**
+      * Attempts to compare this Value to the value given as parameter and returns true if this value is greater than the value given as a parameter.
+      * The types used for the comparison will always be based on the type of this Value based on the following rules.
+      * <ul>
+      *   <li>If this Value is a numeric type, then the other Value will be asked to deliver the same numeric type for the comparison.
+      *   <li>If this Value is a string, then both values will be asked to deliver a double value for the comparison.
+      *   <li>If this Value is a timestamp, then both values will be asked to deliver a long value for the comparison.
+      *   <li>If this Value is a boolean, false will be returned.
+      * </ul>
+      *
+      * @param value the value this value should be compared to
+      * @return true if this value is greater than the value given as a parameter, false otherwise
+      */
+     public boolean greaterThan(Value value){
+         switch(type){
+             case STRING     : return getDouble()>value.getDouble();
+             case INT        : return getInt()>value.getInt();
+             case LONG       : return getLong()>value.getLong();
+             case FLOAT      : return getFloat()>value.getFloat();
+             case DOUBLE     : return getDouble()>value.getDouble();
+             case TIMESTAMP  : return getLong()>value.getLong();
+         }
+         return false;
+     }
+
+     /**
+      * Returns true if the string representation of this value starts with the string representation of the value given as parameter.
+      */
+     public boolean startsWith(Value value){
+         return getString().startsWith(value.getString());
+     }
+
+     /**
+      * Returns true if the string representation of this value ends with the string representation of the value given as parameter.
+      */
+     public boolean endsWith(Value value){
+         return getString().endsWith(value.getString());
+     }
+
+     /**
+      * Returns true if the string representation of this value contains the string representation of the value given as parameter.
+      */
+     public boolean contains(Value value){
+         return getString().indexOf(value.getString())>-1;
+     }
+
+     /**
+      * Returns true if the contents of this value equals the contents of the value given as parameter.
+      */
+     public boolean equals(Object obj){
+         try{
+             Value val=(Value)obj;
+             if(val.type==type){
+                 switch(type){
+                     case NULL       : return true;
+                     case STRING     : return str_value.equals(val.str_value);
+                     case INT        : return int_value==val.int_value;
+                     case LONG       : return int_value==val.int_value;
+                     case FLOAT      : return float_value==val.float_value;
+                     case DOUBLE     : return float_value==val.float_value;
+                     case BOOLEAN    : return int_value==val.int_value;
+                     case TIMESTAMP  : return int_value==val.int_value;
+                     case BINARY     : if(binary.length==val.binary.length){
+                                          for(int i=0;i<binary.length;i++){
+                                              if(binary[i]!=val.binary[i])return false;
+                                          }
+                                       }
+                                       return true;
+                 }
+             }
+         }catch(Exception e){}
+         return false;
+     }
+
+     /**
+      * Returns a string representation of this object.
+      */
+     public String toString(){
+         return getString();
+     }
+
+     /**
+      * Returns a string representation of this object (identical to toString)
+      */
+     public String get(){
+         return getString();
+     }
+
+     /**
+      * Returns this value as an xml tag with the given key set as an attribute called name.
+      * The following string is an example of the int value 1234 created with the key foo &lt;value name="foo" type="int"&gt;1234&lt;/value&gt;
+      */
+     public String toBasicXMLString(String key){
+         switch(type){
+             case STRING     : return "<value name=\""+key+"\" type=\"string\">"+str_value+"</value>";
+             case INT        : return "<value name=\""+key+"\"  type=\"int\">"+int_value+"</value>";
+             case LONG       : return "<value name=\""+key+"\"  type=\"long\">"+int_value+"</value>";
+             case FLOAT      : return "<value name=\""+key+"\"  type=\"float\">"+float_value+"</value>";
+             case DOUBLE     : return "<value name=\""+key+"\"  type=\"double\">"+float_value+"</value>";
+             case BOOLEAN    : if(int_value==1){
+                                     return "<value name=\""+key+"\"  type=\"boolean\">TRUE</value>";
+                               }else{
+                                     return "<value name=\""+key+"\"  type=\"boolean\">FALSE</value>";
+                               }
+             case TIMESTAMP  : return "<value name=\""+key+"\"  type=\"timestamp\">"+new Date(int_value).toString()+"</value>";
+             case BINARY     : return "<value name=\""+key+"\" type=\"binary\">"+getString()+"</value>";
+         }
+         return "<value name=\""+key+"\"  type=\"null\"></value>";
+     }
+     
+     /**
+       * Returns this value as an xml tag.
+       * The following string is an example of the int value 1234 &lt;value type="int"&gt;1234&lt;/value&gt;
+       */
+     public String toBasicXMLString(){
+          switch(type){
+              case STRING     : return "<value type=\"string\">"+str_value+"</value>";
+              case INT        : return "<value type=\"int\">"+int_value+"</value>";
+              case LONG       : return "<value type=\"long\">"+int_value+"</value>";
+              case FLOAT      : return "<value type=\"float\">"+float_value+"</value>";
+              case DOUBLE     : return "<value type=\"double\">"+float_value+"</value>";
+              case BOOLEAN    : if(int_value==1){
+                                      return "<value type=\"boolean\">TRUE</value>";
+                                }else{
+                                      return "<value type=\"boolean\">FALSE</value>";
+                                }
+              case TIMESTAMP  : return "<value type=\"timestamp\">"+new Date(int_value).toString()+"</value>";
+              case BINARY     : return "<value type=\"binary\">"+getString()+"</value>";
+          }
+          return "<value type=\"null\"></value>";
+      }
+
+     /**
+      * Returns a string representation of this value
+      */
+     public String getString(){
+         switch(type){
+             case STRING     : return str_value;
+             case INT        : return ""+int_value;
+             case LONG       : return ""+int_value;
+             case FLOAT      : return ""+float_value;
+             case DOUBLE     : return ""+float_value;
+             case BOOLEAN    : if(int_value==1){
+                                     return "TRUE";
+                               }else{
+                                     return "FALSE";
+                               }
+             case TIMESTAMP  : return new Date(int_value).toString();
+             case BINARY     : StringBuffer buf=new StringBuffer();
+                               for(int i=0;i<binary.length;i++){
+                                  byte b=binary[i];
+                                  buf.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1,3));
+                               }
+                               return buf.toString();
+         }
+         return "";
+     }
+
+     /**
+      * Attempts to return an integer representation of this value.
+      * Numerical values will be returned directly (demoted if necessary).
+      * Boolean values will be returned as 1 or 0.
+      * Timestamp values will be returned as a unix timestamp representation divided by 1000.
+      * String values will be atempted to be converted into an int, if that fails, 0 will be returned.
+      * Everything else will return 0.
+      */
+     public int getInt(){
+         try{
+             switch(type){
+                 case STRING     : return Integer.parseInt(str_value);
+                 case INT        : return (int)int_value;
+                 case LONG       : return (int)int_value;
+                 case FLOAT      : return (int)float_value;
+                 case DOUBLE     : return (int)float_value;
+                 case BOOLEAN    : return (int)int_value;
+                 case TIMESTAMP  : return (int)(int_value/1000);
+             }
+         }catch(Exception e){}
+         return 0;
+     }
+
+     /**
+       * Attempts to return a long representation of this value.
+       * Numerical values will be returned directly.
+       * Boolean values will be returned as 1 or 0.
+       * Timestamp values will be returned as a unix timestamp representation.
+       * String values will be atempted to be converted into an int, if that fails, 0 will be returned.
+       * Everything else will return 0.
+       */
+     public long getLong(){
+         try{
+             switch(type){
+                 case STRING     : return Long.parseLong(str_value);
+                 case INT        : return int_value;
+                 case LONG       : return int_value;
+                 case FLOAT      : return (long)float_value;
+                 case DOUBLE     : return (long)float_value;
+                 case BOOLEAN    : return int_value;
+                 case TIMESTAMP  : return int_value;
+             }
+         }catch(Exception e){}
+         return 0;
+     }
+
+     /**
+      * Attempts to return a float representation of this value.
+      * Numerical values will be returned directly (demoted if necessary).
+      * Boolean values will be returned as 1 or 0.
+      * Timestamp values will be returned as a unix timestamp representation divided by 1000.
+      * String values will be atempted to be converted into a float, if that fails, 0 will be returned.
+      * Everything else will return 0.
+      */
+     public float getFloat(){
+         try{
+             switch(type){
+                 case STRING     : return Float.parseFloat(str_value);
+                 case INT        : return (float)int_value;
+                 case LONG       : return (float)int_value;
+                 case FLOAT      : return (float)float_value;
+                 case DOUBLE     : return (float)float_value;
+                 case BOOLEAN    : return (float)int_value;
+                 case TIMESTAMP  : return (float)(int_value/1000);
+             }
+         }catch(Exception e){}
+         return 0.0f;
+     }
+
+     /**
+      * Attempts to return a double representation of this value.
+      * Numerical values will be returned directly.
+      * Boolean values will be returned as 1 or 0.
+      * Timestamp values will be returned as a unix timestamp representation divided by 1000.
+      * String values will be atempted to be converted into a float, if that fails, 0 will be returned.
+      * Everything else will return 0.
+      */
+     public double getDouble(){
+         try{
+             switch(type){
+                 case STRING     : return Double.parseDouble(str_value);
+                 case INT        : return (double)int_value;
+                 case LONG       : return (double)int_value;
+                 case FLOAT      : return (double)float_value;
+                 case DOUBLE     : return (double)float_value;
+                 case BOOLEAN    : return (double)int_value;
+                 case TIMESTAMP  : return (double)(int_value);
+             }
+         }catch(Exception e){}
+         return 0.0;
+     }
+
+     /**
+      * Returns a boolean representation of this value.
+      * Boolean values will be returned directly.
+      * Integer values equalling 1 will be returned as true.
+      * String values equalling true,1,t,yes,on will be returned as true (case insensitive).
+      * Everything else will be returned as false.
+      *
+      * @return a boolean representation of this value.
+      */
+     public boolean getBoolean(){
+         try{
+             switch(type){
+                 case STRING     : if(str_value.toLowerCase().trim().equals("true"))return true;
+                                   if(str_value.trim().equals("1"))return true;
+                                   if(str_value.toLowerCase().trim().equals("t"))return true;
+                                   if(str_value.toLowerCase().trim().equals("yes"))return true;
+                                   if(str_value.toLowerCase().trim().equals("on"))return true;
+                 case INT        : if(int_value==1)return true;
+                 case LONG       : if(int_value==1)return true;
+                 case FLOAT      : if(float_value==1.0f)return true;
+                 case DOUBLE     : if(float_value==1.0)return true;
+                 case BOOLEAN    : if(int_value==1)return true;
+             }
+         }catch(Exception e){}
+         return false;
+     }
+
+     /**
+      * Attempts to return this value as a Date object.
+      * For non date numerical values, the following rules will be used for conversion:
+      * int and float will be multiplied by 1000 and used as a unix timestamp.
+      * long and double will be used directly as a unix timestamp.
+      * Any other type will result in a Date object initialized with 0.
+      *
+      * @return a Date object representation of this value
+      */
+     public Date getTimestamp(){
+         try{
+             switch(type){
+                 case INT        : return new Date(int_value*1000l);
+                 case LONG       : return new Date(int_value);
+                 case FLOAT      : return new Date((long)(float_value*1000l));
+                 case DOUBLE     : return new Date((long)float_value);
+                 case TIMESTAMP  : return new Date(int_value);
+             }
+         }catch(Exception e){}
+         return new Date(0);
+     }
+
+     public byte[] getBinary(){
+         switch(type){
+             case BINARY        : return binary;
+         }
+         return null;
+     }
+
+     /**
+      * Attempts to write this Value to the given DataOutputStream.
+      * The Value will be written as a byte signifying the type of the Value, followed by the actual Value in the native format used by DataOutput.
+      * The exception to this is the string which is written as an integer followed by each character as a single char.
+      * 
+      * @param out the DataOutputStream the Value should be written to
+      */
+     public void writeToStream(DataOutputStream out) throws IOException{
+         out.writeByte(type);
+         switch(type){
+             case STRING :   out.writeInt(str_value.length());
+                             for(int i=0;i<str_value.length();i++){
+                                 out.writeChar(str_value.charAt(i));
+                             }
+                         break;
+             case INT    :   out.writeInt((int)int_value);
+                         break;
+             case LONG   :   out.writeLong(int_value);
+                         break;
+             case FLOAT  :   out.writeFloat((float)float_value);
+                         break;
+             case DOUBLE :   out.writeDouble(float_value);
+                         break;
+             case BOOLEAN:   out.writeBoolean(int_value==1);
+                         break;
+             case TIMESTAMP: out.writeLong(int_value);
+                         break;
+             case BINARY : out.writeInt(binary.length);
+                           out.write(binary,0,binary.length);
+                         break;
+         }
+     }
+     
+     /**
+       * Attempts to write this Value to the given DataOutputStream.
+       * The Value will be written as a byte signifying the type of the Value, followed by the actual Value in the native format used by DataOutput.
+       * The exception to this is the string which is written as an integer followed by each character as a single char.
+       * 
+       * @param out the DataOutputStream the Value should be written to
+       */
+      public void writeToFile(DataOutput out) throws IOException{
+          out.writeByte(type);
+          switch(type){
+              case STRING :   out.writeInt(str_value.length());
+                              for(int i=0;i<str_value.length();i++){
+                                  out.writeChar(str_value.charAt(i));
+                              }
+                          break;
+              case INT    :   out.writeInt((int)int_value);
+                          break;
+              case LONG   :   out.writeLong(int_value);
+                          break;
+              case FLOAT  :   out.writeFloat((float)float_value);
+                          break;
+              case DOUBLE :   out.writeDouble(float_value);
+                          break;
+              case BOOLEAN:   out.writeBoolean(int_value==1);
+                          break;
+              case TIMESTAMP: out.writeLong(int_value);
+                          break;
+              case BINARY : out.writeInt(binary.length);
+                            out.write(binary,0,binary.length);
+          }
+      }
+
+     /**
+      * Attempts to read a new Value from the given DataInputStream.
+      * The Value should be in the format delivered by writeToStream.
+      *
+      * @param in the DataInputStream the Value should be read from
+      * @return the Value read from the stream
+      */
+     public static Value readFromStream(DataInputStream in) throws IOException{
+         byte type=in.readByte();
+         switch(type){
+             case STRING :   int size=in.readInt();
+                             StringBuffer buf=new StringBuffer();
+                             for(int i=0;i<size;i++){
+                                 buf.append(in.readChar());
+                             }
+                             return new Value(buf.toString());
+             case INT    :   return new Value(in.readInt());
+             case LONG   :   return new Value(in.readLong());
+             case FLOAT  :   return new Value(in.readFloat());
+             case DOUBLE :   return new Value(in.readDouble());
+             case BOOLEAN:   return new Value(in.readBoolean());
+             case TIMESTAMP: return new Value(new Date(in.readLong()));
+             case BINARY : int length=in.readInt();
+                           byte[] abuf=new byte[length];
+                           int read=0;
+                           while(read<length){
+                               read+=in.read(abuf,read,length-read);
+                           }
+                           return new Value(abuf);
+
+         }
+         return new Value();
+     }
+
+    /**
+     * Initializes this Value with the given String.
+     * 
+     * @param val the value this Value object should represent
+     */
+     public Value(String val){
+         str_value=val;
+         type=STRING;
+     }
+     
+     public Value(byte[] val){
+          binary=val;
+          type=BINARY;
+      }
+
+     /**
+      * Initializes this Value with the given Date.
+      * The Dates internal long value delivered by the getTime() method will be used.
+      * 
+      * @param val the value this Value object should represent
+      */
+     public Value(Date val){
+         int_value=val.getTime();
+         type=TIMESTAMP;
+     }
+
+     /**
+      * Initializes this Value as null.
+      */
+     public Value(){
+         type=NULL;
+     }
+
+     /**
+      * Initializes this Value with the given int.
+      * 
+      * @param val the value this Value object should represent
+      */
+     public Value(int val){
+         int_value=val;
+         type=INT;
+     }
+
+     /**
+      * Initializes this Value with the given long.
+      * 
+      * @param val the value this Value object should represent
+      */
+     public Value(long val){
+         int_value=val;
+         type=LONG;
+     }
+
+     /**
+      * Initializes this Value with the given float.
+      * 
+      * @param val the value this Value object should represent
+      */
+     public Value(float val){
+         float_value=val;
+         type=FLOAT;
+     }
+
+     /**
+      * Initializes this Value with the given double.
+      * 
+      * @param val the value this Value object should represent
+      */
+     public Value(double val){
+         float_value=val;
+         type=DOUBLE;
+     }
+
+     /**
+      * Initializes this Value with the given boolean.
+      * 
+      * @param val the value this Value object should represent
+      */
+     public Value(boolean val){
+         if(val){
+             int_value=1;
+         }else{
+             int_value=0;
+         }
+         type=BOOLEAN;
+     }  
+ }
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Conditional.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Conditional.java
new file mode 100644 (file)
index 0000000..9cf2fd7
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class Conditional extends TupleStream{
+    private TupleStream stream;
+    private RowMatcher matcher;
+    private Row next;
+    
+    public Conditional(TupleStream stream, RowMatcher matcher) throws IOException{
+        this.stream=stream;
+        this.matcher=matcher;
+        next=null;
+        readNext();
+    }
+    
+    private void readNext() throws IOException{
+        next=null;
+        while(next==null){
+            if(!stream.hasNext())return;
+            Row row=stream.next();
+            if(matcher.matches(row)){
+                next=row;
+            }
+        }
+    }
+    
+    public boolean hasNext() throws IOException{
+        if(next!=null)return true;
+        return false;
+    }
+    
+    public Row next() throws IOException{
+        Row tmp=next;
+        readNext();
+        return tmp;
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/HeapSort.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/HeapSort.java
new file mode 100644 (file)
index 0000000..6da0421
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public abstract class HeapSort extends TupleStream{
+    public HeapSort(){
+        
+    }
+    public void initialize(TupleStream source,List<SortRule> lst){
+        
+    }
+    public abstract boolean hasNext();
+    public abstract Row next();
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/JavaSort.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/JavaSort.java
new file mode 100644 (file)
index 0000000..1dfb4a1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class JavaSort extends Sort{
+    private List<Row> sortlst;
+    private int offset;
+    private int datasize;
+    
+    public JavaSort(){
+    }
+    public void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException{
+        sortlst=new ArrayList<Row>();
+        offset=0;
+        while(source.hasNext()){
+            sortlst.add(source.next());
+        }
+        Collections.sort(sortlst,new SortComparator(lst));
+        datasize=sortlst.size();
+    }
+    public boolean hasNext(){
+        if(offset<datasize)return true;
+        return false;
+    }
+    public Row next(){
+        return sortlst.get(offset++);
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Join.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Join.java
new file mode 100644 (file)
index 0000000..9588f86
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class Join extends TupleStream{
+    public final static int INNER=0;
+    
+    private int type;
+    private TupleStream left;
+    private TupleStream right;
+    private String key;
+    private RowBuffer buf;
+    private String filename;
+    
+    public Join(String filename,TupleStream left, TupleStream right, String key) throws IOException{
+        this.filename=filename;
+        this.left=left;
+        this.right=right;
+        this.key=key;
+        this.type=INNER;
+        joinData();
+    }
+    
+    public Join(String filename,TupleStream left, TupleStream right, String key,int type) throws IOException{
+        this.filename=filename;
+        this.left=left;
+        this.right=right;
+        this.key=key;
+        this.type=type;
+        joinData();
+    }
+    
+    private void joinData() throws IOException{
+        buf=new RowBuffer(filename);
+        // Raw nested loop operation
+        
+        buf.prepare();
+    }
+    
+    public Row next() throws IOException{
+        return buf.next();
+    }
+    
+    public boolean hasNext() throws IOException{
+        return buf.hasNext();
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/MergeSort.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/MergeSort.java
new file mode 100644 (file)
index 0000000..7760acc
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class MergeSort extends Sort{
+    private int MEMLIMIT=65536;
+    private int BUFFERCACHE=65536;
+    private int BUFFERLIMIT=8192;
+    
+    private RowBuffer result;
+    
+    private int bufnum=0;
+    
+    private String filename;
+    
+    private SortComparator compare;
+    
+    
+    public MergeSort(int cachesize){
+        if(cachesize<32768){
+            MEMLIMIT=32768;
+            BUFFERCACHE=0;
+            BUFFERLIMIT=0;
+        }else if(cachesize<65536){
+            MEMLIMIT=32768;
+            BUFFERCACHE=cachesize-MEMLIMIT;
+            BUFFERLIMIT=BUFFERCACHE/4;
+        }else{
+            MEMLIMIT=cachesize/2;
+            BUFFERCACHE=MEMLIMIT;
+            BUFFERLIMIT=BUFFERCACHE/16;
+        }
+        if(BUFFERLIMIT<8192)BUFFERLIMIT=8192;
+    }
+    
+    public void mergeSort(RowBuffer result,RowBuffer a,RowBuffer b) throws IOException{
+        a.prepare();
+        b.prepare();
+        Row rowb=null;
+        Row rowa=null;
+        while(a.hasNext()&&b.hasNext()){
+            if(rowa==null)rowa=a.next();
+            if(rowb==null)rowb=b.next();
+            int cmp=compare.compare(rowa,rowb);
+            if(cmp<=0){
+                result.addRow(rowa);
+                rowa=null;
+            }else{
+                result.addRow(rowb);
+                rowb=null;
+            }
+        }
+        if(rowa!=null)result.addRow(rowa);
+        if(rowb!=null)result.addRow(rowb);
+        while(a.hasNext()){
+            result.addRow(a.next());
+        }
+        while(b.hasNext()){
+            result.addRow(b.next());
+        }
+    }
+    
+    public void mergeSort(List<RowBuffer> buffers) throws IOException{
+        while(buffers.size()>2){
+            RowBuffer tmp=new RowBuffer(filename+"."+(bufnum++));
+            tmp.setCacheSize(allocBuffer());
+            // Grab two and sort to buf
+            RowBuffer a=buffers.remove(0);
+            RowBuffer b=buffers.remove(0);
+            mergeSort(tmp,a,b);
+            a.close();
+            freeBuffer(a);
+            b.close();
+            freeBuffer(b);
+            buffers.add(tmp);
+        }
+        if(buffers.size()==1){
+            result.close();
+            result=buffers.get(0);
+            result.prepare();
+            return;
+        }
+        if(buffers.size()==2){
+            RowBuffer a=buffers.get(0);
+            RowBuffer b=buffers.get(1);
+            mergeSort(result,a,b);
+            a.close();
+            freeBuffer(a);
+            b.close();
+            freeBuffer(b);
+            result.prepare();
+            return;
+        }
+    }
+    
+    private int allocBuffer(){
+        if(BUFFERCACHE>=BUFFERLIMIT){
+            BUFFERCACHE-=BUFFERLIMIT;
+            return BUFFERLIMIT;
+        }
+        int tmp=BUFFERCACHE;
+        BUFFERCACHE=0;
+        return tmp;
+    }
+    private void freeBuffer(RowBuffer buf){
+        BUFFERCACHE+=buf.getCacheSize();
+    }
+    
+    public void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException{
+        this.filename=filename;
+        compare=new SortComparator(lst);
+        bufnum=0;
+        result=new RowBuffer(filename+".result");
+        result.setCacheSize(BUFFERLIMIT);
+        List<RowBuffer> buffers=new ArrayList<RowBuffer>();
+        int usage=0;
+        List<Row> sortlst=new ArrayList<Row>();
+        while(source.hasNext()){
+            Row row=source.next();
+            if(usage+row.getSize()>MEMLIMIT){
+                RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+                buf.setCacheSize(allocBuffer());
+                Collections.sort(sortlst,new SortComparator(lst));
+                for(int i=0;i<sortlst.size();i++){
+                    buf.addRow(sortlst.get(i));
+                }
+                buffers.add(buf);
+                usage=0;
+                sortlst=new ArrayList<Row>();
+            }
+            sortlst.add(row);
+            usage+=row.getSize();
+        }
+        RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+        buf.setCacheSize(allocBuffer());
+        Collections.sort(sortlst,new SortComparator(lst));
+        for(int i=0;i<sortlst.size();i++){
+            buf.addRow(sortlst.get(i));
+        }
+        buffers.add(buf);
+        mergeSort(buffers);
+    }
+    public boolean hasNext() throws IOException{
+        return result.hasNext();
+    }
+    public Row next() throws IOException{
+        return result.next();
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/MergeSort2.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/MergeSort2.java
new file mode 100644 (file)
index 0000000..754a3d1
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public class MergeSort2 extends Sort{
+    private int MEMLIMIT=65536;
+    private int BUFFERCACHE=65536;
+    private int BUFFERLIMIT=8192;
+    
+    private int PREBUFFERS=256;
+    
+    private RowBuffer result;
+    
+    private int bufnum=0;
+    
+    private String filename;
+    
+    private SortComparator compare;
+    
+    
+    public MergeSort2(int cachesize){
+        if(cachesize<32768){
+            MEMLIMIT=32768;
+            BUFFERCACHE=0;
+            BUFFERLIMIT=0;
+        }else if(cachesize<65536){
+            MEMLIMIT=32768;
+            BUFFERCACHE=cachesize-MEMLIMIT;
+            BUFFERLIMIT=BUFFERCACHE/4;
+        }else{
+            MEMLIMIT=cachesize/2;
+            BUFFERCACHE=MEMLIMIT;
+            BUFFERLIMIT=BUFFERCACHE/16;
+        }
+        if(BUFFERLIMIT<8192)BUFFERLIMIT=8192;
+    }
+    
+    public void mergeSort(RowBuffer result,RowBuffer a,RowBuffer b) throws IOException{
+        a.prepare();
+        b.prepare();
+        Row rowb=null;
+        Row rowa=null;
+        while(a.hasNext()&&b.hasNext()){
+            if(rowa==null)rowa=a.next();
+            if(rowb==null)rowb=b.next();
+            int cmp=compare.compare(rowa,rowb);
+            if(cmp<=0){
+                result.addRow(rowa);
+                rowa=null;
+            }else{
+                result.addRow(rowb);
+                rowb=null;
+            }
+        }
+        if(rowa!=null)result.addRow(rowa);
+        if(rowb!=null)result.addRow(rowb);
+        while(a.hasNext()){
+            result.addRow(a.next());
+        }
+        while(b.hasNext()){
+            result.addRow(b.next());
+        }
+    }
+    
+    public void mergeSort(List<RowBuffer> buffers) throws IOException{
+        while(buffers.size()>2){
+            RowBuffer tmp=new RowBuffer(filename+"."+(bufnum++));
+            tmp.setCacheSize(allocBuffer());
+            // Grab two and sort to buf
+            RowBuffer a=buffers.remove(0);
+            RowBuffer b=buffers.remove(0);
+            mergeSort(tmp,a,b);
+            a.close();
+            freeBuffer(a);
+            b.close();
+            freeBuffer(b);
+            buffers.add(tmp);
+        }
+        if(buffers.size()==1){
+            result.close();
+            result=buffers.get(0);
+            result.prepare();
+            return;
+        }
+        if(buffers.size()==2){
+            RowBuffer a=buffers.get(0);
+            RowBuffer b=buffers.get(1);
+            mergeSort(result,a,b);
+            a.close();
+            freeBuffer(a);
+            b.close();
+            freeBuffer(b);
+            result.prepare();
+            return;
+        }
+    }
+    
+    private int allocBuffer(){
+        if(BUFFERCACHE>=BUFFERLIMIT){
+            BUFFERCACHE-=BUFFERLIMIT;
+            return BUFFERLIMIT;
+        }
+        int tmp=BUFFERCACHE;
+        BUFFERCACHE=0;
+        return tmp;
+    }
+    private void freeBuffer(RowBuffer buf){
+        BUFFERCACHE+=buf.getCacheSize();
+    }
+    
+    public void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException{
+        long prepart=System.currentTimeMillis();
+        this.filename=filename;
+        compare=new SortComparator(lst);
+        bufnum=0;
+        result=new RowBuffer(filename+".result");
+        result.setCacheSize(BUFFERLIMIT);
+        List<RowBuffer> buffers=new ArrayList<RowBuffer>();
+        int usage=0;
+        
+        List<RowBuffer> prebuffers=new ArrayList<RowBuffer>();
+        List<Row> prebufferends=new ArrayList<Row>();
+        for(int i=0;i<PREBUFFERS;i++){
+            RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+            buf.setCacheSize(allocBuffer());
+            prebuffers.add(buf);
+        }
+        int over=0;
+        RowBuffer overflow=new RowBuffer(filename+"."+(bufnum++));
+        overflow.setCacheSize(allocBuffer());
+        while(source.hasNext()){
+            Row rowa=source.next();
+            for(int i=0;(i<PREBUFFERS)&&(rowa!=null);i++){
+                if(i<prebufferends.size()){
+                    Row rowb=prebufferends.get(i);
+                    if(compare.compare(rowa,rowb)>0){
+                        RowBuffer tmp=prebuffers.get(i);
+                        tmp.addRow(rowa);
+                        prebufferends.set(i,rowa);
+                        rowa=null;
+                    }
+                }else{
+                    prebufferends.add(rowa);
+                    RowBuffer tmp=prebuffers.get(i);
+                    tmp.addRow(rowa);
+                    rowa=null;
+                }
+            }
+            if(rowa!=null){
+                overflow.addRow(rowa);
+                over++;
+            }
+        }
+        for(int i=0;i<prebufferends.size();i++){
+            buffers.add(prebuffers.get(i));
+        }
+        long postpart=System.currentTimeMillis();
+        System.out.println("preprocess in "+(postpart-prepart)+" ms overflow:"+over);
+        source=overflow;
+        overflow.prepare();
+        
+        List<Row> sortlst=new ArrayList<Row>();
+        while(source.hasNext()){
+            Row row=source.next();
+            if(usage+row.getSize()>MEMLIMIT){
+                RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+                buf.setCacheSize(allocBuffer());
+                Collections.sort(sortlst,new SortComparator(lst));
+                for(int i=0;i<sortlst.size();i++){
+                    buf.addRow(sortlst.get(i));
+                }
+                buffers.add(buf);
+                usage=0;
+                sortlst=new ArrayList<Row>();
+            }
+            sortlst.add(row);
+            usage+=row.getSize();
+        }
+        RowBuffer buf=new RowBuffer(filename+"."+(bufnum++));
+        buf.setCacheSize(allocBuffer());
+        Collections.sort(sortlst,new SortComparator(lst));
+        for(int i=0;i<sortlst.size();i++){
+            buf.addRow(sortlst.get(i));
+        }
+        buffers.add(buf);
+        mergeSort(buffers);
+    }
+    public boolean hasNext() throws IOException{
+        return result.hasNext();
+    }
+    public Row next() throws IOException{
+        return result.next();
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/QuickSort.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/QuickSort.java
new file mode 100644 (file)
index 0000000..5b3fba8
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public abstract class QuickSort extends TupleStream{
+    public QuickSort(){
+        
+    }
+    public void initialize(TupleStream source,List<SortRule> lst){
+        
+    }
+    public abstract boolean hasNext();
+    public abstract Row next();
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RadixSort.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RadixSort.java
new file mode 100644 (file)
index 0000000..b64f208
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public abstract class RadixSort extends TupleStream{
+    public RadixSort(){
+        
+    }
+    public void initialize(TupleStream source,List<SortRule> lst){
+        
+    }
+    public abstract boolean hasNext();
+    public abstract Row next();
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RowBuffer.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RowBuffer.java
new file mode 100644 (file)
index 0000000..3635c2b
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import java.util.*;
+import java.io.*;
+import com.solidosystems.tuplesoup.core.*;
+
+public class RowBuffer extends TupleStream{
+    private int CACHESIZE=32768;
+    private int cacheusage=0;
+    
+    private int mempointer=0;
+    private boolean diskused=false;
+    
+    private List<Row> membuffer;
+    private String diskbuffer;
+    private DataOutputStream out;
+    private DataInputStream in;
+    
+    private Row next=null;
+    
+    public RowBuffer(String filename){
+        membuffer=new ArrayList<Row>();
+        diskbuffer=filename;
+        out=null;
+        in=null;
+    }
+    
+    public void setCacheSize(int size){
+        CACHESIZE=size;
+    }
+    public int getCacheSize(){
+        return CACHESIZE;
+    }
+    
+    public void addRow(Row row) throws IOException{
+        if(cacheusage+row.getSize()<=CACHESIZE){
+            membuffer.add(row);
+            cacheusage+=row.getSize();
+        }else{
+            cacheusage=CACHESIZE;
+            if(out==null)out=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(diskbuffer),2048));
+            row.writeToStream(out);
+            diskused=true;
+        }
+    }
+    
+    public void prepare() throws IOException{
+        if(out!=null){
+            out.flush();
+            out.close();
+        }
+        mempointer=0;
+        if(diskused)in=new DataInputStream(new BufferedInputStream(new FileInputStream(diskbuffer),2048));
+        readNext();
+    }
+    
+    public void close(){
+        try{
+            File ftest=new File(diskbuffer);
+            if(ftest.exists()){
+                if(out!=null)out.close();
+                if(in!=null)in.close();
+                ftest.delete();
+            }
+        }catch(Exception e){
+            
+        }
+    }
+    
+    private void readNext() throws IOException{
+        if(mempointer<membuffer.size()){
+            next=membuffer.get(mempointer++);
+        }else{
+            if(diskused){
+                try{
+                    next=Row.readFromStream(in);
+                }catch(EOFException e){
+                    next=null;
+                }
+            }else next=null;
+        }
+    }
+    
+    public boolean hasNext() throws IOException{
+        if(next!=null)return true;
+        return false;
+    }
+    
+    public Row next() throws IOException{
+        try{
+            if(next!=null){
+                Row tmp=next;
+                readNext();
+                return tmp;
+            }
+        }catch(Exception e){
+            e.printStackTrace();
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Sort.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/Sort.java
new file mode 100644 (file)
index 0000000..3ec03e8
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+import java.io.*;
+
+public abstract class Sort extends TupleStream{
+    public void initialize(String filename,TupleStream source,String key,int direction) throws IOException{
+        List<SortRule> lst=new ArrayList<SortRule>();
+        lst.add(new SortRule(key,direction));
+        initialize(filename,source,lst);
+    }
+    public void initialize(String filename,TupleStream source,String key,int direction,String key2,int direction2) throws IOException{
+        List<SortRule> lst=new ArrayList<SortRule>();
+        lst.add(new SortRule(key,direction));
+        lst.add(new SortRule(key2,direction2));
+        initialize(filename,source,lst);
+    }
+    public abstract void initialize(String filename,TupleStream source,List<SortRule> lst) throws IOException;
+    public abstract boolean hasNext() throws IOException;
+    public abstract Row next() throws IOException;
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortComparator.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortComparator.java
new file mode 100644 (file)
index 0000000..33fe909
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+import java.util.*;
+
+public class SortComparator implements Comparator<Row>{
+    private List<SortRule> rules;
+    
+    public SortComparator(List<SortRule> rules){
+        this.rules=rules;
+    }
+    
+    private int compare(int rulenum,Row rowa,Row rowb){
+        if(rules.size()<=rulenum)return 0;
+        SortRule rule=rules.get(rulenum);
+        Value a=rowa.get(rule.getKey());
+        Value b=rowb.get(rule.getKey());
+        int result=a.compareTo(b);
+        // TODO: add direction switcher here
+        if(result==0){
+            rulenum++;
+            return compare(rulenum,rowa,rowb);
+        }else{
+             if(rule.getDirection()==SortRule.DESC){
+                 if(result==-1){
+                     result=1;
+                 }else if(result==1)result=-1;
+             }
+             return result;
+        }
+    }
+    
+    public int compare(Row rowa,Row rowb){
+        return compare(0,rowa,rowb);
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortRule.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortRule.java
new file mode 100644 (file)
index 0000000..206ae8d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.filter;
+
+import com.solidosystems.tuplesoup.core.*;
+
+public class SortRule{
+    public static final int ASC=0;
+    public static final int DESC=1;
+    
+    private String key;
+    private int direction;
+    
+    public SortRule(String key, int direction){
+        this.key=key;
+        this.direction=direction;
+    }
+    
+    public int getDirection(){
+        return direction;
+    }
+    
+    public String getKey(){
+        return key;
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/BasicTest.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/BasicTest.java
new file mode 100644 (file)
index 0000000..dabbf7b
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.solidosystems.tuplesoup.test;
+
+import java.util.*;
+
+public class BasicTest{
+    public List<String>errors=new ArrayList<String>();
+    private int lastlength=0;
+    
+    public void err(String str){
+        while(lastlength<40){
+            System.out.print(" ");
+            lastlength++;
+        }
+        outbr(" ERR");
+        outbr(" ! "+str);
+        errors.add(str);
+    }
+    
+    public void printErrorSummary(){
+        outbr("");
+        if(errors.size()==0){
+            outbr("All tests passed!");
+        }else if(errors.size()==1){
+            outbr("1 test failed!");
+        }else{
+            outbr(errors.size()+" tests failed!");
+        }
+    }
+    
+    public static void die(String reason){
+         System.out.println("ERR");
+         System.out.println(" ! "+reason);
+         System.exit(0);
+    }
+    
+    public void ok(){
+        while(lastlength<40){
+            System.out.print(" ");
+            lastlength++;
+        }
+        outbr(" OK");
+    }
+
+    public void outbr(String str){
+        outbr(0,str);
+    }
+    
+    public void out(String str){
+        out(0,str);
+    }
+    
+    public void outbr(int level, String str){
+        switch(level){
+            case 0:System.out.print("");
+                break;
+            case 1:System.out.print(" + ");
+                break;
+            case 2:System.out.print("   * ");
+                break;
+            case 3:System.out.print("     - ");
+                break;
+            case 4:System.out.print("       + ");
+                break;
+        }
+        System.out.println(str);
+    }
+    
+    public void out(int level, String str){
+        lastlength=0;
+        switch(level){
+            case 0: System.out.print("");
+                break;
+            case 1: System.out.print(" + ");
+                    lastlength+=3;
+                break;
+            case 2: System.out.print("   * ");
+                    lastlength+=5;
+                break;
+            case 3: System.out.print("     - ");
+                    lastlength+=7;
+                break;
+        }
+        System.out.print(str);
+        lastlength+=str.length();
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelPerformanceTest.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelPerformanceTest.java
new file mode 100644 (file)
index 0000000..e4173c3
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ package com.solidosystems.tuplesoup.test;
+ import com.solidosystems.tuplesoup.core.*;
+ import com.solidosystems.tuplesoup.filter.*;
+  
+ import java.util.*;
+ import java.io.*;
+
+
+public class ParallelPerformanceTest extends BasicTest implements Runnable{
+    
+    long writetime;
+    long readtime;
+    long randomtime;
+    
+    public ParallelPerformanceTest(){
+        String path="./Volumes/My Book/test/";
+        try{
+            int records=50000;
+            for(int i=1;i<11;i++){
+                outbr("Running Parallel DualFileTable Performance test");
+                outbr(1,i+" x "+(records/i)+" Large records");
+            
+               // outbr(2,"Memory index");
+             /*   Table table=new DualFileTable("Performance-test",path,Table.MEMORY);
+                benchmark(table,i,(records/i));
+                table.close();
+                table.deleteFiles();*/
+            
+              /*  outbr(2,"Flat index");
+                table=new DualFileTable("Performance-test",path,Table.FLAT);
+                benchmark(table,i,(records/i));
+                table.close();
+                table.deleteFiles();*/
+            
+                outbr(2,"Paged index");
+                Table table=new DualFileTable("Performance-test",path,Table.PAGED);
+                benchmark(table,i,(records/i));
+                table.close();
+                table.deleteFiles();
+            
+                outbr("Running Parallel HashedTable Performance test");
+                outbr(1,i+" x "+(records/i)+" Large records");
+            
+            /*    outbr(2,"Memory index");
+                table=new HashedTable("Performance-test",path,Table.MEMORY);
+                benchmark(table,i,(records/i));
+                table.close();
+                table.deleteFiles();
+            
+                outbr(2,"Flat index");
+                table=new HashedTable("Performance-test",path,Table.FLAT);
+                benchmark(table,i,(records/i));
+                table.close();
+                table.deleteFiles();*/
+            
+                outbr(2,"Paged index");
+                table=new HashedTable("Performance-test",path,Table.PAGED);
+                benchmark(table,i,(records/i));
+                table.close();
+                table.deleteFiles();
+            }
+            
+            
+        }catch(Exception e){
+            e.printStackTrace();
+        }
+    }
+    public static void main(String[] args){
+        new ParallelPerformanceTest();
+    }
+    
+    public void benchmark(Table table,int threadcount, int records) throws Exception{
+        writetime=0;
+        readtime=0;
+        randomtime=0;
+        List<Thread> lst=new ArrayList<Thread>();
+        for(int i=0;i<threadcount;i++){
+            Thread thr=new Thread(new ParallelThread(this,table,i+"",records));
+            thr.start();
+            lst.add(thr);
+        }
+        for(int i=0;i<threadcount;i++){
+            lst.get(i).join();
+        }
+        outbr(3,"Write "+writetime+" ms");
+        outbr(3,"Read "+readtime+" ms");
+        outbr(3,"Random "+randomtime+" ms");
+    }
+    
+    public void run(){
+        
+    }
+    
+    public long benchmarkLargeWrite(Table table,int records, String id) throws IOException{
+        long pre=System.currentTimeMillis();
+        for(int i=0;i<records;i++){
+            Row row=new Row(id+i);
+            row.put("key1","foobarbaz");
+            row.put("key2",123456);
+            row.put("key3",3.141592);
+            row.put("key4",true);
+            row.put("key5",new Value(new byte[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}));
+            table.addRow(row);
+        }
+        long post=System.currentTimeMillis();
+        return post-pre;
+    }
+    public long benchmarkLargeRead(Table table,int records, String id) throws IOException{
+        long pre=System.currentTimeMillis();
+        TupleStream stream=table.getRows();
+        while(stream.hasNext()){
+            stream.next();
+        }
+        long post=System.currentTimeMillis();
+        return post-pre;
+    }
+    public long benchmarkLargeRandomRead(Table table,int records, String id) throws IOException{
+        long pre=System.currentTimeMillis();
+        for(int i=0;i<records;i++){
+            Row row=table.getRow(id+(int)(Math.random()*records));
+        }
+        long post=System.currentTimeMillis();
+        return post-pre;
+    }
+
+    public void printStats(Hashtable<String,Long> hash){
+        Set<String> keys=hash.keySet();
+        Iterator<String> it=keys.iterator();
+        while(it.hasNext()){
+            String key=it.next();
+            outbr(4,key+" "+hash.get(key));
+        }
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelThread.java b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelThread.java
new file mode 100644 (file)
index 0000000..2183470
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2007, Solido Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of Solido Systems nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ package com.solidosystems.tuplesoup.test;
+ import com.solidosystems.tuplesoup.core.*;
+ import com.solidosystems.tuplesoup.filter.*;
+  
+ import java.util.*;
+ import java.io.*;
+
+
+public class ParallelThread implements Runnable{
+    String id;
+    int records;
+    ParallelPerformanceTest app;
+    Table table;
+    
+    public ParallelThread(ParallelPerformanceTest app,Table table,String id,int records){
+        this.id=id;
+        this.records=records;
+        this.app=app;
+        this.table=table;
+    }
+    
+    public void run(){
+        try{
+            long time=app.benchmarkLargeWrite(table,records,id);
+            synchronized(app){
+                app.writetime+=time;
+            }
+            time=app.benchmarkLargeRead(table,records,id);
+            synchronized(app){
+                app.readtime+=time;
+            }
+            time=app.benchmarkLargeRandomRead(table,records,id);
+            synchronized(app){
+                app.randomtime+=time;
+            }
+        }catch(Exception e){
+            e.printStackTrace();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Robust/Transactions/mytuplesoup/tuplesoup.jar b/Robust/Transactions/mytuplesoup/tuplesoup.jar
new file mode 100644 (file)
index 0000000..aafa452
Binary files /dev/null and b/Robust/Transactions/mytuplesoup/tuplesoup.jar differ
diff --git a/Robust/Transactions/origtuplesoup/tuplesoup/readme.txt b/Robust/Transactions/origtuplesoup/tuplesoup/readme.txt
new file mode 100644 (file)
index 0000000..bf75b92
--- /dev/null
@@ -0,0 +1,26 @@
+Readme file for Tuplesoup v0.1.1 released by Kasper J. Jeppesen September 7, 2007.
+
+If you have any comments you can reach the developers of tuplesoup at kjj@solidosystems.com
+
+[ Introduction ]
+Tuplesoup is a small easy to use Java based framework for storing and retrieving simple hashes.
+The latest version of Tuplesoup is always available from http://sourceforge.net/projects/tuplesoup
+
+[ License ]
+Tuplesoup has been released as open source under the BSD license by Solido Systems. See the file license.txt for the full license.
+
+[ Documentation ]
+By an amazing combination of laziness and procrastination I have not yet created an actual site for Tuplesoup. However, you can find a some posts about the design and usage of tuplesoup on my tech blog http://syntacticsirup.blogspot.com/
+
+[ Installation ]
+The tuplesoup distribution contains a jar file which can be placed in your java extensions folder or added to your classpath. No further installation steps are necesary.
+
+[ Update ]
+There is currently no procedures needed to perform an update other than just replacing the jar file. However, you should always read the changelog for any update procedures necesary between the file formats of future releases.
+
+[ Changelog ]
+ * 0.1.2
+    - Made table an interface, instantiate DualFileTable to get the same behaviour as before
+    - Added HashedTable which provides better multi threaded performance for single row queries
+ * 0.1.1
+    - First public release
\ No newline at end of file