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 2015/11/02 00:01:01 UTC

svn commit: r1711861 [3/4] - in /directory/mavibot/branches/single-value/mavibot/src: main/java/org/apache/directory/mavibot/btree/ main/java/org/apache/directory/mavibot/btree/exception/ 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=1711861&r1=1711860&r2=1711861&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 Sun Nov  1 23:01:00 2015
@@ -26,6 +26,7 @@ import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -41,6 +42,7 @@ import java.util.concurrent.locks.Reentr
 
 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
 import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
+import org.apache.directory.mavibot.btree.exception.CursorException;
 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
 import org.apache.directory.mavibot.btree.exception.FileException;
 import org.apache.directory.mavibot.btree.exception.InvalidOffsetException;
@@ -98,9 +100,6 @@ public class RecordManager extends Abstr
     public AtomicLong nbUpdateBtreeHeader = new AtomicLong( 0 );
     public AtomicLong nbUpdatePageIOs = new AtomicLong( 0 );
 
-    /** The offset of the end of the file */
-    private long endOfFileOffset;
-
     /**
      * 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.
@@ -224,6 +223,9 @@ public class RecordManager extends Abstr
     private boolean disableReclaimer = false;
 
     public Map<Long, Integer> writeCounter = new HashMap<Long, Integer>();
+    
+    /** The transaction context */
+    private TransactionContext context;
 
 
     /**
@@ -281,9 +283,6 @@ public class RecordManager extends Abstr
             RandomAccessFile randomFile = new RandomAccessFile( file, "rw" );
             fileChannel = randomFile.getChannel();
 
-            // get the current end of file offset
-            endOfFileOffset = fileChannel.size();
-
             if ( isNewFile )
             {
                 initRecordManager();
@@ -322,6 +321,7 @@ public class RecordManager extends Abstr
             reclaimer.reclaim();
             // must update the headers after reclaim operation
             updateRecordManagerHeader();
+            writeRecordManagerHeader();
         }
         catch ( Exception e )
         {
@@ -395,9 +395,7 @@ public class RecordManager extends Abstr
         currentBtreeOfBtreesOffset = NO_PAGE;
 
         updateRecordManagerHeader();
-
-        // Set the offset of the end of the file
-        endOfFileOffset = fileChannel.size();
+        writeRecordManagerHeader();
 
         // First, create the btree of btrees <NameRevision, Long>
         createBtreeOfBtrees();
@@ -408,11 +406,11 @@ public class RecordManager extends Abstr
         // Inject these B-trees into the RecordManager. They are internal B-trees.
         try
         {
-            manageSubBtree( btreeOfBtrees );
+            beginTransaction();
+            writeManagementTree( btreeOfBtrees );
 
             currentBtreeOfBtreesOffset = ( ( PersistedBTree<NameRevision, Long> ) btreeOfBtrees ).getBtreeHeader()
                 .getBTreeHeaderOffset();
-            updateRecordManagerHeader();
 
             // Inject the BtreeOfBtrees into the currentBtreeHeaders map
             currentBTreeHeaders.put( BTREE_OF_BTREES_NAME,
@@ -420,18 +418,20 @@ public class RecordManager extends Abstr
             newBTreeHeaders.put( BTREE_OF_BTREES_NAME,
                 ( ( PersistedBTree<NameRevision, Long> ) btreeOfBtrees ).getBtreeHeader() );
 
-            // The FreePage B-tree
-            manageSubBtree( copiedPageBtree );
+            // The Copied Pages B-tree
+            writeManagementTree( 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() );
+            
+            // And finally, commit the transaction
+            commit();
         }
         catch ( BTreeAlreadyManagedException btame )
         {
@@ -488,9 +488,10 @@ public class RecordManager extends Abstr
      * @throws NoSuchFieldException
      * @throws SecurityException
      * @throws IllegalArgumentException
+     * @throws CursorException 
      */
     private void loadRecordManager() throws IOException, ClassNotFoundException, IllegalAccessException,
-        InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException, KeyNotFoundException
+        InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException, KeyNotFoundException, CursorException
     {
         if ( fileChannel.size() != 0 )
         {
@@ -608,9 +609,6 @@ public class RecordManager extends Abstr
                 // Add the btree into the map of managed B-trees
                 managedBtrees.put( btreeName, ( BTree<Object, Object> ) btree );
             }
-
-            // We are done ! Let's finish with the last initialization parts
-            endOfFileOffset = fileChannel.size();
         }
     }
 
@@ -637,6 +635,19 @@ public class RecordManager extends Abstr
             TXN_LOG.debug( "..o The current thread already holds the lock" );
         }
 
+        // Create the context 
+        try
+        {
+            context = new TransactionContext( fileChannel.size() );
+        }
+        catch ( IOException ioe )
+        {
+            String name = Thread.currentThread().getName();
+            String err = "This thread, '" + name + "' cannot get the file size ";
+            TXN_LOG.error( err );
+            throw new RecordManagerException( err );
+        }
+        
         // Now, check the TLS state
         incrementTxnLevel();
     }
@@ -688,9 +699,22 @@ public class RecordManager extends Abstr
                 return;
 
             case 1:
+                // First, write all the pageIos that are present in the context
+                Collection<WALObject> walObjects = context.getPages();
+                
+                try
+                {
+                    flushObjects( walObjects );
+                }
+                catch ( IOException ioe )
+                {
+                    
+                }
+                
                 // We are done with the transaction, we can update the RMHeader and swap the BTreeHeaders
                 // First update the RMHeader to be sure that we have a way to restore from a crash
                 updateRecordManagerHeader();
+                writeRecordManagerHeader();
 
                 // Swap the BtreeHeaders maps
                 swapCurrentBtreeHeaders();
@@ -715,6 +739,7 @@ public class RecordManager extends Abstr
                 // And update the RMHeader again, removing the old references to BOB and CPB b-tree headers
                 // here, we have to erase the old references to keep only the new ones.
                 updateRecordManagerHeader();
+                writeRecordManagerHeader();
 
                 commitCount++;
 
@@ -961,7 +986,7 @@ public class RecordManager extends Abstr
      */
     /* no qualifier */void checkOffset( long offset )
     {
-        if ( ( offset < 0 ) || ( offset > endOfFileOffset ) || ( ( offset % pageSize ) != 0 ) )
+        if ( ( offset < 0 ) || ( offset > context.getLastOffset() ) || ( ( offset % pageSize ) != 0 ) )
         {
             throw new InvalidOffsetException( "Bad Offset : " + offset );
         }
@@ -1077,10 +1102,6 @@ public class RecordManager extends Abstr
         BTreeFactory.setValueSerializer( btree, valueSerializerFqcn );
 
         // The B-tree allowDuplicates flag
-        int allowDuplicates = readInt( infoPageIos, dataPos );
-        ( ( PersistedBTree<K, V> ) btree ).setAllowDuplicates( allowDuplicates != 0 );
-        dataPos += INT_SIZE;
-
         // Set the recordManager in the btree
         ( ( PersistedBTree<K, V> ) btree ).setRecordManager( this );
 
@@ -1193,43 +1214,23 @@ public class RecordManager extends Abstr
         leaf.setLastOffset( pageIos[pageIos.length - 1].getOffset() );
 
         int[] keyLengths = new int[nbElems];
-        int[] valueLengths = new int[nbElems];
-
-        boolean isNotSubTree = ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB );
+        int valueLength = 0;
 
         // Read each key and value
         for ( int i = 0; i < nbElems; i++ )
         {
-            if ( isNotSubTree )
-            {
-                // Read the number of values
-                int nbValues = byteBuffer.getInt();
-                PersistedValueHolder<V> valueHolder = null;
+            // Read the number of values
+            PersistedValueHolder<V> valueHolder = null;
 
-                if ( nbValues < 0 )
-                {
-                    // This is a sub-btree
-                    byte[] btreeOffsetBytes = new byte[LONG_SIZE];
-                    byteBuffer.get( btreeOffsetBytes );
+            // Read the value's length
+            valueLength = byteBuffer.getInt();
 
-                    // Create the valueHolder. As the number of values is negative, we have to switch
-                    // to a positive value but as we start at -1 for 0 value, add 1.
-                    valueHolder = new PersistedValueHolder<V>( btree, 1 - nbValues, btreeOffsetBytes );
-                }
-                else
-                {
-                    // This is an array
-                    // Read the value's array length
-                    valueLengths[i] = byteBuffer.getInt();
+            // This is a value, read the byte[] associated with it
+            byte[] valuBytes = new byte[valueLength];
+            byteBuffer.get( valuBytes );
+            valueHolder = new PersistedValueHolder<V>( btree, valuBytes );
 
-                    // This is an Array of values, read the byte[] associated with it
-                    byte[] arrayBytes = new byte[valueLengths[i]];
-                    byteBuffer.get( arrayBytes );
-                    valueHolder = new PersistedValueHolder<V>( btree, nbValues, arrayBytes );
-                }
-
-                BTreeFactory.setValue( btree, leaf, i, valueHolder );
-            }
+            BTreeFactory.setValue( btree, leaf, i, valueHolder );
 
             keyLengths[i] = byteBuffer.getInt();
             byte[] data = new byte[keyLengths[i]];
@@ -1548,6 +1549,20 @@ public class RecordManager extends Abstr
         return value;
     }
 
