You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2014/05/16 19:28:23 UTC

svn commit: r1595272 - in /directory/mavibot/branches/with-txns/mavibot/src: main/java/org/apache/directory/mavibot/btree/ test/java/org/apache/directory/mavibot/btree/

Author: elecharny
Date: Fri May 16 17:28:23 2014
New Revision: 1595272

URL: http://svn.apache.org/r1595272
Log:
Added the code that allows us to gather all the updates made on many BTrees within one data structure globally validated when we commit a transaction.
o We now have a Map containing the current revisions of all the btrees, and a Map containing the new revisions
o Added some check to protect the user against operations done on a BTree without recordManager
o Committing the transaction for a delete operation (this was missing)
o We don't anymore start a transaction for subBtrees : it's useless
o Added a helper method to get the btreeHeader
o Removed useless imports
o Injected the BTree into InMemory BtreeHeaders
o Fixed the way we were updating the subBtrees
o Fixed a failing test
o Added some comment and javadoc


Modified:
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
    directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java
    directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java Fri May 16 17:28:23 2014
@@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentLi
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
 
@@ -47,8 +48,8 @@ import org.apache.directory.mavibot.btre
     /** The read transaction timeout */
     protected long readTimeOut = DEFAULT_READ_TIMEOUT;
 
-    /** The copied Header for a managed BTree */
-    //protected BTreeHeader<K, V> newBtreeHeader = new BTreeHeader<K, V>();
+    /** The current Header for a managed BTree */
+    protected BTreeHeader<K, V> currentBtreeHeader;
 
     /** The Key serializer used for this tree.*/
     protected ElementSerializer<K> keySerializer;
@@ -118,6 +119,12 @@ import org.apache.directory.mavibot.btre
      */
     public TupleCursor<K, V> browse() throws IOException, KeyNotFoundException
     {
+        // Check that we have a TransactionManager
+        if ( transactionManager == null )
+        {
+            throw new BTreeCreationException( "We don't have a transactionLManager" );
+        }
+        
         ReadTransaction<K, V> transaction = beginReadTransaction();
 
         if ( transaction == null )
@@ -272,9 +279,25 @@ import org.apache.directory.mavibot.btre
             throw new IllegalArgumentException( "Key must not be null" );
         }
 
-        Tuple<K, V> deleted = delete( key, currentRevision.get() + 1 );
+        // Take the lock if it's not already taken by another thread
+        transactionManager.beginTransaction();
+
+        try
+        {
+            Tuple<K, V> deleted = delete( key, currentRevision.get() + 1 );
+
+            // Commit now
+            transactionManager.commit();
 
-        return deleted;
+            return deleted;
+        }
+        catch ( IOException ioe )
+        {
+            // We have had an exception, we must rollback the transaction
+            transactionManager.rollback();
+            
+            return null;
+        }
     }
 
 
@@ -340,8 +363,12 @@ import org.apache.directory.mavibot.btre
             throw new IllegalArgumentException( "Key must not be null" );
         }
 
-        // Take the lock if it's not already taken by another thread
-        transactionManager.beginTransaction();
+        // Take the lock if it's not already taken by another thread and if we 
+        // aren't on a sub-btree
+        if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+        {
+            transactionManager.beginTransaction();
+        }
         
         try
         {
@@ -352,15 +379,22 @@ import org.apache.directory.mavibot.btre
                 existingValue = ( ( ModifyResult<K, V> ) result ).getModifiedValue();
             }
             
-            // Commit now
-            transactionManager.commit();
+            // Commit now if it's not a sub-btree
+            if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+            {
+                transactionManager.commit();
+            }
     
             return existingValue;
         }
         catch ( IOException ioe )
         {
             // We have had an exception, we must rollback the transaction
-            transactionManager.rollback();
+            // if it's not a sub-btree
+            if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+            {
+                transactionManager.rollback();
+            }
             
             return null;
         }
