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 2017/10/09 20:33:00 UTC

svn commit: r1811602 [5/6] - in /directory/mavibot/branches/single-value/mavibot: ./ src/main/java/org/apache/directory/mavibot/btree/ src/main/java/org/apache/directory/mavibot/btree/exception/ src/test/java/org/apache/directory/mavibot/btree/

Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java?rev=1811602&r1=1811601&r2=1811602&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java Mon Oct  9 20:32:59 2017
@@ -55,6 +55,11 @@ import org.apache.directory.mavibot.btre
 import org.apache.directory.mavibot.btree.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.ehcache.Cache;
+import org.ehcache.CacheManager;
+import org.ehcache.config.builders.CacheConfigurationBuilder;
+import org.ehcache.config.builders.CacheManagerBuilder;
+import org.ehcache.config.builders.ResourcePoolsBuilder;
 
 
 /**
@@ -96,6 +101,8 @@ public class RecordManager implements Tr
     private AtomicLong nbUpdateRMHeader = new AtomicLong( 0 );
     private AtomicLong nbUpdateBtreeHeader = new AtomicLong( 0 );
     private AtomicLong nbUpdatePageIOs = new AtomicLong( 0 );
+    public AtomicLong nbCacheHits = new AtomicLong( 0 );
+    public AtomicLong nbCacheMisses = new AtomicLong( 0 );
 
     /**
      * A B-tree used to manage the page that has been copied in a new version.
@@ -103,28 +110,8 @@ public class RecordManager implements Tr
      **/
     /* no qualifier */BTree<RevisionName, long[]> copiedPageBtree;
 
-    /** A constant for an offset on a non existing page */
-    public static final long NO_PAGE = -1L;
-
-    /** The number of bytes used to store the size of a page */
-    private static final int PAGE_SIZE = 4;
-
-    /** The size of the link to next page */
-    private static final int LINK_SIZE = 8;
-
-    /** Some constants */
-    private static final int BYTE_SIZE = 1;
-    /* no qualifier */static final int INT_SIZE = 4;
-    /* no qualifier */static final int LONG_SIZE = 8;
-
-    /** The default page size */
-    public static final int DEFAULT_PAGE_SIZE = 512;
-
-    /** The minimal page size. Can't be below 64, as we have to store many thing sin the RMHeader */
-    private static final int MIN_PAGE_SIZE = 64;
-
     /** The RecordManager header size */
-    /* no qualifier */static int recordManagerHeaderSize = DEFAULT_PAGE_SIZE;
+    /* no qualifier */static int recordManagerHeaderSize = BTreeConstants.DEFAULT_PAGE_SIZE;
 
     /** A global buffer used to store the RecordManager header */
     private ByteBuffer recordManagerHeaderBuffer;
@@ -142,27 +129,12 @@ public class RecordManager implements Tr
     /** The queue of recently closed transactions */
     private Queue<RevisionName> closedTransactionsQueue = new LinkedBlockingQueue<>();
 
-    /** The default file name */
-    private static final String DEFAULT_FILE_NAME = "mavibot.db";
-
     /** A flag set to true if we want to keep old revisions */
     private boolean keepRevisions;
 
-    /** A flag used by internal btrees */
-    public static final boolean INTERNAL_BTREE = true;
-
-    /** A flag used by internal btrees */
-    public static final boolean NORMAL_BTREE = false;
-
     /** The B-tree of B-trees */
     /* no qualifier */BTree<NameRevision, Long> btreeOfBtrees;
 
-    /** The B-tree of B-trees management btree name */
-    /* no qualifier */static final String BTREE_OF_BTREES_NAME = "_btree_of_btrees_";
-
-    /** The CopiedPages management btree name */
-    /* no qualifier */static final String COPIED_PAGE_BTREE_NAME = "_copiedPageBtree_";
-
     /** A lock to protect the transaction handling */
     private ReentrantLock transactionLock = new ReentrantLock();
 
@@ -184,9 +156,6 @@ public class RecordManager implements Tr
     /** A lock to protect the BtreeHeader maps */
     private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
 
-    /** A value stored into the transaction context for rollbacked transactions */
-    private static final int ROLLBACKED_TXN = 0;
-
     /** A lock to protect the freepage pointers */
     private ReentrantLock freePageLock = new ReentrantLock();
 
@@ -208,10 +177,11 @@ public class RecordManager implements Tr
     
     /** The transaction context */
     private TransactionContext context;
+    
+    
+    /** The page cache */
+    private Cache<Long, Page> pageCache;
 
-    /** Hex chars */
-    private static final byte[] HEX_CHAR = new byte[]
-        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 
 
     /**
@@ -223,7 +193,7 @@ public class RecordManager implements Tr
      */
     public RecordManager( String fileName )
     {
-        this( fileName, DEFAULT_PAGE_SIZE );
+        this( fileName, BTreeConstants.DEFAULT_PAGE_SIZE );
     }
 
 
@@ -245,9 +215,9 @@ public class RecordManager implements Tr
         managedBtrees = new LinkedHashMap<>();
 
         // The page size can't be lower than 512
-        if ( pageSize < MIN_PAGE_SIZE )
+        if ( pageSize < BTreeConstants.MIN_PAGE_SIZE )
         {
-            recordManagerHeader.pageSize = MIN_PAGE_SIZE;
+            recordManagerHeader.pageSize = BTreeConstants.MIN_PAGE_SIZE;
         }
         else
         {
@@ -264,8 +234,16 @@ public class RecordManager implements Tr
         if ( tmpFile.isDirectory() )
         {
             // It's a directory. Check that we don't have an existing mavibot file
-            tmpFile = new File( tmpFile, DEFAULT_FILE_NAME );
+            tmpFile = new File( tmpFile, BTreeConstants.DEFAULT_FILE_NAME );
         }
+        
+        // Create the cache
+        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
+            .withCache( "pageCache", CacheConfigurationBuilder.
+                newCacheConfigurationBuilder( Long.class, Page.class, 
+                ResourcePoolsBuilder.heap( 10000 ) ) ).build( true );
+
+        pageCache = cacheManager.getCache( "pageCache", Long.class, Page.class ); 
 
         // We have to create a new file, if it does not already exist
         boolean isNewFile = createFile( tmpFile );
@@ -387,8 +365,8 @@ public class RecordManager implements Tr
         // Create a new Header
         RecordManagerHeader recordManagerHeader = recordManagerHeaderReference.get();
         recordManagerHeader.nbBtree = 0;
-        recordManagerHeader.firstFreePage = NO_PAGE;
-        recordManagerHeader.currentBtreeOfBtreesOffset = NO_PAGE;
+        recordManagerHeader.firstFreePage = BTreeConstants.NO_PAGE;
+        recordManagerHeader.currentBtreeOfBtreesOffset = BTreeConstants.NO_PAGE;
         recordManagerHeader.idCounter = 0L;
 
         writeRecordManagerHeader( recordManagerHeader );
@@ -396,29 +374,22 @@ public class RecordManager implements Tr
         try ( WriteTransaction transaction = beginWriteTransaction() )
         {
             // First, create the btree of btrees <NameRevision, Long>
-            BTree<NameRevision, Long> btreeOfBtrees = createBtreeOfBtrees( transaction );
+            btreeOfBtrees = createBtreeOfBtrees( transaction );
     
             // Now, create the Copied Page B-tree
             BTree<RevisionName, long[]> copiedPagesBtree = createCopiedPagesBtree( transaction );
     
             // Inject these B-trees into the RecordManager. They are internal B-trees.
-            try
-            {
-                writeManagementTree( transaction, btreeOfBtrees );
-                transaction.recordManagerHeader.btreeOfBtrees = btreeOfBtrees;
-                transaction.recordManagerHeader.nbBtree++;
-                recordManagerHeader.btreeOfBtrees = btreeOfBtrees;
-    
-                // The Copied Pages B-tree
-                writeManagementTree( transaction, copiedPagesBtree );
-                transaction.recordManagerHeader.copiedPagesBtree = copiedPagesBtree;
-                transaction.recordManagerHeader.nbBtree++;
-                recordManagerHeader.copiedPagesBtree = copiedPagesBtree;
-            }
-            catch ( BTreeAlreadyManagedException bame )
-            {
-                transaction.abort();
-            }
+            writeManagementTree( transaction, btreeOfBtrees );
+            transaction.recordManagerHeader.btreeOfBtrees = btreeOfBtrees;
+            transaction.recordManagerHeader.nbBtree++;
+            recordManagerHeader.btreeOfBtrees = btreeOfBtrees;
+
+            // The Copied Pages B-tree
+            writeManagementTree( transaction, copiedPagesBtree );
+            transaction.recordManagerHeader.copiedPagesBtree = copiedPagesBtree;
+            transaction.recordManagerHeader.nbBtree++;
+            recordManagerHeader.copiedPagesBtree = copiedPagesBtree;
         }
     }
 
@@ -430,10 +401,9 @@ public class RecordManager implements Tr
     {
         BTreeConfiguration<NameRevision, Long> configuration = new BTreeConfiguration<>();
         configuration.setKeySerializer( NameRevisionSerializer.INSTANCE );
-        configuration.setName( BTREE_OF_BTREES_NAME );
+        configuration.setName( BTreeConstants.BTREE_OF_BTREES_NAME );
         configuration.setValueSerializer( LongSerializer.INSTANCE );
         configuration.setBtreeType( BTreeTypeEnum.BTREE_OF_BTREES );
-        configuration.setCacheSize( BTreeImpl.DEFAULT_CACHE_SIZE );
 
         return BTreeFactory.createBTree( transaction, configuration );
     }
@@ -446,10 +416,9 @@ public class RecordManager implements Tr
     {
         BTreeConfiguration<RevisionName, long[]> configuration = new BTreeConfiguration<>();
         configuration.setKeySerializer( RevisionNameSerializer.INSTANCE );
-        configuration.setName( COPIED_PAGE_BTREE_NAME );
+        configuration.setName( BTreeConstants.COPIED_PAGE_BTREE_NAME );
         configuration.setValueSerializer( LongArraySerializer.INSTANCE );
         configuration.setBtreeType( BTreeTypeEnum.COPIED_PAGES_BTREE );
-        configuration.setCacheSize( BTreeImpl.DEFAULT_CACHE_SIZE );
 
         return BTreeFactory.createBTree( transaction, configuration );
     }
@@ -494,8 +463,8 @@ public class RecordManager implements Tr
             // +---------------------+
             // | CPB offset          | 8 bytes : The offset of the current Copied Pages B-tree
             // +---------------------+
-
-            // The page size
+            // | ID                  | 8 bytes : The ID counter
+            // +---------------------+
             recordManagerHeader.pageSize = rmhBytes.getInt();
 
             // The number of managed B-trees
@@ -515,6 +484,9 @@ public class RecordManager implements Tr
 
             // The current Copied Pages B-tree offset
             recordManagerHeader.currentCopiedPagesBtreeOffset = rmhBytes.getLong();