+    
+    private <K, V> BTreeInfo<K, V> createBtreeInfo( BTree<K, V> btree )
+    {
+        BTreeInfo<K,V> btreeInfo = new BTreeInfo<K, V>();
+        
+        btreeInfo.setBtree( btree );
+        btreeInfo.setPageSize( btree.getPageSize() );
+        btreeInfo.setBtreeName( btree.getName() );
+        btreeInfo.setKeySerializer( btree.getKeySerializerFQCN() );
+        btreeInfo.setValueSerializer( btree.getValueSerializerFQCN() );
+        
+        return btreeInfo;
+    }
+
 
     /**
      * Manage a B-tree. The btree will be added and managed by this RecordManager. We will create a
@@ -1582,29 +1597,27 @@ public class RecordManager extends Abstr
                 throw new BTreeAlreadyManagedException( name );
             }
 
-            // Now, write the B-tree informations
-            long btreeInfoOffset = writeBtreeInfo( btree );
+            // Get the B-tree header offset
+            PageIO[] btreeHeaderPageIos = getFreePageIOs( 0 );
+            long btreeHeaderOffset = btreeHeaderPageIos[0].getOffset();
             BTreeHeader<K, V> btreeHeader = ( ( AbstractBTree<K, V> ) btree ).getBtreeHeader();
+            ( ( PersistedBTree<K, V> ) btree ).setBtreeHeaderOffset( btreeHeaderOffset );
+            context.addPage( btreeHeaderOffset, btreeHeader );
+
+            // Get the B-tree info offset
+            BTreeInfo<K, V> btreeInfo = createBtreeInfo( btree );
+            PageIO[] btreeInfoPageIos = getFreePageIOs( 0 );
+            long btreeInfoOffset = btreeInfoPageIos[0].getOffset();
             ( ( PersistedBTree<K, V> ) btree ).setBtreeInfoOffset( btreeInfoOffset );
+            context.addPage( btreeInfoOffset, btreeInfo );
 
-            // Serialize the B-tree root page
+            // Get the B-tree root page offset
             Page<K, V> rootPage = btreeHeader.getRootPage();
-
-            PageIO[] rootPageIos = serializePage( btree, btreeHeader.getRevision(), rootPage );
-
-            // Get the reference on the first page
+            PageIO[] rootPageIos = getFreePageIOs( 0 );
             long rootPageOffset = rootPageIos[0].getOffset();
-
-            // Store the rootPageOffset into the Btree header and into the rootPage
             btreeHeader.setRootPageOffset( rootPageOffset );
             ( ( PersistedLeaf<K, V> ) rootPage ).setOffset( rootPageOffset );
 
-            LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() );
-            flushPages( rootPageIos );
-
-            // And the B-tree header
-            long btreeHeaderOffset = writeBtreeHeader( btree, btreeHeader );
-
             // 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
             managedBtrees.put( name, ( BTree<Object, Object> ) btree );
@@ -1620,7 +1633,8 @@ public class RecordManager extends Abstr
             NameRevision nameRevision = new NameRevision( name, 0L );
 
             // Inject it into the B-tree of B-tree
-            btreeOfBtrees.insert( nameRevision, btreeHeaderOffset );
+            btreeOfBtrees.insert( nameRevision, btreeHeader.getId() );
+            
             commit();
         }
         catch ( IOException ioe )
@@ -1632,9 +1646,81 @@ public class RecordManager extends Abstr
 
 
     /**
-     * Managing a btree is a matter of storing an reference to the managed B-tree in the B-tree Of B-trees.
-     * We store a tuple of NameRevision (where revision is 0L) and a offset to the B-tree header.
-     * At the same time, we keep a track of the managed B-trees in a Map.
+     * Write the B-tree informations on disk. We will write the following informations :
+     * <pre>
+     * +------------+
+     * | pageSize   | The B-tree page size (ie, the number of elements per page max)
+     * +------------+
+     * | nameSize   | The B-tree name size
+     * +------------+
+     * | name       | The B-tree name
+     * +------------+
+     * | keySerSize | The keySerializer FQCN size
+     * +------------+
+     * | keySerFQCN | The keySerializer FQCN
+     * +------------+
+     * | valSerSize | The Value serializer FQCN size
+     * +------------+
+     * | valSerKQCN | The valueSerializer FQCN
+     * +------------+
+     * </pre>
+     * @param btree The B-tree which header has to be written
+     * @return The B-tree header offset
+     * @throws IOException If we weren't able to write the B-tree header
+     */
+    private <K, V> long writeBtreeInfo( BTree<K, V> btree ) throws IOException
+    {
+        // We will add the newly managed B-tree at the end of the header.
+        byte[] btreeNameBytes = Strings.getBytesUtf8( btree.getName() );
+        byte[] keySerializerBytes = Strings.getBytesUtf8( btree.getKeySerializerFQCN() );
+        byte[] valueSerializerBytes = Strings.getBytesUtf8( btree.getValueSerializerFQCN() );
+
+        int bufferSize =
+            INT_SIZE + // The page size
+                INT_SIZE + // The name size
+                btreeNameBytes.length + // The name
+                INT_SIZE + // The keySerializerBytes size
+                keySerializerBytes.length + // The keySerializerBytes
+                INT_SIZE + // The valueSerializerBytes size
+                valueSerializerBytes.length; // The valueSerializerBytes
+
+        // Get the pageIOs we need to store the data. We may need more than one.
+        PageIO[] btreeHeaderPageIos = getFreePageIOs( bufferSize );
+
+        // Keep the B-tree header Offset into the B-tree
+        long btreeInfoOffset = btreeHeaderPageIos[0].getOffset();
+
+        // Now store the B-tree information data in the pages :
+        // - the B-tree page size
+        // - the B-tree name
+        // - the keySerializer FQCN
+        // - the valueSerializer FQCN
+        // Starts at 0
+        long position = 0L;
+
+        // The B-tree page size
+        position = store( position, btree.getPageSize(), btreeHeaderPageIos );
+
+        // The tree name
+        position = store( position, btreeNameBytes, btreeHeaderPageIos );
+
+        // The keySerializer FQCN
+        position = store( position, keySerializerBytes, btreeHeaderPageIos );
+
+        // The valueSerialier FQCN
+        position = store( position, valueSerializerBytes, btreeHeaderPageIos );
+
+        // And flush the pages to disk now
+        LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() );
+        flushPages( btreeHeaderPageIos );
+
+        return btreeInfoOffset;
+    }
+
+
+    /**
+     * Write the management BTrees (BOB and CPB). There are special BTrees, we can write them on disk immediately 
+     * (this is done only once anyway : when we create the RecordManager).
      *
      * @param btree The new B-tree to manage.
      * @param treeType flag indicating if this is an internal tree
@@ -1642,7 +1728,7 @@ public class RecordManager extends Abstr
      * @throws BTreeAlreadyManagedException If the B-tree is already managed
      * @throws IOException
      */
-    public synchronized <K, V> void manageSubBtree( BTree<K, V> btree )
+    private synchronized <K, V> void writeManagementTree( BTree<K, V> btree )
         throws BTreeAlreadyManagedException, IOException
     {
         LOG.debug( "Managing the sub-btree {}", btree.getName() );
@@ -1650,13 +1736,6 @@ public class RecordManager extends Abstr
 
         String name = btree.getName();
 
-        if ( managedBtrees.containsKey( name ) )
-        {
-            // There is already a subB-tree with this name in the recordManager...
-            LOG.error( "There is already a sub-B-tree named '{}' managed by this recordManager", name );
-            throw new BTreeAlreadyManagedException( name );
-        }
-
         // Now, write the subB-tree informations
         long btreeInfoOffset = writeBtreeInfo( btree );
         BTreeHeader<K, V> btreeHeader = ( ( AbstractBTree<K, V> ) btree ).getBtreeHeader();
@@ -1666,7 +1745,7 @@ public class RecordManager extends Abstr
         Page<K, V> rootPage = btreeHeader.getRootPage();
 
         PageIO[] rootPageIos = serializePage( btree, btreeHeader.getRevision(), rootPage );
-
+        
         // Get the reference on the first page
         long rootPageOffset = rootPageIos[0].getOffset();
 
@@ -1678,37 +1757,9 @@ public class RecordManager extends Abstr
         LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() );
         flushPages( rootPageIos );
 
-        // And the B-tree header
-        long btreeHeaderOffset = writeBtreeHeader( btree, btreeHeader );
-
-        // 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.COPIED_PAGES_BTREE ) &&
-            ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) )
-        {
-            managedBtrees.put( name, ( BTree<Object, Object> ) btree );
-        }
-
-        // And in the Map of currentBtreeHeaders and newBtreeHeaders
+        // Now, if this is a new B-tree, add it t        // And in the Map of currentBtreeHeaders and newBtreeHeaders
         currentBTreeHeaders.put( name, btreeHeader );
         newBTreeHeaders.put( name, btreeHeader );