@@ -615,7 +649,33 @@ import org.apache.directory.mavibot.btre
      */
     /* no qualifier */void setRevision( long revision )
     {
-        getBtreeHeader().setRevision( revision );
+        transactionManager.getBTreeHeader( getName() ).setRevision( revision );
+    }
+
+
+    /**
+     * Store the new revision in the map of btrees, increment the current revision
+     */
+    protected void storeRevision( BTreeHeader<K, V> btreeHeader, boolean keepRevisions )
+    {
+        long revision = btreeHeader.getRevision();
+
+        if ( keepRevisions )
+        {
+            synchronized ( btreeRevisions )
+            {
+                btreeRevisions.put( revision, btreeHeader );
+            }
+        }
+
+        currentRevision.set( revision );
+        currentBtreeHeader = btreeHeader;
+        
+        // And update the newBTreeHeaders map
+        if ( btreeHeader.getBtree().getType() != BTreeTypeEnum.PERSISTED_SUB )
+        {
+            transactionManager.updateNewBTreeHeaders( btreeHeader );
+        }
     }
 
 
@@ -632,6 +692,13 @@ import org.apache.directory.mavibot.btre
         }
 
         currentRevision.set( revision );
+        currentBtreeHeader = btreeHeader;
+        
+        // And update the newBTreeHeaders map
+        if ( btreeHeader.getBtree().getType() != BTreeTypeEnum.PERSISTED_SUB )
+        {
+            transactionManager.updateNewBTreeHeaders( btreeHeader );
+        }
     }
 
 
@@ -683,7 +750,7 @@ import org.apache.directory.mavibot.btre
      */
     /* no qualifier */void setNbElems( long nbElems )
     {
-        getBtreeHeader().setNbElems( nbElems );
+        transactionManager.getBTreeHeader( getName() ).setNbElems( nbElems );
     }
 
 
@@ -815,13 +882,7 @@ import org.apache.directory.mavibot.btre
      */
     protected BTreeHeader<K, V> getBtreeHeader()
     {
-        synchronized ( btreeRevisions )
-        {
-            long revision = currentRevision.get();
-            BTreeHeader<K, V> btreeHeader = btreeRevisions.get( revision );
-
-            return btreeHeader;
-        }
+        return currentBtreeHeader;
     }
 
 

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java Fri May 16 17:28:23 2014
@@ -31,5 +31,4 @@ public abstract class AbstractTransactio
 {
     /** A lock to protect the transaction handling */
     private ReadWriteLock transactionLock = new ReentrantReadWriteLock();
-
 }

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java Fri May 16 17:28:23 2014
@@ -20,7 +20,6 @@
 package org.apache.directory.mavibot.btree;
 
 
-import java.lang.reflect.Field;
 import java.util.LinkedList;
 
 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java Fri May 16 17:28:23 2014
@@ -138,6 +138,7 @@ import org.slf4j.LoggerFactory;
         newBtreeHeader.setRootPageOffset( 0L );
 
         btreeRevisions.put( 0L,  newBtreeHeader );
+        currentBtreeHeader = newBtreeHeader;
 
         // Now, initialize the BTree
         try
@@ -212,6 +213,7 @@ import org.slf4j.LoggerFactory;
             // This is a new Btree, we have to store the BtreeHeader
             BTreeHeader<K, V> btreeHeader = new BTreeHeader<K, V>();
             btreeHeader.setRootPage( new InMemoryLeaf<K, V>( this ) );
+            btreeHeader.setBtree( this );
             storeRevision( btreeHeader );
         }
 
@@ -297,6 +299,7 @@ import org.slf4j.LoggerFactory;
 
         BTreeHeader<K, V> oldBtreeHeader = getBtreeHeader();
         BTreeHeader<K, V> newBtreeHeader = createNewBtreeHeader( oldBtreeHeader, revision );
+        newBtreeHeader.setBtree( this );
 
         // If the key exists, the existing value will be replaced. We store it
         // to return it to the caller.
@@ -375,6 +378,7 @@ import org.slf4j.LoggerFactory;
 
         BTreeHeader<K, V> oldBtreeHeader = getBtreeHeader();
         BTreeHeader<K, V> newBtreeHeader = createNewBtreeHeader( oldBtreeHeader, revision );
+        newBtreeHeader.setBtree( this );
 
         // If the key exists, the existing value will be replaced. We store it
         // to return it to the caller.

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java Fri May 16 17:28:23 2014
@@ -19,11 +19,12 @@
  */
 package org.apache.directory.mavibot.btree;
 
-import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantLock;
-
-import org.apache.directory.mavibot.btree.exception.RecordManagerException;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 /**
  * An implementation of a TransactionManager for in-memory B-trees
@@ -37,6 +38,15 @@ public class InMemoryTransactionManager 
     
     /** A ThreadLocalStorage used to store the current transaction */
     private static final ThreadLocal<Integer> context = new ThreadLocal<Integer>();
