o reinstated the copiedPage BTree (reverted the changes made in revision 1613792)
o updated SpaceReclaimer

diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
index abfa120..d960174 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
@@ -48,6 +48,7 @@
 import org.apache.directory.mavibot.btree.exception.RecordManagerException;
 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
 import org.apache.directory.mavibot.btree.serializer.IntSerializer;
+import org.apache.directory.mavibot.btree.serializer.LongArraySerializer;
 import org.apache.directory.mavibot.btree.serializer.LongSerializer;
 import org.apache.directory.mavibot.btree.util.Strings;
 import org.slf4j.Logger;
@@ -101,13 +102,10 @@
     private long endOfFileOffset;
 
     /**
-     * A Map used to hold the pages that were copied in a new version.
+     * A B-tree used to manage the page that has been copied in a new version.
      * Those pages can be reclaimed when the associated version is dead.
-     * 
-     * Note: the offsets are of AbstractPageS' while freeing the associated
-     *       PageIOs will be fetched and freed.
      **/
-    /* no qualifier */Map<RevisionName, long[]> copiedPageMap = null;
+    /* no qualifier */ BTree<RevisionName, long[]> copiedPageBtree;
 
     /** A constant for an offset on a non existing page */
     public static final long NO_PAGE = -1L;
@@ -178,6 +176,12 @@
     /** The previous B-tree of B-trees header offset */
     private long previousBtreeOfBtreesOffset = NO_PAGE;
 
+    /** The offset on the current copied pages B-tree */
+    /* no qualifier */ long currentCopiedPagesBtreeOffset = NO_PAGE;
+
+    /** The offset on the previous copied pages B-tree */
+    private long previousCopiedPagesBtreeOffset = NO_PAGE;
+
     /** A lock to protect the transaction handling */
     private ReentrantLock transactionLock = new ReentrantLock();
 
@@ -285,8 +289,6 @@
             }
 
             reclaimer = new SpaceReclaimer( this );
-
-            copiedPageMap = reclaimer.readCopiedPageMap( file.getParentFile() );
             runReclaimer();
         }
         catch ( Exception e )
@@ -387,6 +389,9 @@
         // First, create the btree of btrees <NameRevision, Long>
         createBtreeOfBtrees();
 
+        // Now, initialize the Copied Page B-tree
+        createCopiedPagesBtree();
+
         // Inject these B-trees into the RecordManager. They are internal B-trees.
         try
         {
@@ -401,6 +406,16 @@
                 ( ( PersistedBTree<NameRevision, Long> ) btreeOfBtrees ).getBtreeHeader() );
             newBTreeHeaders.put( BTREE_OF_BTREES_NAME,
                 ( ( PersistedBTree<NameRevision, Long> ) btreeOfBtrees ).getBtreeHeader() );