-
-        // Create the new NameRevision
-        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.COPIED_PAGES_BTREE ) &&
-            ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB ) )
-        {
-            // We can safely increment the number of managed B-trees
-            nbBtree++;
-
-            btreeOfBtrees.insert( nameRevision, btreeHeaderOffset );
-        }
-
-        updateRecordManagerHeader();
     }
 
 
@@ -1734,8 +1785,6 @@ public class RecordManager extends Abstr
     {
         int nbElems = page.getNbElems();
 
-        boolean isNotSubTree = ( btree.getType() != BTreeTypeEnum.PERSISTED_SUB );
-
         if ( nbElems == 0 )
         {
             return serializeRootPage( revision );
@@ -1787,11 +1836,7 @@ public class RecordManager extends Abstr
                 }
                 else
                 {
-                    if ( isNotSubTree )
-                    {
-                        dataSize += serializeLeafValue( ( PersistedLeaf<K, V> ) page, pos, serializedData );
-                    }
-
+                    dataSize += serializeLeafValue( ( PersistedLeaf<K, V> ) page, pos, serializedData );
                     dataSize += serializeLeafKey( ( PersistedLeaf<K, V> ) page, pos, serializedData );
                 }
             }
@@ -1905,54 +1950,22 @@ public class RecordManager extends Abstr
     private <K, V> int serializeLeafValue( PersistedLeaf<K, V> leaf, int pos, List<byte[]> serializedData )
         throws IOException
     {
-        // The value can be an Array or a sub-btree, but we don't care
-        // we just iterate on all the values
         ValueHolder<V> valueHolder = leaf.getValue( pos );
         int dataSize = 0;
-        int nbValues = valueHolder.size();
 
-        if ( nbValues == 0 )
-        {
-            // No value.
-            byte[] buffer = IntSerializer.serialize( nbValues );
-            serializedData.add( buffer );
+        // We have a serialized value. Just flush it
+        byte[] data = ( ( PersistedValueHolder<V> ) valueHolder ).getRaw();
+        dataSize += data.length;
 
-            return buffer.length;
-        }
-
-        if ( !valueHolder.isSubBtree() )
-        {
-            // Write the nb elements first
-            byte[] buffer = IntSerializer.serialize( nbValues );
-            serializedData.add( buffer );
-            dataSize = INT_SIZE;
-
-            // We have a serialized value. Just flush it
-            byte[] data = ( ( PersistedValueHolder<V> ) valueHolder ).getRaw();
-            dataSize += data.length;
-
-            // Store the data size
-            buffer = IntSerializer.serialize( data.length );
-            serializedData.add( buffer );
-            dataSize += INT_SIZE;
+        // Store the data size
+        byte[] buffer = IntSerializer.serialize( data.length );
+        serializedData.add( buffer );
+        dataSize += INT_SIZE;
 
-            // and add the data if it's not 0
-            if ( data.length > 0 )
-            {
-                serializedData.add( data );
-            }
-        }
-        else
+        // and add the data if it's not 0
+        if ( data.length > 0 )
         {
-            // Store the nbVlues as a negative number. We add 1 so that 0 is not confused with an Array value
-            byte[] buffer = IntSerializer.serialize( -( nbValues + 1 ) );
-            serializedData.add( buffer );
-            dataSize += buffer.length;
-
-            // the B-tree offset
-            buffer = LongSerializer.serialize( ( ( PersistedValueHolder<V> ) valueHolder ).getOffset() );
-            serializedData.add( buffer );
-            dataSize += buffer.length;
+            serializedData.add( data );
         }
 
         return dataSize;
@@ -2009,7 +2022,7 @@ public class RecordManager extends Abstr
      * +---------------------+
      * </pre>
      */
-    public void updateRecordManagerHeader()
+    public ByteBuffer updateRecordManagerHeader()
     {
         // The page size
         int position = writeData( RECORD_MANAGER_HEADER_BYTES, 0, pageSize );
@@ -2095,9 +2108,17 @@ public class RecordManager extends Abstr
             LOG_PAGES.debug( "Update RM Header : \n{}", sb.toString() );
         }
 
+        return RECORD_MANAGER_HEADER_BUFFER;
+    }
+    
+    
+    /**
+     * Write the RecordmanagerHeader in disk
+     */
+    private void writeRecordManagerHeader()
+    {
         try
         {
-
             Integer nbTxnStarted = CONTEXT.get();
 
             if ( ( nbTxnStarted == null ) || ( nbTxnStarted <= 1 ) )
@@ -2331,84 +2352,41 @@ public class RecordManager extends Abstr
         return btreeHeaderOffset;
     }
 
-
+    
     /**
-     * Write the B-tree informations on disk. We will write the following informations :
-     * <pre>
-     * +------------+
-     * | pageSize   | The B-tree page size (ie, the number of elements per page max)
-     * +------------+
-     * | nameSize   | The B-tree name size
-     * +------------+
-     * | name       | The B-tree name
-     * +------------+
-     * | keySerSize | The keySerializer FQCN size
-     * +------------+
-     * | keySerFQCN | The keySerializer FQCN
-     * +------------+
-     * | valSerSize | The Value serializer FQCN size
-     * +------------+
-     * | valSerKQCN | The valueSerializer FQCN
-     * +------------+
-     * | dups       | The flags that tell if the dups are allowed
-     * +------------+
-     * </pre>
-     * @param btree The B-tree which header has to be written
-     * @return The B-tree header offset
-     * @throws IOException If we weren't able to write the B-tree header
+     * Write the RootPage content.
+     * 
+     * @param btree The BTree we are working on
+     * @param btreeHeader The BtreeHeader for this BTree
+     * @return The offset of the rootPage
+     * @throws IOException If we have had an error while accessing to the underlying file
      */
-    private <K, V> long writeBtreeInfo( BTree<K, V> btree ) throws IOException
+    private <K, V> long writeRootPage( BTree<K, V> btree, BTreeHeader<K, V> btreeHeader ) throws IOException
     {
-        // We will add the newly managed B-tree at the end of the header.
-        byte[] btreeNameBytes = Strings.getBytesUtf8( btree.getName() );
-        byte[] keySerializerBytes = Strings.getBytesUtf8( btree.getKeySerializerFQCN() );
-        byte[] valueSerializerBytes = Strings.getBytesUtf8( btree.getValueSerializerFQCN() );
-
-        int bufferSize =
-            INT_SIZE + // The page size
-                INT_SIZE + // The name size
-                btreeNameBytes.length + // The name
-                INT_SIZE + // The keySerializerBytes size
-                keySerializerBytes.length + // The keySerializerBytes
-                INT_SIZE + // The valueSerializerBytes size
-                valueSerializerBytes.length + // The valueSerializerBytes
-                INT_SIZE; // The allowDuplicates flag
-
-        // Get the pageIOs we need to store the data. We may need more than one.
-        PageIO[] btreeHeaderPageIos = getFreePageIOs( bufferSize );
-
-        // Keep the B-tree header Offset into the B-tree
-        long btreeInfoOffset = btreeHeaderPageIos[0].getOffset();
-
-        // Now store the B-tree information data in the pages :
-        // - the B-tree page size
-        // - the B-tree name
-        // - the keySerializer FQCN
-        // - the valueSerializer FQCN
-        // - the flags that tell if the dups are allowed
-        // Starts at 0
-        long position = 0L;
-
-        // The B-tree page size
-        position = store( position, btree.getPageSize(), btreeHeaderPageIos );
+        Page<K, V> rootPage = btreeHeader.getRootPage();
+        long pageId = context.getPageId();
 
-        // The tree name
-        position = store( position, btreeNameBytes, btreeHeaderPageIos );
+        context.addPage( pageId, rootPage );
+        
+        return pageId;
 
-        // The keySerializer FQCN
-        position = store( position, keySerializerBytes, btreeHeaderPageIos );
+        /*
+        PageIO[] rootPageIos = serializePage( btree, btreeHeader.getRevision(), rootPage );
 
-        // The valueSerialier FQCN
-        position = store( position, valueSerializerBytes, btreeHeaderPageIos );
+        // Get the reference on the first page
+        long rootPageOffset = rootPageIos[0].getOffset();
 
-        // The allowDuplicates flag
-        position = store( position, ( btree.isAllowDuplicates() ? 1 : 0 ), btreeHeaderPageIos );
+        // Store the rootPageOffset into the Btree header and into the rootPage
+        btreeHeader.setRootPageOffset( rootPageOffset );
 
-        // And flush the pages to disk now
-        LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() );
-        flushPages( btreeHeaderPageIos );
+        ( ( AbstractPage<K, V> ) rootPage ).setOffset( rootPageOffset );
 
-        return btreeInfoOffset;
+        LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() );
+        
+        // Store the PageIO and the rootPage
+        storePages( rootPageIos );
+        context.addPage( rootPageOffset, rootPage );
+        */
     }
 
 
@@ -2590,6 +2568,12 @@ public class RecordManager extends Abstr
      */
     private void flushPages( PageIO... pageIos ) throws IOException
     {
+        if ( pageIos == null )
+        {
+            LOG.debug( "No PageIO to flush" );
+            return;
+        }
+        
         if ( LOG.isDebugEnabled() )
         {
             for ( PageIO pageIo : pageIos )
@@ -2627,6 +2611,88 @@ public class RecordManager extends Abstr
         }
     }
 
+    
+    private <K, V> void flushObjects( Collection<WALObject> walObjects ) throws IOException
+    {
+        if ( ( walObjects == null ) || ( walObjects.size() == 0 ) )
+        {
+            LOG.debug( "No Page to flush" );
+            return;
+        }
+        
+        if ( LOG.isDebugEnabled() )
+        {
+            //for ( Page page : pages )
+            {
+                //dump( page );
+            }
+        }
+
+        for ( WALObject walObject : walObjects )
+        {
+            if ( walObject instanceof BTreeHeader )
+            {
+                // We need to update the rootPage offset first
+                PageIO[] pageIos = walObject.serialize();
+                flushPages( pageIos );
+            }
+            else if ( walObject instanceof BTreeInfo )
+            {
+                // Serialize the instance and write it
+                PageIO[] pageIos = walObject.serialize();
+                flushPages( pageIos );
+            }
+            else if ( walObject instanceof PersistedNode )
+            {
+                
+            }
+            else if ( walObject instanceof PersistedLeaf )
+            {
+                // We can write pages immediately
+                PageIO[] pageIos = walObject.serialize();
+                flushPages( pageIos );
+            }
+            
+            //BTree<K, V> btree =  ( ( AbstractPage<K,V> ) page ).getBtree();
+            //PageIO[] pageIos = serializePage( btree, ( ( AbstractPage<K,V> ) page ).getRevision(), page );
+
+
+            //LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() );
+            //ushPages( pageIos );
+        }
+    }
+
+    /**
+     * Store  the pages in the context. If the page has no Offset, we will
+     * use a virtual offset (ie, a negative one)
+     *
+     * @param pageIos The list of pages to write
+     * @throws IOException If the store failed
+     */
+    /* No qualifier */void storePages( PageIO... pageIos ) throws IOException
+    {
+        if ( LOG.isDebugEnabled() )
+        {
+            for ( PageIO pageIo : pageIos )
+            {
+                dump( pageIo );
+            }
+        }
+
+        for ( PageIO pageIo : pageIos )
+        {
+            pageIo.getData().rewind();
+            long offset = pageIo.getOffset();
+
+            LOG.debug( "Writing a page at position {}", offset );
+            //context.addPageIo( offset, pageIo );
+
+            writeCounter.put( offset, writeCounter.containsKey( offset ) ? writeCounter.get( offset ) + 1 : 1 );
+
+            nbUpdatePageIOs.incrementAndGet();
+        }
+    }
+
 
     /**
      * Compute the page in which we will store data given an offset, when
@@ -2661,7 +2727,7 @@ public class RecordManager extends Abstr
      * @param pageIos The pageIOs we have to store the data in
      * @return The new offset
      */
-    private long store( long position, byte[] bytes, PageIO... pageIos )
+    /* no qualifier */ long store( long position, byte[] bytes, PageIO... pageIos )
     {
         if ( bytes != null )
         {
@@ -2802,7 +2868,7 @@ public class RecordManager extends Abstr
      * @param pageIos The pageIOs we have to store the data in
      * @return The new offset
      */
-    private long store( long position, int value, PageIO... pageIos )
+    /* no qualifier */ long store( long position, int value, PageIO... pageIos )
     {
         // Compute the page in which we will store the data given the
         // current position
@@ -2877,7 +2943,7 @@ public class RecordManager extends Abstr
      * @param pageIos The pageIOs we have to store the data in
      * @return The new offset
      */
-    private long store( long position, long value, PageIO... pageIos )
+    /* no qualifier */ long store( long position, long value, PageIO... pageIos )
     {
         // Compute the page in which we will store the data given the
         // current position
@@ -3120,7 +3186,7 @@ public class RecordManager extends Abstr
      * @param dataSize The data size
      * @return An array of pages, enough to store the full data
      */
-    private PageIO[] getFreePageIOs( int dataSize ) throws IOException
+    /* No qualifier */ PageIO[] getFreePageIOs( int dataSize ) throws IOException
     {
         if ( dataSize == 0 )
         {
@@ -3163,9 +3229,9 @@ public class RecordManager extends Abstr
 
             // We don't have any free page. Reclaim some new page at the end
             // of the file
-            PageIO newPage = new PageIO( endOfFileOffset );
+            PageIO newPage = new PageIO( context.getLastOffset() );
 
-            endOfFileOffset += pageSize;
+            context.addLastOffset( pageSize );
 
             ByteBuffer data = ByteBuffer.allocateDirect( pageSize );
 
@@ -3186,10 +3252,10 @@ public class RecordManager extends Abstr
                 // We have some existing free page. Fetch it from disk
             PageIO pageIo = fetchPage( firstFreePage );
 
-                // Update the firstFreePage pointer
-                firstFreePage = pageIo.getNextPage();
+            // Update the firstFreePage pointer
+            firstFreePage = pageIo.getNextPage();
 
-                freePageLock.unlock();
+            freePageLock.unlock();
 
             // overwrite the data of old page
             ByteBuffer data = ByteBuffer.allocateDirect( pageSize );
@@ -3921,7 +3987,6 @@ public class RecordManager extends Abstr
         config.setName( name );
         config.setKeySerializer( keySerializer );
         config.setValueSerializer( valueSerializer );
-        config.setAllowDuplicates( allowDuplicates );
 
         BTree btree = new PersistedBTree( config );
         manage( btree );
@@ -4027,33 +4092,6 @@ public class RecordManager extends Abstr
     }
 
 
-    /**
-     * Loads a B-tree holding the values of a duplicate key
-     * This tree is also called as dups tree or sub tree
-     *
-     * @param offset the offset of the B-tree header
-     * @return the deserialized B-tree
-     */
-    /* No qualifier */<K, V> BTree<V, V> loadDupsBtree( long btreeHeaderOffset, BTree<K, V> parentBtree )
-    {
-        PageIO[] pageIos = null;
-        try
-        {
-            pageIos = readPageIOs( btreeHeaderOffset, Long.MAX_VALUE );
-
-            BTree<V, V> subBtree = BTreeFactory.<V, V> createPersistedBTree( BTreeTypeEnum.PERSISTED_SUB );
-            loadBtree( pageIos, subBtree, parentBtree );
-
-            return subBtree;
-        }
-        catch ( Exception e )
-        {
-            // should not happen
-            throw new BTreeCreationException( e );
-        }
-    }
-
-
     private void checkFreePages() throws EndOfFileExceededException, IOException
     {
         //System.out.println( "Checking the free pages, starting from " + Long.toHexString( firstFreePage ) );

Added: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java?rev=1711861&view=auto
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java (added)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionContext.java Sun Nov  1 23:01:00 2015
@@ -0,0 +1,125 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The TransactionContext class holds all the modified pages in memory, up to the
+ * moment we have to flush them on disk, when a cmmit is applied, or discard them,
+ * if a rallback is called.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class TransactionContext
+{
+    /** The map containing all the modified pages, using their offset as a key */
+    private Map<Long, WALObject> pageMap = new HashMap<Long, WALObject>();
+    
+    /** The incremental counter used to identify pages */
+    private long pageId;
+    
+    /** The last offset on disk */
+    private long lastOffset;
+    
+    /**
+     * A constructor for the TransactionContext, which initialize the last offset to
+     * the file size.
+     * 
+     * @param lastOffset The last offset fo the associated file
+     */
+    public TransactionContext( long lastOffset )
+    {
+        this.lastOffset = lastOffset;
+        pageId = RecordManager.NO_PAGE;
+    }
+
+
+    /**
+     * Retrieve a Page if it has been stored in the context
+     * @param offset the offset of the Page we are looking for
+     * @return The found Page, or null if it does not exist
+     */
+    public WALObject getPage( Long offset )
+    {
+        return pageMap.get( offset );
+    }
+    
+    
+    /**
+     * Add a page into the TransactionContext
+     * 
+     * @param offset The Page's offset
+     * @param pageIo The Page to add
+     */
+    public void addPage( Long offset, WALObject page )
+    {
+        pageMap.put( offset, page );
+    }
+    
+    
+    /**
+     * @return The list of stored Pages 
+     */
+    public Collection<WALObject> getPages()
+    {
+        return pageMap.values();
+    }
+
+    
+    /**
+     * @return the lastOffset
+     */
+    public long getLastOffset()
+    {
+        return lastOffset;
+    }
+
+
+    /**
+     * @param lastOffset the lastOffset to set
+     */
+    public void setLastOffset( long lastOffset )
+    {
+        this.lastOffset = lastOffset;
+    }
+
+
+    /**
+     * @param addedSize the size to add
+     */
+    public void addLastOffset( long addedSize )
+    {
+        this.lastOffset += addedSize;
+    }
+    
+    
+    /**
+     * @return The unique page ID
+     */
+    public long getPageId()
+    {
+        pageId--;
+        
+        return pageId;
+    }
+}

Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java?rev=1711861&r1=1711860&r2=1711861&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java Sun Nov  1 23:01:00 2015
@@ -23,21 +23,26 @@ package org.apache.directory.mavibot.btr
 import java.io.IOException;
 import java.util.NoSuchElementException;
 
+import org.apache.directory.mavibot.btree.exception.CursorException;
 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
 
 
 /**
  * A Cursor is used to fetch elements in a BTree and is returned by the
- * @see BTree#browse method. The cursor <strng>must</strong> be closed
+ * @see BTree#browse method. The cursor <strong>must</strong> be closed
  * when the user is done with it.
  * <p>
+ * We keep a track of the current position at each level of the B-tree, so
+ * we can navigate in this B-tree forward and backward. Two special positions
+ * are defined : BEFORE_FIRST and AFTER_LAST which are befoe the leftmost and 
+ * after the rightmost elements in the B-tree
  *
  * @param <K> The type for the Key
  * @param <V> The type for the stored value
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class TupleCursor<K, V>
+public class TupleCursor<K, V> //implements Iterator<Tuple<K,V>>
 {
     /** A marker to tell that we are before the first element */
     private static final int BEFORE_FIRST = -1;
@@ -78,59 +83,95 @@ public class TupleCursor<K, V>
 
 
     /**
-     * Change the position in the current cursor to set it after the last key
+     * Positions this Cursor after the last element. This will set the path to the
+     * rightmost page for each level, and the position to the rightmost element
+     * of each page.
+     *
+     * @throws CursorException if there are problems positioning this Cursor or if
+     * this Cursor is closed
      */
-    public void afterLast() throws IOException
+    public void afterLast() throws CursorException
     {
         // First check that we have elements in the BTree
         if ( ( stack == null ) || ( stack.length == 0 ) )
         {
             return;
         }
+        
+        // Update the parent page.
+        ParentPos<K, V> parentPos = stack[0];
+        parentPos.pos = parentPos.page.getNbElems();
+        Page<K, V> childPage = null;
 
-        Page<K, V> child = null;
+        if ( parentPos.page instanceof PersistedNode )
+        {
+            childPage = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos );
+        }
 
-        for ( int i = 0; i < depth; i++ )
+        // Go down the Tree, selecting the rightmost element in each Node
+        for ( int i = 1; i < depth; i++ )
         {
-            ParentPos<K, V> parentPos = stack[i];
+            parentPos = stack[i];
 
-            if ( child != null )
-            {
-                parentPos.page = child;
-                parentPos.pos = child.getNbElems();
-            }
-            else
-            {
-                // We have N+1 children if the page is a Node, so we don't decrement the nbElems field
-                parentPos.pos = parentPos.page.getNbElems();
-            }
+            // We are in the middle of the tree, change the parentPos to be
+            // the one we have selected previously
+            // Set the parentPos to be at the rightmost position for this level.
+            parentPos.page = childPage;
+            parentPos.pos = childPage.getNbElems();
 
-            child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos );
+            // Get the child page, and iterate
+            childPage = ( ( AbstractPage<K, V> ) childPage ).getPage( parentPos.pos );
         }
 
-        // and leaf
-        ParentPos<K, V> parentPos = stack[depth];
+        // Now, we should handle the leaf
+        parentPos = stack[depth];
 
-        if ( child == null )
+        if ( childPage != null )
         {
-            parentPos.pos = parentPos.page.getNbElems() - 1;
+            // The tree had more than one level, so we make the current parentPos
+            // point on the previously selected leaf.
+            parentPos.page = childPage;
         }
-        else
+
+        // Finally, set the position after the rightmost element
+        parentPos.pos = AFTER_LAST;
+    }
+
+    
+    /**
+     * Determines whether or not a call to get() will succeed.
+     *
+     * @return true if a call to the get() method will succeed, false otherwise
+     */
+    public boolean available()
+    {
+        // First check that we have elements in the BTree
+        if ( ( stack == null ) || ( stack.length == 0 ) )
         {
-            parentPos.page = child;
-            parentPos.pos = child.getNbElems() - 1;
+            return false;
         }
 
-        parentPos.valueCursor = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos ).getCursor();
-        parentPos.valueCursor.afterLast();
-        parentPos.pos = AFTER_LAST;
+        // Take the leaf and check if we have no mare values
+        ParentPos<K, V> parentPos = stack[depth];
+
+        if ( parentPos.page == null )
+        {
+            // Empty BTree, get out
+            return false;
+        }
+        
+        // We must not be AFTER_LAST or BEFORE_FIRST 
+        return ( parentPos.pos != BEFORE_FIRST ) && ( parentPos.pos != AFTER_LAST );
     }
 
 
     /**
-     * Change the position in the current cursor before the first key
+     * Positions this Cursor before the first element.
+     *
+     * @throws Exception if there are problems positioning this cursor or if
+     * this Cursor is closed
      */
-    public void beforeFirst() throws IOException
+    public void beforeFirst() throws CursorException
     {
         // First check that we have elements in the BTree
         if ( ( stack == null ) || ( stack.length == 0 ) )
@@ -138,35 +179,32 @@ public class TupleCursor<K, V>
             return;
         }
 
+        ParentPos<K, V> parentPos = stack[0];
+        parentPos.pos = 0;
         Page<K, V> child = null;
+        
+        if ( parentPos.page instanceof PersistedNode )
+        {
+            child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( 0 );
+        }
 
-        for ( int i = 0; i < depth; i++ )
+        for ( int i = 1; i < depth; i++ )
         {
-            ParentPos<K, V> parentPos = stack[i];
+            parentPos = stack[i];
             parentPos.pos = 0;
-
-            if ( child != null )
-            {
-                parentPos.page = child;
-            }
+            parentPos.page = child;
 
             child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( 0 );
         }
 
         // and leaf
-        ParentPos<K, V> parentPos = stack[depth];
+        parentPos = stack[depth];
         parentPos.pos = BEFORE_FIRST;
 
         if ( child != null )
         {
             parentPos.page = child;
         }
-
-        if ( parentPos.valueCursor != null )
-        {
-            parentPos.valueCursor = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( 0 ).getCursor();
-            parentPos.valueCursor.beforeFirst();
-        }
     }
 
 
@@ -225,13 +263,6 @@ public class TupleCursor<K, V>
         }
         else
         {
-            // Check if we have some more value
-            if ( ( parentPos.valueCursor != null ) && parentPos.valueCursor.hasNext() )
-            {
-                // No problem, we still have some values to read
-                return true;
-            }
-
             // Ok, here, we have reached the last value in the leaf. We have to go up and
             // see if we have some remaining values
             int currentDepth = depth - 1;
@@ -258,13 +289,15 @@ public class TupleCursor<K, V>
 
 
     /**
-     * Find the next key/value
+     * Find the next Tuple, from the current position. If we have no more new element, 
+     * a NoSuchElementException will be thrown.
      *
      * @return A Tuple containing the found key and value
      * @throws IOException
-     * @throws EndOfFileExceededException
+     * @throws NoSuchElementException When we have reached the end of the B-tree, or if 
+     * the B-tree is empty
      */
-    public Tuple<K, V> next() throws EndOfFileExceededException, IOException
+    public Tuple<K, V> next() throws NoSuchElementException
     {
         // First check that we have elements in the BTree
         if ( ( stack == null ) || ( stack.length == 0 ) )
@@ -274,46 +307,17 @@ public class TupleCursor<K, V>
 
         ParentPos<K, V> parentPos = stack[depth];
 
-        if ( ( parentPos.page == null ) || ( parentPos.pos == AFTER_LAST ) )
-        {
-            // This is the end : no more value
-            throw new NoSuchElementException( "No more tuples present" );
-        }
-
-        if ( parentPos.pos == parentPos.page.getNbElems() )
+        try
         {
-            // End of the leaf. We have to go back into the stack up to the
-            // parent, and down to the leaf
-            parentPos = findNextParentPos();
-
-            // we also need to check for the type of page cause
-            // findNextParentPos will never return a null ParentPos
-            if ( ( parentPos == null ) || ( parentPos.page == null ) )
-            {
-                // This is the end : no more value
-                throw new NoSuchElementException( "No more tuples present" );
-            }
-        }
-
-        V value = null;
-
-        if ( parentPos.valueCursor.hasNext() )
-        {
-            // Deal with the BeforeFirst case
-            if ( parentPos.pos == BEFORE_FIRST )
-            {
-                parentPos.pos++;
-            }
-
-            value = parentPos.valueCursor.next();
-        }
-        else
-        {
-            if ( parentPos.pos == parentPos.page.getNbElems() - 1 )
+            if ( parentPos.pos == parentPos.page.getNbElems() )
             {
+                // End of the leaf. We have to go back into the stack up to the
+                // parent, and down to the leaf
                 parentPos = findNextParentPos();
-
-                if ( ( parentPos == null ) || ( parentPos.page == null ) )
+    
+                // we also need to check for the type of page cause
+                // findNextParentPos will never return a null ParentPos
+                if ( parentPos == null )
                 {
                     // This is the end : no more value
                     throw new NoSuchElementException( "No more tuples present" );
@@ -323,146 +327,29 @@ public class TupleCursor<K, V>
             {
                 parentPos.pos++;
             }
-
-            try
-            {
-                ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
-
-                parentPos.valueCursor = valueHolder.getCursor();
-
-                value = parentPos.valueCursor.next();
-            }
-            catch ( IllegalArgumentException e )
-            {
-                e.printStackTrace();
-            }
-        }
-
-        AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
-        Tuple<K, V> tuple = new Tuple<K, V>( leaf.getKey( parentPos.pos ), value );
-
-        return tuple;
-    }
-
-
-    /**
-     * Get the next non-duplicate key.
-     * If the BTree contains :
-     *
-     *  <ul>
-     *    <li><1,0></li>
-     *    <li><1,1></li>
-     *    <li><1,2></li>
-     *    <li><2,0></li>
-     *    <li><2,1></li>
-     *  </ul>
-     *
-     *  and cursor is present at <1,1> then the returned tuple will be <2,0> (not <1,2>)
-     *
-     * @return A Tuple containing the found key and value
-     * @throws EndOfFileExceededException
-     * @throws IOException
-     */
-    public Tuple<K, V> nextKey() throws EndOfFileExceededException, IOException
-    {
-        // First check that we have elements in the BTree
-        if ( ( stack == null ) || ( stack.length == 0 ) )
-        {
-            // This is the end : no more value
-            throw new NoSuchElementException( "No more tuples present" );
         }
-
-        ParentPos<K, V> parentPos = stack[depth];
-
-        if ( parentPos.page == null )
+        catch ( IOException ioe )
         {
-            // This is the end : no more value
-            throw new NoSuchElementException( "No more tuples present" );
+            throw new NoSuchElementException( ioe.getMessage());
         }
 
-        if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) )
-        {
-            // End of the leaf. We have to go back into the stack up to the
-            // parent, and down to the next leaf
-            ParentPos<K, V> newParentPos = findNextParentPos();
-
-            // we also need to check the result of the call to
-            // findNextParentPos as it will return a null ParentPos
-            if ( ( newParentPos == null ) || ( newParentPos.page == null ) )
-            {
-                // This is the end : no more value
-                AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
-                ValueHolder<V> valueHolder = leaf.getValue( parentPos.pos );
-                parentPos.pos = AFTER_LAST;
-                parentPos.valueCursor = valueHolder.getCursor();
-                parentPos.valueCursor.afterLast();
+        // Get the value
+        ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
 
-                return null;
-            }
-            else
-            {
-                parentPos = newParentPos;
-            }
-        }
-        else
-        {
-            // Get the next key
-            parentPos.pos++;
-        }
+        V value = valueHolder.get();
 
-        // The key
+        // Get the key
         AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
-        Tuple<K, V> tuple = new Tuple<K, V>();
-        tuple.setKey( leaf.getKey( parentPos.pos ) );
-
-        // The value
-        ValueHolder<V> valueHolder = leaf.getValue( parentPos.pos );
-        parentPos.valueCursor = valueHolder.getCursor();
-        V value = parentPos.valueCursor.next();
-        tuple.setValue( value );
+        K key = leaf.getKey( parentPos.pos );
+        
+        // Build the Tuple
+        Tuple<K, V> tuple = new Tuple<K, V>( key, value );
 
         return tuple;
     }
 
 
     /**
-     * Tells if the cursor can return a next key
-     *
-     * @return true if there are some more keys
-     * @throws IOException
-     * @throws EndOfFileExceededException
-     */
-    public boolean hasNextKey() throws EndOfFileExceededException, IOException
-    {
-        // First check that we have elements in the BTree
-        if ( ( stack == null ) || ( stack.length == 0 ) )
-        {
-            // This is the end : no more key
-            return false;
-        }
-
-        ParentPos<K, V> parentPos = stack[depth];
-
-        if ( parentPos.page == null )
-        {
-            // This is the end : no more key
-            return false;
-        }
-
-        if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) )
-        {
-            // End of the leaf. We have to go back into the stack up to the
-            // parent, and down to the next leaf
-            return hasNextParentPos();
-        }
-        else
-        {
-            return true;
-        }
-    }
-
-
-    /**
      * Tells if the cursor can return a previous element
      *
      * @return true if there are some more elements
@@ -499,12 +386,6 @@ public class TupleCursor<K, V>
                 return false;
             }
 
-            // Check if we have some more value
-            if ( parentPos.valueCursor.hasPrev() )
-            {
-                return true;
-            }
-
             // Ok, here, we have reached the first value in the leaf. We have to go up and
             // see if we have some remaining values
             int currentDepth = depth - 1;
@@ -530,11 +411,13 @@ public class TupleCursor<K, V>
 
 
     /**
-     * Find the previous key/value
+     * Get the previous Tuple, from the current position. If we have no more new element, 
+     * a NoMoreElementException will be thrown.
      *
      * @return A Tuple containing the found key and value
      * @throws IOException
-     * @throws EndOfFileExceededException
+     * @throws NoSuchElementException When we have reached the beginning of the B-tree, or if 
+     * the B-tree is empty
      */
     public Tuple<K, V> prev() throws EndOfFileExceededException, IOException
     {
@@ -546,197 +429,58 @@ public class TupleCursor<K, V>
 
         ParentPos<K, V> parentPos = stack[depth];
 
-        if ( ( parentPos.page == null ) || ( parentPos.pos == BEFORE_FIRST ) )
+        switch( parentPos.pos )
         {
-            // This is the end : no more value
-            throw new NoSuchElementException( "No more tuples present" );
-        }
-
-        if ( ( parentPos.pos == 0 ) && ( !parentPos.valueCursor.hasPrev() ) )
-        {
-            // End of the leaf. We have to go back into the stack up to the
-            // parent, and down to the leaf
-            parentPos = findPrevParentPos();
-
-            // we also need to check for the type of page cause
-            // findPrevParentPos will never return a null ParentPos
-            if ( ( parentPos == null ) || ( parentPos.page == null ) )
-            {
+            case BEFORE_FIRST :
                 // This is the end : no more value
                 throw new NoSuchElementException( "No more tuples present" );
-            }
-        }
 
-        V value = null;
-
-        if ( parentPos.valueCursor.hasPrev() )
-        {
-            // Deal with the AfterLast case
-            if ( parentPos.pos == AFTER_LAST )
-            {
+            case AFTER_LAST :
+                // Move the the last element
                 parentPos.pos = parentPos.page.getNbElems() - 1;
-            }
-
-            value = parentPos.valueCursor.prev();
-        }
-        else
-        {
-            if ( parentPos.pos == 0 )
-            {
+                break;
+            
+            case 0 :
+                // beginning of the leaf. We have to go back into the stack up to the
+                // parent, and down to the leaf on the left, if possible
                 parentPos = findPrevParentPos();
 
-                if ( ( parentPos == null ) || ( parentPos.page == null ) )
+                // we also need to check for the type of page cause
+                // findPrevParentPos will never return a null ParentPos
+                if ( parentPos == null )
                 {
                     // This is the end : no more value
                     throw new NoSuchElementException( "No more tuples present" );
                 }
-            }
-            else
-            {
-                parentPos.pos--;
-
-                try
-                {
-                    ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
-
-                    parentPos.valueCursor = valueHolder.getCursor();
-                    parentPos.valueCursor.afterLast();
-
-                    value = parentPos.valueCursor.prev();
-                }
-                catch ( IllegalArgumentException e )
+                else
                 {
-                    e.printStackTrace();
+                    parentPos.pos--;
                 }
-            }
-        }
-
-        AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
-        Tuple<K, V> tuple = new Tuple<K, V>( leaf.getKey( parentPos.pos ), value );
-
-        return tuple;
-    }
-
-
-    /**
-     * Get the previous non-duplicate key.
-     * If the BTree contains :
-     *
-     *  <ul>
-     *    <li><1,0></li>
-     *    <li><1,1></li>
-     *    <li><1,2></li>
-     *    <li><2,0></li>
-     *    <li><2,1></li>
-     *  </ul>
-     *
-     *  and cursor is present at <2,1> then the returned tuple will be <1,0> (not <2,0>)
-     *
-     * @return A Tuple containing the found key and value
-     * @throws EndOfFileExceededException
-     * @throws IOException
-     */
-    public Tuple<K, V> prevKey() throws EndOfFileExceededException, IOException
-    {
-        // First check that we have elements in the BTree
-        if ( ( stack == null ) || ( stack.length == 0 ) )
-        {
-            // This is the end : no more value
-            throw new NoSuchElementException( "No more tuples present" );
-        }
-
-        ParentPos<K, V> parentPos = stack[depth];
-
-        if ( parentPos.page == null )
-        {
-            // This is the end : no more value
-            throw new NoSuchElementException( "No more tuples present" );
-        }
-
-        if ( parentPos.pos == 0 )
-        {
-            // Beginning of the leaf. We have to go back into the stack up to the
-            // parent, and down to the leaf
-            parentPos = findPrevParentPos();
-
-            if ( ( parentPos == null ) || ( parentPos.page == null ) )
-            {
-                // This is the end : no more value
-                throw new NoSuchElementException( "No more tuples present" );
-            }
-        }
-        else
-        {
-            if ( parentPos.pos == AFTER_LAST )
-            {
-                parentPos.pos = parentPos.page.getNbElems() - 1;
-            }
-            else
-            {
+                
+                break;
+                
+            default :
+                // Simply decrement the position
                 parentPos.pos--;
-            }
+                break;
         }
 
-        // Update the Tuple
-        AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
+        // Get the value
+        ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
+        V value = valueHolder.get();
 
-        // The key
-        Tuple<K, V> tuple = new Tuple<K, V>();
-        tuple.setKey( leaf.getKey( parentPos.pos ) );
-
-        // The value
-        ValueHolder<V> valueHolder = leaf.getValue( parentPos.pos );
-        parentPos.valueCursor = valueHolder.getCursor();
-        V value = parentPos.valueCursor.next();
-        tuple.setValue( value );
+        // Get the key
+        AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
+        K key = leaf.getKey( parentPos.pos );
+        
+        // Construct the Tuple 
+        Tuple<K, V> tuple = new Tuple<K, V>( key, value );
 
         return tuple;
     }
 
 
     /**
-     * Tells if the cursor can return a previous key
-     *
-     * @return true if there are some more keys
-     * @throws IOException
-     * @throws EndOfFileExceededException
-     */
-    public boolean hasPrevKey() throws EndOfFileExceededException, IOException
-    {
-        // First check that we have elements in the BTree
-        if ( ( stack == null ) || ( stack.length == 0 ) )
-        {
-            // This is the end : no more key
-            return false;
-        }
-
-        ParentPos<K, V> parentPos = stack[depth];
-
-        if ( parentPos.page == null )
-        {
-            // This is the end : no more key
-            return false;
-        }
-
-        switch ( parentPos.pos )
-        {
-            case 0:
-                // Beginning of the leaf. We have to go back into the stack up to the
-                // parent, and down to the leaf
-                return hasPrevParentPos();
-
-            case -1:
-                // no previous key
-                return false;
-
-            default:
-                // we have a previous key
-                return true;
-        }
-    }
-
-
-    /**
      * Tells if there is a next ParentPos
      *
      * @return the new ParentPos instance, or null if we have no following leaf
@@ -836,7 +580,6 @@ public class TupleCursor<K, V>
                 parentPos = stack[depth];
                 parentPos.page = child;
                 parentPos.pos = 0;
-                parentPos.valueCursor = ( ( AbstractPage<K, V> ) child ).getValue( 0 ).getCursor();
 
                 return parentPos;
             }
@@ -847,7 +590,33 @@ public class TupleCursor<K, V>
 
 
     /**
-     * Find the leaf containing the previous elements.
+     * Find the leaf containing the previous elements. We are in
+     * 
+     * if the B-tree content is like :
+     * <pre>
+     *                    .
+     *                   |
+     *                   v
+     *           +---+---+---+---+
+     *           |///| X | Y |///|               Level N-1
+     *           +---+---+---+---+
+     *           |   |   |   |   |
+     *   <-...---+   |   |   |   +---...-> 
+     *               |   |   |
+     *       <-...---+   |   |
+     *                   |   |
+     *         +---------+   +-------+
+     *         |                     | 
+     *         v                     v
+     * +---+---+---+---+     +---+---+---+---+
+     * |///|///| T |###|     | Y |///|///|///|   Level N
+     * +---+---+---+---+     +---+---+---+---+
+     *          pos           pos 
+     *   New ParentPos       Current ParentPos
+     * </pre>
+     * 
+     * and we are on Y, then the previous ParentPos instance will contain the page
+     * on the left, teh position beoing on the last element of this page, T
      *
      * @return the new ParentPos instance, or null if we have no previous leaf
      * @throws IOException
@@ -861,6 +630,7 @@ public class TupleCursor<K, V>
             return null;
         }
 
+        // Go up one step
         int currentDepth = depth - 1;
         Page<K, V> child = null;
 
@@ -868,21 +638,21 @@ public class TupleCursor<K, V>
         while ( currentDepth >= 0 )
         {
             // We first go up the tree, until we reach a page whose current position
-            // is not the last one
+            // is not the first one
             ParentPos<K, V> parentPos = stack[currentDepth];
 
             if ( parentPos.pos == 0 )
             {
-                // No more element on the right : go up
+                // No more element on the left : go up
                 currentDepth--;
             }
             else
             {
-                // We can pick the next element at this level
+                // We can pick the previous element at this level
                 parentPos.pos--;
                 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos );
 
-                // and go down the tree through the nodes
+                // and go down the tree through the nodes, positioning on the rightmost element
                 while ( currentDepth < depth - 1 )
                 {
                     currentDepth++;
@@ -896,9 +666,6 @@ public class TupleCursor<K, V>
                 parentPos = stack[depth];
                 parentPos.pos = child.getNbElems() - 1;
                 parentPos.page = child;
-                ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
-                parentPos.valueCursor = valueHolder.getCursor();
-                parentPos.valueCursor.afterLast();
 
                 return parentPos;
             }
@@ -959,7 +726,21 @@ public class TupleCursor<K, V>
 
 
     /**
-     * {@inheritDoc}
+     * Checks if this Cursor is closed. Calls to this operation should not
+     * fail with exceptions if and only if the cursor is in the closed state.
+     *
+     * @return true if this Cursor is closed, false otherwise
+     */
+    public boolean isClosed()
+    {
+        return transaction.isClosed();
+    }
+
+
+    /**
+     * Closes this Cursor and frees any resources it my have allocated.
+     * Repeated calls to this method after this Cursor has already been
+     * called should not fail with exceptions.
      */
     public void close()
     {
@@ -967,6 +748,62 @@ public class TupleCursor<K, V>
     }
 
 
+    /**
+     * Closes this Cursor and frees any resources it my have allocated.
+     * Repeated calls to this method after this Cursor has already been
+     * called should not fail with exceptions.  The reason argument is 
+     * the Exception instance thrown instead of the standard 
+     * CursorClosedException.
+     *
+     * @param reason exception thrown when this Cursor is accessed after close
+     */
+    public void close( Exception reason )
+    {
+        transaction.close();
+    }
+
+
+    /**
+     * Gets the object at the current position.  Cursor implementations may
+     * choose to reuse element objects by re-populating them on advances
+     * instead of creating new objects on each advance.
+     *
+     * @return the object at the current position
+     * @throws NoSuchElementException if the object at this Cursor's current position
+     * cannot be retrieved, or if this Cursor is closed
+     */
+    public Tuple<K, V> get() throws NoSuchElementException
+    {
+        // First check that we have elements in the BTree
+        if ( ( stack == null ) || ( stack.length == 0 ) )
+        {
+            throw new NoSuchElementException( "No tuple present" );
+        }
+
+        ParentPos<K, V> parentPos = stack[depth];
+        
+        if ( ( parentPos.pos != BEFORE_FIRST ) && ( parentPos.pos != AFTER_LAST ) )
+        {
+            // We have some element, build the Tuple
+            // Get the value
+            ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
+
+            V value = valueHolder.get();
+
+            // Get the key
+            AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
+            K key = leaf.getKey( parentPos.pos );
+            
+            // Build the Tuple
+            Tuple<K, V> tuple = new Tuple<K, V>( key, value );
+
+            return tuple;
+        }
+        
+        throw new NoSuchElementException( "No element at this position : " + parentPos.pos );
+    }
+
+
     /**
      * Get the creation date
      * @return The creation date for this cursor

Modified: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java?rev=1711861&r1=1711860&r2=1711861&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueHolder.java Sun Nov  1 23:01:00 2015
@@ -37,29 +37,17 @@ package org.apache.directory.mavibot.btr
 
 
     /**
-     * @return the number of stored values
+     * @return the value stored in the ValueHolder
      */
-    int size();
+    V get();
 
 
     /**
-     * @return a cursor on top of the values
-     */
-    ValueCursor<V> getCursor();
-
-
-    /**
-     * @return true if we store the values in a sub btree
-     */
-    boolean isSubBtree();
-
-
-    /**
-     * Add a new value in the ValueHolder
+     * Set a new value in the ValueHolder
      * 
      * @param newValue The added value
      */
-    void add( V newValue );
+    void set( V newValue );
 
 
     /**
@@ -68,18 +56,6 @@ package org.apache.directory.mavibot.btr
      * @param removedValue The value to remove
      */
     V remove( V removedValue );
-
-    
-    /**
-     * Replaces the single value present in the array.
-     * 
-     * This is only applicable for B-Trees that don't
-     * support duplicate values.
-     *
-     * @param newValue the new value
-     * @return the value that was replaced
-     */
-    V replaceValueArray( V newValue );
     
 
     /**

Added: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java?rev=1711861&view=auto
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java (added)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/WALObject.java Sun Nov  1 23:01:00 2015
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+import java.io.IOException;
+
+/**
+ * A WALObject is an object stored in the TransactionContext before weing written on disk.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface WALObject
+{
+    /**
+     * @return The ID associated with the Object
+     */
+    long getId();
+    
+    
+    /**
+     * @param id Set an ID to this Object
+     */
+    void setId( long id );
+    
+    
+    /**
+     * @return Serialize the Object into PageIOs
+     */
+    PageIO[] serialize() throws IOException;
+}