+    
+    /** A Map keeping the latest revisions for each managed BTree */
+    private Map<String, BTreeHeader<?, ?>> currentBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+    /** A Map storing the new revisions when some change have been made in some BTrees */
+    private Map<String, BTreeHeader<?, ?>> newBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+    
+    /** A lock to protect the BtreeHeader maps */
+    private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
 
     /**
      * {@inheritDoc}
@@ -101,4 +111,33 @@ public class InMemoryTransactionManager 
         // Finally, release the global lock
         transactionLock.unlock();
     }
+    
+    
+    /**
+     * Get the current BTreeHeader for a given Btree. It might not exist
+     */
+    public BTreeHeader getBTreeHeader( String name )
+    {
+        // Get a lock
+        btreeHeadersLock.readLock().lock();
+        
+        // get the current BTree Header for this BTree and revision
+        BTreeHeader<?, ?> btreeHeader = currentBTreeHeaders.get( name );
+        
+        // And unlock 
+        btreeHeadersLock.readLock().unlock();
+
+        return btreeHeader;
+    }
+
+
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
+    {
+        newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
+    }
 }

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java Fri May 16 17:28:23 2014
@@ -125,19 +125,28 @@ public class PersistedBTree<K, V> extend
         btreeHeader.setRootPage( rootPage );
         btreeHeader.setBtree( this );
 
-        if ( btreeType == BTreeTypeEnum.PERSISTED_SUB )
-        {
-            // The subBTree inherits its cache and readTransactions from its parent BTree
-            init( ( PersistedBTree<K, V> ) configuration.getParentBTree() );
-        }
-        else
+        switch ( btreeType )
         {
-            // We will create a new cache and a new readTransactions map 
-            init( null );
-        }
+            case BTREE_OF_BTREES :
+            case COPIED_PAGES_BTREE :
+                // We will create a new cache and a new readTransactions map 
+                init( null );
+                currentBtreeHeader = btreeHeader;
+                break;
 
-        // Add the B-tree header into the revisions
-        btreeRevisions.put( 0L, btreeHeader );
+            case PERSISTED_SUB :
+                init( ( PersistedBTree<K, V> ) configuration.getParentBTree() );
+                btreeRevisions.put( 0L, btreeHeader );
+                currentBtreeHeader = btreeHeader;
+                break;
+                
+            default :
+                // We will create a new cache and a new readTransactions map 
+                init( null );
+                btreeRevisions.put( 0L, btreeHeader );
+                currentBtreeHeader = btreeHeader;
+                break;
+        }
     }
 
 
@@ -221,7 +230,7 @@ public class PersistedBTree<K, V> extend
      */
     /* No qualifier*/long getBtreeOffset()
     {
-        return getBtreeHeader().getBTreeHeaderOffset();
+        return getBTreeHeader( getName() ).getBTreeHeaderOffset();
     }
 
 
@@ -230,7 +239,7 @@ public class PersistedBTree<K, V> extend
      */
     /* No qualifier*/void setBtreeHeaderOffset( long btreeHeaderOffset )
     {
-        getBtreeHeader().setBTreeHeaderOffset( btreeHeaderOffset );
+        getBTreeHeader( getName() ).setBTreeHeaderOffset( btreeHeaderOffset );
     }
 
 
@@ -239,7 +248,7 @@ public class PersistedBTree<K, V> extend
      */
     /* No qualifier*/long getRootPageOffset()
     {
-        return getBtreeHeader().getRootPageOffset();
+        return getBTreeHeader( getName() ).getRootPageOffset();
     }
 
 