+
+            // The current Copied Pages B-tree offset
+            recordManagerHeader.idCounter = rmhBytes.getLong();
             
             // Set the last offset, which is the file's size
             recordManagerHeader.lastOffset = fileChannel.size();
@@ -522,30 +494,32 @@ public class RecordManager implements Tr
             // read the B-tree of B-trees
             try ( Transaction transaction = beginReadTransaction() )
             {
-                PageIO[] bobHeaderPageIos = readPageIOs( recordManagerHeader, recordManagerHeader.currentBtreeOfBtreesOffset, Long.MAX_VALUE );
+                PageIO[] bobHeaderPageIos = readPageIOs( recordManagerHeader.pageSize, recordManagerHeader.currentBtreeOfBtreesOffset, Long.MAX_VALUE );
     
-                recordManagerHeader.btreeOfBtrees = BTreeFactory.<NameRevision, Long> createBTree( BTreeTypeEnum.BTREE_OF_BTREES );
-                ( ( BTreeImpl<NameRevision, Long> ) recordManagerHeader.btreeOfBtrees ).setRecordManagerHeader( transaction.getRecordManagerHeader() );
+                recordManagerHeader.btreeOfBtrees = new BTree<>();
+                
+                //recordManagerHeader.btreeOfBtrees = BTreeFactory.<NameRevision, Long> createBTree( BTreeTypeEnum.BTREE_OF_BTREES );
+                //( ( BTree<NameRevision, Long> ) recordManagerHeader.btreeOfBtrees ).setRecordManagerHeader( transaction.getRecordManagerHeader() );
     
                 loadBtree( transaction, bobHeaderPageIos, recordManagerHeader.btreeOfBtrees );
+                recordManagerHeader.btreeOfBtrees.setType( BTreeTypeEnum.BTREE_OF_BTREES );
 
                 // read the copied page B-tree
-                PageIO[] copiedPagesPageIos = readPageIOs( recordManagerHeader, recordManagerHeader.currentCopiedPagesBtreeOffset, Long.MAX_VALUE );
+                PageIO[] copiedPagesPageIos = readPageIOs( recordManagerHeader.pageSize, recordManagerHeader.currentCopiedPagesBtreeOffset, Long.MAX_VALUE );
     
                 recordManagerHeader.copiedPagesBtree = BTreeFactory.<RevisionName, long[]> createBTree( BTreeTypeEnum.COPIED_PAGES_BTREE );
-                ( ( BTreeImpl<RevisionName, long[]> ) recordManagerHeader.copiedPagesBtree ).setRecordManagerHeader( transaction.getRecordManagerHeader() );
+                //( ( BTree<RevisionName, long[]> ) recordManagerHeader.copiedPagesBtree ).setRecordManagerHeader( transaction.getRecordManagerHeader() );
     
                 loadBtree( transaction, copiedPagesPageIos, recordManagerHeader.copiedPagesBtree );
             }
 
-            // Now, read all the B-trees from the btree of btrees
-            /*
-            Transaction transaction = beginReadTransaction();
             Map<String, Long> loadedBtrees = new HashMap<>();
-            
-            try
+
+            // Now, read all the B-trees from the btree of btrees
+            try ( Transaction transaction = beginReadTransaction() )
             {
-                TupleCursor<NameRevision, Long> btreeCursor = btreeOfBtrees.browse( transaction );
+            
+                TupleCursor<NameRevision, Long> btreeCursor = transaction.getRecordManagerHeader().btreeOfBtrees.browse( transaction );
     
                 // loop on all the btrees we have, and keep only the latest revision
                 long currentRevision = -1L;
@@ -577,28 +551,23 @@ public class RecordManager implements Tr
                         currentRevision = nameRevision.getRevision();
                     }
                 }
-            }
-            finally
-            {
-                transaction.commit();
-            }
 
-            // TODO : clean up the old revisions...
+                // TODO : clean up the old revisions...
 
-            // Now, we can load the real btrees using the offsets
-            for ( Map.Entry<String, Long> loadedBtree : loadedBtrees.entrySet() )
-            {
-                long btreeOffset = loadedBtree.getValue();
-
-                PageIO[] btreePageIos = readPageIOs( btreeOffset, Long.MAX_VALUE );
+                // Now, we can load the real btrees using the offsets
+                for ( Map.Entry<String, Long> loadedBtree : loadedBtrees.entrySet() )
+                {
+                    long btreeOffset = loadedBtree.getValue();
 
-                BTree<?, ?> btree = BTreeFactory.<NameRevision, Long> createPersistedBTree();
-                loadBtree( btreePageIos, btree );
+                    PageIO[] btreePageIos = readPageIOs( recordManagerHeader.pageSize, btreeOffset, Long.MAX_VALUE );
+                
+                    BTree<?, ?> btree = new BTree<>();
+                    loadBtree( transaction, btreePageIos, btree );
 
-                // Add the btree into the map of managed B-trees
-                managedBtrees.put( loadedBtree.getKey(), ( BTree<Object, Object> ) btree );
+                    // Add the btree into the map of managed B-trees
+                    recordManagerHeader.btreeMap.put( loadedBtree.getKey(), ( BTree<Object, Object> ) btree );
+                }
             }
-            */
         }
     }
 