Added: directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java?rev=1711861&view=auto
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java (added)
+++ directory/mavibot/branches/single-value/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/CursorException.java Sun Nov  1 23:01:00 2015
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.mavibot.btree.exception;
+
+/**
+ * An class for exceptions which add Cursor specific information to
+ * Exceptions.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CursorException extends Exception
+{
+    /** The serial version UUID */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * Creates a new instance of CursorException.
+     */
+    public CursorException()
+    {
+    }
+
+
+    /**
+     * Creates a new instance of CursorException.
+     *
+     * @param explanation The message associated with the exception
+     */
+    public CursorException( String explanation )
+    {
+        super( explanation );
+    }
+
+
+    /**
+     * Creates a new instance of LdapException.
+     */
+    public CursorException( Throwable cause )
+    {
+        super( cause );
+    }
+
+
+    /**
+     * Creates a new instance of CursorException.
+     *
+     * @param explanation The message associated with the exception
+     * @param cause The root cause for this exception
+     */
+    public CursorException( String explanation, Throwable cause )
+    {
+        super( explanation, cause );
+    }
+}

Modified: directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java?rev=1711861&r1=1711860&r2=1711861&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/BulkLoaderTest.java Sun Nov  1 23:01:00 2015
@@ -39,6 +39,7 @@ import java.util.TreeSet;
 
 import org.apache.directory.mavibot.btree.BulkLoader.LevelEnum;
 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