@@ -328,7 +337,7 @@ public class PersistedBTree<K, V> extend
     private DeleteResult<K, V> processDelete( K key, V value, long revision ) throws IOException
     {
         // Get the current B-tree header, and delete the value from it
-        BTreeHeader<K, V> btreeHeader = getBtreeHeader();
+        BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
 
         // Try to delete the entry starting from the root page. Here, the root
         // page may be either a Node or a Leaf
@@ -385,7 +394,18 @@ public class PersistedBTree<K, V> extend
                 recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
 
                 // Store the new revision
-                storeRevision( newBtreeHeader );
+                storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+                break;
+                
+            case PERSISTED_SUB :
+                // Sub-B-trees are only updating the CopiedPage B-tree
+                recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
+                
+                //btreeRevisions.put( revision, newBtreeHeader );
+
+                currentRevision.set( revision );
+
 
                 break;
 
@@ -397,7 +417,7 @@ public class PersistedBTree<K, V> extend
                 recordManager.freePages( this, revision, result.getCopiedPages() );
 
                 // Store the new revision
-                storeRevision( newBtreeHeader );
+                storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
 
                 break;
 
@@ -409,7 +429,7 @@ public class PersistedBTree<K, V> extend
                 recordManager.freePages( this, revision, result.getCopiedPages() );
 
                 // Store the new revision
-                storeRevision( newBtreeHeader );
+                storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
 
                 break;
 
@@ -461,6 +481,18 @@ public class PersistedBTree<K, V> extend
         }
     }
 
+    
+    private BTreeHeader<K, V> getBTreeHeader( String name )
+    {
+        if ( btreeType == BTreeTypeEnum.PERSISTED_SUB )
+        {
+            return getBtreeHeader();
+        }
+        
+        BTreeHeader<K, V> btreeHeader = recordManager.getBTreeHeader( getName() );
+
+        return btreeHeader;
+    }
 
     /**
      * Insert the tuple into the B-tree rootPage, get back the new rootPage
@@ -468,7 +500,7 @@ public class PersistedBTree<K, V> extend
     private InsertResult<K, V> processInsert( K key, V value, long revision ) throws IOException
     {
         // Get the current B-tree header, and insert the value into it
-        BTreeHeader<K, V> btreeHeader = getBtreeHeader();
+        BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
         InsertResult<K, V> result = btreeHeader.getRootPage().insert( key, value, revision );
 
         // Create a new BTreeHeader
@@ -544,7 +576,7 @@ public class PersistedBTree<K, V> extend
                 recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
 
                 // Store the new revision
-                storeRevision( newBtreeHeader );
+                storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
 
                 break;
 
@@ -552,12 +584,12 @@ public class PersistedBTree<K, V> extend
                 // Sub-B-trees are only updating the CopiedPage B-tree
                 recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
                 
-                //btreeRevisions.clear();
-                
-                btreeRevisions.put( revision, newBtreeHeader );
+                //btreeRevisions.put( revision, newBtreeHeader );
 
-                currentRevision.set( revision );
+                // Store the new revision
+                storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
 
+                currentRevision.set( revision );
 
                 break;
 
@@ -569,7 +601,7 @@ public class PersistedBTree<K, V> extend
                 recordManager.freePages( this, revision, result.getCopiedPages() );
 
                 // Store the new revision
-                storeRevision( newBtreeHeader );
+                storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
 
                 break;
 
@@ -581,7 +613,7 @@ public class PersistedBTree<K, V> extend
                 recordManager.freePages( this, revision, result.getCopiedPages() );
 
                 // Store the new revision
-                storeRevision( newBtreeHeader );
+                storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
 
                 break;
 
@@ -667,13 +699,13 @@ public class PersistedBTree<K, V> extend
      */
     public Page<K, V> getRootPage()
     {
-        return getBtreeHeader().getRootPage();
+        return getBTreeHeader( getName() ).getRootPage();
     }
 
 
     /* no qualifier */void setRootPage( Page<K, V> root )
     {
-        getBtreeHeader().setRootPage( root );
+        getBTreeHeader( getName() ).setRootPage( root );
     }
 
 
