You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by ka...@apache.org on 2009/03/17 11:14:04 UTC

svn commit: r755179 [1/3] - in /labs/bananadb/trunk: ./ src/main/java/org/apache/labs/bananadb/entity/ src/main/java/org/apache/labs/bananadb/entity/isolation/ src/main/java/org/apache/labs/bananadb/entity/serialization/ src/main/java/org/apache/labs/b...

Author: kalle
Date: Tue Mar 17 10:14:03 2009
New Revision: 755179

URL: http://svn.apache.org/viewvc?rev=755179&view=rev
Log:
BananaDB  

v0.3, complete rewrite from scratch. still a few features missing, but works just fine as it is.


Added:
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/
      - copied from r754666, labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/index/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Configuration.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Sequence.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Transaction.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/
      - copied from r754666, labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/hashtable/txn/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/FallBackHashCodeCalculator.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/HashCodeCalculator.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Marshaller.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableMarshaller.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableUnmarshaller.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializationRegistry.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Unmarshaller.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Cursor.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/FileHandler.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/HashCodesPartition.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Hashtable.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/KeysPartition.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Log.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Metadata.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/ValuesPartition.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/
      - copied from r754666, labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/lock/
    labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/entity/
    labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/entity/TestEntityStore.java
    labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/store/
    labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/store/StoreTest.java
    labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/store/TestStore.java
Removed:
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/README.txt
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/Transaction.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/hashtable/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/index/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/lock/
    labs/bananadb/trunk/src/test/java/log4j.properties
    labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/hashtable/
Modified:
    labs/bananadb/trunk/FILES.txt
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/AbstractIndex.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Entity.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityCursor.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityStore.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryIndex.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryKey.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryIndex.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryKey.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/AbstractIsolation.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/DeadlockException.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/Isolation.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationDeadlocking.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationLastCommitWins.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationUpdated.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockFactory.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockObtainFailedException.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockReleaseFailedException.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockStressTest.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockVerifyServer.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/NativeFSLockFactory.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/NoLockFactory.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/NoSuchDirectoryException.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/SimpleFSLockFactory.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/SingleInstanceLockFactory.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/VerifyingLockFactory.java
    labs/bananadb/trunk/src/site/apt/index.apt

Modified: labs/bananadb/trunk/FILES.txt
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/FILES.txt?rev=755179&r1=755178&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/FILES.txt (original)
+++ labs/bananadb/trunk/FILES.txt Tue Mar 17 10:14:03 2009
@@ -1,71 +1,125 @@
 = Files =
 
-== values.[0-9]+ ==
+This scheme supports up to ~180PB value data and ~150PB key data. 
 
-Hashtable entity values, the serialized V part of the Hashtable<K, V>.
-There can be any number of these files, refered to as partitions in the code.
+== [0-9]+.v ==
+
+Values postings partition file.
+
+This file is NOT affected by rehashing.
 
 Header: 1024 bytes
 {{{
 
-int         next value postings start offset
-int         capacity
+int         Offset in this partition for next new posting.
+int         Bytes left for use in this partition.
 
 }}}
 
+
 Posting data:
 {{{
 
-int         value length in bytes. 0 = null
-byte[]      serialized value
+byte        Flag
+            0 = never used
+            1 = in use
+            2 = deleted
+
+int         Length in bytes of serializaed value.
+            0 == null
+byte[]      Serialized value.
 
 }}}
 
-== keys ==
+== [0-9]+.k ==
+
+Key postings partition file.
 
-Hashtable key postings list, the serialized K part of the Hashtable<K, V>.
-If keys share the same hash code,
-or if the capacity is not great enough for keys to get a unique posting  the the hashtable
-entities will be added to a list that must be iterated in order to find the correct posting.
+Chained postings. Each posting contains a unique key value and points at how to
+find the value associated with this key.
+
+This file is NOT affected by rehashing.
 
 Header: 1024 bytes
 {{{
 
-int         next available key posting offset
-int         entity count
-int         postings start offset -- will change after rehash
-int         postings end offset -- will change after rehash
-int         capacity
-long        version -- increased by 1 after each change to the database
+int         Offset in this partition for next new posting.
+int         Bytes left for use in this partition.
 
 }}}
 
 Posting data:
 {{{
 
-deleted key posting values are all set to -2.
+byte        Flag
+            0 = never used
+            1 = in use
+            2 = deleted
+
+int         Partition id of next key posting with the same hash code.
+            -1 == end of keys chain
+int         Offset in above key postings partition.
 
-int         offset position in this file to the next entry with the same hash, -1 = null
-int         key hash
-int         value partition number, -1 = null value
-int         offset position in value partition, -1 = null
-int         key length in bytes, 0 = null // todo remove
-byte[]      serialized key (if not null)
+long        Key hash code
 
+int         Paritition id of value posting.
+            -1 == null
+int         Offset in above value postings partition.
+
+int         Length in bytes of serialized key.
+byte[]      Serialized key
 
 }}}
 
-== hashtable ==
+== [0-9]+.hc ==
+
+Hash code postings partition file.
 
-The actual key entity hashtable, points at the first position in entities-file for the given hash.
-The position for any given key is calculated with: hash & (capacity - 1);
+Chained postings. Each postings has a unique hash code value and points at how to find
+the key posting for this hash code.
 
+This file is affected by rehashing.
 
 Header: 1024 bytes
 {{{
 
-int         hash posting start offset -- will change after rehash
-int         capacity
+int         Offset in this partition for next new posting.
+int         Bytes left for use in this partition.
+
+}}}
+
+Posting data:
+{{{
+
+byte        Flag
+            0 = never used
+            1 = in use
+            2 = deleted
+
+long        Key hash code.
+
+int         Partition id of next hash code posting with the same hashtable posting position.
+            -1 == null
+int         Offset in above hash code postings partition.
+
+int         Partition id of first key posting with this hash code.
+int         Offset in above key postings partition.
+
+}}}
+
+== [0-9]+.ht ==
+
+Hashtable file. There is never more than one of these that are valid at any given time.
+
+The position in the hashtable for a given hash code is calculated as (hash & (capacity - 1)).
+At this position there is a posting that points at the first known hash code posting.
+
+This file is affected by rehashing.
+
+Header: 1024 bytes
+{{{
+
+int         This hashtable postings file capacity.
 
 }}}
 
@@ -73,9 +127,24 @@
 Posting data:
 {{{
 
-byte        0 = no posting. Any other value means there is a posting.
-int         offset position in key postings to first entity with this hash
-int         offset position in key postings to last entity with this hash (used at rehash time)
+int         Partition id of first hash code posting with this hashtable position.
+            -1 == null
+int         Offset in above hash code postings partition.
 
 }}}
 
+== metadata ==
+
+Contains information about the database.
+
+{{{
+
+int         File format version. 
+long        Commit version, will increase by one after each modification to the database.
+int         Current hashtable file id. -- will change after rehash.
+int         Current hash code partition
+int         Current keys partition
+int         Current values partition
+long        Total number of value postings.
+
+}}}
\ No newline at end of file

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/AbstractIndex.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/AbstractIndex.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/AbstractIndex.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/AbstractIndex.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,12 +23,12 @@
  * Date: 2008-jul-23
  * Time: 02:34:19
  */