+import org.apache.directory.mavibot.btree.exception.CursorException;
 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
 import org.apache.directory.mavibot.btree.serializer.LongSerializer;
@@ -55,7 +56,7 @@ import org.junit.Test;
 public class BulkLoaderTest
 {
     private void checkBtree( BTree<Long, String> oldBtree, BTree<Long, String> newBtree )
-        throws EndOfFileExceededException, IOException, KeyNotFoundException
+        throws EndOfFileExceededException, IOException, KeyNotFoundException, CursorException
     {
         assertEquals( oldBtree.getNbElems(), newBtree.getNbElems() );
 
@@ -76,79 +77,12 @@ public class BulkLoaderTest
 
 
     /**
-     * Test that we can compact a btree which has no element
-     */
-    @Test
-    public void testInMemoryBulkLoadNoElement() throws IOException, KeyNotFoundException
-    {
-        BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-            StringSerializer.INSTANCE );
-        btree.setPageSize( 4 );
-
-        BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-        checkBtree( btree, newBtree );
-        TupleCursor<Long, String> cursorOld = btree.browse();
-        TupleCursor<Long, String> cursorNew = btree.browse();
-
-        assertFalse( cursorOld.hasNext() );
-        assertFalse( cursorNew.hasNext() );
-    }
-
-
-    /**
-     * Test that we can compact a btree which has a partially full leaf only
-     */
-    @Ignore
-    @Test
-    public void testInMemoryBulkLoad3Elements() throws IOException, KeyNotFoundException
-    {
-        BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-            StringSerializer.INSTANCE );
-        btree.setPageSize( 4 );
-
-        for ( Long i = 0L; i < 3L; i++ )
-        {
-            String value = "V" + i;
-            btree.insert( i, value );
-        }
-
-        BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-        checkBtree( btree, newBtree );
-    }
-
-
-    /**
-     * Test that we can compact a btree which has a 2 full leaves
-     */
-    @Ignore
-    @Test
-    public void testInMemoryBulkLoad8Elements() throws IOException, KeyNotFoundException
-    {
-        BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-            StringSerializer.INSTANCE );
-        btree.setPageSize( 4 );
-
-        for ( Long i = 0L; i < 8L; i++ )
-        {
-            String value = "V" + i;
-            btree.insert( i, value );
-        }
-
-        BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-        checkBtree( btree, newBtree );
-    }
-
-
-    /**
      * Test that we can load 100 BTrees with 0 to 1000 elements
      * @throws BTreeAlreadyManagedException 
      */
     @Test
     public void testPersistedBulkLoad1000Elements() throws IOException, KeyNotFoundException,
