From: navid Date: Wed, 21 Jan 2009 20:00:15 +0000 (+0000) Subject: *** empty log message *** X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=5fdd0f0f952c89240173eb46165082ae2c9f7ff7;p=IRC.git *** empty log message *** --- diff --git a/Robust/Transactions/dstm2/src/dstm2/AtomicByteArray.java b/Robust/Transactions/dstm2/src/dstm2/AtomicByteArray.java new file mode 100644 index 00000000..d81ec46c --- /dev/null +++ b/Robust/Transactions/dstm2/src/dstm2/AtomicByteArray.java @@ -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 index 00000000..b1741c55 --- /dev/null +++ b/Robust/Transactions/dstm2/src/dstm2/AtomicIntArray.java @@ -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 index 00000000..a321c25b --- /dev/null +++ b/Robust/Transactions/dstm2/src/dstm2/AtomicLongArray.java @@ -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{ + transient volatile int modCount; + private volatile int size; + AtomicArray> elementData; + private Factory factory; + + public ArrayList() { + this(10); + } + + public ArrayList(int initialCapacity) { + super (); + if (initialCapacity < 0) + throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); + this .elementData = new AtomicArray>(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> newar = new AtomicArray>(entry.class, newCapacity); + for (int i=0; i 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 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 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 index 00000000..df7c54ed --- /dev/null +++ b/Robust/Transactions/dstm2/src/dstm2/util/HashMap.java @@ -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 implements Iterable{ + + /** + * 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[] table; + dstm2.AtomicArray table; + final private Factory factory; + + //transient Entry[] 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 HashMap 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.class, capacity); +// for(int i = 0; i < capacity; i++) { +// table[i] = factory.create(); +// } + //table = new Entry[capacity]; + init(); + } + + /** + * Constructs an empty HashMap 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 HashMap 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 HashMap with the same mappings as the + * specified Map. The HashMap is created with + * default load factor (0.75) and an initial capacity sufficient to + * hold the mappings in the specified Map. + * + * @param m the map whose mappings are to be placed in this map. + * @throws NullPointerException if the specified map is null. + */ + public HashMap(HashMap 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 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 maskNull(T key) { + return key == null ? (T)NULL_KEY : key; + } + + /** + * Returns key represented by specified internal representation. + */ + static 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 true if this map contains no key-value mappings. + * + * @return true 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 null if the map contains no mapping for this key. + * A return value of null does not necessarily indicate + * that the map contains no mapping for the key; it is also possible that + * the map explicitly maps the key to null. The + * containsKey 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 + * null 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 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 e = table[i]; +// //Entry e = table[i]; +// while (true) { +// if (e == null) +// return null; +// if (e.getKey() == NULL_KEY) +// return e.getValue(); +// e = e.getNext(); +// } +// } + + /** + * Returns true if this map contains a mapping for the + * specified key. + * + * @param key The key whose presence in this map is to be tested + * @return true 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 null + * if there was no mapping for key. A null return can + * also indicate that the HashMap previously associated + * null with the specified key. + */ + public V put(int key, V 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) { + 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 e = table.get(i); e != null; e = e.getNext()) { + if (e.getHash() == hash) { + e.setValue(value); + return; + } + } + + createEntry(hash, value, i); + } + + void putAllForCreate(HashMap m) { + for (Iterator> i = m.entrySet().iterator(); i.hasNext(); ) { + HashMap.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 oldTable = table; + int oldCapacity = capacity; + if (oldCapacity == MAXIMUM_CAPACITY) { + threshold = Integer.MAX_VALUE; + return; + } + + dstm2.AtomicArray newTable = new dstm2.AtomicArray(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 newTable, int nc) { + dstm2.AtomicArray 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(HashMap 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> i = m.entrySet().iterator(); i.hasNext(); ) { + HashMap.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 null + * if there was no mapping for key. A null return can + * also indicate that the map previously associated null + * with the specified key. + */ + public V 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 tab = table; + for (int i = 0; i < capacity; i++) + table.set(i, null); + size.set(0); + } + + /** + * Returns true 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 true if this map maps one or more keys to the + * specified value. + */ + public boolean containsValue(Object value) { + if (value == null) + return containsNullValue(); + + dstm2.AtomicArray 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 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(); + V getValue(); + TEntry getNext(); + void setHash(int h); + void setValue(V 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, V 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, V 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 implements Iterator { + TEntry next; // next entry to return + int expectedModCount; // For fast-fail + int index; // current slot + TEntry current; // current entry + + HashIterator() { + expectedModCount = modCount; + dstm2.AtomicArray 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 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 { + public V next() { + return nextEntry().getValue(); + } + } + + private class KeyIterator extends HashIterator { + public Integer next() { + return nextEntry().getHash(); + } + } + +// private class EntryIterator extends HashIterator> { +// public Map.Entry next() { +// return nextEntry(); +// } +// } + + // Subclass overrides these to alter behavior of views' iterator() method + public Iterator newKeyIterator() { + return new KeyIterator(); + } + public Iterator newValueIterator() { + return new ValueIterator(); + } +// Iterator> newEntryIterator() { +// return new EntryIterator(); +// } + + + // Views + + private transient Set> entrySet = null; + + + + private class KeySet extends AbstractSet { + public Iterator 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 Map.Entry. 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 + * Iterator.remove, Collection.remove, + * removeAll, retainAll, and clear operations. + * It does not support the add or addAll operations. + * + * @return a collection view of the mappings contained in this map. + * @see Map.Entry + */ + public Set> entrySet() { + Set> es = entrySet; + return (es != null ? es : (entrySet = (Set>) (Set) new EntrySet())); + } + + private class EntrySet {//extends AbstractSet/*>*/ { +// public Iterator/*>*/ iterator() { +// return newEntryIterator(); +// } + public boolean contains(HashMap.TEntry o) { + HashMap.TEntry e = (HashMap.TEntry) o; + TEntry candidate = getEntry(e.getHash()); + return candidate != null && candidate.equals(e); + } + public boolean remove(HashMap.TEntry o) { + return removeMapping(o) != null; + } + public int size() { + return size.get(); + } + public void clear() { + HashMap.this.clear(); + } + } + + /** + * Save the state of the HashMap instance to a stream (i.e., + * serialize it). + * + * @serialData The capacity of the HashMap (the length of the + * bucket array) is emitted (int), followed by the + * size 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 entrySet().iterator(). + * + */ + private void writeObject(java.io.ObjectOutputStream s) + throws IOException + { + Iterator> 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 e = i.next(); + s.writeObject(e.getHash()); + s.writeObject(e.getValue()); + } + } + + private static final long serialVersionUID = 362498820763181265L; + + /** + * Reconstitute the HashMap 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 iterator() { + return new Iterator() { + int tableIndex = 0; + public TEntry cursor = table.get(tableIndex); + public boolean hasNext() { + return cursor != null; + } + public V 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/dstm2/src/dstm2/util/IntHashMap.java b/Robust/Transactions/dstm2/src/dstm2/util/IntHashMap.java new file mode 100644 index 00000000..ffb67a48 --- /dev/null +++ b/Robust/Transactions/dstm2/src/dstm2/util/IntHashMap.java @@ -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{ + + /** + * 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[] table; + dstm2.AtomicArray table; + final private Factory factory; + + //transient Entry[] 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 HashMap 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.class, capacity); +// for(int i = 0; i < capacity; i++) { +// table[i] = factory.create(); +// } + //table = new Entry[capacity]; + init(); + } + + /** + * Constructs an empty HashMap 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 HashMap 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 HashMap with the same mappings as the + * specified Map. The HashMap is created with + * default load factor (0.75) and an initial capacity sufficient to + * hold the mappings in the specified Map. + * + * @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 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 maskNull(T key) { + return key == null ? (T)NULL_KEY : key; + } + + /** + * Returns key represented by specified internal representation. + */ + static 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 true if this map contains no key-value mappings. + * + * @return true 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 null if the map contains no mapping for this key. + * A return value of null does not necessarily indicate + * that the map contains no mapping for the key; it is also possible that + * the map explicitly maps the key to null. The + * containsKey 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 + * null 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 e = table[i]; +// //Entry e = table[i]; +// while (true) { +// if (e == null) +// return null; +// if (e.getKey() == NULL_KEY) +// return e.getValue(); +// e = e.getNext(); +// } +// } + + /** + * Returns true if this map contains a mapping for the + * specified key. + * + * @param key The key whose presence in this map is to be tested + * @return true 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 null + * if there was no mapping for key. A null return can + * also indicate that the HashMap previously associated + * null 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 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 oldTable = table; + int oldCapacity = capacity; + if (oldCapacity == MAXIMUM_CAPACITY) { + threshold = Integer.MAX_VALUE; + return; + } + + dstm2.AtomicArray newTable = new dstm2.AtomicArray(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 newTable, int nc) { + dstm2.AtomicArray 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 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 null + * if there was no mapping for key. A null return can + * also indicate that the map previously associated null + * 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 tab = table; + for (int i = 0; i < capacity; i++) + table.set(i, null); + size.set(0); + } + + /** + * Returns true 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 true if this map maps one or more keys to the + * specified value. + */ + public boolean containsValue(Object value) { + if (value == null) + return containsNullValue(); + + dstm2.AtomicArray 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 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 implements Iterator { + TEntry next; // next entry to return + int expectedModCount; // For fast-fail + int index; // current slot + TEntry current; // current entry + + HashIterator() { + expectedModCount = modCount; + dstm2.AtomicArray 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 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 { + public Integer next() { + return nextEntry().getValue(); + } + } + + private class KeyIterator extends HashIterator { + public Integer next() { + return nextEntry().getHash(); + } + } + +// private class EntryIterator extends HashIterator> { +// public Map.Entry next() { +// return nextEntry(); +// } +// } + + // Subclass overrides these to alter behavior of views' iterator() method + public Iterator newKeyIterator() { + return new KeyIterator(); + } + public Iterator newValueIterator() { + return new ValueIterator(); + } +// Iterator> newEntryIterator() { +// return new EntryIterator(); +// } + + + // Views + + private transient Set entrySet = null; + + + + private class KeySet extends AbstractSet { + public Iterator 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 Map.Entry. 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 + * Iterator.remove, Collection.remove, + * removeAll, retainAll, and clear operations. + * It does not support the add or addAll operations. + * + * @return a collection view of the mappings contained in this map. + * @see Map.Entry + */ + public Set entrySet() { + Set es = entrySet; + return (es != null ? es : (entrySet = (Set) (Set) new EntrySet())); + } + + private class EntrySet {//extends AbstractSet/*>*/ { +// public Iterator/*>*/ 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 HashMap instance to a stream (i.e., + * serialize it). + * + * @serialData The capacity of the HashMap (the length of the + * bucket array) is emitted (int), followed by the + * size 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 entrySet().iterator(). + * + */ + private void writeObject(java.io.ObjectOutputStream s) + throws IOException + { + Iterator 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 HashMap 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 iterator() { + return new Iterator() { + 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 index 00000000..60c816d5 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/license.txt @@ -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 index 00000000..bf75b92e --- /dev/null +++ b/Robust/Transactions/mytuplesoup/readme.txt @@ -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 index 00000000..8bfbe140 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/DualFileTable.java @@ -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 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: + *
    + *
  • stat_table_add + *
  • stat_table_update + *
  • stat_table_delete + *
  • stat_table_add_size + *
  • stat_table_update_size + *
  • stat_table_read_size + *
  • stat_table_read + *
  • stat_table_cache_hit + *
  • stat_table_cache_miss + *
  • stat_table_cache_drop + *
+ * Furthermore, the index will be asked to deliver separate index specific counters + */ + public Hashtable readStatistics(){ + Hashtable hash=new Hashtable(); + 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 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(); + } + + /** + * 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 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 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 index 00000000..b7d19687 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/HashedTable.java @@ -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 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
(); + for(int i=0;i readStatistics(){ + Hashtable results=new Hashtable(); + for(int i=0;i tmp=tableset.get(i).readStatistics(); + Set keys=tmp.keySet(); + Iterator 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 rows) throws IOException{ + List> listset=new ArrayList>(); + for(int i=0;i()); + } + for(int i=0;i0){ + 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 rows,RowMatcher matcher) throws IOException{ + List> listset=new ArrayList>(); + for(int i=0;i()); + } + for(int i=0;i0){ + 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 index 00000000..0684c3b8 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/IndexedTableReader.java @@ -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 Listfileaentries; + private Listfilebentries; + + private Listentries; + + private Hashtablefileabuffer; + private Hashtablefilebbuffer; + + private Listrows; + private int rowpointer; + private Row next=null; + + private DualFileTable table; + + private RowMatcher matcher=null; + + public IndexedTableReader(DualFileTable table,Listentries) throws IOException{ + this.table=table; + this.rows=rows; + rowpointer=0; + + this.entries=entries; + fileaentries=new ArrayList(); + filebentries=new ArrayList(); + + Iterator 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(); + filebbuffer=new Hashtable(); + + readNext(); + } + + + public IndexedTableReader(DualFileTable table,Listentries,RowMatcher matcher) throws IOException{ + this.table=table; + this.rows=rows; + rowpointer=0; + this.matcher=matcher; + + this.entries=entries; + fileaentries=new ArrayList(); + filebentries=new ArrayList(); + + Iterator 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(); + filebbuffer=new Hashtable(); + + 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 index 00000000..f200fa9b --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/PagedIndex.java @@ -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 readStatistics(){ + Hashtable hash=new Hashtable(); + 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 scanIndex(List rows) throws IOException{ + List lst=new ArrayList(); + for(int i=0;i scanIndex() throws IOException{ + ArrayList lst=new ArrayList(); + for(int i=0;i values; + + /** + * Creates a new empty row with the given row id. + */ + public Row(String id){ + this.id=id; + size=-1; + values=new Hashtable(); + } + + /** + * Returns the number of keys in this row. + */ + public int getKeyCount(){ + return values.size(); + } + + public Set 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 keys=values.keySet(); + out.writeInt(keys.size()); + Iterator 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 keys=values.keySet(); + out.writeInt(keys.size()); + Iterator 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{"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 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\n"); + Iterator 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("\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 index 00000000..1debd7ba --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/RowMatcher.java @@ -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 index 00000000..5ff49fae --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Table.java @@ -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: + *
    + *
  • stat_table_add + *
  • stat_table_update + *
  • stat_table_delete + *
  • stat_table_add_size + *
  • stat_table_update_size + *
  • stat_table_read_size + *
  • stat_table_read + *
  • stat_table_cache_hit + *
  • stat_table_cache_miss + *
  • stat_table_cache_drop + *
+ * Furthermore, the index will be asked to deliver separate index specific counters + */ + public Hashtable 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 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 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 index 00000000..ba8b76ff --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndex.java @@ -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 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 scanIndex(List rows) throws IOException; + public List 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 index 00000000..229d5f4d --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexEntry.java @@ -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{ + 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(position0)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 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()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()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()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 index 00000000..9385902d --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TableIndexPageTransactional.java @@ -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 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()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()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()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 index 00000000..f6a7e81d --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStream.java @@ -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 index 00000000..8d71ce4c --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/TupleStreamMerger.java @@ -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 streams; + private TupleStream current=null; + private Row next=null; + + public TupleStreamMerger(){ + streams=new ArrayList(); + } + + 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 index 00000000..0da44524 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/core/Value.java @@ -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. + *
    + *
  • If this Value is a numeric type, then the other Value will be asked to deliver the same numeric type for the comparison. + *
  • If this Value is a string, then both values will be asked to deliver a double value for the comparison. + *
  • If this Value is a timestamp, then both values will be asked to deliver a long value for the comparison. + *
  • If this Value is a boolean, false will be returned. + *
+ * + * @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() + *
  • If this Value is a numeric type, then the other Value will be asked to deliver the same numeric type for the comparison. + *
  • If this Value is a string, then both values will be asked to deliver a double value for the comparison. + *
  • If this Value is a timestamp, then both values will be asked to deliver a long value for the comparison. + *
  • If this Value is a boolean, false will be returned. + * + * + * @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"+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 : return ""+getString()+""; + } + return ""; + } + + /** + * Returns this value as an xml tag. + * The following string is an example of the int value 1234 <value type="int">1234</value> + */ + public String toBasicXMLString(){ + 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 : return ""+getString()+""; + } + return ""; + } + + /** + * 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 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 index 00000000..1dfb4a1f --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/JavaSort.java @@ -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 sortlst; + private int offset; + private int datasize; + + public JavaSort(){ + } + public void initialize(String filename,TupleStream source,List lst) throws IOException{ + sortlst=new ArrayList(); + offset=0; + while(source.hasNext()){ + sortlst.add(source.next()); + } + Collections.sort(sortlst,new SortComparator(lst)); + datasize=sortlst.size(); + } + public boolean hasNext(){ + if(offset 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 lst) throws IOException{ + this.filename=filename; + compare=new SortComparator(lst); + bufnum=0; + result=new RowBuffer(filename+".result"); + result.setCacheSize(BUFFERLIMIT); + List buffers=new ArrayList(); + int usage=0; + List sortlst=new ArrayList(); + 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.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 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 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 buffers=new ArrayList(); + int usage=0; + + List prebuffers=new ArrayList(); + List prebufferends=new ArrayList(); + for(int i=0;i0){ + 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 sortlst=new ArrayList(); + 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.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 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 index 00000000..b64f2086 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RadixSort.java @@ -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 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 index 00000000..3635c2b6 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/RowBuffer.java @@ -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 membuffer; + private String diskbuffer; + private DataOutputStream out; + private DataInputStream in; + + private Row next=null; + + public RowBuffer(String filename){ + membuffer=new ArrayList(); + 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 lst=new ArrayList(); + 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 lst=new ArrayList(); + 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 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 index 00000000..33fe9093 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortComparator.java @@ -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{ + private List rules; + + public SortComparator(List 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 index 00000000..206ae8d6 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/filter/SortRule.java @@ -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 index 00000000..dabbf7b7 --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/BasicTest.java @@ -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 Listerrors=new ArrayList(); + 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 index 00000000..e4173c3f --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelPerformanceTest.java @@ -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 lst=new ArrayList(); + for(int i=0;i hash){ + Set keys=hash.keySet(); + Iterator 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 index 00000000..2183470d --- /dev/null +++ b/Robust/Transactions/mytuplesoup/src/com/solidosystems/tuplesoup/test/ParallelThread.java @@ -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 index 00000000..aafa4525 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 index 00000000..bf75b92e --- /dev/null +++ b/Robust/Transactions/origtuplesoup/tuplesoup/readme.txt @@ -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