@@ -700,7 +732,7 @@ public class PersistedBTree<K, V> extend
      */
     protected ReadTransaction<K, V> beginReadTransaction()
     {
-        BTreeHeader<K, V> btreeHeader = getBtreeHeader();
+        BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
 
         ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( recordManager, btreeHeader, readTransactions );
 
@@ -743,9 +775,9 @@ public class PersistedBTree<K, V> extend
         sb.append( "[" ).append( getName() ).append( "]" );
         sb.append( "( pageSize:" ).append( getPageSize() );
 
-        if ( getBtreeHeader().getRootPage() != null )
+        if ( getBTreeHeader( getName() ).getRootPage() != null )
         {
-            sb.append( ", nbEntries:" ).append( getBtreeHeader().getNbElems() );
+            sb.append( ", nbEntries:" ).append( getBTreeHeader( getName() ).getNbElems() );
         }
         else
         {
@@ -766,7 +798,7 @@ public class PersistedBTree<K, V> extend
         sb.append( ", DuplicatesAllowed: " ).append( isAllowDuplicates() );
 
         sb.append( ") : \n" );
-        sb.append( getBtreeHeader().getRootPage().dumpPage( "" ) );
+        sb.append( getBTreeHeader( getName() ).getRootPage().dumpPage( "" ) );
 
         return sb.toString();
     }

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java Fri May 16 17:28:23 2014
@@ -255,6 +255,7 @@ import org.apache.directory.mavibot.btre
 
             try
             {
+                // The sub-btree will not be added into the BOB.
                 parentBtree.getRecordManager().manage( valueBtree, RecordManager.INTERNAL_BTREE );
                 raw = null;
             }

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java Fri May 16 17:28:23 2014
@@ -36,7 +36,9 @@ import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
 import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
@@ -192,7 +194,16 @@ public class RecordManager extends Abstr
 
     /** The list of PageIO that can be freed after a roolback */
     private List<PageIO> allocatedPages = new ArrayList<PageIO>();
+    
+    /** A Map keeping the latest revisions for each managed BTree */
+    private Map<String, BTreeHeader<?, ?>> currentBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
 
+    /** A Map storing the new revisions when some change have been made in some BTrees */
+    private Map<String, BTreeHeader<?, ?>> newBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+    
+    /** A lock to protect the BtreeHeader maps */
+    private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
+    
     /**
      * Create a Record manager which will either create the underlying file
      * or load an existing one. If a folder is provided, then we will create
@@ -351,12 +362,20 @@ public class RecordManager extends Abstr
 
             currentBtreeOfBtreesOffset = ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader().getBTreeHeaderOffset();
             updateRecordManagerHeader();
+            
+            // Inject the BtreeOfBtrees into the currentBtreeHeaders map
+            currentBTreeHeaders.put( BTREE_OF_BTREES_NAME,  ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader() );
+            newBTreeHeaders.put( BTREE_OF_BTREES_NAME,  ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader() );
 
             // The FreePage B-tree
             manage( copiedPageBtree, INTERNAL_BTREE );
 
             currentCopiedPagesBtreeOffset = ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader().getBTreeHeaderOffset();
             updateRecordManagerHeader();
+            
+            // Inject the CopiedPagesBTree into the currentBtreeHeaders map
+            currentBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader() );
+            newBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader() );
         }
         catch ( BTreeAlreadyManagedException btame )
         {
@@ -560,55 +579,96 @@ public class RecordManager extends Abstr
      */
     public void commit()
     {
-        int nbTxnStarted = context.get();
-        
-        if ( nbTxnStarted == 0 )
+        if ( !fileChannel.isOpen() )
         {
-            // The transaction was rollbacked, quit immediatelly
+            // The file has been closed, nothing remains to commit, let's get out
             transactionLock.unlock();
-            
             return;
         }
-        else
+
+        int nbTxnStarted = context.get();
+        
+        switch ( nbTxnStarted )
         {
-            if ( !fileChannel.isOpen() )
-            {
-                // The file has been closed, nothing remains to commit, let's get out
+            case 0 :
+                // The transaction was rollbacked, quit immediatelly
                 transactionLock.unlock();
+                
                 return;
-            }
-    
-            // We are done with the transaction
-            // First update the RMHeader to be sure that we have a way to restore from a crash
-            updateRecordManagerHeader();
-    
-            // We can now free pages
-            for ( PageIO pageIo : freedPages )
-            {
-                try
+            
+            case 1 :
+                // We are done with the transaction, we can update the RMHeader and swap the BTreeHeaders
+                // First update the RMHeader to be sure that we have a way to restore from a crash
+                updateRecordManagerHeader();
+                
+                // Swap the BtreeHeaders maps
+                swapCurrentBtreeHeaders();
+        
+                // We can now free pages
+                for ( PageIO pageIo : freedPages )
                 {
-                    free( pageIo );
+                    try
+                    {
+                        free( pageIo );
+                    }
+                    catch ( IOException ioe )
+                    {
+                        throw new RecordManagerException( ioe.getMessage() );
+                    }
                 }
-                catch ( IOException ioe )
+        
+                // Release the allocated and freed pages list
+                freedPages.clear();
+                allocatedPages.clear();
+        
+                // And update the RMHeader again, removing the old references to BOB and CPB b-tree headers
+                // here, we have to erase the old references to keep only the new ones.
+                updateRecordManagerHeader();
+                
+                // And decrement the number of started transactions
+                context.set( nbTxnStarted - 1 );
+
+                // Finally, release the global lock
+                transactionLock.unlock();
+                
+                return;
+                
+            default :
+                // We are inner an existing transaction. Just update the necessary elements
+                // Update the RMHeader to be sure that we have a way to restore from a crash
+                updateRecordManagerHeader();
+                
+                // Swap the BtreeHeaders maps
+                swapCurrentBtreeHeaders();
+        
+                // We can now free pages
+                for ( PageIO pageIo : freedPages )
                 {
-                    throw new RecordManagerException( ioe.getMessage() );
+                    try
+                    {
+                        free( pageIo );
+                    }
+                    catch ( IOException ioe )
+                    {
+                        throw new RecordManagerException( ioe.getMessage() );
+                    }
                 }
-            }
-    
-            // Release the allocated and freed pages list
-            freedPages.clear();
-            allocatedPages.clear();
-    
-            // And update the RMHeader again, removing the old references to BOB and CPB b-tree headers
-            // here, we have to erase the old references to keep only the new ones.
-            updateRecordManagerHeader();
-            
-            // And decrement the number of started transactions
-            context.set( nbTxnStarted - 1 );
-        }
+        
+                // Release the allocated and freed pages list
+                freedPages.clear();
+                allocatedPages.clear();
+        
+                // And update the RMHeader again, removing the old references to BOB and CPB b-tree headers
+                // here, we have to erase the old references to keep only the new ones.
+                updateRecordManagerHeader();
+                
+                // And decrement the number of started transactions
+                context.set( nbTxnStarted - 1 );
 
-        // Finally, release the global lock
-        transactionLock.unlock();
+                // Finally, release the global lock
+                transactionLock.unlock();
+                return;
+        }
     }
 
 