-        BTreeAlreadyManagedException
+        BTreeAlreadyManagedException, CursorException
     {
         for ( int i = 1000000; i < 1000001; i++ )
         {
@@ -266,146 +200,6 @@ public class BulkLoaderTest
 
 
     /**
-     * Test that we can compact a btree which has a full parent node, with all the leaves full.
-     */
-    @Test
-    public void testInMemoryBulkLoad20Elements() throws IOException, KeyNotFoundException
-    {
-        BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-            StringSerializer.INSTANCE );
-        btree.setPageSize( 4 );
-
-        for ( Long i = 0L; i < 20L; i++ )
-        {
-            String value = "V" + i;
-            btree.insert( i, value );
-        }
-
-        BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-        checkBtree( btree, newBtree );
-    }
-
-
-    /**
-     * Test that we can compact a btree which has two full parent nodes, with all the leaves full.
-     * That means we have an upper node with one element.
-     */
-    @Ignore
-    @Test
-    public void testInMemoryBulkLoad40Elements() throws IOException, KeyNotFoundException
-    {
-        BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-            StringSerializer.INSTANCE );
-        btree.setPageSize( 4 );
-
-        for ( Long i = 0L; i < 40L; i++ )
-        {
-            String value = "V" + i;
-            btree.insert( i, value );
-        }
-
-        BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-        checkBtree( btree, newBtree );
-    }
-
-
-    /**
-     * Test that we can compact a btree which has two full parent nodes, with all the leaves full.
-     * That means we have an upper node with one element.
-     */
-    @Test
-    public void testInMemoryBulkLoad100Elements() throws IOException, KeyNotFoundException
-    {
-        BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-            StringSerializer.INSTANCE );
-        btree.setPageSize( 4 );
-
-        for ( Long i = 0L; i < 100L; i++ )
-        {
-            String value = "V" + i;
-            btree.insert( i, value );
-        }
-
-        BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-        checkBtree( btree, newBtree );
-    }
-
-
-    @Ignore
-    @Test
-    public void testInMemoryBulkLoadN() throws IOException, KeyNotFoundException
-    {
-        Random random = new Random( System.nanoTime() );
-        long t0 = System.currentTimeMillis();
-
-        for ( long n = 0L; n < 2500L; n++ )
-        {
-            BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-                StringSerializer.INSTANCE );
-            btree.setPageSize( 4 );
-
-            for ( Long i = 0L; i < n; i++ )
-            {
-                String value = "V" + i;
-                btree.insert( i, value );
-            }
-
-            //long t1 = System.currentTimeMillis();
-
-            //System.out.println( "Delta initial load = " + ( t1 - t0 ) );
-
-            //long t2 = System.currentTimeMillis();
-
-            BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-            //long t3 = System.currentTimeMillis();
-
-            //System.out.println( "Delta initial load = " + ( t3 - t2 ) );
-
-            //System.out.println( "Checking for N = " + n );
-            checkBtree( btree, newBtree );
-        }
-    }
-
-
-    @Ignore
-    @Test
-    public void testInMemoryBulkLoad21() throws IOException, KeyNotFoundException
-    {
-        Random random = new Random( System.nanoTime() );
-        long t0 = System.currentTimeMillis();
-
-        BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
-            StringSerializer.INSTANCE );
-        btree.setPageSize( 4 );
-
-        for ( Long i = 0L; i < 21; i++ )
-        {
-            String value = "V" + i;
-            btree.insert( i, value );
-        }
-
-        //long t1 = System.currentTimeMillis();
-
-        //System.out.println( "Delta initial load = " + ( t1 - t0 ) );
-
-        //long t2 = System.currentTimeMillis();
-
-        BTree<Long, String> newBtree = ( BTree<Long, String> ) BulkLoader.compact( btree );
-
-        //long t3 = System.currentTimeMillis();
-
-        //System.out.println( "Delta initial load = " + ( t3 - t2 ) );
-
-        //System.out.println( "Checking for N = " + 21 );
-        checkBtree( btree, newBtree );
-    }
-
-
-    /**
      * test the computeLeafLevel method
      */
     @Test