+
+            // The FreePage B-tree
+            manageSubBtree( copiedPageBtree );
+
+            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 )
         {
@@ -433,6 +448,22 @@
 
 
     /**
+     * Create the CopiedPagesBtree
+     */
+    private void createCopiedPagesBtree()
+    {
+        PersistedBTreeConfiguration<RevisionName, long[]> configuration = new PersistedBTreeConfiguration<RevisionName, long[]>();
+        configuration.setKeySerializer( RevisionNameSerializer.INSTANCE );
+        configuration.setName( COPIED_PAGE_BTREE_NAME );
+        configuration.setValueSerializer( LongArraySerializer.INSTANCE );
+        configuration.setBtreeType( BTreeTypeEnum.COPIED_PAGES_BTREE );
+        configuration.setCacheSize( PersistedBTree.DEFAULT_CACHE_SIZE );
+
+        copiedPageBtree = BTreeFactory.createPersistedBTree( configuration );
+    }
+
+
+    /**
      * Load the BTrees from the disk.
      *
      * @throws InstantiationException
@@ -489,6 +520,12 @@
             // The previous BOB offset
             previousBtreeOfBtreesOffset = recordManagerHeader.getLong();
 
+            // The current Copied Pages B-tree offset
+            currentCopiedPagesBtreeOffset = recordManagerHeader.getLong();
+
+            // The previous Copied Pages B-tree offset
+            previousCopiedPagesBtreeOffset = recordManagerHeader.getLong();
+
             // read the B-tree of B-trees
             PageIO[] bobHeaderPageIos = readPageIOs( currentBtreeOfBtreesOffset, Long.MAX_VALUE );
 
@@ -497,6 +534,14 @@
 
             loadBtree( bobHeaderPageIos, btreeOfBtrees );
 
+            // read the copied page B-tree
+            PageIO[] copiedPagesPageIos = readPageIOs( currentCopiedPagesBtreeOffset, Long.MAX_VALUE );
+
+            copiedPageBtree = BTreeFactory.<RevisionName, long[]> createPersistedBTree( BTreeTypeEnum.COPIED_PAGES_BTREE );
+            //( ( PersistedBTree<RevisionName, long[]> ) copiedPageBtree ).setBtreeHeaderOffset( currentCopiedPagesBtreeOffset );
+
+            loadBtree( copiedPagesPageIos, copiedPageBtree );
+
             // Now, read all the B-trees from the btree of btrees
             TupleCursor<NameRevision, Long> btreeCursor = btreeOfBtrees.browse();
             Map<String, Long> loadedBtrees = new HashMap<String, Long>();
@@ -534,6 +579,7 @@
 
             // TODO : clean up the old revisions...
 
+
             // Now, we can load the real btrees using the offsets
             for ( String btreeName : loadedBtrees.keySet() )
             {
@@ -1620,7 +1666,9 @@
 
         // Now, if this is a new B-tree, add it to the B-tree of B-trees
         // Add the btree into the map of managed B-trees
-        if ( ( btree.getType() != BTreeTypeEnum.BTREE_OF_BTREES ) && ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) )
+        if ( ( btree.getType() != BTreeTypeEnum.BTREE_OF_BTREES ) && 
+            ( btree.getType() != BTreeTypeEnum.COPIED_PAGES_BTREE ) && 
+            ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) )
         {
             managedBtrees.put( name, ( BTree<Object, Object> ) btree );
         }
@@ -1633,7 +1681,9 @@
         NameRevision nameRevision = new NameRevision( name, 0L );
 
         // Inject it into the B-tree of B-tree
-        if ( ( btree.getType() != BTreeTypeEnum.BTREE_OF_BTREES ) && ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) )
+        if ( ( btree.getType() != BTreeTypeEnum.BTREE_OF_BTREES ) && 
+            ( btree.getType() != BTreeTypeEnum.COPIED_PAGES_BTREE ) && 
+            ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) )
         {
             // We can safely increment the number of managed B-trees
             nbBtree++;
@@ -1959,6 +2009,12 @@
         // The offset of the copied pages B-tree
         position = writeData( RECORD_MANAGER_HEADER_BYTES, position, previousBtreeOfBtreesOffset );
 
+        // The offset of the current B-tree of B-trees
+        position = writeData( RECORD_MANAGER_HEADER_BYTES, position, currentCopiedPagesBtreeOffset );
+
+        // The offset of the copied pages B-tree
+        position = writeData( RECORD_MANAGER_HEADER_BYTES, position, previousCopiedPagesBtreeOffset );
+
         // Write the RecordManager header on disk
         RECORD_MANAGER_HEADER_BUFFER.put( RECORD_MANAGER_HEADER_BYTES );
         RECORD_MANAGER_HEADER_BUFFER.flip();
@@ -1970,10 +2026,10 @@
             StringBuilder sb = new StringBuilder();
 
             sb.append( "First free page     : 0x" ).append( Long.toHexString( firstFreePage ) ).append( "\n" );
-            sb.append( "Current BOB header  : 0x" ).append( Long.toHexString( currentBtreeOfBtreesOffset ) )
-                .append( "\n" );
-            sb.append( "Previous BOB header : 0x" ).append( Long.toHexString( previousBtreeOfBtreesOffset ) )
-                .append( "\n" );
+            sb.append( "Current BOB header  : 0x" ).append( Long.toHexString( currentBtreeOfBtreesOffset ) ).append( "\n" );
+            sb.append( "Previous BOB header : 0x" ).append( Long.toHexString( previousBtreeOfBtreesOffset ) ).append( "\n" );
+            sb.append( "Current CPB header  : 0x" ).append( Long.toHexString( currentCopiedPagesBtreeOffset ) ).append( "\n" );
+            sb.append( "Previous CPB header : 0x" ).append( Long.toHexString( previousCopiedPagesBtreeOffset ) ).append( "\n" );
 
             if ( firstFreePage != NO_PAGE )
             {
@@ -2039,6 +2095,7 @@
 
         // Reset the old versions
         previousBtreeOfBtreesOffset = -1L;
+        previousCopiedPagesBtreeOffset = -1L;
 
         nbUpdateRMHeader.incrementAndGet();
     }
@@ -2072,6 +2129,12 @@
             previousBtreeOfBtreesOffset = currentBtreeOfBtreesOffset;
             currentBtreeOfBtreesOffset = newBtreeOfBtreesOffset;
         }
+
+        if ( newCopiedPageBtreeOffset != -1L )
+        {
+            previousCopiedPagesBtreeOffset = currentCopiedPagesBtreeOffset;
+            currentCopiedPagesBtreeOffset = newCopiedPageBtreeOffset;
+        }
     }
 
 
@@ -2149,7 +2212,10 @@
             pageOffsets[pos++] = ( ( AbstractPage<K, V> ) page ).getOffset();
         }
 
-        copiedPageMap.put( revisionName, pageOffsets );
+        copiedPageBtree.insert( revisionName, pageOffsets );
+
+        // Update the CopiedPageBtree offset
+        currentCopiedPagesBtreeOffset = ( ( AbstractBTree<RevisionName, long[]> ) copiedPageBtree ).getBtreeHeader().getBTreeHeaderOffset();
     }
 
 
@@ -3191,6 +3257,7 @@
         }
 
         // Close the management B-trees
+        copiedPageBtree.close();
         btreeOfBtrees.close();
 
         managedBtrees.clear();
@@ -3201,8 +3268,6 @@
         // And close the channel
         fileChannel.close();
 
-        reclaimer.storeCopiedPageMap( file.getParentFile() );
-
         commit();
     }
 
@@ -3524,7 +3589,7 @@
     {
         RevisionName revisionName = new RevisionName( revision, name );
 
-        copiedPageMap.put( revisionName, copiedPages );
+        copiedPageBtree.insert( revisionName, copiedPages );
     }
 
 
@@ -3542,6 +3607,11 @@
             return;
         }
 
+        if ( btree == copiedPageBtree )
+        {
+            return;
+        }
+
         NameRevision nameRevision = new NameRevision( btree.getName(), rootPage.getRevision() );
 
         ( ( AbstractBTree<NameRevision, Long> ) btreeOfBtrees ).insert( nameRevision,
@@ -3692,7 +3762,10 @@
                 // Deal with standard B-trees
                 RevisionName revisionName = new RevisionName( revision, btree.getName() );
 
-                copiedPageMap.put( revisionName, pageOffsets );
+                copiedPageBtree.insert( revisionName, pageOffsets );
+
+                // Update the RecordManager Copiedpage Offset
+                currentCopiedPagesBtreeOffset = ( ( PersistedBTree<RevisionName, long[]> ) copiedPageBtree ).getBtreeOffset();
             }
             else
             {
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/SpaceReclaimer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/SpaceReclaimer.java
index 2f29402..e119ecc 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/SpaceReclaimer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/SpaceReclaimer.java
@@ -63,104 +63,7 @@
     public SpaceReclaimer( RecordManager rm )
     {
         this.rm = rm;
-    }
-
-    
-    /**
-     * stores the copied page map, if not empty, in a file under the given directory
-     * 
-     * @param dir the directory where mavibot database file is present
-     */
-    /* no qualifier */ void storeCopiedPageMap( File dir )
-    {
-        if ( rm.copiedPageMap.isEmpty() )
-        {
-            LOG.debug( "Copied page map is empty, nothing to store on disk." );
-            return;
-        }
-        
-        File file = new File( dir, COPIED_PAGE_MAP_DATA_FILE );
-
-        try
-        {
-            LOG.debug( "Storing {} RevisionNames of Copied page map", rm.copiedPageMap.size() );
-            
-            OutputStream fileOut = new FileOutputStream( file );
-            
-            ObjectOutputStream objOut = new ObjectOutputStream( fileOut );
-            
-            objOut.writeObject( rm.copiedPageMap );
-            
-            objOut.close();
-            
-            LOG.debug( "Successfully stored copied page map in {}", file.getAbsolutePath() );
-        }
-        catch( Exception e )
-        {
-            LOG.warn( "Failed to store the copied page map in {}", file.getAbsolutePath() );
-            LOG.warn( "", e );
-        }
-    }
-
-
-    /**
-     * reads the copied page map from the file named {@link #COPIED_PAGE_MAP_DATA_FILE} if it
-     * is present under the given directory
-     * 
-     * @param dir the directory where mavibot database file is present
-     * 
-     * @return
-     */
-    /* no qualifier */ ConcurrentHashMap<RevisionName, long[]> readCopiedPageMap( File dir )
-    {
-        
-        ConcurrentHashMap<RevisionName, long[]> map = new ConcurrentHashMap<RevisionName, long[]>();
-        
-        File file = new File( dir, COPIED_PAGE_MAP_DATA_FILE );
-        
-        if ( !file.exists() )
-        {
-            LOG.debug( "Copied page map store {} doesn't exist, returning empty map", file.getAbsolutePath() );
-            return map;
-        }
-
-        try
-        {
-            LOG.debug( "Reading Copied page map data stored in {}", file.getAbsolutePath() );
-            
-            InputStream fileIn = new FileInputStream( file );
-            
-            ObjectInputStream objIn = new ObjectInputStream( fileIn );
-            
-            map = ( ConcurrentHashMap<RevisionName, long[]> ) objIn.readObject();
-            
-            objIn.close();
-            
-            LOG.debug( "Successfully read copied page map containing {} RevisionNames", map.size() );
-        }
-        catch( Exception e )
-        {
-            LOG.warn( "Failed to read the copied page map from {}", file.getAbsolutePath() );
-            LOG.warn( "", e );
-        }
-        finally
-        {
-            boolean deleted = file.delete();
-            
-            // this is dangerous, cause during a subsequent restart the pages
-            // will be freed again, but this time they might have been in use
-            if( !deleted )
-            {
-                String warn = "Failed to delete the copied page map store " + file.getAbsolutePath() +
-                    " Make sure the approapriate permissions are given to delete this file by mavibot process." ;
-                LOG.warn( warn );
-                
-                throw new RuntimeException( warn );
-            }
-        }
-        
-        return map;
-    }
+    }    
 
     
     /**
@@ -207,7 +110,7 @@
                     rm.free( offsets );
 
                     RevisionName key = new RevisionName( rv, name );
-                    rm.copiedPageMap.remove( key );
+                    rm.copiedPageBtree.delete( key );
                 }
             }
         }
@@ -228,21 +131,13 @@
      */
     private List<RevisionOffset> getRevisions( String name ) throws Exception
     {
-        long nbElems = rm.copiedPageMap.size();
-        //System.out.println( "Total number of entries in CPB " + nbElems );
-
-        if ( nbElems == 0 )
-        {
-            return Collections.EMPTY_LIST;
-        }
-
-        Iterator<Map.Entry<RevisionName, long[]>> cursor = rm.copiedPageMap.entrySet().iterator();
+        TupleCursor<RevisionName, long[]> cursor = rm.copiedPageBtree.browse();
 
         List<RevisionOffset> lst = new ArrayList<RevisionOffset>();
 
         while ( cursor.hasNext() )
         {
-            Map.Entry<RevisionName, long[]> t = cursor.next();
+            Tuple<RevisionName, long[]> t = cursor.next();
             RevisionName rn = t.getKey();
             if ( name.equals( rn.getName() ) )
             {