@@ -639,6 +699,9 @@ public class RecordManager extends Abstr
 
         // And update the RMHeader
         updateRecordManagerHeader();
+        
+        // And restore the BTreeHeaders new Map to the current state
+        revertBtreeHeaders();
 
         transactionLock.unlock();
     }
@@ -824,12 +887,20 @@ public class RecordManager extends Abstr
         ( ( PersistedBTree<K, V> ) btree ).setAllowDuplicates( allowDuplicates != 0 );
         dataPos += INT_SIZE;
 
+        // Set the recordManager in the btree
+        ( ( PersistedBTree<K, V> ) btree ).setRecordManager( this );
+
         // Set the current revision to the one stored in the B-tree header
-        ((PersistedBTree<K, V>)btree).storeRevision( btreeHeader );
+        // Here, we have to tell the BTree to keep this revision in the
+        // btreeRevisions Map, thus the 'true' parameter at the end.
+        ((PersistedBTree<K, V>)btree).storeRevision( btreeHeader, true );
 
         // Now, init the B-tree
-        ( ( PersistedBTree<K, V> ) btree ).setRecordManager( this );
         ( ( PersistedBTree<K, V> ) btree ).init( parentBTree );
+        
+        // Update the BtreeHeaders Maps
+        currentBTreeHeaders.put( btree.getName(), ( ( PersistedBTree<K, V> ) btree ).getBtreeHeader() );
+        newBTreeHeaders.put( btree.getName(), ( ( PersistedBTree<K, V> ) btree ).getBtreeHeader() );
 
         // Read the rootPage pages on disk
         PageIO[] rootPageIos = readPageIOs( rootPageOffset, Long.MAX_VALUE );