@@ -575,7 +369,7 @@ public class BulkLoaderTest
     //@Ignore("The test is failing atm due to the sub-btree construction which is not working correctly when we have too many elements")
     @Test
     public void testPersistedBulkLoad1000ElementsMultipleValues() throws IOException, KeyNotFoundException,
-        BTreeAlreadyManagedException
+        BTreeAlreadyManagedException, CursorException
     {
         for ( int i = 1; i < 1001; i++ )
         {
@@ -709,7 +503,7 @@ public class BulkLoaderTest
      */
     @Test
     public void testPersistedBulkLoad1000ElementsMultipleValuesDebug() throws IOException, KeyNotFoundException,
-        BTreeAlreadyManagedException
+        BTreeAlreadyManagedException, CursorException
     {
         Random random = new Random( System.currentTimeMillis() );
         File file = File.createTempFile( "managedbtreebuilder", ".data" );

Modified: directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java
URL: http://svn.apache.org/viewvc/directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java?rev=1711861&r1=1711860&r2=1711861&view=diff
==============================================================================
--- directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java (original)
+++ directory/mavibot/branches/single-value/mavibot/src/test/java/org/apache/directory/mavibot/btree/PageReclaimerTest.java Sun Nov  1 23:01:00 2015
@@ -263,7 +263,6 @@ public class PageReclaimerTest
         config.setName( "dump-tree" );
         config.setKeySerializer( IntSerializer.INSTANCE );
         config.setValueSerializer( StringSerializer.INSTANCE );
-        config.setAllowDuplicates( false );
         config.setPageSize( 4 );
 
         BTree btree = new PersistedBTree( config );