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/22 23:12:13 UTC

svn commit: r757265 [1/2] - in /labs/bananadb/trunk/src: main/java/org/apache/labs/bananadb/ main/java/org/apache/labs/bananadb/entity/ main/java/org/apache/labs/bananadb/entity/isolation/ main/java/org/apache/labs/bananadb/store/ main/java/org/apache/...

Author: kalle
Date: Sun Mar 22 22:12:12 2009
New Revision: 757265

URL: http://svn.apache.org/viewvc?rev=757265&view=rev
Log:
Banana DB  

Revisions on all store postings, preparation for ACID Durability
Abstract and dummy sequence manager for auto incrementing primary keys 
Site

Added:
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/FileHandler.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/Metadata.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/HashCodesPartition.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/Hashtable.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/KeysPartition.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/ValuesPartition.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockListener.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/SequenceManager.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/StaticSequenceManager.java
Removed:
    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/Metadata.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/ValuesPartition.java
Modified:
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/Benchmark.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/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/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/Store.java
    labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java
    labs/bananadb/trunk/src/site/apt/index.apt
    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

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/Benchmark.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/Benchmark.java?rev=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/Benchmark.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/Benchmark.java Sun Mar 22 22:12:12 2009
@@ -66,7 +66,7 @@
 
     final long writeStart = System.currentTimeMillis();
 