@@ -606,7 +575,7 @@ public class RecordManager implements Tr
     private <K, V> BTree<K, V> readBTree( Transaction transaction, long btreeOffset ) throws NoSuchFieldException, InstantiationException, EndOfFileExceededException,
         IOException, IllegalAccessException, ClassNotFoundException
     {
-        PageIO[] btreePageIos = readPageIOs( transaction.getRecordManagerHeader(), btreeOffset, Long.MAX_VALUE );
+        PageIO[] btreePageIos = readPageIOs( transaction.getRecordManagerHeader().pageSize, btreeOffset, Long.MAX_VALUE );
 
         BTree<K, V> btree = BTreeFactory.<K, V> createBTree();
         loadBtree( transaction, btreePageIos, btree );
@@ -676,7 +645,7 @@ public class RecordManager implements Tr
      * @param limit The maximum bytes to read. Set this value to -1 when the size is unknown.
      * @return An array of pages
      */
-    /*no qualifier*/PageIO[] readPageIOs( RecordManagerHeader recordManagerHeader, long position, long limit ) 
+    /*no qualifier*/PageIO[] readPageIOs( int pageSize, long position, long limit ) 
         throws IOException, EndOfFileExceededException
     {
         LOG.debug( "Read PageIOs at position {}", position );
@@ -686,27 +655,27 @@ public class RecordManager implements Tr
             limit = Long.MAX_VALUE;
         }
 
-        PageIO firstPage = fetchPage( recordManagerHeader, position );
+        PageIO firstPage = fetchPageIO( pageSize, position );
         firstPage.setSize();
         List<PageIO> listPages = new ArrayList<>();
         listPages.add( firstPage );
-        long dataRead = recordManagerHeader.pageSize - LONG_SIZE - INT_SIZE;
+        long dataRead = pageSize - BTreeConstants.LONG_SIZE - BTreeConstants.INT_SIZE;
 
         // Iterate on the pages, if needed
         long nextPage = firstPage.getNextPage();
 
-        if ( ( dataRead < limit ) && ( nextPage != NO_PAGE ) )
+        if ( ( dataRead < limit ) && ( nextPage != BTreeConstants.NO_PAGE ) )
         {
             while ( dataRead < limit )
             {
-                PageIO page = fetchPage( recordManagerHeader, nextPage );
+                PageIO page = fetchPageIO( pageSize, nextPage );
                 listPages.add( page );
                 nextPage = page.getNextPage();
-                dataRead += recordManagerHeader.pageSize - LONG_SIZE;
+                dataRead += pageSize - BTreeConstants.LONG_SIZE;
 
-                if ( nextPage == NO_PAGE )
+                if ( nextPage == BTreeConstants.NO_PAGE )
                 {
-                    page.setNextPage( NO_PAGE );
+                    page.setNextPage( BTreeConstants.NO_PAGE );
                     break;
                 }
             }
@@ -778,81 +747,79 @@ public class RecordManager implements Tr
         throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException
     {
         RecordManagerHeader recordManagerHeader = transaction.getRecordManagerHeader();
+        int pageSize = recordManagerHeader.pageSize;
+        BTreeInfo<K, V> btreeInfo = new BTreeInfo<>();
         long dataPos = 0L;
 
         // Process the B-tree header
-        BTreeHeader<K, V> btreeHeader = new BTreeHeader<>();
-        btreeHeader.setBtree( btree );
+        BTreeHeader<K, V> btreeHeader = new BTreeHeader<>( btreeInfo );
 
         // The BtreeHeader offset
         btreeHeader.setOffset( pageIos[0].getOffset() );
 
         // The B-tree header page ID
-        long id = readLong( recordManagerHeader, pageIos, dataPos );
+        long id = readLong( pageSize, pageIos, dataPos );
         btreeHeader.setId( id );
-        dataPos += LONG_SIZE;
+        dataPos += BTreeConstants.LONG_SIZE;
 
         // The B-tree current revision
-        long revision = readLong( recordManagerHeader, pageIos, dataPos );
+        long revision = readLong( pageSize, pageIos, dataPos );
         btreeHeader.setRevision( revision );
-        dataPos += LONG_SIZE;
+        dataPos += BTreeConstants.LONG_SIZE;
 
         // The nb elems in the tree
-        long nbElems = readLong( recordManagerHeader, pageIos, dataPos );
+        long nbElems = readLong( pageSize, pageIos, dataPos );
         btreeHeader.setNbElems( nbElems );
-        dataPos += LONG_SIZE;
+        dataPos += BTreeConstants.LONG_SIZE;
 
         // The b-tree rootPage offset
-        long rootPageOffset = readLong( recordManagerHeader, pageIos, dataPos );
-        dataPos += LONG_SIZE;
+        long rootPageOffset = readLong( pageSize, pageIos, dataPos );
+        dataPos += BTreeConstants.LONG_SIZE;
 
         // The B-tree information offset
-        long btreeInfoOffset = readLong( recordManagerHeader, pageIos, dataPos );
+        long btreeInfoOffset = readLong( pageSize, pageIos, dataPos );
+        btree.setBtreeInfo( btreeInfo );
 
         // Now, process the common informations
-        PageIO[] infoPageIos = readPageIOs( recordManagerHeader, btreeInfoOffset, Long.MAX_VALUE );
+        PageIO[] infoPageIos = readPageIOs( recordManagerHeader.pageSize, btreeInfoOffset, Long.MAX_VALUE );
         dataPos = 0L;
 
         // The B-tree page numbers of elements
-        int btreePageNbElem = readInt( recordManagerHeader, infoPageIos, dataPos );
+        int btreePageNbElem = readInt( pageSize, infoPageIos, dataPos );
         BTreeFactory.setPageNbElem( btree, btreePageNbElem );
-        dataPos += INT_SIZE;
+        dataPos += BTreeConstants.INT_SIZE;
 
         // The tree name
-        ByteBuffer btreeNameBytes = readBytes( recordManagerHeader, infoPageIos, dataPos );
-        dataPos += INT_SIZE + btreeNameBytes.limit();
+        ByteBuffer btreeNameBytes = readBytes( pageSize, infoPageIos, dataPos );
+        dataPos += BTreeConstants.INT_SIZE + btreeNameBytes.limit();
         String btreeName = Strings.utf8ToString( btreeNameBytes );
         BTreeFactory.setName( btree, btreeName );
 
         // The keySerializer FQCN
-        ByteBuffer keySerializerBytes = readBytes( recordManagerHeader, infoPageIos, dataPos );
-        dataPos += INT_SIZE + keySerializerBytes.limit();
+        ByteBuffer keySerializerBytes = readBytes( pageSize, infoPageIos, dataPos );
+        dataPos += BTreeConstants.INT_SIZE + keySerializerBytes.limit();
 
         String keySerializerFqcn = Strings.utf8ToString( keySerializerBytes );
 
         BTreeFactory.setKeySerializer( btree, keySerializerFqcn );
 
         // The valueSerialier FQCN
-        ByteBuffer valueSerializerBytes = readBytes( recordManagerHeader, infoPageIos, dataPos );
+        ByteBuffer valueSerializerBytes = readBytes( pageSize, infoPageIos, dataPos );
 
         String valueSerializerFqcn = Strings.utf8ToString( valueSerializerBytes );
 
         BTreeFactory.setValueSerializer( btree, valueSerializerFqcn );
 
         // Update the BtreeHeader reference
-        ( ( BTreeImpl<K, V> ) btree ).setBtreeHeader( btreeHeader );
+        btree.setBtreeHeader( btreeHeader );
 
         // Read the rootPage pages on disk
-        PageIO[] rootPageIos = readPageIOs( recordManagerHeader, rootPageOffset, Long.MAX_VALUE );
+        PageIO[] rootPageIos = readPageIOs( recordManagerHeader.pageSize, rootPageOffset, Long.MAX_VALUE );
         BTreeFactory.setRecordManager( btree, this );
 
-        Page<K, V> btreeRoot = readPage( transaction, btree, rootPageIos );
+        Page<K, V> btreeRoot = readPage( recordManagerHeader.pageSize, btreeInfo, rootPageIos );
 
         BTreeFactory.setRootPage( btree, btreeRoot );
-        
-        // And create the BTreeInfo page
-        BTreeInfo<K, V> btreeInfo = createBtreeInfo( btree );
-        ( ( BTreeImpl<K, V> ) btree ).setBtreeInfo( btreeInfo );
     }
 
 
@@ -863,103 +830,79 @@ public class RecordManager implements Tr
      * @return The read Page if successful
      * @throws IOException If the deserialization failed
      */
-    private <K, V> Page<K, V> readPage( Transaction transaction, BTree<K, V> btree, PageIO[] pageIos ) throws IOException
+    /* No qualifier*/ <K, V> Page<K, V> readPage( int pageSize, BTreeInfo<K, V> btreeInfo, PageIO[] pageIos ) throws IOException
     {
-        RecordManagerHeader recordManagerHeader = transaction.getRecordManagerHeader();
         long position = 0L;
 
-        // The revision
-        long id = readLong( recordManagerHeader, pageIos, position );
-        position += LONG_SIZE;
+        // The id
+        long id = readLong( pageSize, pageIos, position );
+        position += BTreeConstants.LONG_SIZE;
 
         // The revision
-        long revision = readLong( recordManagerHeader, pageIos, position );
-        position += LONG_SIZE;
+        long revision = readLong( pageSize, pageIos, position );
+        position += BTreeConstants.LONG_SIZE;
 
         // The number of elements in the page
-        int nbElems = readInt( recordManagerHeader, pageIos, position );
-        position += INT_SIZE;
+        int nbElems = readInt( pageSize, pageIos, position );
+        position += BTreeConstants.INT_SIZE;
 
         // The size of the data containing the keys and values
         Page<K, V> page = null;
 
+        // Reads the bytes containing all the keys and values, if we have some
+        // We read  big blog of data into  ByteBuffer, then we will process
+        // this ByteBuffer
+        ByteBuffer byteBuffer = readBytes( pageSize, pageIos, position );
+
         // Now, deserialize the data block. If the number of elements
         // is positive, it's a Leaf, otherwise it's a Node
         // Note that only a leaf can have 0 elements, and it's the root page then.
         if ( nbElems >= 0 )
         {
-            // Its a leaf, create it
-            Leaf<K, V> leaf = ( Leaf<K, V> ) BTreeFactory.createLeaf( btree, revision, nbElems );
-            leaf.setId( id );
-
-            // Store the page offset on disk
-            leaf.setOffset( pageIos[0].getOffset() );
-            
-            // The size of the data containing the keys and values
-            // Reads the bytes containing all the keys and values, if we have some
-            // We read  big blob of data into  ByteBuffer, then we will process
-            // this ByteBuffer
-            ByteBuffer byteBuffer = readBytes( recordManagerHeader, pageIos, position );
-
-            leaf.deserialize( transaction, byteBuffer );
-            
-            return leaf;
+            // It's a leaf
+            page = readLeafKeysAndValues( btreeInfo, nbElems, revision, byteBuffer, pageIos );
         }
         else
         {
             // It's a node
-            //page = readNodeKeysAndValues( btree, -nbElems, revision, byteBuffer, pageIos );
+            page = readNodeKeysAndValues( btreeInfo, -nbElems, revision, byteBuffer, pageIos );
         }
 
         ( ( AbstractPage<K, V> ) page ).setOffset( pageIos[0].getOffset() );
+        ( ( AbstractWALObject<K, V> ) page ).setId( id );
         
-        /*if ( pageIos.length > 1 )
-        {
-            ( ( AbstractPage<K, V> ) page ).setLastOffset( pageIos[pageIos.length - 1].getOffset() );
-        }*/
-
         return page;
     }
 
 
+/**
+ * Deserialize a Leaf from some PageIOs
+ */
+    private <K, V> Leaf<K, V> readLeafKeysAndValues( BTreeInfo<K, V> btreeInfo, int nbElems, long revision,
+        ByteBuffer byteBuffer, PageIO[] pageIos ) throws IOException
+    {
+        // Its a leaf, create it
+        Leaf<K, V> leaf = new Leaf<>( btreeInfo, revision, nbElems );
+    
+        // Store the page offset on disk
+        leaf.setOffset( pageIos[0].getOffset() );
+    
+        return leaf.deserialize( byteBuffer );
+    }
+
+
     /**
      * Deserialize a Node from some PageIos
      */
-    private <K, V> Node<K, V> readNodeKeysAndValues( BTree<K, V> btree, int nbElems, long revision,
+    private <K, V> Node<K, V> readNodeKeysAndValues( BTreeInfo<K, V> btreeInfo, int nbElems, long revision,
         ByteBuffer byteBuffer, PageIO[] pageIos ) throws IOException
     {
-        Node<K, V> node = ( Node<K, V> ) BTreeFactory.createNode( btree, revision, nbElems );
-
-        // Read each value and key
-        for ( int i = 0; i < nbElems; i++ )
-        {
-            // This is an Offset
-            long offset = LongSerializer.INSTANCE.deserialize( byteBuffer );
-
-            PageHolder<K, V> valueHolder = new PageHolder<>( btree, null, offset );
-            node.setValue( i, valueHolder );
-
-            // Read the key length
-            int keyLength = byteBuffer.getInt();
-
-            int currentPosition = byteBuffer.position();
-
-            // and the key value
-            K key = btree.getKeySerializer().deserialize( byteBuffer );
-
-            // Set the new position now
-            byteBuffer.position( currentPosition + keyLength );
-
-            BTreeFactory.setKey( btree, node, i, key );
-        }
-
-        // and read the last value, as it's a node
-        long offset = LongSerializer.INSTANCE.deserialize( byteBuffer );
-
-        PageHolder<K, V> valueHolder = new PageHolder<>( btree, null, offset );
-        node.setValue( nbElems, valueHolder );
-
-        return node;
+        Node<K, V> node = new Node<>( btreeInfo, revision, nbElems );
+        
+        // Store the page offset on disk
+        node.setOffset( pageIos[0].getOffset() );
+        
+        return node.deserialize( byteBuffer );
     }
 
 
@@ -970,21 +913,21 @@ public class RecordManager implements Tr
      * @param position The position in the data stored in those pages
      * @return The byte[] we have read
      */
-    /* no qualifier */ByteBuffer readBytes( RecordManagerHeader recordManagerHeader, PageIO[] pageIos, long position )
+    /* no qualifier */static ByteBuffer readBytes( int pageSize, PageIO[] pageIos, long position )
     {
         // Read the byte[] length first
-        int length = readInt( recordManagerHeader, pageIos, position );
-        position += INT_SIZE;
+        int length = readInt( pageSize, pageIos, position );
+        position += BTreeConstants.INT_SIZE;
 
         // Compute the page in which we will store the data given the
         // current position
-        int pageNb = computePageNb( recordManagerHeader, position );
+        int pageNb = computePageNb( pageSize, position );
 
         // Compute the position in the current page
-        int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+        int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
         // Check that the length is correct : it should fit in the provided pageIos
-        int pageEnd = computePageNb( recordManagerHeader, position + length );
+        int pageEnd = computePageNb( pageSize, position + length );
 
         if ( pageEnd > pageIos.length )
         {
@@ -1029,7 +972,7 @@ public class RecordManager implements Tr
                 pageData.limit( oldLimit );
                 pageData.reset();
                 pageNb++;
-                pagePos = LINK_SIZE;
+                pagePos = BTreeConstants.LINK_SIZE;
                 pageData = pageIos[pageNb].getData();
                 length -= remaining;
                 remaining = pageData.capacity() - pagePos;
@@ -1048,20 +991,20 @@ public class RecordManager implements Tr
      * @param position The position in the data stored in those pages
      * @return The int we have read
      */
-    /* no qualifier */int readInt( RecordManagerHeader recordManagerHeader, PageIO[] pageIos, long position )
+    /* no qualifier */static int readInt( int pageSize, PageIO[] pageIos, long position )
     {
         // Compute the page in which we will store the data given the
         // current position
-        int pageNb = computePageNb( recordManagerHeader, position );
+        int pageNb = computePageNb( pageSize, position );
 
         // Compute the position in the current page
-        int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+        int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
         ByteBuffer pageData = pageIos[pageNb].getData();
         int remaining = pageData.capacity() - pagePos;
         int value;
 
-        if ( remaining >= INT_SIZE )
+        if ( remaining >= BTreeConstants.INT_SIZE )
         {
             value = pageData.getInt( pagePos );
         }
@@ -1086,7 +1029,7 @@ public class RecordManager implements Tr
 
             // Now deal with the next page
             pageData = pageIos[pageNb + 1].getData();
-            pagePos = LINK_SIZE;
+            pagePos = BTreeConstants.LINK_SIZE;
 
             switch ( remaining )
             {
@@ -1114,14 +1057,14 @@ public class RecordManager implements Tr
      * @param position The position in the data stored in those pages
      * @return The byte we have read
      */
-    private byte readByte( RecordManagerHeader recordManagerHeader, PageIO[] pageIos, long position )
+    private byte readByte( int pageSize, PageIO[] pageIos, long position )
     {
         // Compute the page in which we will store the data given the
         // current position
-        int pageNb = computePageNb( recordManagerHeader, position );
+        int pageNb = computePageNb( pageSize, position );
 
         // Compute the position in the current page
-        int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+        int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
         ByteBuffer pageData = pageIos[pageNb].getData();
 
@@ -1135,20 +1078,20 @@ public class RecordManager implements Tr
      * @param position The position in the data stored in those pages
      * @return The long we have read
      */
-    /* no qualifier */long readLong( RecordManagerHeader recordManagerHeader, PageIO[] pageIos, long position )
+    /* no qualifier */static long readLong( int pageSize, PageIO[] pageIos, long position )
     {
         // Compute the page in which we will store the data given the
         // current position
-        int pageNb = computePageNb( recordManagerHeader, position );
+        int pageNb = computePageNb( pageSize, position );
 
         // Compute the position in the current page
-        int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+        int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
         ByteBuffer pageData = pageIos[pageNb].getData();
         int remaining = pageData.capacity() - pagePos;
         long value = 0L;
 
-        if ( remaining >= LONG_SIZE )
+        if ( remaining >= BTreeConstants.LONG_SIZE )
         {
             value = pageData.getLong( pagePos );
         }
@@ -1187,7 +1130,7 @@ public class RecordManager implements Tr
 
             // Now deal with the next page
             pageData = pageIos[pageNb + 1].getData();
-            pagePos = LINK_SIZE;
+            pagePos = BTreeConstants.LINK_SIZE;
 
             switch ( remaining )
             {
@@ -1225,13 +1168,12 @@ public class RecordManager implements Tr
     }
 
     
-    private <K, V> BTreeInfo<K, V> createBtreeInfo( BTree<K, V> btree )
+    private <K, V> BTreeInfo<K, V> createBtreeInfo( BTree<K, V> btree, String name )
     {
         BTreeInfo<K,V> btreeInfo = new BTreeInfo<>();
         
-        btreeInfo.setBtree( btree );
         btreeInfo.setPageNbElem( btree.getPageNbElem() );
-        btreeInfo.setBtreeName( btree.getName() );
+        btreeInfo.setName( name );
         btreeInfo.setKeySerializerFQCN( btree.getKeySerializerFQCN() );
         btreeInfo.setValueSerializerFQCN( btree.getValueSerializerFQCN() );
         
@@ -1256,7 +1198,7 @@ public class RecordManager implements Tr
     public synchronized <K, V> void manage( WriteTransaction transaction, BTree<K, V> btree ) throws BTreeAlreadyManagedException, IOException
     {
         long revision = transaction.getRevision();
-        RecordManagerHeader recordManagerHeader = transaction.getRecordManagerHeader();
+        RecordManagerHeader recordManagerHeader = transaction.recordManagerHeader;
 
         try
         {
@@ -1265,7 +1207,7 @@ public class RecordManager implements Tr
 
             String name = btree.getName();
 
-            if ( managedBtrees.containsKey( name ) )
+            if ( recordManagerHeader.containsBTree( name ) )
             {
                 // There is already a B-tree with this name in the recordManager...
                 LOG.error( "There is already a B-tree named '{}' managed by this recordManager", name );
@@ -1274,28 +1216,30 @@ public class RecordManager implements Tr
             }
 
             // Create the B-tree info
-            BTreeInfo<K, V> btreeInfo = createBtreeInfo( btree );
+            BTreeInfo<K, V> btreeInfo = btree.getBtreeInfo();
             btreeInfo.initId( recordManagerHeader );
             transaction.addWALObject( btreeInfo );
-            ( ( BTreeImpl<K, V> ) btree ).setBtreeInfo( btreeInfo );
+            btree.setBtreeInfo( btreeInfo );
 
             // Create the first root page, with the context revision. It will be empty
-            Leaf<K, V> rootPage = new Leaf<>( btree, revision, 0 );
-            rootPage.initId( recordManagerHeader );
+            Leaf<K, V> rootPage = transaction.newLeaf( btreeInfo, 0 );
             transaction.addWALObject( rootPage );
 
             // Create a B-tree header, and initialize it
-            BTreeHeader<K, V> btreeHeader = new BTreeHeader<>();
+            BTreeHeader<K, V> btreeHeader = new BTreeHeader<>( btreeInfo );
             btreeHeader.setRootPage( rootPage );
-            btreeHeader.setBtree( btree );
             btreeHeader.setRevision( revision );
-            ((BTreeImpl<K, V>)btree).setBtreeHeader( btreeHeader );
+            btree.setBtreeHeader( btreeHeader );
             btreeHeader.initId( recordManagerHeader );
 
             transaction.addWALObject( btreeHeader );
 
             // We can safely increment the number of managed B-trees
-            transaction.recordManagerHeader.nbBtree++;
+            recordManagerHeader.nbBtree++;
+            
+            // Finally add the new B-tree in the map of managed B-trees.
+            recordManagerHeader.addBTree( btree );
+            
         }
         catch ( IOException ioe )
         {
@@ -1303,7 +1247,31 @@ public class RecordManager implements Tr
             throw ioe;
         }
     }
-    
+
+
+    /**
+     * Insert an entry in the BTree.
+     * <p>
+     * We will replace the value if the provided key already exists in the
+     * btree.
+     * <p>
+     * The revision number is the revision to use to insert the data.
+     *
+     * @param key Inserted key
+     * @param value Inserted value
+     * @param revision The revision to use
+     * @return an instance of the InsertResult.
+     */
+    public <K, V> InsertResult<K, V> insert( WriteTransaction transaction, String btreeName, K key, V value ) throws KeyNotFoundException, IOException
+    {
+        // Fetch the B-tree from the BOB 
+        long revision = transaction.getRevision();
+        
+        BTree<K, V> btree = getBtree( transaction, btreeName, revision );
+        
+        return btree.insert( transaction, key, value );
+    }
+
     
     /**
      * Inject a newly created BTree in the BtreeOfBtrees
@@ -1317,7 +1285,7 @@ public class RecordManager implements Tr
         NameRevision nameRevision = new NameRevision( btree.getName(), recordManagerHeader.getRevision() );
 
         // Inject it into the B-tree of B-tree
-        btreeOfBtrees.insert( transaction, nameRevision, ((BTreeImpl<K, V>)btree).getBtreeHeader().getOffset() );
+        btreeOfBtrees.insert( transaction, nameRevision, btree.getBtreeHeader().getOffset() );
     }
     
     
@@ -1334,7 +1302,7 @@ public class RecordManager implements Tr
         // Order the WALObject by B-tree name
         for ( WALObject<?, ?> walObject : transaction.getCopiedPageMap().values() )
         {
-            if ( walObject.getBtree().getType() != BTreeTypeEnum.COPIED_PAGES_BTREE )
+            if ( walObject.getBtreeInfo().getType() != BTreeTypeEnum.COPIED_PAGES_BTREE )
             {
                 String name = walObject.getName();
                 
@@ -1382,14 +1350,13 @@ public class RecordManager implements Tr
      * @throws IOException
      */
     private synchronized <K, V> void writeManagementTree( WriteTransaction transaction, BTree<K, V> btree )
-        throws BTreeAlreadyManagedException, IOException
     {
         LOG.debug( "Managing the sub-btree {}", btree.getName() );
+        BTreeInfo<K, V> btreeInfo = btree.getBtreeInfo();
         
         // Create the first root page, with version 0L. It will be empty
         // and increment the revision at the same time
-        Leaf<K, V> rootPage = new Leaf<>( btree, transaction.getRevision(), 0 );
-        rootPage.initId( transaction.getRecordManagerHeader() );
+        Leaf<K, V> rootPage = transaction.newLeaf( btreeInfo, 0 );
 
         LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() );
         
@@ -1397,22 +1364,19 @@ public class RecordManager implements Tr
         transaction.addWALObject( rootPage );
 
         // Now, create the b-tree info
-        BTreeInfo<K, V> btreeInfo = createBtreeInfo( btree );
         btreeInfo.initId( transaction.getRecordManagerHeader() );
-        ( ( BTreeImpl<K, V> ) btree ).setBtreeInfo( btreeInfo );
 
         // Store the B-tree info in the WAL
         transaction.addWALObject( btreeInfo );
 
         // Last, not least, Create a B-tree header, and initialize it
-        BTreeHeader<K, V> btreeHeader = new BTreeHeader<>();
-        btreeHeader.setBtree( btree );
+        BTreeHeader<K, V> btreeHeader = new BTreeHeader<>( btreeInfo );
         btreeHeader.setRootPage( rootPage );
         btreeHeader.setRevision( transaction.getRevision() );
         btreeHeader.initId( transaction.getRecordManagerHeader() );
 
         // Store the BtreeHeader in the BTree
-        ( ( BTreeImpl<K, V> ) btree ).setBtreeHeader( btreeHeader );
+        btree.setBtreeHeader( btreeHeader );
         
         // Store the B-tree header in the WAL
         transaction.addWALObject( btreeHeader );
@@ -1532,7 +1496,7 @@ public class RecordManager implements Tr
         btreeOfBtrees.insert( transaction, nameRevision, btreeHeaderOffset );
 
         // Update the B-tree of B-trees offset
-        //transaction.recordManagerHeader.currentBtreeOfBtreesOffset = getNewBTreeHeader( BTREE_OF_BTREES_NAME ).getOffset();
+        //transaction.recordManagerHeader.currentBtreeOfBtreesOffset = getNewBTreeHeader( BTreeConstants.BTREE_OF_BTREES_NAME ).getOffset();
     }
 
 
@@ -1562,7 +1526,7 @@ public class RecordManager implements Tr
 
         // Update the CopiedPageBtree offset
         recordManagerHeader.currentCopiedPagesBtreeOffset = 
-            ( ( BTreeImpl<RevisionName, long[]> ) copiedPageBtree ).getBtreeHeader().getOffset();
+            ( ( BTree<RevisionName, long[]> ) copiedPageBtree ).getBtreeHeader().getOffset();
     }
 
 
@@ -1591,10 +1555,10 @@ public class RecordManager implements Tr
         RecordManagerHeader recordManagerHeader = transaction.getRecordManagerHeader();
         
         int bufferSize =
-            LONG_SIZE + // The revision
-                LONG_SIZE + // the number of element
-                LONG_SIZE + // The root page offset
-                LONG_SIZE; // The B-tree info page offset
+            BTreeConstants.LONG_SIZE + // The revision
+                BTreeConstants.LONG_SIZE + // the number of element
+                BTreeConstants.LONG_SIZE + // The root page offset
+                BTreeConstants.LONG_SIZE; // The B-tree info page offset
 
         // Get the pageIOs we need to store the data. We may need more than one.
         PageIO[] pageIOs = getFreePageIOs( recordManagerHeader, bufferSize );
@@ -1620,7 +1584,7 @@ public class RecordManager implements Tr
         position = store( recordManagerHeader, position, btreeHeader.getRootPageOffset(), btreeHeaderPageIos );
 
         // The B-tree info page offset
-        position = store( recordManagerHeader, position, ( ( BTreeImpl<K, V> ) btree ).getBtreeInfoOffset(), btreeHeaderPageIos );
+        position = store( recordManagerHeader, position, btree.getBtreeInfoOffset(), btreeHeaderPageIos );
 
         // And flush the pages to disk now
         LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() );
@@ -1636,7 +1600,7 @@ public class RecordManager implements Tr
             sb.append( "    RootPage : 0x" ).append( Long.toHexString( btreeHeader.getRootPageOffset() ) )
                 .append( "\n" );
             sb.append( "    Info     : 0x" )
-                .append( Long.toHexString( ( ( BTreeImpl<K, V> ) btree ).getBtreeInfoOffset() ) ).append( "\n" );
+                .append( Long.toHexString( btree.getBtreeInfoOffset() ) ).append( "\n" );
 
             LOG_PAGES.debug( "Btree Header[{}]\n{}", btreeHeader.getRevision(), sb.toString() );
         }
@@ -1762,22 +1726,22 @@ public class RecordManager implements Tr
     {
         // Read the pageIOs associated with this B-tree
         PageIO[] pageIos;
-        long newBtreeHeaderOffset = NO_PAGE;
-        long offset = ( ( BTreeImpl<K, V> ) btree ).getBtreeOffset();
+        long newBtreeHeaderOffset = BTreeConstants.NO_PAGE;
+        long offset = btree.getBtreeOffset();
         RecordManagerHeader recordManagerHeader = transaction.getRecordManagerHeader();
 
         if ( onPlace )
         {
             // We just have to update the existing BTreeHeader
-            long headerSize = LONG_SIZE + LONG_SIZE + LONG_SIZE;
+            long headerSize = BTreeConstants.LONG_SIZE + BTreeConstants.LONG_SIZE + BTreeConstants.LONG_SIZE;
 
-            pageIos = readPageIOs( recordManagerHeader, offset, headerSize );
+            pageIos = readPageIOs( recordManagerHeader.pageSize, offset, headerSize );
 
             // Now, update the revision
             long position = 0;
 
             position = store( recordManagerHeader, position, transaction.getRevision(), pageIos );
-            position = store( recordManagerHeader, position, btree.getNbElems( recordManagerHeader ), pageIos );
+            position = store( recordManagerHeader, position, btree.getNbElems(), pageIos );
             store( recordManagerHeader, position, btreeHeaderOffset, pageIos );
 
             // Write the pages on disk
@@ -1785,7 +1749,7 @@ public class RecordManager implements Tr
             {
                 LOG.debug( "-----> Flushing the '{}' B-treeHeader", btree.getName() );
                 LOG.debug( "  revision : " + transaction.getRevision() + ", NbElems : " 
-                    + btree.getNbElems( recordManagerHeader )
+                    + btree.getNbElems()
                     + ", btreeHeader offset : 0x"
                     + Long.toHexString( btreeHeaderOffset ) );
             }
@@ -1798,7 +1762,7 @@ public class RecordManager implements Tr
         else
         {
             // We have to read and copy the existing BTreeHeader and to create a new one
-            pageIos = readPageIOs( recordManagerHeader, offset, Long.MAX_VALUE );
+            pageIos = readPageIOs( recordManagerHeader.pageSize, offset, Long.MAX_VALUE );
 
             // Now, copy every read page
             PageIO[] newPageIOs = new PageIO[pageIos.length];
@@ -1833,7 +1797,7 @@ public class RecordManager implements Tr
             long position = 0;
 
             position = store( recordManagerHeader, position, transaction.getRevision(), newPageIOs );
-            position = store( recordManagerHeader, position, btree.getNbElems( recordManagerHeader ), newPageIOs );
+            position = store( recordManagerHeader, position, btree.getNbElems(), newPageIOs );
             store( recordManagerHeader, position, btreeHeaderOffset, newPageIOs );
 
             // Get new place on disk to store the modified BTreeHeader if it's not onPlace
@@ -1975,20 +1939,30 @@ public class RecordManager implements Tr
      * @param offset The position in the data
      * @return The page number in which the offset will start
      */
-    private int computePageNb( RecordManagerHeader recordManagerHeader, long offset )
+    private static int computePageNb( int pageSize, long offset )
     {
         long pageNb = 0;
 
-        offset -= recordManagerHeader.pageSize - LINK_SIZE - PAGE_SIZE;
+        offset -= pageSize - BTreeConstants.LINK_SIZE - BTreeConstants.PAGE_SIZE;
 
         if ( offset < 0 )
         {
             return ( int ) pageNb;
         }
 
-        pageNb = 1 + offset / ( recordManagerHeader.pageSize - LINK_SIZE );
+        pageNb = 1 + offset / ( pageSize - BTreeConstants.LINK_SIZE );
 
         return ( int ) pageNb;
+/*
+        long pageOffset = offset - recordManagerHeader.pageSize - BTreeConstants.LINK_SIZE - BTreeConstants.PAGE_SIZE;
+
+        if ( pageOffset < 0 )
+        {
+            return 0;
+        }
+
+        return ( int ) ( 1 + pageOffset / ( recordManagerHeader.pageSize - BTreeConstants.LINK_SIZE ) );
+        */
     }
 
 
@@ -2003,6 +1977,8 @@ public class RecordManager implements Tr
      */
     /* no qualifier */ long store( RecordManagerHeader recordManagerHeader, long position, byte[] bytes, PageIO... pageIos )
     {
+        int pageSize = recordManagerHeader.pageSize;
+        
         if ( bytes != null )
         {
             // Write the bytes length
@@ -2010,13 +1986,13 @@ public class RecordManager implements Tr
 
             // Compute the page in which we will store the data given the
             // current position
-            int pageNb = computePageNb( recordManagerHeader, position );
+            int pageNb = computePageNb( pageSize, position );
 
             // Get back the buffer in this page
             ByteBuffer pageData = pageIos[pageNb].getData();
 
             // Compute the position in the current page
-            int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+            int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
             // Compute the remaining size in the page
             int remaining = pageData.capacity() - pagePos;
@@ -2041,7 +2017,7 @@ public class RecordManager implements Tr
                     pageData.reset();
                     pageNb++;
                     pageData = pageIos[pageNb].getData();
-                    pagePos = LINK_SIZE;
+                    pagePos = BTreeConstants.LINK_SIZE;
                     nbStored -= remaining;
                     remaining = pageData.capacity() - pagePos;
                 }
@@ -2072,17 +2048,19 @@ public class RecordManager implements Tr
      */
     /* No qualifier */ long storeRaw( RecordManagerHeader recordManagerHeader, long position, byte[] bytes, PageIO... pageIos )
     {
+        int pageSize = recordManagerHeader.pageSize;
+        
         if ( bytes != null )
         {
             // Compute the page in which we will store the data given the
             // current position
-            int pageNb = computePageNb( recordManagerHeader, position );
+            int pageNb = computePageNb( pageSize, position );
 
             // Get back the buffer in this page
             ByteBuffer pageData = pageIos[pageNb].getData();
 
             // Compute the position in the current page
-            int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+            int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
             // Compute the remaining size in the page
             int remaining = pageData.capacity() - pagePos;
@@ -2114,7 +2092,7 @@ public class RecordManager implements Tr
                     }
 
                     pageData = pageIos[pageNb].getData();
-                    pagePos = LINK_SIZE;
+                    pagePos = BTreeConstants.LINK_SIZE;
                     nbStored -= remaining;
                     remaining = pageData.capacity() - pagePos;
                 }
@@ -2144,12 +2122,14 @@ public class RecordManager implements Tr
      */
     /* no qualifier */ long store( RecordManagerHeader recordManagerHeader, long position, int value, PageIO... pageIos )
     {
+        int pageSize = recordManagerHeader.pageSize;
+        
         // Compute the page in which we will store the data given the
         // current position
-        int pageNb = computePageNb( recordManagerHeader, position );
+        int pageNb = computePageNb( pageSize, position );
 
         // Compute the position in the current page
-        int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+        int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
         // Get back the buffer in this page
         ByteBuffer pageData = pageIos[pageNb].getData();
@@ -2157,7 +2137,7 @@ public class RecordManager implements Tr
         // Compute the remaining size in the page
         int remaining = pageData.capacity() - pagePos;
 
-        if ( remaining < INT_SIZE )
+        if ( remaining < BTreeConstants.INT_SIZE )
         {
             // We have to copy the serialized length on two pages
 
@@ -2178,7 +2158,7 @@ public class RecordManager implements Tr
 
             // Now deal with the next page
             pageData = pageIos[pageNb + 1].getData();
-            pagePos = LINK_SIZE;
+            pagePos = BTreeConstants.LINK_SIZE;
 
             switch ( remaining )
             {
@@ -2202,7 +2182,7 @@ public class RecordManager implements Tr
         }
 
         // Increment the position to reflect the addition of an Int (4 bytes)
-        position += INT_SIZE;
+        position += BTreeConstants.INT_SIZE;
 
         return position;
     }
@@ -2219,12 +2199,14 @@ public class RecordManager implements Tr
      */
     /* no qualifier */ long store( RecordManagerHeader recordManagerHeader, long position, long value, PageIO... pageIos )
     {
+        int pageSize = recordManagerHeader.pageSize;
+        
         // Compute the page in which we will store the data given the
         // current position
-        int pageNb = computePageNb( recordManagerHeader, position );
+        int pageNb = computePageNb( pageSize, position );
 
         // Compute the position in the current page
-        int pagePos = ( int ) ( position + ( pageNb + 1 ) * LONG_SIZE + INT_SIZE ) - pageNb * recordManagerHeader.pageSize;
+        int pagePos = ( int ) ( position + ( pageNb + 1 ) * BTreeConstants.LONG_SIZE + BTreeConstants.INT_SIZE ) - pageNb * pageSize;
 
         // Get back the buffer in this page
         ByteBuffer pageData = pageIos[pageNb].getData();
@@ -2232,7 +2214,7 @@ public class RecordManager implements Tr
         // Compute the remaining size in the page
         int remaining = pageData.capacity() - pagePos;
 
-        if ( remaining < LONG_SIZE )
+        if ( remaining < BTreeConstants.LONG_SIZE )
         {
             // We have to copy the serialized length on two pages
 
@@ -2269,7 +2251,7 @@ public class RecordManager implements Tr
 
             // Now deal with the next page
             pageData = pageIos[pageNb + 1].getData();
-            pagePos = LINK_SIZE;
+            pagePos = BTreeConstants.LINK_SIZE;
 
             switch ( remaining )
             {
@@ -2309,7 +2291,7 @@ public class RecordManager implements Tr
         }
 
         // Increment the position to reflect the addition of an Long (8 bytes)
-        position += LONG_SIZE;
+        position += BTreeConstants.LONG_SIZE;
 
         return position;
     }
@@ -2324,7 +2306,7 @@ public class RecordManager implements Tr
      * @return A PageHolder containing the copied page
      * @throws IOException If the page can't be written on disk
      */
-    /* No qualifier*/<K, V> PageHolder<K, V> writePage( WriteTransaction transaction, BTree<K, V> btree, Page<K, V> newPage,
+    /* No qualifier*/<K, V> long writePage( WriteTransaction transaction, BTreeInfo<K, V> btreeInfo, Page<K, V> newPage,
         long newRevision ) throws IOException
     {
         // We first need to save the new page on disk
@@ -2332,7 +2314,7 @@ public class RecordManager implements Tr
 
         if ( LOG_PAGES.isDebugEnabled() )
         {
-            LOG_PAGES.debug( "Write data for '{}' btree", btree.getName() );
+            LOG_PAGES.debug( "Write data for '{}' btree", btreeInfo.getName() );
 
             logPageIos( pageIos );
         }
@@ -2343,10 +2325,10 @@ public class RecordManager implements Tr
         // Build the resulting reference
         long offset = pageIos[0].getOffset();
 
-        return new PageHolder<>( btree, newPage, offset );
+        return offset;
     }
 
-
+    
     /* No qualifier */static void logPageIos( PageIO[] pageIos )
     {
         int pageNb = 0;
@@ -2430,13 +2412,13 @@ public class RecordManager implements Tr
         // pages is :
         // NbPages = ( (dataSize - (PageSize - 8 - 4 )) / (PageSize - 8) ) + 1
         // NbPages += ( if (dataSize - (PageSize - 8 - 4 )) % (PageSize - 8) > 0 : 1 : 0 )
-        int availableSize = recordManagerHeader.pageSize - LONG_SIZE;
+        int availableSize = recordManagerHeader.pageSize - BTreeConstants.LONG_SIZE;
         int nbNeededPages = 1;
 
         // Compute the number of pages that will be full but the first page
-        if ( dataSize > availableSize - INT_SIZE )
+        if ( dataSize > availableSize - BTreeConstants.INT_SIZE )
         {
-            int remainingSize = dataSize - ( availableSize - INT_SIZE );
+            int remainingSize = dataSize - ( availableSize - BTreeConstants.INT_SIZE );
             nbNeededPages += remainingSize / availableSize;
             int remain = remainingSize % availableSize;
 
@@ -2494,7 +2476,7 @@ public class RecordManager implements Tr
     /* No qualifier*/ PageIO fetchNewPage( RecordManagerHeader recordManagerHeader ) throws IOException
     {
         //System.out.println( "Fetching new page" );
-        if ( recordManagerHeader.firstFreePage == NO_PAGE )
+        if ( recordManagerHeader.firstFreePage == BTreeConstants.NO_PAGE )
         {
             nbCreatedPages.incrementAndGet();
 
@@ -2503,13 +2485,13 @@ public class RecordManager implements Tr
             long lastOffset = recordManagerHeader.lastOffset;
             PageIO newPage = new PageIO( lastOffset );
 
-            ByteBuffer data = ByteBuffer.allocateDirect( recordManagerHeader.pageSize );
+            ByteBuffer data = ByteBuffer.allocate( recordManagerHeader.pageSize );
 
             // Move the last offset one page forward
             recordManagerHeader.lastOffset = lastOffset + recordManagerHeader.pageSize;
             
             newPage.setData( data );
-            newPage.setNextPage( NO_PAGE );
+            newPage.setNextPage( BTreeConstants.NO_PAGE );
             newPage.setSize( 0 );
 
             LOG.debug( "Requiring a new page at offset {}", newPage.getOffset() );
@@ -2523,7 +2505,7 @@ public class RecordManager implements Tr
             freePageLock.lock();
 
                 // We have some existing free page. Fetch it from disk
-            PageIO pageIo = fetchPage( recordManagerHeader, recordManagerHeader.firstFreePage );
+            PageIO pageIo = fetchPageIO( recordManagerHeader.pageSize, recordManagerHeader.firstFreePage );
 
             // Update the firstFreePage pointer
             recordManagerHeader.firstFreePage = pageIo.getNextPage();
@@ -2531,10 +2513,10 @@ public class RecordManager implements Tr
             freePageLock.unlock();
 
             // overwrite the data of old page
-            ByteBuffer data = ByteBuffer.allocateDirect( recordManagerHeader.pageSize );
+            ByteBuffer data = ByteBuffer.allocate( recordManagerHeader.pageSize );
             pageIo.setData( data );
 
-            pageIo.setNextPage( NO_PAGE );
+            pageIo.setNextPage( BTreeConstants.NO_PAGE );
             pageIo.setSize( 0 );
 
             LOG.debug( "Reused page at offset {}", pageIo.getOffset() );
@@ -2542,6 +2524,46 @@ public class RecordManager implements Tr
             return pageIo;
         }
     }
+    
+    
+    /** 
+     * Fetch a page from cache, or from disk
+     */
+    /* no qualifier */<K, V> Page<K, V> getPage( BTreeInfo btreeInfo, int pageSize, long offset ) throws IOException
+    {
+        Page<K, V> page = ( Page<K, V> )pageCache.get( offset );
+        
+        if ( page == null )
+        {
+            nbCacheMisses.incrementAndGet();
+            PageIO[] pageIos = readPageIOs( pageSize, offset, BTreeConstants.NO_LIMIT );
+            
+            Page<K, V> foundPage = ( Page<K, V> )readPage( pageSize, btreeInfo, pageIos );
+            pageCache.put( offset, foundPage );
+            
+            return foundPage;
+        }
+        else
+        {
+            nbCacheHits.incrementAndGet();
+            
+            return page;
+        }
+    }
+    
+    
+    /* No qualifier */ <K, V> void putPage( WALObject<K, V> walObject )
+    {
+        if ( walObject instanceof Page )
+        {
+            long key = walObject.getOffset();
+            
+            if ( key >= 0L )
+            {
+                pageCache.put( key, ( Page<K, V> )walObject );
+            }
+        }
+    }
 
 
     /**
@@ -2550,11 +2572,11 @@ public class RecordManager implements Tr
      * @param offset The position in the file
      * @return The found page
      */
-    /* no qualifier */PageIO fetchPage( RecordManagerHeader recordManagerHeader, long offset ) throws IOException, EndOfFileExceededException
+    /* no qualifier */PageIO fetchPageIO( int pageSize, long offset ) throws IOException
     {
         checkOffset( offset );
 
-        if ( fileChannel.size() < offset + recordManagerHeader.pageSize )
+        if ( fileChannel.size() < offset + pageSize )
         {
             // Error : we are past the end of the file
             throw new EndOfFileExceededException( "We are fetching a page on " + offset +
@@ -2565,7 +2587,7 @@ public class RecordManager implements Tr
             // Read the page
             fileChannel.position( offset );
 
-            ByteBuffer data = ByteBuffer.allocate( recordManagerHeader.pageSize );
+            ByteBuffer data = ByteBuffer.allocate( pageSize );
             fileChannel.read( data );
             data.rewind();
 
@@ -2601,7 +2623,7 @@ public class RecordManager implements Tr
         }
         else
         {
-            recordManagerHeader.pageSize = DEFAULT_PAGE_SIZE;
+            recordManagerHeader.pageSize = BTreeConstants.DEFAULT_PAGE_SIZE;
         }
     }
 
@@ -2642,7 +2664,7 @@ public class RecordManager implements Tr
     public static String dump( byte octet )
     {
         return new String( new byte[]
-            { HEX_CHAR[( octet & 0x00F0 ) >> 4], HEX_CHAR[octet & 0x000F] } );
+            { BTreeConstants.HEX_CHAR[( octet & 0x00F0 ) >> 4], BTreeConstants.HEX_CHAR[octet & 0x000F] } );
     }
 
 
@@ -2653,8 +2675,8 @@ public class RecordManager implements Tr
     {
         ByteBuffer buffer = pageIo.getData();
         buffer.mark();
-        byte[] longBuffer = new byte[LONG_SIZE];
-        byte[] intBuffer = new byte[INT_SIZE];
+        byte[] longBuffer = new byte[BTreeConstants.LONG_SIZE];
+        byte[] intBuffer = new byte[BTreeConstants.INT_SIZE];
 
         // get the next page offset
         buffer.get( longBuffer );
@@ -2761,7 +2783,7 @@ public class RecordManager implements Tr
             dumpBtreeHeader( recordManagerHeader, currentBtreeOfBtreesPage );
 
             // Dump the previous B-tree of B-trees if any
-            if ( previousBtreeOfBtreesPage != NO_PAGE )
+            if ( previousBtreeOfBtreesPage != BTreeConstants.NO_PAGE )
             {
                 dumpBtreeHeader( recordManagerHeader, previousBtreeOfBtreesPage );
             }
@@ -2770,7 +2792,7 @@ public class RecordManager implements Tr
             dumpBtreeHeader( recordManagerHeader, currentCopiedPagesBtreePage );
 
             // Dump the previous B-tree of B-trees if any
-            if ( previousCopiedPagesBtreePage != NO_PAGE )
+            if ( previousCopiedPagesBtreePage != BTreeConstants.NO_PAGE )
             {
                 dumpBtreeHeader( recordManagerHeader, previousCopiedPagesBtreePage );
             }
@@ -2789,14 +2811,14 @@ public class RecordManager implements Tr
     /**
      * Dump the free pages
      */
-    private void dumpFreePages( RecordManagerHeader recordManagerHeader, long freePageOffset ) throws EndOfFileExceededException, IOException
+    private void dumpFreePages( RecordManagerHeader recordManagerHeader, long freePageOffset ) throws IOException
     {
         System.out.println( "\n  FreePages : " );
         int pageNb = 1;
 
-        while ( freePageOffset != NO_PAGE )
+        while ( freePageOffset != BTreeConstants.NO_PAGE )
         {
-            PageIO pageIo = fetchPage( recordManagerHeader, freePageOffset );
+            PageIO pageIo = fetchPageIO( recordManagerHeader.pageSize, freePageOffset );
 
             System.out.println( "    freePage[" + pageNb + "] : 0x" + Long.toHexString( pageIo.getOffset() ) );
 
@@ -2811,35 +2833,37 @@ public class RecordManager implements Tr
      */
     private long dumpBtreeHeader( RecordManagerHeader recordManagerHeader, long btreeOffset ) throws EndOfFileExceededException, IOException
     {
+        int pageSize = recordManagerHeader.pageSize;
+        
         // First read the B-tree header
-        PageIO[] pageIos = readPageIOs( recordManagerHeader, btreeOffset, Long.MAX_VALUE );
+        PageIO[] pageIos = readPageIOs( pageSize, btreeOffset, Long.MAX_VALUE );
 
         long dataPos = 0L;
 
         // The B-tree current revision
-        long revision = readLong( recordManagerHeader, pageIos, dataPos );
-        dataPos += LONG_SIZE;
+        long revision = readLong( pageSize, pageIos, dataPos );
+        dataPos += BTreeConstants.LONG_SIZE;
 
         // The nb elems in the tree
-        long nbElems = readLong( recordManagerHeader, pageIos, dataPos );
-        dataPos += LONG_SIZE;
+        long nbElems = readLong( pageSize, pageIos, dataPos );
+        dataPos += BTreeConstants.LONG_SIZE;
 
         // The B-tree rootPage offset
-        long rootPageOffset = readLong( recordManagerHeader, pageIos, dataPos );
-        dataPos += LONG_SIZE;
+        long rootPageOffset = readLong( pageSize, pageIos, dataPos );
+        dataPos += BTreeConstants.LONG_SIZE;
 
         // The B-tree page size
-        int btreePageSize = readInt( recordManagerHeader, pageIos, dataPos );
-        dataPos += INT_SIZE;
+        int btreePageSize = readInt( pageSize, pageIos, dataPos );
+        dataPos += BTreeConstants.INT_SIZE;
 
         // The tree name
-        ByteBuffer btreeNameBytes = readBytes( recordManagerHeader, pageIos, dataPos );
-        dataPos += INT_SIZE + btreeNameBytes.limit();
+        ByteBuffer btreeNameBytes = readBytes( pageSize, pageIos, dataPos );
+        dataPos += BTreeConstants.INT_SIZE + btreeNameBytes.limit();
         String btreeName = Strings.utf8ToString( btreeNameBytes );
 
         // The keySerializer FQCN
-        ByteBuffer keySerializerBytes = readBytes( recordManagerHeader, pageIos, dataPos );
-        dataPos += INT_SIZE + keySerializerBytes.limit();
+        ByteBuffer keySerializerBytes = readBytes( pageSize, pageIos, dataPos );
+        dataPos += BTreeConstants.INT_SIZE + keySerializerBytes.limit();
 
         String keySerializerFqcn = "";
 
@@ -2849,10 +2873,10 @@ public class RecordManager implements Tr
         }
 
         // The valueSerialier FQCN
-        ByteBuffer valueSerializerBytes = readBytes( recordManagerHeader, pageIos, dataPos );
+        ByteBuffer valueSerializerBytes = readBytes( pageSize, pageIos, dataPos );
 
         String valueSerializerFqcn = "";
-        dataPos += INT_SIZE + valueSerializerBytes.limit();
+        dataPos += BTreeConstants.INT_SIZE + valueSerializerBytes.limit();
 
         if ( valueSerializerBytes != null )
         {
@@ -2860,10 +2884,10 @@ public class RecordManager implements Tr
         }
 
         // The B-tree allowDuplicates flag
-        int allowDuplicates = readInt( recordManagerHeader, pageIos, dataPos );
+        int allowDuplicates = readInt( pageSize, pageIos, dataPos );
         boolean dupsAllowed = allowDuplicates != 0;
 
-        dataPos += INT_SIZE;
+        dataPos += BTreeConstants.INT_SIZE;
 
         //        System.out.println( "\n  B-Tree " + btreeName );
         //        System.out.println( "  ------------------------- " );
@@ -2993,13 +3017,23 @@ public class RecordManager implements Tr
      * @param name The b-tree name we are looking for
      * @return The managed b-tree
      */
-    public <K, V> BTree<K, V> getBtree( Transaction transaction, String name ) throws IOException
+    public <K, V> BTree<K, V> getBtree( Transaction transaction, String name, long revision ) throws IOException
     {
         RecordManagerHeader recordManagerHeader = transaction.getRecordManagerHeader();
+        
+        // Get the btree from the recordManagerHeader if we have it 
+        BTree<K, V> btree = transaction.getBTree( name );
+        
+        if ( btree != null )
+        {
+            return btree;
+        }
+        
+        // Not already loaded, so load it
         BTree<NameRevision, Long> btreeOfBtrees = recordManagerHeader.getBtreeOfBtrees();
         
-        // Find the newest B-tree reference in the BOB
-        NameRevision nameRevision = new NameRevision( name, Long.MAX_VALUE );
+        // Find the next B-tree reference in the BOB (so revision +1, as we will pick the prev revision)
+        NameRevision nameRevision = new NameRevision( name, revision + 1L );
         
         TupleCursor<NameRevision, Long> cursor = btreeOfBtrees.browseFrom( transaction, nameRevision );
         
@@ -3065,7 +3099,7 @@ public class RecordManager implements Tr
             {
                 long pageOffset = ( ( AbstractPage<K, V> ) page ).getOffset();
 
-                PageIO[] pageIos = readPageIOs( recordManagerHeader, pageOffset, Long.MAX_VALUE );
+                PageIO[] pageIos = readPageIOs( recordManagerHeader.pageSize, pageOffset, Long.MAX_VALUE );
 
                 for ( PageIO pageIo : pageIos )
                 {
@@ -3104,7 +3138,7 @@ public class RecordManager implements Tr
                 copiedPageBtree.insert( transaction, revisionName, pageOffsets );
 
                 // Update the RecordManager Copiedpage Offset
-                recordManagerHeader.currentCopiedPagesBtreeOffset = ( ( BTreeImpl<RevisionName, long[]> ) copiedPageBtree )
+                recordManagerHeader.currentCopiedPagesBtreeOffset = ( ( BTree<RevisionName, long[]> ) copiedPageBtree )
                     .getBtreeOffset();
             }
             else
@@ -3112,7 +3146,7 @@ public class RecordManager implements Tr
                 // Managed B-trees : we simply free the copied pages
                 for ( long pageOffset : pageOffsets )
                 {
-                    PageIO[] pageIos = readPageIOs( recordManagerHeader, pageOffset, Long.MAX_VALUE );
+                    PageIO[] pageIos = readPageIOs( recordManagerHeader.pageSize, pageOffset, Long.MAX_VALUE );
 
                     for ( PageIO pageIo : pageIos )
                     {
@@ -3170,7 +3204,7 @@ public class RecordManager implements Tr
         int pageIndex = 0;
             for ( int i = 0; i < offsets.length; i++ )
             {
-                PageIO[] ios = readPageIOs( recordManagerHeader, offsets[i], Long.MAX_VALUE );
+                PageIO[] ios = readPageIOs( recordManagerHeader.pageSize, offsets[i], Long.MAX_VALUE );
 
                 for ( PageIO io : ios )
                 {
@@ -3242,7 +3276,8 @@ public class RecordManager implements Tr
         config.setKeySerializer( keySerializer );
         config.setValueSerializer( valueSerializer );
 
-        BTree<K, V> btree = new BTreeImpl<>( transaction,  config );
+        BTree<K, V> btree = new BTree<>( transaction, config );
+        
         manage( transaction, btree );
 
         return btree;
@@ -3300,7 +3335,7 @@ public class RecordManager implements Tr
      */
     public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
     {
-        newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
+        newBTreeHeaders.put( btreeHeader.getName(), btreeHeader );
     }
 
 
@@ -3356,7 +3391,7 @@ public class RecordManager implements Tr
 
         long currentFreePageOffset = recordManagerHeader.firstFreePage;
 
-        while ( currentFreePageOffset != NO_PAGE )
+        while ( currentFreePageOffset != BTreeConstants.NO_PAGE )
         {
             //System.out.println( "Next page offset :" + Long.toHexString( currentFreePageOffset ) );
 
@@ -3372,7 +3407,7 @@ public class RecordManager implements Tr
             }
 
             freePageOffsets.add( currentFreePageOffset );
-            PageIO pageIO = fetchPage( recordManagerHeader, currentFreePageOffset );
+            PageIO pageIO = fetchPageIO( recordManagerHeader.pageSize, currentFreePageOffset );
 
             currentFreePageOffset = pageIO.getNextPage();
         }
@@ -3408,12 +3443,21 @@ public class RecordManager implements Tr
     /**
      * @return A copy of the current RecordManager header
      */
-    /* No qualifier */ RecordManagerHeader getRecordManagerHeader()
+    /* No qualifier */ RecordManagerHeader getRecordManagerHeaderCopy()
     {
         return recordManagerHeaderReference.get().copy();
     }
-
-
+    
+    
+    /**
+     * @return The current RecordManager header
+     */
+    /* No qualifier */ RecordManagerHeader getCurrentRecordManagerHeader()
+    {
+        return recordManagerHeaderReference.get();
+    }
+    
+    
     /**
      * @see Object#toString()
      */
@@ -3426,12 +3470,12 @@ public class RecordManager implements Tr
         
         RecordManagerHeader recordManagerHeader = recordManagerHeaderReference.get();
 
-        if ( recordManagerHeader.firstFreePage != NO_PAGE )
+        if ( recordManagerHeader.firstFreePage != BTreeConstants.NO_PAGE )
         {
             long current = recordManagerHeader.firstFreePage;
             boolean isFirst = true;
 
-            while ( current != NO_PAGE )
+            while ( current != BTreeConstants.NO_PAGE )
             {
                 if ( isFirst )
                 {
@@ -3446,7 +3490,7 @@ public class RecordManager implements Tr
 
                 try
                 {
-                    pageIo = fetchPage( recordManagerHeader, current );
+                    pageIo = fetchPageIO( recordManagerHeader.pageSize, current );
                     sb.append( pageIo.getOffset() );
                     current = pageIo.getNextPage();
                 }

Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManagerHeader.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManagerHeader.java?rev=1811602&r1=1811601&r2=1811602&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManagerHeader.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManagerHeader.java Mon Oct  9 20:32:59 2017
@@ -2,6 +2,8 @@ package org.apache.directory.mavibot.btr
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -42,13 +44,16 @@ public class RecordManagerHeader
     /* no qualifier */long revision;
     
     /** The RecordManager underlying page size. */
-    /* no qualifier */int pageSize = RecordManager.DEFAULT_PAGE_SIZE;
+    /* no qualifier */int pageSize = BTreeConstants.DEFAULT_PAGE_SIZE;
     
     /** The number of managed B-trees */
     /* no qualifier */int nbBtree;
 
     /** The first and last free page */
     /* no qualifier */long firstFreePage;
+    
+    /** A map of the current managed B-trees */
+    /* no qualifier */Map<String, BTree> btreeMap = new HashMap<>(); 
 
     /** The b-tree of b-trees, where we store user's b-trees. */
     /* no qualifier */BTree<NameRevision, Long> btreeOfBtrees;
@@ -60,18 +65,19 @@ public class RecordManagerHeader
     /* no qualifier */long currentBtreeOfBtreesOffset;
 
     /** The offset on the current copied pages B-tree */
-    /* no qualifier */long currentCopiedPagesBtreeOffset = RecordManager.NO_PAGE;
+    /* no qualifier */long currentCopiedPagesBtreeOffset = BTreeConstants.NO_PAGE;
     
     /** The page ID incremental counter */
     /* no qualifier */long idCounter = 0;
     
     /** The offset of the end of the file */
-    /* no qualifier */long lastOffset = RecordManager.NO_PAGE;
+    /* no qualifier */long lastOffset = BTreeConstants.NO_PAGE;
     
     
     /** The lock used to protect the recordManagerHeader while accessing it */
     private ReadWriteLock lock = new ReentrantReadWriteLock();
     
+    
     /**
      * Copy the current data structure and returns it.
      * 
@@ -94,6 +100,17 @@ public class RecordManagerHeader
             copy.lastOffset = lastOffset;
             copy.idCounter = idCounter;
             
+            // Copy the map
+            Map<String, BTree> newBTreeMap = new HashMap<>( btreeMap.size() );
+            
+            for ( Map.Entry<String, BTree> entry : btreeMap.entrySet() )
+            {
+                BTree btree = entry.getValue();
+                newBTreeMap.put( entry.getKey(), btree.copy() );
+            }
+            
+            copy.btreeMap = newBTreeMap;
+            
             return copy;
         }
         finally
@@ -120,6 +137,7 @@ public class RecordManagerHeader
             currentCopiedPagesBtreeOffset = update.currentCopiedPagesBtreeOffset;
             firstFreePage = update.firstFreePage;
             lastOffset = update.lastOffset;
+            idCounter = update.idCounter;
         }
         finally
         {
@@ -148,6 +166,24 @@ public class RecordManagerHeader
     {
         return copiedPagesBtree;
     }
+    
+    
+    /* No qualifier */ <K, V> BTree<K, V> getBTree( String name )
+    {
+        return btreeMap.get( name );
+    }
+    
+    
+    /* No qualifier */ <K, V> void addBTree( BTree<K, V> btree )
+    {
+        btreeMap.put( btree.getName(), btree );
+    }
+    
+    
+    /* No qualifier */ boolean containsBTree( String name )
+    {
+        return btreeMap.get( name ) != null;
+    }
 
 
     /**
@@ -167,6 +203,8 @@ public class RecordManagerHeader
      * +---------------------+
      * | current CP offset   | 8 bytes : The offset of the current CopiedPages B-tree
      * +---------------------+
+     * | ID                  | 8 bytes : The page ID
+     * +---------------------+
      * </pre>
      */
     /* No qualifier */ ByteBuffer serialize( RecordManager recordManager )
@@ -189,7 +227,10 @@ public class RecordManagerHeader
         position = recordManager.writeData( recordManagerHeaderBytes, position, currentBtreeOfBtreesOffset );
 
         // The offset of the current B-tree of B-trees
-        recordManager.writeData( recordManagerHeaderBytes, position, currentCopiedPagesBtreeOffset );
+        position = recordManager.writeData( recordManagerHeaderBytes, position, currentCopiedPagesBtreeOffset );
+
+        // The ID counter
+        recordManager.writeData( recordManagerHeaderBytes, position, idCounter );
 
         // Write the RecordManager header on disk
         recordManager.getRecordManagerHeaderBuffer().put( recordManagerHeaderBytes );
@@ -213,14 +254,14 @@ public class RecordManagerHeader
             sb.append( String.format( "%16x", currentCopiedPagesBtreeOffset ) );
             sb.append( "\n" );
 
-            if ( firstFreePage != RecordManager.NO_PAGE )
+            if ( firstFreePage != BTreeConstants.NO_PAGE )
             {
                 long freePage = firstFreePage;
                 sb.append( "free pages list : " );
 
                 boolean isFirst = true;
 
-                while ( freePage != RecordManager.NO_PAGE )
+                while ( freePage != BTreeConstants.NO_PAGE )
                 {
                     if ( isFirst )
                     {
@@ -235,7 +276,7 @@ public class RecordManagerHeader
 
                     try
                     {
-                        PageIO[] freePageIO = recordManager.readPageIOs( this, freePage, 8 );
+                        PageIO[] freePageIO = recordManager.readPageIOs( this.pageSize, freePage, 8 );
 
                         freePage = freePageIO[0].getNextPage();
                     }
@@ -269,6 +310,34 @@ public class RecordManagerHeader
         sb.append( "    BOB current offset :  " ).append( String.format( "%16x", currentBtreeOfBtreesOffset ) ).append( '\n' );
         sb.append( "    CPB current offset :  " ).append( String.format( "%16x", currentCopiedPagesBtreeOffset ) ).append( '\n' );
         sb.append( "    last offset :         " ).append( String.format( "%16x", lastOffset ) ).append( '\n' );
+        
+        if ( btreeMap.isEmpty() )
+        {
+            sb.append( "    No managed B-trees\n" );
+        }
+        else
+        {
+            sb.append( "    Managed B-trees :\n" );
+            sb.append( "        {" );
+            boolean isFirst = true;
+            
+            for ( String name : btreeMap.keySet() )
+            {
+                if ( isFirst )
+                {
+                    isFirst = false;
+                }
+                else
+                {
+                    sb.append(  ", " );
+                }
+                
+                sb.append( name );
+            }
+
+            sb.append( "}\n" );
+        }
+        
         return sb.toString();
     }
 }

Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RemoveResult.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RemoveResult.java?rev=1811602&r1=1811601&r2=1811602&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RemoveResult.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RemoveResult.java Mon Oct  9 20:32:59 2017
@@ -34,15 +34,19 @@ import java.util.List;
  */
 /* No qualifier*/class RemoveResult<K, V> extends AbstractDeleteResult<K, V>
 {
+    /** The position in the page where the element has been found */
+    private int pos;
+
     /**
      * The default constructor for RemoveResult.
      * 
      * @param modifiedPage The modified page
      * @param removedElement The removed element (can be null if the key wasn't present in the tree)
      */
-    public RemoveResult( Page<K, V> modifiedPage, Tuple<K, V> removedElement )
+    public RemoveResult( Page<K, V> modifiedPage, Tuple<K, V> removedElement, int pos )
     {
         super( modifiedPage, removedElement );
+        this.pos = pos;
     }
 
 
@@ -53,9 +57,28 @@ import java.util.List;
      * @param modifiedPage The modified page
      * @param removedElement The removed element (can be null if the key wasn't present in the tree)
      */
-    public RemoveResult( List<Page<K, V>> copiedPages, Page<K, V> modifiedPage, Tuple<K, V> removedElement )
+    public RemoveResult( List<Page<K, V>> copiedPages, Page<K, V> modifiedPage, Tuple<K, V> removedElement , int pos )
     {
         super( copiedPages, modifiedPage, removedElement );
+        this.pos = pos;
+    }
+    
+    
+    /**
+     * @return The position of the removed element
+     */
+    int getPos()
+    {
+        return pos;
+    }
+
+
+    /**
+     * @param pos The position fo the removed element
+     */
+    void setPos( int pos )
+    {
+        this.pos = pos;
     }
 
 
@@ -69,6 +92,7 @@ import java.util.List;
 
         sb.append( "RemoveResult :" );
         sb.append( "\n    removed element = " ).append( getRemovedElement() );
+        sb.append( "\n    Position = " ).append( pos );
         sb.append( "\n    modifiedPage = " ).append( getModifiedPage() );
 
         return sb.toString();

Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionOffsets.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionOffsets.java?rev=1811602&r1=1811601&r2=1811602&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionOffsets.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionOffsets.java Mon Oct  9 20:32:59 2017
@@ -24,7 +24,7 @@ import java.util.Arrays;
 
 
 /**
- * A class to hold name, revision, and copied page offsets of a B-Tree.
+ * A class to hold a revision, and copied page offsets of a B-Tree. This is used by the CPB.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
@@ -50,36 +50,60 @@ public class RevisionOffsets
     }
 
 
+    /**
+     * @return The revison
+     */
     public long getRevision()
     {
         return revision;
     }
 
 
+    /**
+     * @param revision The revision to set
+     */
     /* no qualifier */void setRevision( long revision )
     {
         this.revision = revision;
     }
 
 
+    /**
+     * @return The list of copied page offsets
+     */
     public long[] getOffsets()
     {
         return offsets;
     }
 
 
+    /**
+     * @param offsets The copied page offsets
+     */
     /* no qualifier */void setOffsets( long[] offsets )
     {
         this.offsets = offsets;
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
     public int hashCode()
     {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ( int ) ( revision ^ ( revision >>> 32 ) );
+        int prime = 31;
+        int result = 17;
+        result = prime * result + ( int ) revision;
+        long offsetSum = 0L;
+
+        for ( long offset : offsets )
+        {
+            offsetSum += offset;
+        }
+        
+        result += ( int ) ( offsetSum * result );
+        
         return result;
     }
 
@@ -102,12 +126,7 @@ public class RevisionOffsets
 
         RevisionOffsets other = ( RevisionOffsets ) obj;
 
-        if ( revision != other.revision )
-        {
-            return false;
-        }
-
-        return true;
+        return revision == other.revision;
     }
 
 

Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/Transaction.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/Transaction.java?rev=1811602&r1=1811601&r2=1811602&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/Transaction.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/Transaction.java Mon Oct  9 20:32:59 2017
@@ -67,6 +67,17 @@ public interface Transaction extends Clo
      * @return The current transaction revision
      */
     long getRevision();
+    
+    
+    /**
+     * Retrieve a Page from the cache, or read it from the disk.
+     * 
+     * @param btreeInfo The {@link BtreeInfo} reference
+     * @param offset The page offset
+     * @return The found {@link Page}
+     * @throws IOException If we weren't able to fetch a page
+     */
+    <K, V> Page<K, V> getPage( BTreeInfo<K, V> btreeInfo , long offset ) throws IOException;
 
 
     /**
@@ -93,4 +104,14 @@ public interface Transaction extends Clo
      * @return The associated {@link RecordManagerHeader}
      */
     RecordManagerHeader getRecordManagerHeader();
+
+
+    /**
+     * Get a managed B-tree, knowing its name. It will return the B-tree version
+     * of the given transaction.
+     *
+     * @param name The B-tree we are looking for
+     * @return The found B-tree, or a BTreeNotFoundException if the B-tree does not exist.
+     */
+    <K, V> BTree<K, V> getBTree( String name );
 }