-public abstract class AbstractIndex<K, T> {
+public abstract class AbstractIndex<K, V> {
 
-  public abstract EntityCursor<T> cursor();
+  public abstract EntityCursor<V> cursor();
 
-  public abstract EntityCursor<T> cursor(K start);
+  public abstract EntityCursor<V> cursor(K start);
 
-  public abstract EntityCursor<T> cursor(K start, K end);
+  public abstract EntityCursor<V> cursor(K start, K end);
 
 }

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Configuration.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Configuration.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Configuration.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Configuration.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,71 @@
+package org.apache.labs.bananadb.entity;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import org.apache.labs.bananadb.entity.isolation.Isolation;
+import org.apache.labs.bananadb.entity.isolation.IsolationUpdated;
+import org.apache.labs.bananadb.entity.serialization.SerializationRegistry;
+import org.apache.labs.bananadb.entity.serialization.FallBackHashCodeCalculator;
+import org.apache.labs.bananadb.entity.serialization.SerializableMarshaller;
+import org.apache.labs.bananadb.entity.serialization.SerializableUnmarshaller;
+import org.apache.labs.bananadb.store.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 07:40:44
+ */
+public class Configuration extends org.apache.labs.bananadb.store.Configuration {
+
+  private static final Log log = new Log(Configuration.class);
+
+  public Configuration(File dataPath) throws IOException {
+    super(dataPath);
+  }
+
+  private Isolation defaultIsolation = new IsolationUpdated();
+
+  private SerializationRegistry serializationRegistry;
+
+  public SerializationRegistry getSerializationRegistry() {
+    if (serializationRegistry == null) {
+      log.info("Creating a default serialization registry");
+      serializationRegistry = new SerializationRegistry();
+      serializationRegistry.getHashCodeCalculators().put(Object.class, new FallBackHashCodeCalculator());
+      serializationRegistry.getMarshallers().put(Serializable.class, new SerializableMarshaller());
+      serializationRegistry.getUnmarshallers().put(Serializable.class, new SerializableUnmarshaller());
+    }
+    return serializationRegistry;
+  }
+
+  public void setSerializationRegistry(SerializationRegistry serializationRegistry) {
+    this.serializationRegistry = serializationRegistry;
+  }
+
+  public Isolation getDefaultIsolation() {
+    return defaultIsolation;
+  }
+
+  public void setDefaultIsolation(Isolation defaultIsolation) {
+    this.defaultIsolation = defaultIsolation;
+  }
+}

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Entity.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Entity.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Entity.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Entity.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -18,10 +18,19 @@
  */
 
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+
+
+
 /**
  * User: kalle
  * Date: 2008-jul-24
  * Time: 19:12:08
  */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
 public @interface Entity {
 }

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityCursor.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityCursor.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityCursor.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityCursor.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityStore.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityStore.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityStore.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/EntityStore.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -18,19 +18,139 @@
  */
 
 
+import org.apache.labs.bananadb.entity.serialization.HashCodeCalculator;
+import org.apache.labs.bananadb.entity.serialization.Marshaller;
+import org.apache.labs.bananadb.entity.serialization.Unmarshaller;
+import org.apache.labs.bananadb.entity.Transaction;
+import org.apache.labs.bananadb.store.*;
+import org.apache.labs.bananadb.store.Configuration;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.io.File;
+import java.io.IOException;
+
+
 /**
  * User: kalle
  * Date: 2008-jul-23
  * Time: 02:54:45
  */
-public class EntityStore {
+public class EntityStore extends Store {
+
+  private org.apache.labs.bananadb.entity.Configuration configuration;
+
+  public EntityStore(File dataPath) throws IOException {
+    this(new org.apache.labs.bananadb.entity.Configuration(dataPath));
+  }
+
+  public EntityStore(org.apache.labs.bananadb.entity.Configuration configuration) {
+    super(configuration);
+    this.configuration = configuration;
+  }
+
+  public org.apache.labs.bananadb.entity.Configuration getConfiguration() {
+    return configuration;
+  }
+
+  private Map<Class, PrimaryIndex> primaryIndexByEntityClass = new HashMap<Class, PrimaryIndex>();
+
+
+  @SuppressWarnings("unchecked")
+  public <PK, V> PrimaryIndex<PK, V> getPrimaryIndex(Class<PK> keyClass, Class<V> entityClass) {
+    PrimaryIndex<PK, V> primaryIndex = primaryIndexByEntityClass.get(entityClass);
+    if (primaryIndex == null) {
+
+      if (!entityClass.isAnnotationPresent(Entity.class)) {
+        throw new RuntimeException("Entity class " + entityClass.getName() + " is not annotated with @Entity");
+      }
+
+      Method primaryKeyGetter;
+      Method primaryKeySetter;
+      Sequence primaryKeySequence;
+      {
+        List<Field> pkFields = new ArrayList<Field>();
+        for (Field field : entityClass.getDeclaredFields()) {
+          if (field.isAnnotationPresent(PrimaryKey.class)) {
+            pkFields.add(field);
+          }
+        }
+        if (pkFields.size() == 0) {
+          throw new RuntimeException("No field in class " + entityClass.getName() + " annotated with @PrimaryKey");
+        } else if (pkFields.size() > 1) {
+          StringBuilder sb = new StringBuilder(1000);
+          for (Field pkField : pkFields) {
+            if (sb.length() > 0) {
+              sb.append(", ");
+            }
+            sb.append(pkField.getName());
+          }
+          throw new RuntimeException("Multiple fields in class " + entityClass.getName() + "  annotated with @PrimaryKey: " + sb.toString());
+        }
+        Field primaryKeyField = pkFields.get(0);
+        StringBuffer name = new StringBuffer(primaryKeyField.getName());
+        name.setCharAt(0, Character.toUpperCase(name.charAt(0)));
+        String getterName = "get" + name.toString();
+        try {
+          primaryKeyGetter = entityClass.getMethod(getterName);
+        } catch (NoSuchMethodException e) {
+          throw new RuntimeException("@PrimaryKey field " + primaryKeyField.getName() + " of @Entity class " + entityClass.getName() + " does not have a getter method named " + getterName);
+        }
+        String setterName = "set" + name.toString();
+        try {
+          primaryKeySetter = entityClass.getMethod(setterName, primaryKeyField.getType());
+        } catch (NoSuchMethodException e) {
+          throw new RuntimeException("@PrimaryKey field " + primaryKeyField.getName() + " of @Entity class " + entityClass.getName() + " does not have a setter method named " + setterName);
+        }
+        PrimaryKey primaryKey = primaryKeyField.getAnnotation(PrimaryKey.class);
+        if ("[unassigned]".equals(primaryKey.sequence())) {
+          primaryKeySequence = new Sequence(this, entityClass.getName());
+        } else {
+          primaryKeySequence = new Sequence(this, primaryKey.sequence());
+        }
+      }
+
+      Marshaller keyMarshaller = getConfiguration().getSerializationRegistry().getMarshaller(keyClass);
+      Unmarshaller keyUnmarshaller = getConfiguration().getSerializationRegistry().getUnmarshaller(keyClass);
+      HashCodeCalculator keyHashCodeCalculator = getConfiguration().getSerializationRegistry().getHashCodeCalcualtor(keyClass);
+      Marshaller entityMarshaller = getConfiguration().getSerializationRegistry().getMarshaller(entityClass);
+      Unmarshaller entityUnmarshaller = getConfiguration().getSerializationRegistry().getUnmarshaller(entityClass);
+
+      primaryIndex = new PrimaryIndex<PK, V>(
+          this,
+          primaryKeySequence,
+          primaryKeyGetter, primaryKeySetter,
+          keyClass, entityClass,
+          keyMarshaller, keyUnmarshaller, keyHashCodeCalculator,
+          entityMarshaller, entityUnmarshaller
+      );
+
+      primaryIndexByEntityClass.put(entityClass, primaryIndex);
+    }
+
+    return primaryIndex;
+  }
 
-  public <PK, T> PrimaryIndex<PK, T> getPrimaryIndex(Class primaryKeyClass, Class entityClass) {
-    return null;
+  public <PK, SK, V> SecondaryIndex<PK, SK, V> getSecondaryIndex(PrimaryIndex<PK, V> primaryIndex, Class<SK> secondaryKeyClass, String secondaryKeyAttributeName) {
+    throw new UnsupportedOperationException();
   }
 
-  public <PK, SK, T> SecondaryIndex<PK, SK, T> getSecondaryIndex(PrimaryIndex<PK, T> primaryIndex, Class secondaryKeyClass, String secondaryKeyAttributeName) {
-    return null;
+  private ThreadLocal<Transaction> transactions = new ThreadLocal<Transaction>() {
+    @Override
+    protected Transaction initialValue() {
+      return new Transaction(EntityStore.this);
+    }
+  };
+
+  /**
+   * @return A thread local transaction.
+   */
+  public Transaction getTxn() {
+    return transactions.get();
   }
 
 }

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryIndex.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryIndex.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryIndex.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryIndex.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,17 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
+
+import org.apache.labs.bananadb.entity.serialization.Marshaller;
+import org.apache.labs.bananadb.entity.serialization.Unmarshaller;
+import org.apache.labs.bananadb.entity.serialization.HashCodeCalculator;
+import org.apache.labs.bananadb.store.Accessor;
+import org.apache.labs.bananadb.store.lock.Lock;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.nio.charset.Charset;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,29 +36,400 @@
  * Date: 2008-jul-23
  * Time: 02:33:45
  */
-public class PrimaryIndex<PK, T> extends AbstractIndex<PK, T> {
+public class PrimaryIndex<K, E> extends AbstractIndex<K, E> {
+
+  private EntityStore entityStore;
+
+  private Marshaller keyMarshaller;
+  private Unmarshaller keyUnmarshaller;
+  private HashCodeCalculator keyHashCodeCalculator;
+  private Marshaller entityMarshaller;
+  private Unmarshaller entityUnmarshaller;
+
+  private Class<K> keyClass;
+  private Class<E> entityClass;
+
+  private Method primaryKeyGetter;
+  private Method primaryKeySetter;
+
+  private Sequence<K> primaryKeySequence;
+
+  public PrimaryIndex(EntityStore entityStore, Sequence<K> primaryKeySequence, Method primaryKeyGetter, Method primaryKeySetter, Class<K> keyClass, Class<E> entityClass, Marshaller keyMarshaller, Unmarshaller keyUnmarshaller, HashCodeCalculator keyHashCodeCalculator, Marshaller entityMarshaller, Unmarshaller entityUnmarshaller) {
+    this.entityStore = entityStore;
+
+    this.primaryKeySequence = primaryKeySequence;
+
+    this.primaryKeyGetter = primaryKeyGetter;
+    this.primaryKeySetter = primaryKeySetter;
+
+    this.keyClass = keyClass;
+    this.entityClass = entityClass;
+
+    this.keyMarshaller = keyMarshaller;
+    this.keyUnmarshaller = keyUnmarshaller;
+    this.keyHashCodeCalculator = keyHashCodeCalculator;
+    this.entityMarshaller = entityMarshaller;
+    this.entityUnmarshaller = entityUnmarshaller;
+
+    try {
+      entityClassName = entityClass.getName().getBytes("UTF8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException(e);
+    }
+    entityClassNameHashCode = entityClass.getName().hashCode();
+  }
+
+  @SuppressWarnings("unchecked")
+  public E get(Accessor accessor, K key) throws IOException {
+//    long keyHashCode = keyHashCodeCalculator.calcualteLongHashCode(key);
+//    byte[] keyBytes = keyMarshaller.marshall(key);
 
-  public T get(PK key) {
-   return null;
+    long keyHashCode = calculatePrimaryIndexKeyHashCode(key);
+    byte[] keyBytes = marshalPrimayIndexKey(key);
+
+    byte[] entityBytes = entityStore.get(accessor, keyBytes, keyHashCode);
+    return (E) entityUnmarshaller.unmarshall(entityBytes);
   }
 
-  public T put(T entity) {
-    return null;
+  public boolean containsKey(Accessor accessor, K key) throws IOException {
+    long keyHashCode = keyHashCodeCalculator.calcualteLongHashCode(key);
+    byte[] keyBytes = keyMarshaller.marshall(key);
+    return entityStore.containsKey(accessor, keyBytes, keyHashCode);
+  }
+
+  @SuppressWarnings("unchecked")
+  public E put(Accessor accessor, E entity) throws IOException {
+    K key = getPrimaryKey(entity);
+    if (key == null) {
+      if (primaryKeySequence == null) {
+        throw new UnsupportedOperationException("Null keys are not allowed. Did you perhaps forget to set sequence() to something in the @PrimaryKey annotation of entity class " + entityClass.getName() + "?");
+      }
+      key = primaryKeySequence.next();
+      setPrimaryKey(entity, key);
+    }
+//    long keyHashCode = keyHashCodeCalculator.calcualteLongHashCode(key);
+//    byte[] keyBytes = keyMarshaller.marshall(key);
+    long keyHashCode = calculatePrimaryIndexKeyHashCode(key);
+    byte[] keyBytes = marshalPrimayIndexKey(key);
+
+    byte[] entityBytes = entityMarshaller.marshall(entity);
+    byte[] oldEntityBytes = entityStore.put(accessor, keyBytes, keyHashCode, entityBytes);
+    if (oldEntityBytes == null) {
+      return null;
+    } else {
+      return (E) entityUnmarshaller.unmarshall(oldEntityBytes);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public E remove(Accessor accessor, K key) throws IOException {
+//    long keyHashCode = keyHashCodeCalculator.calcualteLongHashCode(key);
+//    byte[] keyBytes = keyMarshaller.marshall(key);
+
+    long keyHashCode = calculatePrimaryIndexKeyHashCode(key);
+    byte[] keyBytes = marshalPrimayIndexKey(key);    
+
+    byte[] oldEntityBytes = entityStore.remove(accessor, keyBytes, keyHashCode);
+    if (oldEntityBytes == null) {
+      return null;
+    } else {
+      return (E) entityUnmarshaller.unmarshall(oldEntityBytes);
+    }
+  }
+
+
+  @SuppressWarnings("unchecked")
+  public K getPrimaryKey(E entity) {
+    try {
+      return (K) primaryKeyGetter.invoke(entity);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(e);
+    } catch (InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
   }
 
-  public T remove(PK key) {
-   return null;
+  public void setPrimaryKey(E entity, K key) {
+    try {
+      primaryKeySetter.invoke(entity, key);
+    } catch (IllegalAccessException e) {
+      throw new RuntimeException(e);
+    } catch (InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
   }
 
-  public EntityCursor<T> cursor() {
-    return null;
+  public EntityCursor<E> cursor() {
+    throw new UnsupportedOperationException();
   }
 
-  public EntityCursor<T> cursor(PK start) {
-    return null;
+  public EntityCursor<E> cursor(K start) {
+    throw new UnsupportedOperationException();
   }
 
-  public EntityCursor<T> cursor(PK start, PK end) {
-    return null;
+  public EntityCursor<E> cursor(K start, K end) {
+    throw new UnsupportedOperationException();
   }
+
+  public Class<K> getKeyClass() {
+    return keyClass;
+  }
+
+  public Class<E> getEntityClass() {
+    return entityClass;
+  }
+
+  public EntityStore getEntityStore() {
+    return entityStore;
+  }
+
+  public Sequence<K> getPrimaryKeySequence() {
+    return primaryKeySequence;
+  }
+
+
+  // transactional
+
+  public class CachedKey {
+    private byte[] bytes;
+    private int hashCode;
+
+    private CachedKey(K key) throws IOException {
+      bytes = keyMarshaller.marshall(key);
+      hashCode = keyHashCodeCalculator.calcualteIntegerHashCode(key);
+    }
+
+    public K getObject() throws IOException {
+      return (K) keyUnmarshaller.unmarshall(bytes);
+    }
+
+    public int getHashCode() {
+      return hashCode;
+    }
+
+    public PrimaryIndex<K, E> getPrimaryIndex() {
+      return PrimaryIndex.this;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      CachedKey cachedKey = (CachedKey) o;
+
+      if (hashCode != cachedKey.hashCode) return false;
+      if (!Arrays.equals(bytes, cachedKey.bytes)) return false;
+      if (getPrimaryIndex() != cachedKey.getPrimaryIndex()) return false;
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      return hashCode;
+    }
+  }
+
+  public class CachedEntity {
+
+    private byte[] bytes;
+
+    private CachedEntity(E entity) throws IOException {
+      if (entity != null) {
+      bytes = entityMarshaller.marshall(entity);
+      } else {
+        bytes = null;
+      }
+    }
+
+    public E getObject() throws IOException {
+      if (bytes == null) {
+        return null;
+      }
+      return (E) entityUnmarshaller.unmarshall(bytes);
+    }    
+
+    public PrimaryIndex<K, E> getPrimaryIndex() {
+      return PrimaryIndex.this;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      CachedEntity that = (CachedEntity) o;
+
+      if (!Arrays.equals(bytes, that.bytes)) return false;
+
+      return true;
+    }
+
+    @Override
+    public int hashCode() {
+      return bytes != null ? Arrays.hashCode(bytes) : 0;
+    }
+  }
+
+
+  public E get(final K key) throws IOException {
+
+    final Transaction txn = getEntityStore().getTxn();
+
+    Lock.With<E> with = new Lock.With<E>(txn.getLock(), txn.getLockWaitTimeoutMilliseconds()) {
+      protected E doBody() throws IOException {
+
+        txn.getIsolation().checkVersion(txn);
+
+        CachedKey cachedKey = new CachedKey(key);
+
+        if (txn.getRemoved().containsKey(cachedKey)) {
+          return null;
+        }
+        E v;
+        if (txn.getCreated().containsKey(cachedKey)) {
+          v = (E) txn.getCreated().get(cachedKey).getObject();
+        } else if (txn.getReplaced().containsKey(cachedKey)) {
+          v = (E) txn.getReplaced().get(cachedKey).getObject();
+        } else {
+          v = get(txn.getAccessor(), key);
+        }
+        return v;
+      }
+    };
+    return with.run();
+  }
+
+  public E put(final E entity) throws IOException {
+
+    final Transaction txn = getEntityStore().getTxn();
+
+    Lock.With<E> with = new Lock.With<E>(txn.getLock(), txn.getLockWaitTimeoutMilliseconds()) {
+      protected E doBody() throws IOException {
+
+        K key = getPrimaryKey(entity);
+
+        CachedKey cachedKey = new CachedKey(key);
+        CachedEntity cachedEntity = new CachedEntity(entity);
+
+        txn.getIsolation().checkVersion(txn);
+
+        E v;
+        if (txn.getCreated().containsKey(cachedKey)) {
+          v = (E) txn.getCreated().put(cachedKey, cachedEntity).getObject();
+        } else if (txn.getReplaced().containsKey(cachedKey)) {
+          v = (E) txn.getReplaced().put(cachedKey, cachedEntity).getObject();
+        } else {
+          if (containsKey(txn.getAccessor(), key)) {
+            txn.getReplaced().put(cachedKey, cachedEntity);
+            if (txn.getRemoved().containsKey(cachedKey)) {
+              txn.getRemoved().remove(cachedKey);
+              v = null;
+            } else {
+              v = get(txn.getAccessor(), key);
+            }
+          } else {
+            txn.getCreated().put(cachedKey, cachedEntity);
+            v = null;
+            txn.getRemoved().remove(cachedKey); // todo not needed?
+          }
+        }
+        return v;
+      }
+    };
+    return with.run();
+  }
+
+  public E remove(final K key) throws IOException {
+
+    final Transaction txn = getEntityStore().getTxn();
+
+    Lock.With<E> with = new Lock.With<E>(txn.getLock(), txn.getLockWaitTimeoutMilliseconds()) {
+      protected E doBody() throws IOException {
+
+        txn.getIsolation().checkVersion(txn);
+
+        CachedKey cachedKey = new CachedKey(key);
+
+
+        if (txn.getRemoved().containsKey(cachedKey)) {
+          return null;
+        }
+        E v;
+        if (txn.getCreated().containsKey(cachedKey)) {
+          v = (E) txn.getCreated().remove(cachedKey).getObject();
+        } else if (txn.getReplaced().containsKey(cachedKey)) {
+          v = (E) txn.getReplaced().remove(cachedKey).getObject();
+        } else {
+          v = get(txn.getAccessor(), key);
+          txn.getRemoved().put(cachedKey, new CachedEntity(v));
+        }
+        return v;
+      }
+    };
+    return with.run();
+  }
+
+  public boolean containsKey(final K key) throws IOException {
+
+    final Transaction txn = getEntityStore().getTxn();
+
+    Lock.With<Boolean> with = new Lock.With<Boolean>(txn.getLock(), txn.getLockWaitTimeoutMilliseconds()) {
+      protected Boolean doBody() throws IOException {
+
+        txn.getIsolation().checkVersion(txn);
+
+        CachedKey cachedKey = new CachedKey(key);
+
+        return !txn.getRemoved().containsKey(cachedKey)
+            && (txn.getReplaced().containsKey(cachedKey) || txn.getCreated().containsKey(cachedKey) || containsKey(txn.getAccessor(), key));
+      }
+    };
+    return with.run();
+  }
+
+//  public int size() throws IOException {
+//
+//    isolation.checkVersion(Transaction.this);
+//
+//    Lock.With<Integer> with = new Lock.With<Integer>(lock, lockWaitTimeoutMilliseconds) {
+//      protected Integer doBody() throws IOException {
+//        int size = entityStore.size(accessor);
+//        size += created.size();
+//        size += replaced.size();
+//        size -= removed.size();
+//        size += isolation.getSizeModifier();
+//        return size;
+//      }
+//    };
+//    return with.run();
+//  }
+
+
+  //
+
+  private final byte[] entityClassName;
+  private final long entityClassNameHashCode;
+
+  private byte[] marshalPrimayIndexKey(K key) throws IOException {
+    byte[] keyBytes = keyMarshaller.marshall(key);
+    byte[] out = new byte[keyBytes.length + entityClassName.length];
+    System.arraycopy(keyBytes, 0, out, 0, keyBytes.length);
+    System.arraycopy(entityClassName, 0, out, keyBytes.length, entityClassName.length);
+    return out;
+  }
+
+  private K unmarshalPrimaryIndexKey(byte[] bytes) throws IOException {
+    return (K)keyUnmarshaller.unmarshall(bytes, 0, bytes.length - entityClassName.length);
+  }
+
+  private long calculatePrimaryIndexKeyHashCode(K key) {
+    long result;
+    result = entityClassNameHashCode << 32;
+    result += keyHashCodeCalculator.calcualteIntegerHashCode(key);
+    return result;
+  }
+
+
+
 }

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryKey.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryKey.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryKey.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/PrimaryKey.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,9 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,8 +28,9 @@
  * Date: 2008-jul-23
  * Time: 02:47:59
  */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
 public @interface PrimaryKey {
-
   public String sequence() default "[unassigned]";
 
 }

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryIndex.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryIndex.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryIndex.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryIndex.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryKey.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryKey.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryKey.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/SecondaryKey.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,9 @@
-package org.apache.labs.bananadb.index;
+package org.apache.labs.bananadb.entity;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -23,6 +28,8 @@
  * Date: 2008-jul-23
  * Time: 02:49:08
  */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
 public @interface SecondaryKey {
 
   public Class otherEndClass();

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Sequence.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Sequence.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Sequence.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Sequence.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,46 @@
+package org.apache.labs.bananadb.entity;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 05:51:45
+ */
+public class Sequence<K> {
+
+  private EntityStore entityStore;
+  private String name;
+
+  public Sequence(EntityStore entityStore, String name) {
+    this.entityStore = entityStore;
+    this.name = name;
+  }
+
+  public K next() {
+    throw new UnsupportedOperationException("Not implemented");
+  }
+
+  public EntityStore getEntityStore() {
+    return entityStore;
+  }
+
+  public String getName() {
+    return name;
+  }
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Transaction.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Transaction.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Transaction.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Transaction.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,168 @@
+package org.apache.labs.bananadb.entity;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import org.apache.labs.bananadb.store.lock.Lock;
+import org.apache.labs.bananadb.store.lock.SingleInstanceLockFactory;
+import org.apache.labs.bananadb.store.Accessor;
+import org.apache.labs.bananadb.store.Metadata;
+import org.apache.labs.bananadb.entity.EntityStore;
+import org.apache.labs.bananadb.entity.PrimaryIndex;
+import org.apache.labs.bananadb.entity.isolation.Isolation;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author kalle
+ * @since 2009-mar-14 13:29:29
+ */
+public class Transaction {
+
+  private Lock lock = new SingleInstanceLockFactory().makeLock("transaction");
+  private long lockWaitTimeoutMilliseconds = 60000;
+
+  private Isolation isolation;
+
+  private long commitVersion = 0l;
+
+  private Accessor accessor;
+
+  private Map<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> created;
+  private Map<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> replaced;
+
+  /** contains the value in the hashtable when it was removed */
+  private Map<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> removed;
+
+  private EntityStore entityStore;
+
+  public Transaction(EntityStore entityStore) {
+    this.entityStore = entityStore;
+    isolation = entityStore.getConfiguration().getDefaultIsolation();
+  }
+
+  public void begin() throws IOException {
+    if (accessor != null) {
+      throw new IOException("Transaction has already begun");
+    }
+    accessor = entityStore.createAccessor(false);
+    created = new HashMap<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>();
+    replaced = new HashMap<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>();
+    removed = new HashMap<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>();
+
+    Metadata.Header mdh = new Metadata.Header();
+    accessor.getMetadata().readHeader(mdh);
+    commitVersion = mdh.getCommitVersion();
+  }
+
+  public void commit() throws IOException {
+    Lock.With with = new Lock.With(lock, lockWaitTimeoutMilliseconds) {
+      protected Object doBody() throws IOException {
+        if (accessor == null) {
+          throw new IOException("Transaction is not started");
+        }
+
+        isolation.checkVersion(Transaction.this);
+
+        for (Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e : removed.entrySet()) {
+          e.getKey().getPrimaryIndex().remove(accessor, e.getKey().getObject());
+        }
+        for (Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e : created.entrySet()) {
+          e.getKey().getPrimaryIndex().put(accessor, e.getValue().getObject());
+        }
+        for (Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e : replaced.entrySet()) {
+          e.getKey().getPrimaryIndex().put(accessor, e.getValue().getObject());
+        }
+        accessor.close();
+        accessor = null;
+        created = null;
+        replaced = null;
+        removed = null;
+        
+        return null;
+      }
+    };
+    with.run();
+  }
+
+  public void abort() throws IOException {
+    Lock.With with = new Lock.With(lock, lockWaitTimeoutMilliseconds) {
+      protected Object doBody() throws IOException {
+        if (accessor == null) {
+          throw new IOException("Transaction is not started");
+        }
+        accessor = null;
+        created = null;
+        replaced = null;
+        removed = null;
+        return null;
+      }
+    };
+    with.run();
+  }
+
+
+  public long getCommitVersion() {
+    return commitVersion;
+  }
+
+  public Accessor getAccessor() {
+    return accessor;
+  }
+
+  public Map<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> getCreated() {
+    return created;
+  }
+
+  public Map<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> getReplaced() {
+    return replaced;
+  }
+
+  public Map<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> getRemoved() {
+    return removed;
+  }
+
+  public EntityStore getEntityStore() {
+    return entityStore;
+  }
+
+  public void setCommitVersion(long commitVersion) {
+    this.commitVersion = commitVersion;
+  }
+
+  public Isolation getIsolation() {
+    return isolation;
+  }
+
+  public void setIsolation(Isolation isolation) {
+    this.isolation = isolation;
+  }
+
+  Lock getLock() {
+    return lock;
+  }
+
+  public long getLockWaitTimeoutMilliseconds() {
+    return lockWaitTimeoutMilliseconds;
+  }
+
+  public void setLockWaitTimeoutMilliseconds(long lockWaitTimeoutMilliseconds) {
+    this.lockWaitTimeoutMilliseconds = lockWaitTimeoutMilliseconds;
+  }
+}

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/AbstractIsolation.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/AbstractIsolation.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/AbstractIsolation.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/AbstractIsolation.java Tue Mar 17 10:14:03 2009
@@ -1,10 +1,10 @@
-package org.apache.labs.bananadb.hashtable.txn;
+package org.apache.labs.bananadb.entity.isolation;
 
 /**
  * @author kalle
  * @since 2009-mar-14 16:24:29
  */
-public abstract class AbstractIsolation<K, V> implements Isolation<K, V> {
+public abstract class AbstractIsolation implements Isolation {
 
   public int getSizeModifier() {
     return 0;

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/DeadlockException.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/DeadlockException.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/DeadlockException.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/DeadlockException.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,4 @@
-package org.apache.labs.bananadb.hashtable.txn;
+package org.apache.labs.bananadb.entity.isolation;
 
 import java.io.IOException;
 

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/Isolation.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/Isolation.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/Isolation.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/Isolation.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,6 @@
-package org.apache.labs.bananadb.hashtable.txn;
+package org.apache.labs.bananadb.entity.isolation;
+
+import org.apache.labs.bananadb.entity.Transaction;
 
 import java.io.IOException;
 
@@ -25,9 +27,9 @@
  * @author kalle
  * @since 2009-mar-14 15:39:32
  */
-public interface Isolation<K, V> {
+public interface Isolation {
 
-  public abstract void checkVersion(Transaction<K, V> txn) throws IOException;
+  public abstract void checkVersion(Transaction txn) throws IOException;
   public abstract int getSizeModifier();
 
 }

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationDeadlocking.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationDeadlocking.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationDeadlocking.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationDeadlocking.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,8 @@
-package org.apache.labs.bananadb.hashtable.txn;
+package org.apache.labs.bananadb.entity.isolation;
+
+import org.apache.labs.bananadb.store.Metadata;
+import org.apache.labs.bananadb.entity.PrimaryIndex;
+import org.apache.labs.bananadb.entity.Transaction;
 
 import java.io.IOException;
 import java.util.Iterator;
@@ -10,27 +14,35 @@
  * @author kalle
  * @since 2009-mar-14 15:40:40
  */
-public class IsolationDeadlocking<K, V> extends AbstractIsolation<K, V> {
+public class IsolationDeadlocking extends AbstractIsolation {
+
+  public void checkVersion(Transaction txn) throws IOException {
+
+    Metadata.Header mdh = new Metadata.Header();
+    txn.getAccessor().getMetadata().readHeader(mdh);
+
+    if (txn.getCommitVersion() != mdh.getCommitVersion()) {
 
-  public void checkVersion(Transaction<K, V> txn) throws IOException {
-    org.apache.labs.bananadb.hashtable.Hashtable.KeyPostingsFileHeader keyPostingsFileHeader = txn.getHashtable().new KeyPostingsFileHeader(txn.getAccessor());
-    if (txn.getHashtableVersion() != keyPostingsFileHeader.getVersion()) {
+      txn.setCommitVersion(mdh.getCommitVersion());
 
-      txn.setHashtableVersion(keyPostingsFileHeader.getVersion());
+      Set<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> deadlocks = new HashSet<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>>();
 
-      Set<Map.Entry<K, V>> deadlocks = new HashSet<Map.Entry<K, V>>();
+      for (Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e : txn.getRemoved().entrySet()) {
 
-      for (Map.Entry<K, V> e : txn.getRemoved().entrySet()) {
-        boolean contains = txn.getHashtable().containsKey(txn.getAccessor(), e.getKey());
+        Object key = e.getKey().getObject();
+        Object entity = e.getValue().getObject();
+
+        PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+        boolean contains = primaryIndex.containsKey(txn.getAccessor(), key);
         if (!contains) {
           deadlocks.add(e);
         } else {
-          V v = txn.getHashtable().get(txn.getAccessor(), e.getKey());
-          if (v == null && e.getValue() != null) {
+          Object v = primaryIndex.get(txn.getAccessor(), entity);
+          if (v == null && e.getValue().getObject() != null) {
             deadlocks.add(e);
-          } else if (v != null && e.getValue() == null) {
+          } else if (v != null && entity == null) {
             deadlocks.add(e);
-          } else if (v != null && e.getValue() != null && !v.equals(e.getValue())) {
+          } else if (v != null && entity != null && !v.equals(entity)) {
             deadlocks.add(e);
           }
         }
@@ -38,30 +50,36 @@
 
       if (deadlocks.size() > 0) {
         StringBuilder sb = new StringBuilder();
-        for (Map.Entry<K, V> e : deadlocks) {
+        for (Map.Entry e : deadlocks) {
           if (sb.length() > 0) {
             sb.append("; ");
           }
-          sb.append(e.getKey().toString());          
+          sb.append(e.getKey().toString());
         }
         throw new DeadlockException("Some of the keys removed in this transaction was removed from the hashtable while the transaction was running: " + sb.toString());
       }
 
-      Set<K> moved = new HashSet<K>();
-      for (Iterator<Map.Entry<K, V>> it = txn.getCreated().entrySet().iterator(); it.hasNext();) {
-        Map.Entry<K, V> e = it.next();
-        if (txn.getHashtable().containsKey(txn.getAccessor(), e.getKey())) {
+      Set<PrimaryIndex.CachedKey> moved = new HashSet<PrimaryIndex.CachedKey>();
+      for (Iterator<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> it = txn.getCreated().entrySet().iterator(); it.hasNext();) {
+        Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e = it.next();
+        PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+        Object key = e.getKey().getObject();
+
+        if (primaryIndex.containsKey(txn.getAccessor(), key)) {
           txn.getReplaced().put(e.getKey(), e.getValue());
           moved.add(e.getKey());
           it.remove();
         }
       }
 
-      for (Iterator<Map.Entry<K, V>> it = txn.getReplaced().entrySet().iterator(); it.hasNext();) {
-        Map.Entry<K, V> e = it.next();
-        if (!moved.contains(e.getKey()) && !txn.getHashtable().containsKey(txn.getAccessor(), e.getKey())) {
-          txn.getCreated().put(e.getKey(), e.getValue());
-          it.remove();
+      for (Iterator<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> it = txn.getReplaced().entrySet().iterator(); it.hasNext();) {
+        Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e = it.next();
+        PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+        if (!moved.contains(e.getKey())) {
+          if (!primaryIndex.containsKey(txn.getAccessor(), e.getKey().getObject())) {
+            txn.getCreated().put(e.getKey(), e.getValue());
+            it.remove();
+          }
         }
       }
 

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationLastCommitWins.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationLastCommitWins.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationLastCommitWins.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationLastCommitWins.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,8 @@
-package org.apache.labs.bananadb.hashtable.txn;
+package org.apache.labs.bananadb.entity.isolation;
+
+import org.apache.labs.bananadb.store.Metadata;
+import org.apache.labs.bananadb.entity.PrimaryIndex;
+import org.apache.labs.bananadb.entity.Transaction;
 
 import java.io.IOException;
 import java.util.Iterator;
@@ -10,42 +14,50 @@
  * @author kalle
  * @since 2009-mar-14 15:40:40
  */
-public class IsolationLastCommitWins<K, V> extends AbstractIsolation<K, V> {
+public class IsolationLastCommitWins extends AbstractIsolation {
 
   private int sizeModifier = 0;
 
-  public void checkVersion(Transaction<K, V> txn) throws IOException {
-    org.apache.labs.bananadb.hashtable.Hashtable.KeyPostingsFileHeader keyPostingsFileHeader = txn.getHashtable().new KeyPostingsFileHeader(txn.getAccessor());
-    if (txn.getHashtableVersion() != keyPostingsFileHeader.getVersion()) {
+  public void checkVersion(Transaction txn) throws IOException {
+
+    Metadata.Header mdh = new Metadata.Header();
+    txn.getAccessor().getMetadata().readHeader(mdh);
 
-      txn.setHashtableVersion(keyPostingsFileHeader.getVersion());
+    if (txn.getCommitVersion() != mdh.getCommitVersion()) {
+
+      txn.setCommitVersion(mdh.getCommitVersion());
 
       // todo if this contains a deleted entity and the entity already is deleted in the hashtable
       // todo then the size is -1 off per such occurance.
 
       int removedConflicts = 0;
-      for (Map.Entry<K, V> e : txn.getRemoved().entrySet()) {
-        if (!txn.getHashtable().containsKey(txn.getAccessor(), e.getKey())) {
+      for (Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e : txn.getRemoved().entrySet()) {
+        PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+        if (!primaryIndex.containsKey(txn.getAccessor(), e.getKey().getObject())) {
           removedConflicts++;
         }
       }
       this.sizeModifier = removedConflicts;
 
-      Set<K> moved = new HashSet<K>();
-      for (Iterator<Map.Entry<K, V>> it = txn.getCreated().entrySet().iterator(); it.hasNext();) {
-        Map.Entry<K, V> e = it.next();
-        if (txn.getHashtable().containsKey(txn.getAccessor(), e.getKey())) {
+      Set<PrimaryIndex.CachedKey> moved = new HashSet<PrimaryIndex.CachedKey>();
+      for (Iterator<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> it = txn.getCreated().entrySet().iterator(); it.hasNext();) {
+        Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e = it.next();
+        PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+        if (primaryIndex.containsKey(txn.getAccessor(), e.getKey().getObject())) {
           txn.getReplaced().put(e.getKey(), e.getValue());
           moved.add(e.getKey());
           it.remove();
         }
       }
 
-      for (Iterator<Map.Entry<K, V>> it = txn.getReplaced().entrySet().iterator(); it.hasNext();) {
-        Map.Entry<K, V> e = it.next();
-        if (!moved.contains(e.getKey()) && !txn.getHashtable().containsKey(txn.getAccessor(), e.getKey())) {
-          txn.getCreated().put(e.getKey(), e.getValue());
-          it.remove();
+      for (Iterator<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> it = txn.getReplaced().entrySet().iterator(); it.hasNext();) {
+        Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e = it.next();
+        if (!moved.contains(e.getKey())) {
+          PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+          if (!primaryIndex.containsKey(txn.getAccessor(), e.getKey().getObject())) {
+            txn.getCreated().put(e.getKey(), e.getValue());
+            it.remove();
+          }
         }
       }
 

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationUpdated.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationUpdated.java?rev=755179&r1=754666&r2=755179&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationUpdated.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/isolation/IsolationUpdated.java Tue Mar 17 10:14:03 2009
@@ -1,4 +1,8 @@
-package org.apache.labs.bananadb.hashtable.txn;
+package org.apache.labs.bananadb.entity.isolation;
+
+import org.apache.labs.bananadb.store.Metadata;
+import org.apache.labs.bananadb.entity.PrimaryIndex;
+import org.apache.labs.bananadb.entity.Transaction;
 
 import java.io.IOException;
 import java.util.Iterator;
@@ -10,39 +14,47 @@
  * @author kalle
  * @since 2009-mar-14 15:40:40
  */
-public class IsolationUpdated<K, V> extends AbstractIsolation<K, V> {
+public class IsolationUpdated extends AbstractIsolation {
+
+  public void checkVersion(Transaction txn) throws IOException {
+
+    Metadata.Header mdh = new Metadata.Header();
+    txn.getAccessor().getMetadata().readHeader(mdh);
 
-  public void checkVersion(Transaction<K, V> txn) throws IOException {
-    org.apache.labs.bananadb.hashtable.Hashtable.KeyPostingsFileHeader keyPostingsFileHeader = txn.getHashtable().new KeyPostingsFileHeader(txn.getAccessor());
-    if (txn.getHashtableVersion() != keyPostingsFileHeader.getVersion()) {
+    if (txn.getCommitVersion() != mdh.getCommitVersion()) {
 
-      txn.setHashtableVersion(keyPostingsFileHeader.getVersion());
+      txn.setCommitVersion(mdh.getCommitVersion());
 
-      for (Iterator<K> it = txn.getRemoved().keySet().iterator(); it.hasNext();) {
-        K key = it.next();
-        if (!txn.getHashtable().containsKey(txn.getAccessor(), key)) {
+      for (Iterator<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> it = txn.getRemoved().entrySet().iterator(); it.hasNext();) {
+        Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e = it.next();
+        PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+        if (!primaryIndex.containsKey(txn.getAccessor(), e.getKey().getObject())) {
           it.remove();
         }
       }
 
-      Set<K> moved = new HashSet<K>();
-      for (Iterator<Map.Entry<K, V>> it = txn.getCreated().entrySet().iterator(); it.hasNext();) {
-        Map.Entry<K, V> e = it.next();
-        if (txn.getHashtable().containsKey(txn.getAccessor(), e.getKey())) {
+      Set<PrimaryIndex.CachedKey> moved = new HashSet<PrimaryIndex.CachedKey>();
+      for (Iterator<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> it = txn.getCreated().entrySet().iterator(); it.hasNext();) {
+        Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e = it.next();
+        PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+        if (primaryIndex.containsKey(txn.getAccessor(), e.getKey().getObject())) {
           txn.getReplaced().put(e.getKey(), e.getValue());
           moved.add(e.getKey());
           it.remove();
         }
       }
 
-      for (Iterator<Map.Entry<K, V>> it = txn.getReplaced().entrySet().iterator(); it.hasNext();) {
-        Map.Entry<K, V> e = it.next();
-        if (!moved.contains(e.getKey()) && !txn.getHashtable().containsKey(txn.getAccessor(), e.getKey())) {
-          txn.getCreated().put(e.getKey(), e.getValue());
-          it.remove();
+      for (Iterator<Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity>> it = txn.getReplaced().entrySet().iterator(); it.hasNext();) {
+        Map.Entry<PrimaryIndex.CachedKey, PrimaryIndex.CachedEntity> e = it.next();
+        if (!moved.contains(e.getKey())) {
+          PrimaryIndex primaryIndex = e.getKey().getPrimaryIndex();
+          if (!primaryIndex.containsKey(txn.getAccessor(), e.getKey().getObject())) {
+            txn.getCreated().put(e.getKey(), e.getValue());
+            it.remove();
+          }
         }
       }
-      
+
     }
   }
 

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/FallBackHashCodeCalculator.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/FallBackHashCodeCalculator.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/FallBackHashCodeCalculator.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/FallBackHashCodeCalculator.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,36 @@
+package org.apache.labs.bananadb.entity.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * Uses {@link Object#hashCode()}.
+ *
+ * @author kalle
+ * @since 2009-mar-17 06:32:30
+ */
+public class FallBackHashCodeCalculator extends HashCodeCalculator {
+
+  public long calcualteLongHashCode(Object object) {
+    return calcualteIntegerHashCode(object);
+  }
+
+  public int calcualteIntegerHashCode(Object object) {
+    return object.hashCode();
+  }
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/HashCodeCalculator.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/HashCodeCalculator.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/HashCodeCalculator.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/HashCodeCalculator.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,30 @@
+package org.apache.labs.bananadb.entity.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 03:59:08
+ */
+public abstract class HashCodeCalculator {
+
+  public abstract long calcualteLongHashCode(Object object);
+  public abstract int calcualteIntegerHashCode(Object object);
+
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Marshaller.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Marshaller.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Marshaller.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Marshaller.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,32 @@
+package org.apache.labs.bananadb.entity.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import java.io.IOException;
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 03:44:55
+ */
+public abstract class Marshaller {
+  
+  public abstract byte[] marshall(Object object) throws IOException;
+
+
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableMarshaller.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableMarshaller.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableMarshaller.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableMarshaller.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,37 @@
+package org.apache.labs.bananadb.entity.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import java.io.*;
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 06:34:08
+ */
+public class SerializableMarshaller extends Marshaller  {
+
+  public byte[] marshall(Object object) throws IOException {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
+    ObjectOutputStream oos = new ObjectOutputStream(baos);
+    oos.writeObject(object);
+    oos.close();
+    return baos.toByteArray();
+  }
+  
+}
\ No newline at end of file

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableUnmarshaller.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableUnmarshaller.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableUnmarshaller.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializableUnmarshaller.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,40 @@
+package org.apache.labs.bananadb.entity.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import java.io.*;
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 06:34:08
+ */
+public class SerializableUnmarshaller extends Unmarshaller {
+
+  public Serializable unmarshall(byte[] bytes, int startOffset, int length) throws IOException {
+    ObjectInputStream oos = new ObjectInputStream(new ByteArrayInputStream(bytes, startOffset, length));
+    Serializable object;
+    try {
+      object = (Serializable) oos.readObject();
+    } catch (ClassNotFoundException e) {
+      throw new IOException(e);
+    }
+    oos.close();
+    return object;
+  }
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializationRegistry.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializationRegistry.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializationRegistry.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/SerializationRegistry.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,106 @@
+package org.apache.labs.bananadb.entity.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 04:16:12
+ */
+public class SerializationRegistry {
+
+  private Map<Class, Marshaller> marshallers = new HashMap<Class, Marshaller>();
+  private Map<Class, Unmarshaller> unmarshallers = new HashMap<Class, Unmarshaller>();
+  private Map<Class, HashCodeCalculator> hashCodeCalculators = new HashMap<Class, HashCodeCalculator>();
+
+  public SerializationRegistry() {
+  }
+
+  public Marshaller getMarshaller(Class type) {
+    Marshaller marshaller;
+    for (Class _class : getAllClasses(type)) {
+      if ((marshaller = marshallers.get(_class)) != null) {
+        return marshaller;
+      }
+    }
+    throw new IllegalArgumentException("No applicable marshaller found for class " + type.getName());
+  }
+
+
+  public Unmarshaller getUnmarshaller(Class type) {
+    Unmarshaller unmarshaller;
+    for (Class _class : getAllClasses(type)) {
+      if ((unmarshaller = unmarshallers.get(_class)) != null) {
+        return unmarshaller;
+      }
+    }
+    throw new IllegalArgumentException("No applicable unmarshaller found for class " + type.getName());
+  }
+
+  public HashCodeCalculator getHashCodeCalcualtor(Class type) {
+    HashCodeCalculator calculator;
+    for (Class _class : getAllClasses(type)) {
+      if ((calculator = hashCodeCalculators.get(_class)) != null) {
+        return calculator;
+      }
+    }
+    throw new IllegalArgumentException("No applicable hash code calculator found for class " + type.getName());
+  }
+
+  private List<Class> getAllClasses(Class type) {
+    List<Class> all = new ArrayList<Class>();
+    all.add(type);
+    Class tmp = type;
+    while ((tmp = tmp.getSuperclass()) != Object.class) {
+      all.add(tmp);
+    }
+    all.add(Object.class);
+
+    List<Class> allInterfaces = new ArrayList<Class>();
+    for (Class tmp2 : all) {
+      addInterfaces(tmp2, allInterfaces);
+    }
+
+    all.addAll(allInterfaces);
+    return all;
+  }
+
+  private void addInterfaces(Class _class, List<Class> all) {
+    for (Class _interface : _class.getInterfaces()) {
+      all.add(_interface);
+      addInterfaces(_interface, all);
+    }
+  }
+
+  public Map<Class, Marshaller> getMarshallers() {
+    return marshallers;
+  }
+
+  public Map<Class, Unmarshaller> getUnmarshallers() {
+    return unmarshallers;
+  }
+
+  public Map<Class, HashCodeCalculator> getHashCodeCalculators() {
+    return hashCodeCalculators;
+  }
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Unmarshaller.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Unmarshaller.java?rev=755179&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Unmarshaller.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/serialization/Unmarshaller.java Tue Mar 17 10:14:03 2009
@@ -0,0 +1,33 @@
+package org.apache.labs.bananadb.entity.serialization;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * @author kalle
+ * @since 2009-mar-17 03:58:21
+ */
+public abstract class Unmarshaller {
+
+  public Object unmarshall(byte[] bytes) throws java.io.IOException {
+    return unmarshall(bytes, 0, bytes.length);
+  }
+  
+  public abstract Object unmarshall(byte[] bytes, int startOffset, int length) throws java.io.IOException;
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org