-    Lock.With with = new Lock.With(accessor.getWriteLock(), 0) {
+    Lock.With with = new Lock.With(accessor.getStoreWriteLock(), 0) {
       public Object doBody() throws IOException {
 
         int replaced = 0;

Modified: 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=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Transaction.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/entity/Transaction.java Sun Mar 22 22:12:12 2009
@@ -19,9 +19,8 @@
 
 
 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.store.data.Metadata;
 import org.apache.labs.bananadb.entity.EntityStore;
 import org.apache.labs.bananadb.entity.PrimaryIndex;
 import org.apache.labs.bananadb.entity.isolation.Isolation;
@@ -71,7 +70,7 @@
   }
 
   public void commit() throws IOException {
-    Lock.With with = new Lock.With(accessor.getWriteLock(), entityStore.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+    Lock.With with = new Lock.With(accessor.getStoreWriteLock(), entityStore.getConfiguration().getLockWaitTimeoutMilliseconds()) {
       public Object doBody() throws IOException {
         if (accessor == null) {
           throw new IOException("Transaction is not started");

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=757265&r1=757264&r2=757265&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 Sun Mar 22 22:12:12 2009
@@ -1,6 +1,6 @@
 package org.apache.labs.bananadb.entity.isolation;
 
-import org.apache.labs.bananadb.store.Metadata;
+import org.apache.labs.bananadb.store.data.Metadata;
 import org.apache.labs.bananadb.entity.PrimaryIndex;
 import org.apache.labs.bananadb.entity.Transaction;
 

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=757265&r1=757264&r2=757265&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 Sun Mar 22 22:12:12 2009
@@ -1,6 +1,6 @@
 package org.apache.labs.bananadb.entity.isolation;
 
-import org.apache.labs.bananadb.store.Metadata;
+import org.apache.labs.bananadb.store.data.Metadata;
 import org.apache.labs.bananadb.entity.PrimaryIndex;
 import org.apache.labs.bananadb.entity.Transaction;
 

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=757265&r1=757264&r2=757265&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 Sun Mar 22 22:12:12 2009
@@ -1,6 +1,6 @@
 package org.apache.labs.bananadb.entity.isolation;
 
-import org.apache.labs.bananadb.store.Metadata;
+import org.apache.labs.bananadb.store.data.Metadata;
 import org.apache.labs.bananadb.entity.PrimaryIndex;
 import org.apache.labs.bananadb.entity.Transaction;
 

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java?rev=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Accessor.java Sun Mar 22 22:12:12 2009
@@ -19,6 +19,12 @@
 
 
 import org.apache.labs.bananadb.store.lock.Lock;
+import org.apache.labs.bananadb.store.data.bananatrie.HashCodesPartition;
+import org.apache.labs.bananadb.store.data.bananatrie.Hashtable;
+import org.apache.labs.bananadb.store.data.bananatrie.KeysPartition;
+import org.apache.labs.bananadb.store.data.bananatrie.ValuesPartition;
+import org.apache.labs.bananadb.store.data.FileHandler;
+import org.apache.labs.bananadb.store.data.Metadata;
 
 import java.io.IOException;
 import java.util.Map;
@@ -41,7 +47,8 @@
   private Store store;
   private String access;
 
-  private Lock writeLock;
+  private Lock storeWriteLock;
+  private Metadata.Header lockedMetadata;
 
   private Metadata metadata;
   private Hashtable hashtable;
@@ -49,11 +56,12 @@
   private Map<Integer, KeysPartition> keyPartitions = new HashMap<Integer, KeysPartition>();
   private Map<Integer, ValuesPartition> valuePartitions = new HashMap<Integer, ValuesPartition>();
 
+
   Accessor(final Store store, boolean readOnly) throws IOException {
     this.store = store;
     access = readOnly ? "r" : "rw";
-    writeLock = store.getConfiguration().getLockFactory().makeLock("lock");
-    metadata = new Metadata(store.getConfiguration().getDataPath(), access);
+    storeWriteLock = store.getConfiguration().getLockFactory().makeLock("lock");
+    metadata = new Metadata(store.getConfiguration().getDataPath(), access, store.getConfiguration().getLockFactory());
 
     if (metadata.getFile().exists()) {
       metadata.open();
@@ -67,7 +75,7 @@
 
       log.info("Creating new store..");
 
-      Lock.With width = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+      Lock.With width = new Lock.With(storeWriteLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
         public Object doBody() throws IOException {
           if (!metadata.getFile().exists()) {
 
@@ -82,7 +90,7 @@
             mdh.setValuePostingsCount(0);
             metadata.writeHeader(mdh);
 
-            hashtable = new Hashtable(store.getConfiguration().getDataPath(), 0, access);
+            hashtable = new Hashtable(store.getConfiguration().getDataPath(), 0, access, store.getConfiguration().getLockFactory());
             hashtable.format((store.getConfiguration().getInitialCapacity() * Hashtable.Posting.POSTING_BYTE_SIZE) + hashtable.getHeaderByteSize());
             hashtable.open();
             Hashtable.Header hth = new Hashtable.Header();
@@ -139,7 +147,7 @@
       if (hashtable != null) {
         hashtable.getRAF().close();
       }
-      hashtable = new Hashtable(store.getConfiguration().getDataPath(), metadataHeader.getCurrentHashtableId(), access);
+      hashtable = new Hashtable(store.getConfiguration().getDataPath(), metadataHeader.getCurrentHashtableId(), access, store.getConfiguration().getLockFactory());
       hashtable.open();
     }
     return hashtable;
@@ -148,10 +156,10 @@
   public HashCodesPartition getHashCodesPartition(int partitionId) throws IOException {
     HashCodesPartition partition = hashCodesPartitions.get(partitionId);
     if (partition == null) {
-      partition = new HashCodesPartition(store.getConfiguration().getDataPath(), partitionId, access);
+      partition = new HashCodesPartition(store.getConfiguration().getDataPath(), partitionId, access, store.getConfiguration().getLockFactory());
       if (!partition.getFile().exists()) {
         final HashCodesPartition p = partition;
-        Lock.With with = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+        Lock.With with = new Lock.With(storeWriteLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
           public Object doBody() throws IOException {
             if (!p.getFile().exists()) {
               p.format(store.getConfiguration().getHashCodesPartitionByteSize());
@@ -176,10 +184,10 @@
   public KeysPartition getKeysPartition(int partitionId) throws IOException {
     KeysPartition partition = keyPartitions.get(partitionId);
     if (partition == null) {
-      partition = new KeysPartition(store.getConfiguration().getDataPath(), partitionId, access);
+      partition = new KeysPartition(store.getConfiguration().getDataPath(), partitionId, access, store.getConfiguration().getLockFactory());
       if (!partition.getFile().exists()) {
         final KeysPartition p = partition;
-        Lock.With with = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+        Lock.With with = new Lock.With(storeWriteLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
           public Object doBody() throws IOException {
             if (!p.getFile().exists()) {
               p.format(store.getConfiguration().getKeysPartitionByteSize());
@@ -204,10 +212,10 @@
   public ValuesPartition getValuesPartition(int partitionId) throws IOException {
     ValuesPartition partition = valuePartitions.get(partitionId);
     if (partition == null) {
-      partition = new ValuesPartition(store.getConfiguration().getDataPath(), partitionId, access);
+      partition = new ValuesPartition(store.getConfiguration().getDataPath(), partitionId, access, store.getConfiguration().getLockFactory());
       if (!partition.getFile().exists()) {
         final ValuesPartition p = partition;
-        Lock.With with = new Lock.With(writeLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
+        Lock.With with = new Lock.With(storeWriteLock, store.getConfiguration().getLockWaitTimeoutMilliseconds()) {
           public Object doBody() throws IOException {
             if (!p.getFile().exists()) {
               p.format(store.getConfiguration().getValuesPartitionByteSize());
@@ -376,8 +384,8 @@
     }
   }
 
-  public Lock getWriteLock() {
-    return writeLock;
+  public Lock getStoreWriteLock() {
+    return storeWriteLock;
   }
 
   public Store getStore() {

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java?rev=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Configuration.java Sun Mar 22 22:12:12 2009
@@ -20,6 +20,7 @@
 
 import org.apache.labs.bananadb.store.lock.LockFactory;
 import org.apache.labs.bananadb.store.lock.NativeFSLockFactory;
+import org.apache.labs.bananadb.store.sequence.SequenceManager;
 
 import java.io.File;
 import java.io.IOException;
@@ -64,7 +65,6 @@
    */
   private double automaticRehashThreadshold = 0.125d;
 
-
   private LockFactory lockFactory;
 
   private long lockWaitTimeoutMilliseconds = 60000;

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java?rev=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/Store.java Sun Mar 22 22:12:12 2009
@@ -19,6 +19,14 @@
  */
 
 import org.apache.labs.bananadb.store.lock.Lock;
+import org.apache.labs.bananadb.store.data.bananatrie.HashCodesPartition;
+import org.apache.labs.bananadb.store.data.bananatrie.Hashtable;
+import org.apache.labs.bananadb.store.data.bananatrie.KeysPartition;
+import org.apache.labs.bananadb.store.data.bananatrie.ValuesPartition;
+import org.apache.labs.bananadb.store.data.Metadata;
+import org.apache.labs.bananadb.store.data.FileHandler;
+import org.apache.labs.bananadb.store.sequence.SequenceManager;
+import org.apache.labs.bananadb.store.sequence.StaticSequenceManager;
 
 import java.io.File;
 import java.io.IOException;
@@ -36,6 +44,8 @@
   private static final Log log = new Log(Store.class);
 
   private Configuration configuration;
+  private SequenceManager sequenceManager = new StaticSequenceManager();
+  private List<Accessor> accessors = new ArrayList<Accessor>();
 
   public Store(File dataPath) throws IOException {
     this(new Configuration(dataPath));
@@ -57,8 +67,10 @@
     }
   }
 
+  public SequenceManager getSequenceManager() {
+    return sequenceManager;
+  }
 
-  private List<Accessor> accessors = new ArrayList<Accessor>();
 
   List<Accessor> getAccessors() {
     return accessors;
@@ -149,6 +161,30 @@
     return valuePosting.getBytes();
   }
 
+  public byte[] put(final Accessor accessor, final byte[] key, final long hashCode, final byte[] value) throws IOException {
+    validateKey(key);
+
+    long revision = incrementAndGetRevision(accessor);
+
+    return put(accessor, key, hashCode, value, revision);
+  }
+
+  private long incrementAndGetRevision(final Accessor accessor) throws IOException {
+    Lock.With<Long> with = new Lock.With<Long>(accessor.getStoreWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
+      public Long doBody() throws IOException {
+        Metadata metadata = accessor.getMetadata();
+        Metadata.Header mdh = new Metadata.Header();
+        metadata.readHeader(mdh);
+        mdh.setCommitVersion(mdh.getCommitVersion() + 1);
+        metadata.writeHeader(mdh);
+        return mdh.getCommitVersion();
+      }
+    };
+    long revision = with.run();
+    return revision;
+  }
+
+
   /**
    * Write locking.
    *
@@ -159,19 +195,13 @@
    * @return
    * @throws IOException
    */
-  public byte[] put(final Accessor accessor, final byte[] key, final long hashCode, final byte[] value) throws IOException {
+  public byte[] put(final Accessor accessor, final byte[] key, final long hashCode, final byte[] value, final long revision) throws IOException {
 
     validateKey(key);
 
-    Lock.With<byte[]> with = new Lock.With<byte[]>(accessor.getWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
+    Lock.With<byte[]> with = new Lock.With<byte[]>(accessor.getStoreWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
       public byte[] doBody() throws IOException {
-        byte[] ret = doPut(accessor, key, hashCode, value);
-        Metadata metadata = accessor.getMetadata();
-        Metadata.Header mdh = new Metadata.Header();
-        metadata.readHeader(mdh);
-        mdh.setCommitVersion(mdh.getCommitVersion() + 1);
-        metadata.writeHeader(mdh);
-        return ret;
+        return doPut(accessor, key, hashCode, value, revision);
       }
     };
     return with.run();
@@ -187,7 +217,7 @@
    * @return
    * @throws IOException
    */
-  private byte[] doPut(final Accessor accessor, final byte[] key, final long hashCode, final byte[] value) throws IOException {
+  private byte[] doPut(final Accessor accessor, final byte[] key, final long hashCode, final byte[] value, final long revision) throws IOException {
 
 
     //
@@ -198,7 +228,9 @@
     int newValuePostingPartitionOffset;
 
     ValuesPartition.Posting valuePosting = new ValuesPartition.Posting();
+    valuePosting.setFlag(FileHandler.Posting.FLAG_IN_USE);
 
+    valuePosting.setCreatedRevision(revision);
     if (value == null || value.length == 0) {
       valuePosting.setBytesLength(0);
       valuePosting.setBytes(null);
@@ -226,6 +258,7 @@
     //
 
     KeysPartition.Posting newKeyPosting = new KeysPartition.Posting();
+    newKeyPosting.setCreatedRevision(revision);
     newKeyPosting.setFlag((byte) 1);
     newKeyPosting.setBytes(key);
     newKeyPosting.setBytesLength(key.length);
@@ -249,15 +282,18 @@
 
     Hashtable hashtable = accessor.getHashtable();
     Hashtable.Posting hashtablePosting = new Hashtable.Posting();
+
     HashCodesPartition.Posting hashCodePosting = new HashCodesPartition.Posting();
 
     int hashtablePostingOffset = hashtable.calculateHashCodePostingOffset(hashCode);
-    hashtable.readPosting(hashtablePosting, hashtablePostingOffset);
-    if (hashtablePosting.getFlag() != (byte) 1) {
+    hashtable.getRAF().seek(hashtablePostingOffset);
+    byte flag = hashtable.getRAF().readByte();
+    if (flag != FileHandler.Posting.FLAG_IN_USE) {
 
       // this is the first time we create a posting at this hashtable position
       // that means there is no hash code posting either
 
+      hashCodePosting.setCreatedRevision(revision);
       hashCodePosting.setFlag((byte) 1);
       hashCodePosting.setFirstKeyPostingPartition(newKeyPostingPartition);
       hashCodePosting.setFirstKeyPostingPartitionOffset(newKeyPostingPartitionOffset);
@@ -277,6 +313,7 @@
       hashtablePosting.setFlag((byte) 1);
       hashtablePosting.setHashCodePostingPartition(newHashCodePostingPatition);
       hashtablePosting.setHashCodePostingPartitionOffset(newHashCodePostingPatitionOffset);
+      hashtablePosting.setCreatedRevision(revision);
       hashtable.writePosting(hashtablePosting, hashtablePostingOffset);
 
       return null;
@@ -285,12 +322,14 @@
 
       // there is a hashtable posting at the position for this hash code
 
+      hashtable.readPosting(hashtablePosting, hashtablePostingOffset);
+
       //
       // seek to the correct hash code posting
-      //
+      //      
 
       HashCodesPartition hashCodesPartition = accessor.getHashCodesPartition(hashtablePosting.getHashCodePostingPartition());
-      int currentHashCodesPotingPartitionOffset = hashtablePosting.getHashCodePostingPartitionOffset();
+      int currentHashCodesPostingPartitionOffset = hashtablePosting.getHashCodePostingPartitionOffset();
       hashCodesPartition.readPosting(hashCodePosting, hashtablePosting.getHashCodePostingPartitionOffset());
       while (hashCode != hashCodePosting.getKeyHashCode()) {
         if (hashCodePosting.getNextPostingPartition() < 0) {
@@ -302,6 +341,7 @@
           //
 
           HashCodesPartition.Posting newHashCodePosting = new HashCodesPartition.Posting();
+          newHashCodePosting.setCreatedRevision(revision);
           newHashCodePosting.setFlag((byte) 1);
           newHashCodePosting.setKeyHashCode(hashCode);
           newHashCodePosting.setNextPostingPartition(-1);
@@ -323,7 +363,7 @@
 
           hashCodePosting.setNextPostingPartition(newHashCodePostingPartition);
           hashCodePosting.setNextPostingPartitionOffset(newHashCodePostingPartitionOffset);
-          hashCodesPartition.writePosting(hashCodePosting, currentHashCodesPotingPartitionOffset);
+          hashCodesPartition.writePosting(hashCodePosting, currentHashCodesPostingPartitionOffset);
 
           return null;
 
@@ -331,7 +371,7 @@
         if (hashCodePosting.getNextPostingPartition() != hashCodesPartition.getPartitionId()) {
           hashCodesPartition = accessor.getHashCodesPartition(hashCodePosting.getNextPostingPartition());
         }
-        currentHashCodesPotingPartitionOffset = hashCodePosting.getNextPostingPartitionOffset();
+        currentHashCodesPostingPartitionOffset = hashCodePosting.getNextPostingPartitionOffset();
         hashCodesPartition.readPosting(hashCodePosting, hashCodePosting.getNextPostingPartitionOffset());
       }
 
@@ -385,11 +425,11 @@
 
         hashCodePosting.setFirstKeyPostingPartition(newKeyPostingPartition);
         hashCodePosting.setFirstKeyPostingPartitionOffset(newKeyPostingPartitionOffset);
-        hashCodesPartition.writePosting(hashCodePosting, currentHashCodesPotingPartitionOffset);
+        hashCodesPartition.writePosting(hashCodePosting, currentHashCodesPostingPartitionOffset);
       } else {
 
         // mark old key as deleted
-        keysPartition.deletePosting(currentKeyPostingPartitionOffset);
+        keysPartition.deletePosting(currentKeyPostingPartitionOffset, revision);
 
         // update previous key posting in chain to point chain at new key posting rather than the deleted
         if (previousKeyPostingPartition != currentKeyPostingPartition) {
@@ -413,7 +453,7 @@
       }
 
       // mark the old value as deleted
-      valuesPartition.deletePosting(keyPosting.getValuePostingPartitionOffset());
+      valuesPartition.deletePosting(keyPosting.getValuePostingPartitionOffset(), revision);
 
       return oldValue;
 
@@ -421,23 +461,29 @@
 
   }
 
+  public byte[] remove(final Accessor accessor, final byte[] key, final long hashCode) throws IOException {
+    long revision = incrementAndGetRevision(accessor);
+    return remove(accessor, key, hashCode, revision);
+  }
+
   /**
    * Write locking.
    *
    * @param accessor
    * @param key
    * @param hashCode
+   * @param revision revision flaggad as deletion revision
    * @return
    * @throws IOException
    */
-  public byte[] remove(final Accessor accessor, final byte[] key, final long hashCode) throws IOException {
+  public byte[] remove(final Accessor accessor, final byte[] key, final long hashCode, final long revision) throws IOException {
 
     validateKey(key);
 
-    Lock.With<byte[]> with = new Lock.With<byte[]>(accessor.getWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
+    Lock.With<byte[]> with = new Lock.With<byte[]>(accessor.getStoreWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
       public byte[] doBody() throws IOException {
 
-        byte[] ret = doRemove(accessor, key, hashCode);
+        byte[] ret = doRemove(accessor, key, hashCode, revision);
 
         Metadata metadata = accessor.getMetadata();
         Metadata.Header mdh = new Metadata.Header();
@@ -461,7 +507,7 @@
    * @return
    * @throws IOException
    */
-  private byte[] doRemove(final Accessor accessor, final byte[] key, final long hashCode) throws IOException {
+  private byte[] doRemove(final Accessor accessor, final byte[] key, final long hashCode, final long revision) throws IOException {
 
     Hashtable.Posting hashtablePosting = new Hashtable.Posting();
 
@@ -552,9 +598,9 @@
         // so delete the hashtable and hash code posting
         //
 
-        hashCodesPartition.deletePosting(currentHashCodePostingPartitionOffset);
+        hashCodesPartition.deletePosting(currentHashCodePostingPartitionOffset, revision);
 
-        hashtable.deletePosting(hashtablePostingOffset);
+        hashtable.deletePosting(hashtablePostingOffset, revision);
 
       }
 
@@ -578,7 +624,7 @@
 
 
     // mark old key as deleted
-    keysPartition.deletePosting(currentKeyPostingPartitionOffset);
+    keysPartition.deletePosting(currentKeyPostingPartitionOffset, revision);
 
 
     // read the old value
@@ -594,7 +640,7 @@
     }
 
     // mark the old value as deleted
-    oldValuePartition.deletePosting(keyPosting.getValuePostingPartitionOffset());
+    oldValuePartition.deletePosting(keyPosting.getValuePostingPartitionOffset(), revision);
 
     return oldValue;
 
@@ -679,19 +725,19 @@
    * @throws IOException
    */
   public void rehash(final Accessor accessor, final int resolution) throws IOException {
-    Lock.With with = new Lock.With(accessor.getWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
+    Lock.With with = new Lock.With(accessor.getStoreWriteLock(), getConfiguration().getLockWaitTimeoutMilliseconds()) {
       public Object doBody() throws IOException {
 
         log.info("Rehashing hashtable capacity ??? -> " + resolution);
 
-        Metadata metadata = accessor.getMetadata();        
+        Metadata metadata = accessor.getMetadata();
         Metadata.Header mdh = new Metadata.Header();
         metadata.readHeader(mdh);
         int topOldHashCodesPartition = mdh.getCurrentHashCodesPartition();
         mdh.setCurrentHashCodesPartition(mdh.getCurrentHashCodesPartition() + 1);
         metadata.writeHeader(mdh);
 
-        Hashtable rehashedTable = new Hashtable(getConfiguration().getDataPath(), mdh.getCurrentHashtableId() + 1, accessor.getAccess());
+        Hashtable rehashedTable = new Hashtable(getConfiguration().getDataPath(), mdh.getCurrentHashtableId() + 1, accessor.getAccess(), getConfiguration().getLockFactory());
         rehashedTable.format((resolution * Hashtable.Posting.POSTING_BYTE_SIZE) + rehashedTable.getHeaderByteSize());
         rehashedTable.open();
 
@@ -699,7 +745,7 @@
         rehashedTableHeader.setPostingsCapacity(resolution);
         rehashedTable.writeHeader(rehashedTableHeader);
 
-        // will format a new one!
+        // will data a new one!
         HashCodesPartition rehashCodesPartition = accessor.getHashCodesPartition(mdh.getCurrentHashCodesPartition());
 
         Hashtable.Posting rehashedTablePosting = new Hashtable.Posting();
@@ -708,7 +754,7 @@
         rehashCodesPartition.readHeader(rehashCodeHeader);
 
         for (int currentOldHashCodePostingsPartitionId = 0; currentOldHashCodePostingsPartitionId <= topOldHashCodesPartition; currentOldHashCodePostingsPartitionId++) {
-          HashCodesPartition currentOldHashCodesPartition = new HashCodesPartition(getConfiguration().getDataPath(), currentOldHashCodePostingsPartitionId, accessor.getAccess());
+          HashCodesPartition currentOldHashCodesPartition = new HashCodesPartition(getConfiguration().getDataPath(), currentOldHashCodePostingsPartitionId, accessor.getAccess(), getConfiguration().getLockFactory());
           if (currentOldHashCodesPartition.exists()) {
             currentOldHashCodesPartition.open();
             HashCodesPartition.Header hcph = new HashCodesPartition.Header();
@@ -799,6 +845,8 @@
       rehashCodePosting.setKeyHashCode(hashCodePosting.getKeyHashCode());
       rehashCodePosting.setNextPostingPartition(-1);
       rehashCodePosting.setNextPostingPartitionOffset(-1);
+      rehashCodePosting.setCreatedRevision(hashCodePosting.getCreatedRevision());
+      rehashCodePosting.setDeletedRevision(hashCodePosting.getDeletedRevision());
 
       rehashCodePartition.writePosting(rehashCodePosting, rehashCodeHeader.getNextPostingOffset());
 

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/FileHandler.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/FileHandler.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/FileHandler.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/FileHandler.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,214 @@
+package org.apache.labs.bananadb.store.data;
+
+/*
+ * 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.LockFactory;
+import org.apache.labs.bananadb.store.Log;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.FileOutputStream;
+import java.util.Arrays;
+
+/**
+ * @author kalle
+ * @since 2009-mar-16 15:28:29
+ */
+public abstract class FileHandler<H extends FileHandler.Header, P extends FileHandler.Posting> {
+
+  private static final Log log = new Log(FileHandler.class);
+
+  private File file;
+  private RandomAccessFile RAF;
+  private String access;
+  private Lock lock;
+
+  private H header;
+
+  protected FileHandler(File directory, int id, String suffix, String access, LockFactory lockFactory) throws IOException {
+    StringBuilder sb = new StringBuilder(15);
+    sb.append(String.valueOf(id));
+    while (sb.length() < 8) {
+      sb.insert(0, "0");
+    }
+    sb.append(".");
+    sb.append(suffix);
+    this.file = new File(directory, sb.toString());
+    this.access = access;
+
+    lock = lockFactory.makeLock(sb.toString());
+  }
+
+  public Lock getLock() {
+    return lock;
+  }
+
+  public void format(long size) throws IOException {
+    format(size, (byte) 0);
+  }
+
+  public boolean exists() {
+    return getFile().exists();
+  }
+
+  public void format(long size, byte defaultValue) throws IOException {
+    log.info("Formatting " + file.getAbsolutePath() + "..");
+
+    long ms = System.currentTimeMillis();
+
+    long leftToWrite = size;
+
+    FileOutputStream fos = new FileOutputStream(file);
+    int bufSize = Math.min(1024 * 1024, (int)(size / 5));
+    byte[] bytes = new byte[bufSize];
+    Arrays.fill(bytes, defaultValue);
+    while (leftToWrite >= bytes.length) {
+      fos.write(bytes);
+      leftToWrite -= bytes.length;
+    }
+    if (leftToWrite > 0) {
+      fos.write(bytes, defaultValue, (int) leftToWrite);
+    }
+    fos.close();
+
+    log.info("It took " + (System.currentTimeMillis() - ms) + " milliseconds to data " + file.getAbsolutePath());
+  }
+
+  public void open() throws IOException {
+    if (RAF != null) {
+      throw new IOException("Already open");
+    }
+    this.RAF = new RandomAccessFile(file, access);
+  }
+
+  public void close() throws IOException {
+    if (RAF == null) {
+      throw new IOException("Already closed");
+    }
+    RAF.close();
+  }
+
+  public abstract int getHeaderByteSize();
+
+  public File getFile() {
+    return file;
+  }
+
+  public RandomAccessFile getRAF() {
+    return RAF;
+  }
+
+  public static abstract class Header {
+  }
+
+  public static abstract class Posting {
+
+    public static final byte FLAG_NEVER_USED = (byte)0;
+    public static final byte FLAG_IN_USE = (byte)1;
+    public static final byte FLAG_DELETED = (byte)2;
+    
+    public abstract int getPostingByteSize();
+    public abstract byte getFlag();
+    public abstract void setFlag(byte flag);
+    public abstract long getCreatedRevision();
+    public abstract void setCreatedRevision(long revision);
+    public abstract long getDeletedRevision();
+    public abstract void setDeletedRevision(long revision);
+
+  }
+
+//  public void writePosting(P posting) throws IOException {
+//    writePosting(posting, getRAF());
+//  }
+  
+  /**
+   * Marks the posting at the start offset as deleted
+   * @param startOffset
+   * @param revision
+   * @throws IOException
+   */
+  public void deletePosting(int startOffset, long revision) throws IOException {
+    deletePosting(startOffset, RAF, revision);
+  }
+
+  public abstract void deletePosting(int startOffset, RandomAccessFile RAF, long revision) throws IOException;
+
+  public void writePosting(P posting, int startOffset) throws IOException {
+    writePosting(posting, startOffset, getRAF());
+  }
+
+  public void writePosting(P posting, int startOffset, RandomAccessFile RAF) throws IOException {
+    RAF.seek(startOffset);
+    writePosting(posting, RAF);
+  }
+
+  public void writePosting(P posting) throws IOException {
+    writePosting(posting, getRAF());
+  }
+
+  public abstract void writePosting(P posting, RandomAccessFile RAF) throws IOException;
+
+//  public void readPosting(P posting) throws IOException {
+//    readPosting(posting, getRAF());
+//  }
+
+  public void readPosting(P posting, int startOffset) throws IOException {
+    readPosting(posting, startOffset, getRAF());
+  }
+
+  public void readPosting(P posting, int startOffset, RandomAccessFile RAF) throws IOException {
+    RAF.seek(startOffset);
+    readPosting(posting, RAF);
+  }
+
+  public abstract void readPosting(P posting, RandomAccessFile RAF) throws IOException;
+
+
+  public void writeHeader(H header) throws IOException {
+    writeHeader(header, 0, getRAF());
+  }
+
+  public void writeHeader(H header, int startOffset) throws IOException {
+    writeHeader(header, startOffset, getRAF());
+  }
+
+  public void writeHeader(H header, int startOffset, RandomAccessFile RAF) throws IOException {
+    RAF.seek(startOffset);
+    writeHeader(header, RAF);
+  }
+
+  public abstract void writeHeader(H header, RandomAccessFile RAF) throws IOException;
+
+  public void readHeader(H header) throws IOException {
+    readHeader(header, 0, RAF);
+  }
+
+  public void readHeader(H header, int startOffset) throws IOException {
+    readHeader(header, startOffset, getRAF());
+  }
+
+  public void readHeader(H header, int startOffset, RandomAccessFile RAF) throws IOException {
+    RAF.seek(startOffset);
+    readHeader(header, RAF);
+  }
+
+  public abstract void readHeader(H header, RandomAccessFile RAF) throws IOException;
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/Metadata.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/Metadata.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/Metadata.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/Metadata.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,174 @@
+package org.apache.labs.bananadb.store.data;
+
+/*
+ * 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.LockFactory;
+
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * @author kalle
+ * @since 2009-mar-16 14:16:39
+ */
+public class Metadata extends FileHandler<Metadata.Header, FileHandler.Posting> {
+
+  public Metadata(File directory, String access, LockFactory lockFactory) throws IOException {
+    super(directory, 0, "md", access, lockFactory);
+  }
+
+  public static final int HEADER_BYTE_SIZE = 1024;
+  public int getHeaderByteSize() {
+    return HEADER_BYTE_SIZE;
+  }
+
+  public static class Header extends FileHandler.Header {
+    /**
+     * File format version.
+     */
+    private int fileFormatVersion;
+
+    /**
+     * Current hashtable file id. -- will change after rehash.
+     */
+    private int currentHashtableId;
+
+    /** Current hash codes partition used for appending new postings */
+    private int currentHashCodesPartition;
+
+    /** Current keys partition used for appending new postings */
+    private int currentKeysPartition;
+
+    /** Current values partition used for appending new postings */
+    private int currentValuesPartition;
+
+    /**
+     * Total number of value postings.
+     */
+    private long valuePostingsCount;
+
+    /**
+     * Commit version, will increase by one after each modification to the database.
+     */
+    private long commitVersion;
+
+    public int getCurrentHashCodesPartition() {
+      return currentHashCodesPartition;
+    }
+
+    public void setCurrentHashCodesPartition(int currentHashCodesPartition) {
+      this.currentHashCodesPartition = currentHashCodesPartition;
+    }
+
+    public int getCurrentKeysPartition() {
+      return currentKeysPartition;
+    }
+
+    public void setCurrentKeysPartition(int currentKeysPartition) {
+      this.currentKeysPartition = currentKeysPartition;
+    }
+
+    public int getCurrentValuesPartition() {
+      return currentValuesPartition;
+    }
+
+    public void setCurrentValuesPartition(int currentValuesPartition) {
+      this.currentValuesPartition = currentValuesPartition;
+    }
+
+    public int getFileFormatVersion() {
+      return fileFormatVersion;
+    }
+
+    public void setFileFormatVersion(int fileFormatVersion) {
+      this.fileFormatVersion = fileFormatVersion;
+    }
+
+    public int getCurrentHashtableId() {
+      return currentHashtableId;
+    }
+
+    public void setCurrentHashtableId(int currentHashtableId) {
+      this.currentHashtableId = currentHashtableId;
+    }
+
+    public long getValuePostingsCount() {
+      return valuePostingsCount;
+    }
+
+    public void setValuePostingsCount(long valuePostingsCount) {
+      this.valuePostingsCount = valuePostingsCount;
+    }
+
+    public long getCommitVersion() {
+      return commitVersion;
+    }
+
+    public void setCommitVersion(long commitVersion) {
+      this.commitVersion = commitVersion;
+    }
+
+    public long increaseCommitVersion(long value) {
+      return commitVersion += value;
+    }
+
+    public long increaseValuePostingsCount(long value) {
+      return valuePostingsCount += value;
+    }
+
+    public long decreaseValuePostingsCount(long value) {
+      return valuePostingsCount -= value;
+    }
+
+  }
+
+  public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+    header.fileFormatVersion = RAF.readInt();
+    header.commitVersion = RAF.readLong();
+    header.currentHashtableId = RAF.readInt();
+    header.currentHashCodesPartition = RAF.readInt();
+    header.currentKeysPartition = RAF.readInt();
+    header.currentValuesPartition = RAF.readInt();
+    header.valuePostingsCount = RAF.readLong();
+    System.currentTimeMillis();
+  }
+
+  public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+    RAF.writeInt(header.fileFormatVersion);
+    RAF.writeLong(header.commitVersion);
+    RAF.writeInt(header.currentHashtableId);
+    RAF.writeInt(header.currentHashCodesPartition);
+    RAF.writeInt(header.currentKeysPartition);
+    RAF.writeInt(header.currentValuesPartition);
+    RAF.writeLong(header.valuePostingsCount);
+  }
+
+  public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    throw new UnsupportedOperationException();
+  }
+
+  public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    throw new UnsupportedOperationException();
+  }
+
+  public void deletePosting(int startOffset, RandomAccessFile RAF, long revision) throws IOException {
+    throw new UnsupportedOperationException();
+  }
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/HashCodesPartition.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/HashCodesPartition.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/HashCodesPartition.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/HashCodesPartition.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,239 @@
+package org.apache.labs.bananadb.store.data.bananatrie;
+
+/*
+ * 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.LockFactory;
+import org.apache.labs.bananadb.store.data.FileHandler;
+
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Hash code postings partition file.
+ * <p/>
+ * Chained postings. Each postings has a unique hash code value and points at how to find
+ * the key posting for this hash code.
+ * <p/>
+ * This file is affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:37
+ */
+public class HashCodesPartition extends FileHandler<HashCodesPartition.Header, HashCodesPartition.Posting> {
+
+  private int partitionId;
+
+  public HashCodesPartition(File directory, int partitionId, String access, LockFactory lockFactory) throws IOException {
+    super(directory, partitionId, "hc", access, lockFactory);
+    this.partitionId = partitionId;
+  }
+
+  public int getPartitionId() {
+    return partitionId;
+  }
+
+  public static final int HEADER_BYTE_SIZE = 1024;
+
+  public int getHeaderByteSize() {
+    return HEADER_BYTE_SIZE;
+  }
+
+  public static class Header extends FileHandler.Header {
+
+    /**
+     * Offset in this partition for next new posting.
+     */
+    private int nextPostingOffset;
+    /**
+     * Bytes left for use in this partition.
+     */
+    private int bytesLeft;
+
+    public int getNextPostingOffset() {
+      return nextPostingOffset;
+    }
+
+    public void setNextPostingOffset(int nextPostingOffset) {
+      this.nextPostingOffset = nextPostingOffset;
+    }
+
+    public int getBytesLeft() {
+      return bytesLeft;
+    }
+
+    public void setBytesLeft(int bytesLeft) {
+      this.bytesLeft = bytesLeft;
+    }
+
+
+  }
+
+  public static final int POSTING_BYTE_SIZE = 1 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
+
+  public static class Posting extends FileHandler.Posting {
+
+    public int getPostingByteSize() {
+      return POSTING_BYTE_SIZE;
+    }
+
+    /**
+     * 0 = never used
+     * 1 = in use
+     * 2 = deleted
+     */
+    private byte flag;
+
+    /**
+     * Key hash code.
+     */
+    private long keyHashCode;
+
+    private long createdRevision;
+
+
+    /**
+     * Partition id of next hash code posting with the same hashtable posting position.
+     * -1 == no more hash code postings in chain
+     */
+    private int nextPostingPartition;
+
+    /**
+     * Offset in above hash code postings partition.
+     */
+    private int nextPostingPartitionOffset;
+
+
+    /**
+     * Partition id of first key posting with this hash code.
+     */
+    private int firstKeyPostingPartition;
+
+    /**
+     * Offset in above key postings partition.
+     */
+    private int firstKeyPostingPartitionOffset;
+
+    private long deletedRevision = -1;
+
+
+    public byte getFlag() {
+      return flag;
+    }
+
+    public void setFlag(byte flag) {
+      this.flag = flag;
+    }
+
+    public long getKeyHashCode() {
+      return keyHashCode;
+    }
+
+    public void setKeyHashCode(long keyHashCode) {
+      this.keyHashCode = keyHashCode;
+    }
+
+    public int getNextPostingPartition() {
+      return nextPostingPartition;
+    }
+
+    public void setNextPostingPartition(int nextPostingPartition) {
+      this.nextPostingPartition = nextPostingPartition;
+    }
+
+    public int getNextPostingPartitionOffset() {
+      return nextPostingPartitionOffset;
+    }
+
+    public void setNextPostingPartitionOffset(int nextPostingPartitionOffset) {
+      this.nextPostingPartitionOffset = nextPostingPartitionOffset;
+    }
+
+    public int getFirstKeyPostingPartition() {
+      return firstKeyPostingPartition;
+    }
+
+    public void setFirstKeyPostingPartition(int firstKeyPostingPartition) {
+      this.firstKeyPostingPartition = firstKeyPostingPartition;
+    }
+
+    public int getFirstKeyPostingPartitionOffset() {
+      return firstKeyPostingPartitionOffset;
+    }
+
+    public void setFirstKeyPostingPartitionOffset(int firstKeyPostingPartitionOffset) {
+      this.firstKeyPostingPartitionOffset = firstKeyPostingPartitionOffset;
+    }
+
+    public long getCreatedRevision() {
+      return createdRevision;
+    }
+
+    public void setCreatedRevision(long createdRevision) {
+      this.createdRevision = createdRevision;
+    }
+
+    public long getDeletedRevision() {
+      return deletedRevision;
+    }
+
+    public void setDeletedRevision(long deletedRevision) {
+      this.deletedRevision = deletedRevision;
+    }
+  }
+
+  public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+    header.nextPostingOffset = RAF.readInt();
+    header.bytesLeft = RAF.readInt();
+  }
+
+  public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+    RAF.writeInt(header.nextPostingOffset);
+    RAF.writeInt(header.bytesLeft);
+  }
+
+
+  public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    posting.flag = RAF.readByte();
+    posting.keyHashCode = RAF.readLong();
+    posting.createdRevision = RAF.readLong();
+    posting.nextPostingPartition = RAF.readInt();
+    posting.nextPostingPartitionOffset = RAF.readInt();
+    posting.firstKeyPostingPartition = RAF.readInt();
+    posting.firstKeyPostingPartitionOffset = RAF.readInt();
+    posting.deletedRevision = RAF.readLong();
+  }
+
+  public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    RAF.writeByte(posting.flag);
+    RAF.writeLong(posting.keyHashCode);
+    RAF.writeLong(posting.createdRevision);
+    RAF.writeInt(posting.nextPostingPartition);
+    RAF.writeInt(posting.nextPostingPartitionOffset);
+    RAF.writeInt(posting.firstKeyPostingPartition);
+    RAF.writeInt(posting.firstKeyPostingPartitionOffset);
+    RAF.writeLong(posting.deletedRevision);
+  }
+
+  public void deletePosting(int startOffset, RandomAccessFile RAF, long revision) throws IOException {
+    RAF.seek(startOffset);
+    RAF.writeByte((byte) 2);
+    RAF.seek(8 + 4 + 4 + 4 + 4);
+    RAF.writeLong(revision);
+  }
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/Hashtable.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/Hashtable.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/Hashtable.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/Hashtable.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,193 @@
+package org.apache.labs.bananadb.store.data.bananatrie;
+
+/*
+ * 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.LockFactory;
+import org.apache.labs.bananadb.store.data.FileHandler;
+
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Hashtable file. There is never more than one of these that are valid at any given time.
+ * <p/>
+ * 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.
+ * <p/>
+ * This file is affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:56
+ */
+public class Hashtable extends FileHandler<Hashtable.Header, Hashtable.Posting> {
+
+
+  private int versionId;
+
+  /**
+   * header as when file was openend. used only to read capacity. but that is also all the header contains..
+   */
+  private Header header;
+
+  public Hashtable(File directory, int versionId, String access, LockFactory lockFactory) throws IOException {
+    super(directory, versionId, "ht", access, lockFactory);
+    this.versionId = versionId;
+  }
+
+  @Override
+  public void open() throws IOException {
+    super.open();
+    readHeader(header = new Header());
+  }
+
+  public int getVersionId() {
+    return versionId;
+  }
+
+  public static final int HEADER_BYTE_SIZE = 1024;
+
+  public int getHeaderByteSize() {
+    return HEADER_BYTE_SIZE;
+  }
+
+  public static class Header extends FileHandler.Header {
+    /**
+     * This hashtable postings file capacity.
+     */
+    private int postingsCapacity;
+
+    public int getPostingsCapacity() {
+      return postingsCapacity;
+    }
+
+    public void setPostingsCapacity(int postingsCapacity) {
+      this.postingsCapacity = postingsCapacity;
+    }
+  }
+
+
+  public static class Posting extends FileHandler.Posting {
+
+    public static final int POSTING_BYTE_SIZE = 1 + 8 + 4 + 4 + 8;
+
+    public int getPostingByteSize() {
+      return POSTING_BYTE_SIZE;
+    }
+
+    /**
+     * 0 = never used
+     * 1 = in use
+     * 2 = deleted
+     */
+    private byte flag;
+
+    private long createdRevision;
+
+    /**
+     * Partition id of first hash code posting with this hashtable position. -1 == null
+     */
+    private int hashCodePostingPartition;
+
+    /**
+     * Offset in above hash code postings partition.
+     */
+    private int hashCodePostingPartitionOffset;
+
+    private long deletedRevision = -1;
+
+    public byte getFlag() {
+      return flag;
+    }
+
+    public void setFlag(byte flag) {
+      this.flag = flag;
+    }
+
+    public int getHashCodePostingPartition() {
+      return hashCodePostingPartition;
+    }
+
+    public void setHashCodePostingPartition(int hashCodePostingPartition) {
+      this.hashCodePostingPartition = hashCodePostingPartition;
+    }
+
+    public int getHashCodePostingPartitionOffset() {
+      return hashCodePostingPartitionOffset;
+    }
+
+    public void setHashCodePostingPartitionOffset(int hashCodePostingPartitionOffset) {
+      this.hashCodePostingPartitionOffset = hashCodePostingPartitionOffset;
+    }
+
+    public long getCreatedRevision() {
+      return createdRevision;
+    }
+
+    public void setCreatedRevision(long createdRevision) {
+      this.createdRevision = createdRevision;
+    }
+
+    public long getDeletedRevision() {
+      return deletedRevision;
+    }
+
+    public void setDeletedRevision(long deletedRevision) {
+      this.deletedRevision = deletedRevision;
+    }
+  }
+
+  public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+    header.postingsCapacity = RAF.readInt();
+  }
+
+  public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+    RAF.writeInt(header.postingsCapacity);
+    this.header = new Header();
+    this.header.postingsCapacity = header.postingsCapacity;
+  }
+
+  public int calculateHashCodePostingOffset(long hashCode) {
+    return (int) (HEADER_BYTE_SIZE + (Posting.POSTING_BYTE_SIZE * (hashCode & (header.postingsCapacity - 1))));
+  }
+
+  public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    posting.flag = RAF.readByte();
+    posting.createdRevision = RAF.readLong();
+    posting.hashCodePostingPartition = RAF.readInt();
+    posting.hashCodePostingPartitionOffset = RAF.readInt();
+    posting.deletedRevision = RAF.readLong();
+  }
+
+  public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    RAF.writeByte(posting.flag);
+    RAF.writeLong(posting.createdRevision);
+    RAF.writeInt(posting.hashCodePostingPartition);
+    RAF.writeInt(posting.hashCodePostingPartitionOffset);
+    RAF.writeLong(posting.deletedRevision);
+  }
+
+  public void deletePosting(int startOffset, RandomAccessFile RAF, long revision) throws IOException {
+    RAF.seek(startOffset);
+    RAF.writeByte((byte) 2);
+    RAF.seek(8 + 4 + 4);
+    RAF.writeLong(revision);
+  }
+
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/KeysPartition.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/KeysPartition.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/KeysPartition.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/KeysPartition.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,274 @@
+package org.apache.labs.bananadb.store.data.bananatrie;
+
+/*
+ * 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.LockFactory;
+import org.apache.labs.bananadb.store.data.FileHandler;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.RandomAccessFile;
+
+/**
+ * Key postings partition file.
+ * <p/>
+ * Chained postings. Each posting contains a unique key value and points at how to
+ * find the value associated with this key.
+ * <p/>
+ * This file is NOT affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:22
+ */
+public class KeysPartition extends FileHandler<KeysPartition.Header, KeysPartition.Posting> {
+
+  private int partitionId;
+
+  public KeysPartition(File directory, int partitionId, String access, LockFactory lockFactory) throws IOException {
+    super(directory, partitionId, "k", access, lockFactory);
+    this.partitionId = partitionId;
+  }
+
+  public static final int HEADER_BYTE_SIZE = 1024;
+
+  public int getHeaderByteSize() {
+    return HEADER_BYTE_SIZE;
+  }
+
+  public int getPartitionId() {
+    return partitionId;
+  }
+
+  public static class Header extends FileHandler.Header {
+
+    /**
+     * Offset in this partition for next new posting.
+     */
+    private int nextPostingOffset;
+    /**
+     * Bytes left for use in this partition.
+     */
+    private int bytesLeft;
+
+    public int getNextPostingOffset() {
+      return nextPostingOffset;
+    }
+
+    public void setNextPostingOffset(int nextPostingOffset) {
+      this.nextPostingOffset = nextPostingOffset;
+    }
+
+    public int getBytesLeft() {
+      return bytesLeft;
+    }
+
+    public void setBytesLeft(int bytesLeft) {
+      this.bytesLeft = bytesLeft;
+    }
+  }
+
+  public static class Posting extends FileHandler.Posting {
+
+
+    /**
+     * 0 = never used
+     * 1 = in use
+     * 2 = deleted
+     */
+    private byte flag;
+
+    private long createdRevision;
+
+    /**
+     * Partition id of next key posting with the same hash code.
+     * -1 == end of keys chain
+     * -2 == deleted key
+     */
+    private int nextKeyPostingPartition;
+    /**
+     * Offset in above key postings partition.
+     */
+    private int nextKeyPostingPartitionOffset;
+
+    /**
+     * Key hash code
+     */
+    private long keyHashCode;
+
+    /**
+     * Paritition id of value posting. -1 == null
+     */
+    private int valuePostingPartition;
+    /**
+     * Offset in above value postings partition.
+     */
+    private int valuePostingPartitionOffset;
+
+    /**
+     * Length in bytes of serialized key.
+     */
+    private int bytesLength;
+    /**
+     * Serialized key
+     */
+    private byte[] bytes;
+
+    private long deletedRevision = -1;
+
+    public int getPostingByteSize() {
+      return 1 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + bytesLength + 8;
+    }
+
+    public byte getFlag() {
+      return flag;
+    }
+
+    public void setFlag(byte flag) {
+      this.flag = flag;
+    }
+
+    public int getNextKeyPostingPartition() {
+      return nextKeyPostingPartition;
+    }
+
+    public void setNextKeyPostingPartition(int nextKeyPostingPartition) {
+      this.nextKeyPostingPartition = nextKeyPostingPartition;
+    }
+
+    public int getNextKeyPostingPartitionOffset() {
+      return nextKeyPostingPartitionOffset;
+    }
+
+    public void setNextKeyPostingPartitionOffset(int nextKeyPostingPartitionOffset) {
+      this.nextKeyPostingPartitionOffset = nextKeyPostingPartitionOffset;
+    }
+
+    public long getKeyHashCode() {
+      return keyHashCode;
+    }
+
+    public void setKeyHashCode(long keyHashCode) {
+      this.keyHashCode = keyHashCode;
+    }
+
+    public int getValuePostingPartition() {
+      return valuePostingPartition;
+    }
+
+    public void setValuePostingPartition(int valuePostingPartition) {
+      this.valuePostingPartition = valuePostingPartition;
+    }
+
+    public int getValuePostingPartitionOffset() {
+      return valuePostingPartitionOffset;
+    }
+
+    public void setValuePostingPartitionOffset(int valuePostingPartitionOffset) {
+      this.valuePostingPartitionOffset = valuePostingPartitionOffset;
+    }
+
+    public int getBytesLength() {
+      return bytesLength;
+    }
+
+    public void setBytesLength(int bytesLength) {
+      this.bytesLength = bytesLength;
+    }
+
+    public byte[] getBytes() {
+      return bytes;
+    }
+
+    public void setBytes(byte[] bytes) {
+      this.bytes = bytes;
+    }
+
+    public long getCreatedRevision() {
+      return createdRevision;
+    }
+
+    public void setCreatedRevision(long createdRevision) {
+      this.createdRevision = createdRevision;
+    }
+
+    public long getDeletedRevision() {
+      return deletedRevision;
+    }
+
+    public void setDeletedRevision(long deletedRevision) {
+      this.deletedRevision = deletedRevision;
+    }
+  }
+
+  public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+    header.nextPostingOffset = RAF.readInt();
+    header.bytesLeft = RAF.readInt();
+  }
+
+  public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+    RAF.writeInt(header.nextPostingOffset);
+    RAF.writeInt(header.bytesLeft);
+  }
+
+  public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    posting.flag = RAF.readByte();
+    posting.createdRevision = RAF.readLong();
+    posting.nextKeyPostingPartition = RAF.readInt();
+    posting.nextKeyPostingPartitionOffset = RAF.readInt();
+    posting.keyHashCode = RAF.readLong();
+    posting.valuePostingPartition = RAF.readInt();
+    posting.valuePostingPartitionOffset = RAF.readInt();
+    posting.bytesLength = RAF.readInt();
+    if (posting.bytesLength > 0) {
+      if (posting.bytes == null || posting.bytes.length != posting.bytesLength) {
+        posting.bytes = new byte[posting.bytesLength];
+      }
+      int read = RAF.read(posting.bytes, 0, posting.bytesLength);
+      if (read != posting.bytesLength) {
+        throw new IOException("Unexcpected EOF");
+      }
+    }
+    posting.deletedRevision = RAF.readLong();
+  }
+
+  public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    RAF.writeByte(posting.flag);
+    RAF.writeLong(posting.createdRevision);
+    RAF.writeInt(posting.nextKeyPostingPartition);
+    RAF.writeInt(posting.nextKeyPostingPartitionOffset);
+    RAF.writeLong(posting.keyHashCode);
+    RAF.writeInt(posting.valuePostingPartition);
+    RAF.writeInt(posting.valuePostingPartitionOffset);
+    RAF.writeInt(posting.bytesLength);
+    if (posting.bytesLength > 0) {
+      RAF.write(posting.bytes, 0, posting.bytesLength);
+    }
+    RAF.writeLong(posting.deletedRevision);
+  }
+
+  public void deletePosting(int startOffset, RandomAccessFile RAF, long revision) throws IOException {
+    RAF.seek(startOffset);
+    RAF.writeByte((byte) 2);
+    RAF.skipBytes(8 + 4 + 4 + 8 + 4 + 4);
+    RAF.skipBytes(RAF.readInt());
+    RAF.writeLong(revision);
+  }
+
+
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/ValuesPartition.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/ValuesPartition.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/ValuesPartition.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/data/bananatrie/ValuesPartition.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,196 @@
+package org.apache.labs.bananadb.store.data.bananatrie;
+
+/*
+ * 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.LockFactory;
+import org.apache.labs.bananadb.store.data.FileHandler;
+
+import java.io.RandomAccessFile;
+import java.io.IOException;
+import java.io.File;
+
+/**
+ * Values postings partition file.
+ * <p/>
+ * This file is NOT affected by rehashing.
+ *
+ * @author kalle
+ * @since 2009-mar-16 14:00:13
+ */
+public class ValuesPartition extends FileHandler<ValuesPartition.Header, ValuesPartition.Posting> {
+
+
+  private int partitionId;
+
+  public ValuesPartition(File directory, int partitionId, String access, LockFactory lockFactory) throws IOException {
+    super(directory, partitionId, "v", access, lockFactory);
+    this.partitionId = partitionId;
+  }
+
+  public static final int HEADER_BYTE_SIZE = 1024;
+
+  public int getHeaderByteSize() {
+    return HEADER_BYTE_SIZE;
+  }
+
+  public int getPartitionId() {
+    return partitionId;
+  }
+
+
+  public static class Header extends FileHandler.Header {
+
+    /**
+     * Offset in this partition for next new posting.
+     */
+    private int nextPostingOffset;
+    /**
+     * Bytes left for use in this partition.
+     */
+    private int bytesLeft;
+
+    public int getNextPostingOffset() {
+      return nextPostingOffset;
+    }
+
+    public void setNextPostingOffset(int nextPostingOffset) {
+      this.nextPostingOffset = nextPostingOffset;
+    }
+
+    public int getBytesLeft() {
+      return bytesLeft;
+    }
+
+    public void setBytesLeft(int bytesLeft) {
+      this.bytesLeft = bytesLeft;
+    }
+  }
+
+  public static class Posting extends FileHandler.Posting {
+
+    /**
+     * 0 = never used
+     * 1 = in use
+     * 2 = deleted
+     */
+    private byte flag;
+
+    private long createdRevision;
+    private long deletedRevision = -1;
+
+    /**
+     * Length in bytes of serializaed value.
+     * 0 == null
+     */
+    private int bytesLength;
+
+    /**
+     * Serialized value.
+     */
+    private byte[] bytes;
+
+
+    public int getPostingByteSize() {
+      return 1 + 8 + 8 + 8 + 4 + bytesLength + 8;
+    }
+
+    public byte getFlag() {
+      return flag;
+    }
+
+    public void setFlag(byte flag) {
+      this.flag = flag;
+    }
+
+    public int getBytesLength() {
+      return bytesLength;
+    }
+
+    public void setBytesLength(int valueBytesLength) {
+      this.bytesLength = valueBytesLength;
+    }
+
+    public byte[] getBytes() {
+      return bytes;
+    }
+
+    public void setBytes(byte[] valueBytes) {
+      this.bytes = valueBytes;
+    }
+
+    public long getCreatedRevision() {
+      return createdRevision;
+    }
+
+    public void setCreatedRevision(long createdRevision) {
+      this.createdRevision = createdRevision;
+    }
+
+    public long getDeletedRevision() {
+      return deletedRevision;
+    }
+
+    public void setDeletedRevision(long deletedRevision) {
+      this.deletedRevision = deletedRevision;
+    }
+  }
+
+  public void readHeader(Header header, RandomAccessFile RAF) throws IOException {
+    header.nextPostingOffset = RAF.readInt();
+    header.bytesLeft = RAF.readInt();
+  }
+
+  public void writeHeader(Header header, RandomAccessFile RAF) throws IOException {
+    RAF.writeInt(header.nextPostingOffset);
+    RAF.writeInt(header.bytesLeft);
+  }
+
+  public void readPosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    posting.flag = RAF.readByte();
+    posting.createdRevision = RAF.readLong();
+    posting.bytesLength = RAF.readInt();
+    if (posting.bytesLength > 0) {
+      posting.bytes = new byte[posting.bytesLength];
+      int read = RAF.read(posting.bytes, 0, posting.bytesLength);
+      if (read != posting.bytesLength) {
+        throw new IOException("Unexpected EOF");
+      }
+    }
+    posting.deletedRevision = RAF.readLong();
+  }
+
+  public void writePosting(Posting posting, RandomAccessFile RAF) throws IOException {
+    RAF.writeByte(posting.flag);
+    RAF.writeLong(posting.createdRevision);
+    RAF.writeInt(posting.bytesLength);
+    if (posting.bytesLength > 0) {
+      RAF.write(posting.bytes, 0, posting.bytesLength);
+    }
+    RAF.writeLong(posting.deletedRevision);
+  }
+
+  public void deletePosting(int startOffset, RandomAccessFile RAF, long revision) throws IOException {
+    RAF.seek(startOffset);
+    RAF.writeByte((byte) 2);
+    RAF.skipBytes(8);
+    RAF.skipBytes(RAF.readInt());
+    RAF.writeLong(revision);
+  }
+
+}

Modified: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java?rev=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java (original)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/Lock.java Sun Mar 22 22:12:12 2009
@@ -19,8 +19,13 @@
 
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.Set;
 
-/** An interprocess mutex lock.
+/**
+ * An interprocess mutex lock.
  * <p>Typical use might look like:<pre>
  * new Lock.With(directory.makeLock("my.lock")) {
  *     public Object doBody() {
@@ -31,12 +36,22 @@
  */
 public abstract class Lock {
 
-  /** How long {@link #obtain(long)} waits, in milliseconds,
-   *  in between attempts to acquire the lock. */
+  private Set<LockListener> listeners = new LinkedHashSet<LockListener>();
+
+  public Set<LockListener> getListeners() {
+    return listeners;
+  }
+  
+  /**
+   * How long {@link #obtain(long)} waits, in milliseconds,
+   * in between attempts to acquire the lock.
+   */
   public static long LOCK_POLL_INTERVAL = 1000;
 
-  /** Pass this value to {@link #obtain(long)} to try
-   *  forever to obtain the lock. */
+  /**
+   * Pass this value to {@link #obtain(long)} to try
+   * forever to obtain the lock.
+   */
   public static final long LOCK_OBTAIN_WAIT_FOREVER = -1;
 
   /**
@@ -44,22 +59,32 @@
    */
   private AtomicInteger lockDepth = new AtomicInteger(0);
 
-  /** Attempts to obtain exclusive access and immediately return
-   *  upon success or failure.
+  /**
+   * Attempts to obtain exclusive access and immediately return
+   * upon success or failure.
+   *
    * @return true iff exclusive access is obtained
+   * @throws IOException
    */
   public final synchronized boolean obtain() throws IOException {
+    boolean obtained;
+    int depth = 0;
     if (lockDepth.get() > 0) {
-      lockDepth.incrementAndGet();
-      return true;
+      depth = lockDepth.incrementAndGet();
+      obtained = true;
+    } else if (obtained = doObtain()) {
+      depth = lockDepth.incrementAndGet();
     }
-    boolean obtained = doObtain();
+
     if (obtained) {
-      lockDepth.incrementAndGet();
+      for (LockListener listener : getListeners()) {
+        listener.obtained(this, depth);
+      }
     }
     return obtained;
   }
 
+
   protected abstract boolean doObtain() throws IOException;
 
 
@@ -70,18 +95,20 @@
    */
   protected Throwable failureReason;
 
-  /** Attempts to obtain an exclusive lock within amount of
-   *  time given. Polls once per {@link #LOCK_POLL_INTERVAL}
-   *  (currently 1000) milliseconds until lockWaitTimeout is
-   *  passed.
+  /**
+   * Attempts to obtain an exclusive lock within amount of
+   * time given. Polls once per {@link #LOCK_POLL_INTERVAL}
+   * (currently 1000) milliseconds until lockWaitTimeout is
+   * passed.
+   *
    * @param lockWaitTimeout length of time to wait in
-   *        milliseconds or {@link
-   *        #LOCK_OBTAIN_WAIT_FOREVER} to retry forever
+   *                        milliseconds or {@link
+   *                        #LOCK_OBTAIN_WAIT_FOREVER} to retry forever
    * @return true if lock was obtained
    * @throws LockObtainFailedException if lock wait times out
-   * @throws IllegalArgumentException if lockWaitTimeout is
-   *         out of bounds
-   * @throws IOException if obtain() throws IOException
+   * @throws IllegalArgumentException  if lockWaitTimeout is
+   *                                   out of bounds
+   * @throws IOException               if obtain() throws IOException
    */
   public boolean obtain(long lockWaitTimeout) throws LockObtainFailedException, IOException {
     failureReason = null;
@@ -113,57 +140,77 @@
     return locked;
   }
 
-  /** Releases exclusive access. */
+  /**
+   * Releases exclusive access.
+   */
   public final synchronized void release() throws IOException {
+    int depth = 0;
+    boolean released;
     if (lockDepth.get() > 1) {
-      lockDepth.decrementAndGet();
-      return;
-    }
-    if (doRelease()) {
-      lockDepth.decrementAndGet();
+      depth = lockDepth.decrementAndGet();
+      released = true;
+    } else if (released = doRelease()) {
+      depth  = lockDepth.decrementAndGet();
+    }
+    if (released) {
+      for (LockListener listener : getListeners()) {
+        listener.released(this, depth);
+      }
     }
+
   }
 
-  /** Releases exclusive access. */
+  /**
+   * Releases exclusive access.
+   */
   public abstract boolean doRelease() throws IOException;
 
 
-  /** Returns true if the resource is currently locked.  Note that one must
-   * still call {@link #obtain()} before using the resource. */
+  /**
+   * Returns true if the resource is currently locked.  Note that one must
+   * still call {@link #obtain()} before using the resource.
+   */
   public abstract boolean isLocked();
 
 
-  /** Utility class for executing code with exclusive access. */
+  /**
+   * Utility class for executing code with exclusive access.
+   */
   public abstract static class With<T> {
     private Lock lock;
-    private long lockWaitTimeout;
-
-
-    /** Constructs an executor that will grab the named lock. */
+    private long lockWaitTimeout;    
+    
+    /**
+     * Constructs an executor that will grab the named lock.
+     */
     public With(Lock lock, long lockWaitTimeout) {
       this.lock = lock;
       this.lockWaitTimeout = lockWaitTimeout;
     }
 
-    /** Code to execute with exclusive access. */
+    /**
+     * Code to execute with exclusive access.
+     */
     public abstract T doBody() throws IOException;
 
-    /** Calls {@link #doBody} while <i>lock</i> is obtained.  Blocks if lock
+    /**
+     * Calls {@link #doBody} while <i>lock</i> is obtained.  Blocks if lock
      * cannot be obtained immediately.  Retries to obtain lock once per second
      * until it is obtained, or until it has tried ten times. Lock is released when
      * {@link #doBody} exits.
+     *
      * @throws LockObtainFailedException if lock could not
-     * be obtained
-     * @throws IOException if {@link Lock#obtain} throws IOException
+     *                                   be obtained
+     * @throws IOException               if {@link Lock#obtain} throws IOException
      */
     public T run() throws LockObtainFailedException, IOException {
       boolean locked = false;
       try {
-         locked = lock.obtain(lockWaitTimeout);
-         return doBody();
+        locked = lock.obtain(lockWaitTimeout);
+        return doBody();
       } finally {
         if (locked)
-	      lock.release();
+          lock.release();
       }
     }
   }

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockListener.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockListener.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockListener.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/lock/LockListener.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,18 @@
+package org.apache.labs.bananadb.store.lock;
+
+/**
+ *
+ *
+ * @author kalle
+ * @since 2009-mar-21 03:04:07
+ */
+public interface LockListener {
+
+  public abstract void obtained(Lock lock, int depth);
+  public abstract void released(Lock lock, int depth);
+
+// todo this could be useful?
+//  public abstract void obtained(Lock.With lock, int depth);
+//  public abstract void released(Lock.With lock, int depth);
+
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/SequenceManager.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/SequenceManager.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/SequenceManager.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/SequenceManager.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,38 @@
+package org.apache.labs.bananadb.store.sequence;
+
+/**
+ * @author kalle
+ * @since 2009-mar-22 15:03:35
+ */
+public abstract class SequenceManager {
+
+
+  public abstract SequenceManager.Sequence.ReservedSequenceRange reserve(String name, int requestedSize);
+  public abstract void register(Sequence sequence);
+
+  public abstract <T> Sequence<T> sequenceFactory(Class<T> valueType, String name);
+
+  public abstract class Sequence<T> {
+
+    private String name;
+
+    protected Sequence(String name) {
+      this.name = name;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public abstract Class<T> getValueType();
+    public abstract ReservedSequenceRange<T> reserve(int requestedSize);
+    protected abstract void release(ReservedSequenceRange<T> reservation);
+
+    public abstract class ReservedSequenceRange<T> {
+      public abstract int size();
+      public abstract T nextValue();
+      public abstract boolean hasNextValue();
+    }
+
+  }
+}

Added: labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/StaticSequenceManager.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/StaticSequenceManager.java?rev=757265&view=auto
==============================================================================
--- labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/StaticSequenceManager.java (added)
+++ labs/bananadb/trunk/src/main/java/org/apache/labs/bananadb/store/sequence/StaticSequenceManager.java Sun Mar 22 22:12:12 2009
@@ -0,0 +1,100 @@
+package org.apache.labs.bananadb.store.sequence;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * For tests only!
+ *
+ * @author kalle
+ * @since 2009-mar-22 15:17:25
+ */
+public class StaticSequenceManager extends SequenceManager {
+
+  private Map<String, Sequence> sequences = new HashMap<String, Sequence>();
+
+  public SequenceManager.Sequence.ReservedSequenceRange reserve(String name, int requestedSize) {
+    return sequences.get(name).reserve(requestedSize);
+  }
+
+  public void register(Sequence sequence) {
+    Sequence old = sequences.get(sequence.getName());
+    if (old != null) {
+      throw new RuntimeException("Already contains a sequence with that name: " + sequence.toString());
+    }
+    sequences.put(sequence.getName(), sequence);
+  }
+
+  @SuppressWarnings("unchecked")
+  public <T> Sequence<T> sequenceFactory(Class<T> valueType, String name) {
+    if (valueType == Long.class) {
+      return  (Sequence<T>) new LongSequence(name);
+    }
+    throw new UnsupportedOperationException("Unregistred value type class " + valueType.getName());
+  }
+
+  public class LongSequence extends SequenceManager.Sequence<Long> {
+
+    protected LongSequence(String name) {
+      super(name);
+    }
+
+    private AtomicLong value = new AtomicLong();
+
+    public Class<Long> getValueType() {
+      return Long.class;
+    }
+
+    public ReservedSequenceRange<Long> reserve(int requestedSize) {
+      long start = value.addAndGet(requestedSize);
+      return new LongRange(start, start + requestedSize);
+    }
+
+    protected void release(ReservedSequenceRange<Long> reservation) {
+      // ignored
+    }
+
+    public class LongRange extends ReservedSequenceRange<Long> {
+
+      private long start;
+      private long end;
+      private long size;
+      private AtomicLong current;
+
+      protected LongRange(long start, long end) {
+        this.start = start;
+        this.end = end;
+        size = end - start;
+        current = new AtomicLong(start);
+      }
+
+      public boolean hasNextValue() {
+        return current.get() < end;
+      }
+
+      public Long nextValue() {
+        if (!hasNextValue()) {
+          throw new NoSuchElementException();
+        }
+        return current.incrementAndGet();
+      }
+
+      public int size() {
+        return (int) size;
+      }
+
+      @Override
+      public String toString() {
+        return "LongRange{" +
+            "start=" + start +
+            ", end=" + end +
+            ", size=" + size +
+            ", current=" + current +
+            '}';
+      }
+    }
+
+  }
+}

Modified: labs/bananadb/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/site/apt/index.apt?rev=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/site/apt/index.apt (original)
+++ labs/bananadb/trunk/src/site/apt/index.apt Sun Mar 22 22:12:12 2009
@@ -89,10 +89,12 @@
 
 Compared to other databases
 
- Banana DB is very similar to other key/value database implementations.
+ The Banana DB API is very similar to other key/value database implementations.
+
  The main reason for the existence of Banana DB
- is the lack of a key value database in Java
- that is distributed under the Apache Software License.
+ is the lack of a key value database implemented in Java
+ with a very simple consumer API
+ distributed under the Apache Software License.
  
  I am not a lawyer. Please double-check any information regarding licensing models mentioned below.
 
@@ -101,11 +103,14 @@
 
     {{{http://www.oracle.com/database/berkeley-db.html}http://www.oracle.com/database/berkeley-db.html}}
 
-    Berkeley DB and Banana DB is more or less the same thing if you leave out the fact they
-    use completly different underlying file formats. Berkeley DB is also ACID compliant
-    which Banana DB is not.
+    Berkeley DB is a key/value postings database with ancestry. 
+
+    The Banana DB entity store consumer API
+    is very similair to the Berkeley DB Java Edition consumer API.
+
+    Berkeley DB handles huge data dataset on HDD well, Banana DB does not.
 
-    The Banana DB entity store API is almost identical to the Berkeley DB Java Edition API.
+    Berkeley DB is ACID compliant which Banana DB is not.
 
     Berkeley DB has a dual license model.
 
@@ -123,11 +128,12 @@
     {{{http://jdbm.sourceforge.net/}http://jdbm.sourceforge.net/}}
 
     JDBM has similar features as Banana DB
-    but a more complex user API compared to Banana DB.
-    In addition, it also supports pluggable storage formats,
-    including B+Tree and HTree storage.
-    JDBM is also ACID compliant
-    which Banana DB is not.
+    but a more complex consumer API compared to Banana DB.
+
+    JDBM has a pluggable storage and include support complex data formats such as B+Tree and HTree
+    and thus handles huge data dataset on HDD well, Banana DB does not.
+
+    JDBM is ACID compliant which Banana DB is not.
 
     It is licensed with BSD open source license.
 

Modified: labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/store/StoreTest.java
URL: http://svn.apache.org/viewvc/labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/store/StoreTest.java?rev=757265&r1=757264&r2=757265&view=diff
==============================================================================
--- labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/store/StoreTest.java (original)
+++ labs/bananadb/trunk/src/test/java/org/apache/labs/bananadb/store/StoreTest.java Sun Mar 22 22:12:12 2009
@@ -21,6 +21,7 @@
 import junit.framework.TestCase;
 
 import java.io.File;
+import java.util.Random;
 
 import org.apache.commons.io.FileUtils;
 
@@ -50,4 +51,29 @@
     return path;
   }
 
+  protected byte[][] keys;
+  protected long[] hashes;
+  protected byte[][] values;
+
+
+  protected void randomizeKeyValues(int items) {
+
+    long seed = System.currentTimeMillis();
+    System.err.println("seed = " + seed);
+    Random random = new Random(seed);
+
+
+    keys = new byte[items][];
+    hashes = new long[items];
+    values = new byte[items][];
+
+    for (int i = 0; i < items; i++) {
+      keys[i] = new byte[random.nextInt(10)+1];
+      random.nextBytes(keys[i]);
+      hashes[i] = random.nextLong();
+      values[i] = new byte[random.nextInt(1000)];
+      random.nextBytes(values[i]);
+    }
+  }
+
 }



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