@@ -1341,6 +1412,10 @@ public class RecordManager extends Abstr
         {
             // Add the btree into the map of managed B-trees
             managedBtrees.put( name, ( BTree<Object, Object> ) btree );
+            
+            // And in the Map of currentBtreeHeaders and newBtreeHeaders
+            currentBTreeHeaders.put( name, btreeHeader );
+            newBTreeHeaders.put( name, btreeHeader );
 
             // We can safely increment the number of managed B-trees
             nbBtree++;
@@ -1859,7 +1934,7 @@ public class RecordManager extends Abstr
         btreeOfBtrees.insert( nameRevision, btreeHeaderOffset );
 
         // Update the B-tree of B-trees
-        currentBtreeOfBtreesOffset = ((AbstractBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader().getBTreeHeaderOffset();
+        currentBtreeOfBtreesOffset = getBTreeHeader( BTREE_OF_BTREES_NAME ).getBTreeHeaderOffset();
     }
 
 
@@ -3527,11 +3602,79 @@ public class RecordManager extends Abstr
         RevisionName revisionName = new RevisionName( 
             readTransaction.getRevision(), 
             readTransaction.getBtreeHeader().getBtree().getName() );
-        closedTransactionsQueue.add( revisionName );
+        //closedTransactionsQueue.add( revisionName );
+    }
+    
+    
+    /**
+     * Get the current BTreeHeader for a given Btree. It might not exist
+     */
+    public BTreeHeader getBTreeHeader( String name )
+    {
+        // Get a lock
+        btreeHeadersLock.readLock().lock();
+        
+        // get the current BTree Header for this BTree and revision
+        BTreeHeader<?, ?> btreeHeader = currentBTreeHeaders.get( name );
+        
+        // And unlock 
+        btreeHeadersLock.readLock().unlock();
+
+        return btreeHeader;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
+    {
+        newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
+    }
+    
+    
+    /**
+     * Swap the current BtreeHeader map with the new one. This method will only
+     * be called in a single trhead, when the current transaction will be committed.
+     */
+    private void swapCurrentBtreeHeaders()
+    {
+        // Copy the reference to the current BtreeHeader Map
+        Map<String, BTreeHeader<?, ?>> tmp = currentBTreeHeaders;
+        
+        // Get a write lock
+        btreeHeadersLock.writeLock().lock();
+
+        // Swap the new BTreeHeader Map
+        currentBTreeHeaders = newBTreeHeaders;
+        
+        // And unlock 
+        btreeHeadersLock.writeLock().unlock();
+
+        // Last, not least, clear the Map and reinject the latest revision in it
+        tmp.clear();
+        tmp.putAll( currentBTreeHeaders );
+
+        // And update the new BTreeHeader map
+        newBTreeHeaders = tmp;
     }
     
     
     /**
+     * revert the new BTreeHeaders Map to the current BTreeHeader Map. This method
+     * is called when we have to rollback a transaction.
+     */
+    private void revertBtreeHeaders()
+    {
+        // Clean up teh new BTreeHeaders Map
+        newBTreeHeaders.clear();
+        
+        // Reinject the latest revision in it
+        newBTreeHeaders.putAll( currentBTreeHeaders );
+    }
+
+    
+    /**
      * Loads a B-tree holding the values of a duplicate key
      * This tree is also called as dups tree or sub tree
      *

Modified: directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java Fri May 16 17:28:23 2014
@@ -43,4 +43,21 @@ public interface TransactionManager
      * Rollback a transaction
      */
     void rollback();
+    
+    
+    /**
+     * Gets the current BtreeHeader for a given BTree.
+     * 
+     * @param btreeName The Btree name we are looking the BtreeHeader for
+     * @return the current BTreeHeader
+     */
+    BTreeHeader<?, ?> getBTreeHeader( String btreeName );
+    
+    
+    /**
+     * Updates the map of new BTreeHeaders
+     * 
+     * @param btreeHeader The new BtreeHeader
+     */
+    void updateNewBTreeHeaders( BTreeHeader<?, ?> btreeHeader );
 }

Modified: directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java?rev=1595272&r1=1595271&r2=1595272&view=diff
==============================================================================
--- directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java (original)
+++ directory/mavibot/branches/with-txns/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java Fri May 16 17:28:23 2014
@@ -142,11 +142,14 @@ public class PersistedBTreeDuplicateKeyT
 
 
     @Test
-    public void testBrowseEmptyTree() throws IOException, KeyNotFoundException
+    public void testBrowseEmptyTree() throws IOException, KeyNotFoundException, BTreeAlreadyManagedException
     {
         IntSerializer serializer = IntSerializer.INSTANCE;
 
         BTree<Integer, Integer> btree = BTreeFactory.createPersistedBTree( "master", serializer, serializer );
+        
+        // Inject the newly created BTree into teh recordManager
+        recordManager1.manage( btree );
 
         TupleCursor<Integer, Integer> cursor = btree.browse();
         assertFalse( cursor.hasNext() );