Author: kayyagari
Date: Fri Apr 12 15:44:46 2013
New Revision: 1467318

URL: http://svn.apache.org/r1467318
Log:
o implemented beforeFirst() and afterLast() navigation to Cursor
o tests

Added:
    
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/InternalUtil.java
Modified:
    
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/BTreeFactory.java
    
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Cursor.java
    
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Leaf.java
    
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/test/java/org/apache/mavibot/btree/BTreeDuplicateKeyTest.java

Modified: 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/BTreeFactory.java
URL: 
http://svn.apache.org/viewvc/labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/BTreeFactory.java?rev=1467318&r1=1467317&r2=1467318&view=diff
==============================================================================
--- 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/BTreeFactory.java
 (original)
+++ 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/BTreeFactory.java
 Fri Apr 12 15:44:46 2013
@@ -20,6 +20,9 @@
 package org.apache.mavibot.btree;
 
 
+import java.io.IOException;
+import java.util.LinkedList;
+
 import org.apache.mavibot.btree.serializer.ElementSerializer;
 
 
@@ -237,4 +240,46 @@ public class BTreeFactory
     {
         page.setValue( pos, value );
     }
+    
+
+    /**
+     * Includes the intermediate nodes in the path up to and including the 
right most leaf of the tree
+     * 
+     * @param btree the btree
+     * @return a LinkedList of all the nodes and the final leaf
+     * @throws IOException
+     */
+    public static LinkedList getPathToRightMostLeaf( BTree btree ) throws 
IOException
+    {
+        LinkedList<ParentPos> stack = new LinkedList<ParentPos>();
+        
+        ParentPos last = new ParentPos( btree.rootPage, 
btree.rootPage.getNbElems() );
+        stack.push( last );
+        
+        
+        if( btree.rootPage instanceof Leaf )
+        {
+            InternalUtil.setLastDupsContainer( last, btree );
+        }
+        else
+        {
+            Node node = ( Node ) btree.rootPage;
+            
+            while( true )
+            {
+                Page p = ( Page ) node.children[node.getNbElems()].getValue( 
btree );
+                
+                last = new ParentPos( p, p.getNbElems() );
+                stack.push( last );
+                
+                if( p instanceof Leaf )
+                {
+                    InternalUtil.setLastDupsContainer( last, btree );
+                    break;
+                }
+            }
+        }
+        
+        return stack;
+    }
 }

Modified: 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Cursor.java
URL: 
http://svn.apache.org/viewvc/labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Cursor.java?rev=1467318&r1=1467317&r2=1467318&view=diff
==============================================================================
--- 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Cursor.java
 (original)
+++ 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Cursor.java
 Fri Apr 12 15:44:46 2013
@@ -25,7 +25,7 @@ import java.util.LinkedList;
 import java.util.NoSuchElementException;
 
 import org.apache.mavibot.btree.exception.EndOfFileExceededException;
-
+import static org.apache.mavibot.btree.InternalUtil.*;
 
 /**
  * A Cursor is used to fetch elements in a BTree and is returned by the
@@ -54,6 +54,8 @@ public class Cursor<K, V>
 
     private boolean allowDuplicates;
     
+    /** a copy of the stack given at the time of initializing the cursor. This 
is used for moving the cursor to start position */
+    private LinkedList<ParentPos<K, V>> _initialStack;
 
     /**
      * Creates a new instance of Cursor, starting on a page at a given 
position.
@@ -67,8 +69,12 @@ public class Cursor<K, V>
         this.stack = stack;
         this.btree = btree;
         this.allowDuplicates = btree.isAllowDuplicates();
+        
+        _initialStack = new LinkedList<ParentPos<K,V>>();
+        
+        cloneStack( stack, _initialStack );
     }
-
+    
 
     /**
      * Find the next key/value
@@ -111,7 +117,7 @@ public class Cursor<K, V>
         
         if( allowDuplicates )
         {
-            setDupsContainer( parentPos );
+            setDupsContainer( parentPos, btree );
         
             // can happen if next() is called after prev()
             if ( parentPos.dupPos < 0 )
@@ -125,7 +131,7 @@ public class Cursor<K, V>
             if( parentPos.dupsContainer.getNbElems() ==  parentPos.dupPos )
             {
                 parentPos.pos++;
-                changeNextDupsContainer( parentPos );
+                changeNextDupsContainer( parentPos, btree );
             }
         }
         else
@@ -137,7 +143,7 @@ public class Cursor<K, V>
         return tuple;
     }
 
-
+    
     /**
      * Find the leaf containing the following elements.
      * 
@@ -185,7 +191,7 @@ public class Cursor<K, V>
 
                 if( allowDuplicates )
                 {
-                    setDupsContainer( newParentPos );
+                    setDupsContainer( newParentPos, btree );
                 }
 
                 return newParentPos;
@@ -242,7 +248,7 @@ public class Cursor<K, V>
 
                 if( allowDuplicates )
                 {
-                    changePrevDupsContainer( newParentPos );
+                    changePrevDupsContainer( newParentPos, btree );
                 }
 
                 return newParentPos;
@@ -286,7 +292,7 @@ public class Cursor<K, V>
         
         if( allowDuplicates )
         {
-            setDupsContainer( parentPos );
+            setDupsContainer( parentPos, btree );
             
             // can happen if prev() was called after next()
             if( parentPos.pos == parentPos.page.getNbElems() )
@@ -300,7 +306,7 @@ public class Cursor<K, V>
             }
             else if( parentPos.dupPos == 0 )
             {
-                changePrevDupsContainer( parentPos );
+                changePrevDupsContainer( parentPos, btree );
                 parentPos.pos--;
                 parentPos.dupPos--;
             }
@@ -419,38 +425,132 @@ public class Cursor<K, V>
         return transaction.getCreationDate();
     }
     
+    
+    /**
+     * Moves the cursor to the next non-duplicate key.
 
-    private void setDupsContainer( ParentPos<K, V> parentPos ) throws 
IOException
+     * If the BTree contains 
+     * 
+     *  <ul>
+     *    <li><1,0></li>
+     *    <li><1,1></li>
+     *    <li><2,0></li>
+     *    <li><2,1></li>
+     *  </ul>
+     *   
+     *  and cursor is present at <1,0> then the cursor will move to <2,0>
+     *  
+     * @throws EndOfFileExceededException
+     * @throws IOException
+     */
+    public void moveToNextNonDuplicateKey() throws EndOfFileExceededException, 
IOException
     {
-        if( parentPos.dupsContainer == null )
+        ParentPos<K, V> parentPos = stack.getFirst();
+
+        if ( parentPos.page == null )
         {
-            Leaf<K, V> leaf = ( Leaf<K, V> ) ( parentPos.page );
-            BTree<V, V> dupsContainer = ( BTree<V, V> ) 
leaf.values[parentPos.pos].getValue( btree );
-            parentPos.dupsContainer = dupsContainer;
+            return;
         }
-    }
-    
-    private void changeNextDupsContainer( ParentPos<K, V> parentPos ) throws 
IOException
+
+        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();
+        }
+        else
+        {
+            parentPos.pos++;
+            changeNextDupsContainer( parentPos, btree );
+        }
+    }    
+
+
+    /**
+     * Moves the cursor to the previous non-duplicate key
+     * If the BTree contains 
+     * 
+     *  <ul>
+     *    <li><1,0></li>
+     *    <li><1,1></li>
+     *    <li><2,0></li>
+     *    <li><2,1></li>
+     *  </ul>
+     *   
+     *  and cursor is present at <2,1> then the cursor will move to <1,1>
+     * 
+     * @throws EndOfFileExceededException
+     * @throws IOException
+     */
+    public void moveToPrevNonDuplicateKey() throws EndOfFileExceededException, 
IOException
     {
-        if( parentPos.pos < parentPos.page.getNbElems() )
+        ParentPos<K, V> parentPos = stack.peek();
+
+        if ( parentPos.page == null )
         {
-            Leaf<K, V> leaf = ( Leaf<K, V> ) ( parentPos.page );
-            BTree<V, V> dupsContainer = ( BTree<V, V> ) 
leaf.values[parentPos.pos].getValue( btree );
-            parentPos.dupsContainer = dupsContainer;
-            parentPos.dupPos = 0;
+            // This is the end : no more value
+            return;
         }
-    }
 
-    private void changePrevDupsContainer( ParentPos<K, V> parentPos ) throws 
IOException
+        if ( parentPos.pos == 0 )
+        {
+            // End of the leaf. We have to go back into the stack up to the
+            // parent, and down to the leaf
+            parentPos = findPreviousParentPos();
+        }
+        else
+        {
+            changePrevDupsContainer( parentPos, btree );
+            parentPos.pos--;
+        }
+    }
+    
+    
+    /**
+     * moves the cursor to the same position that was given at the time of 
instantiating the cursor.
+     * 
+     *  For example, if the cursor was created using browse() method, then 
beforeFirst() will
+     *  place the cursor before the 0th position.
+     *  
+     *  If the cursor was created using browseFrom(K), then calling 
beforeFirst() will reset the position
+     *  to the just before the position where K is present.
+     */
+    public void beforeFirst() throws IOException
     {
-        int index = parentPos.pos - 1;
-        if( index >= 0 )
+        cloneStack( _initialStack, stack );
+    }
+    
+    
+    /**
+     * Places the cursor at the end of the last position
+     * 
+     * @throws IOException
+     */
+    public void afterLast() throws IOException
+    {
+        stack.clear();
+        stack = ( LinkedList<ParentPos<K, V>> ) 
BTreeFactory.getPathToRightMostLeaf( btree );
+    }
+    
+    
+    /**
+     * clones the original stack of ParentPos objects
+     * 
+     * @param original the original stack
+     * @param clone the stack where the cloned ParentPos objects to be copied
+     */
+    private void cloneStack( LinkedList<ParentPos<K, V>> original, 
LinkedList<ParentPos<K, V>> clone )
+    {
+        clone.clear();
+        
+        // preserve the first position
+        for( ParentPos<K, V> o : original )
         {
-            Leaf<K, V> leaf = ( Leaf<K, V> ) ( parentPos.page );
-            BTree<V, V> dupsContainer = ( BTree<V, V> ) 
leaf.values[index].getValue( btree );
-            parentPos.dupsContainer = dupsContainer;
-            parentPos.dupPos = ( int ) parentPos.dupsContainer.getNbElems();
+            ParentPos<K, V> tmp = new ParentPos<K, V>( o.page, o.pos );
+            tmp.dupPos = o.dupPos;
+            tmp.dupsContainer = o.dupsContainer;
+            clone.add( tmp );
         }
     }
-
+    
 }

Added: 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/InternalUtil.java
URL: 
http://svn.apache.org/viewvc/labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/InternalUtil.java?rev=1467318&view=auto
==============================================================================
--- 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/InternalUtil.java
 (added)
+++ 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/InternalUtil.java
 Fri Apr 12 15:44:46 2013
@@ -0,0 +1,127 @@
+/*
+ *   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.mavibot.btree;
+
+
+import java.io.IOException;
+
+
+/**
+ * A class containing utility methods to be used internally. 
+ *
+ * @author <a href="mailto:[email protected]";>Apache Directory 
Project</a>
+ */
+@SuppressWarnings("all")
+/* No qualifier */class InternalUtil
+{
+
+    /**
+     * Sets the multi-value container(a.k.a dupsContainer) of the key at the 
given position.
+     * 
+     * This method will not update the existing value of 'dupsPos'. To change 
this value
+     * use {@link #changeNextDupsContainer(ParentPos, BTree)} or {@link 
#changePrevDupsContainer(ParentPos, BTree)}
+     *  
+     * @param parentPos the parent position object
+     * @param btree the BTree
+     */
+    public static void setDupsContainer( ParentPos parentPos, BTree btree )
+    {
+        if ( !btree.isAllowDuplicates() )
+        {
+            return;
+        }
+
+        try
+        {
+            if ( parentPos.dupsContainer == null )
+            {
+                Leaf leaf = ( Leaf ) ( parentPos.page );
+                BTree dupsContainer = ( BTree ) 
leaf.values[parentPos.pos].getValue( btree );
+                parentPos.dupsContainer = dupsContainer;
+            }
+        }
+        catch ( IOException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     * Sets the multi-value container(a.k.a dupsContainer) of the key at the 
given position
+     * and resets the 'dupsPos' to zero. This is mostly used by Cursor while 
navigating using
+     * next() 
+     *
+     * @param parentPos the parent position object
+     * @param btree the BTree
+     */
+    public static void changeNextDupsContainer( ParentPos parentPos, BTree 
btree ) throws IOException
+    {
+        if ( !btree.isAllowDuplicates() )
+        {
+            return;
+        }
+
+        if ( parentPos.pos < parentPos.page.getNbElems() )
+        {
+            Leaf leaf = ( Leaf ) ( parentPos.page );
+            BTree dupsContainer = ( BTree ) 
leaf.values[parentPos.pos].getValue( btree );
+            parentPos.dupsContainer = dupsContainer;
+            parentPos.dupPos = 0;
+        }
+    }
+
+
+    /**
+     * Sets the multi-value container(a.k.a dupsContainer) of the key at the 
index below the given position( i.e pos - 1)
+     * and resets the 'dupsPos' to the number of elements present in the 
multi-value container.
+     * This is used by Cursor while navigating using prev() 
+     *
+     * @param parentPos the parent position object
+     * @param btree the BTree
+     */
+    public static void changePrevDupsContainer( ParentPos parentPos, BTree 
btree ) throws IOException
+    {
+        if ( !btree.isAllowDuplicates() )
+        {
+            return;
+        }
+
+        int index = parentPos.pos - 1;
+        if ( index >= 0 )
+        {
+            Leaf leaf = ( Leaf ) ( parentPos.page );
+            BTree dupsContainer = ( BTree ) leaf.values[index].getValue( btree 
);
+            parentPos.dupsContainer = dupsContainer;
+            parentPos.dupPos = ( int ) parentPos.dupsContainer.getNbElems();
+        }
+    }
+
+
+    /**
+     * Same as @see #changePrevDupsContainer(ParentPos, BTree) but with a 
different name
+     * to make it sound semantically right when used inside {@link 
BTreeFactory#getPathToRightMostLeaf(BTree)} 
+     */
+    public static void setLastDupsContainer( ParentPos parentPos, BTree btree 
) throws IOException
+    {
+        changePrevDupsContainer( parentPos, btree );
+    }
+}

Modified: 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Leaf.java
URL: 
http://svn.apache.org/viewvc/labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Leaf.java?rev=1467318&r1=1467317&r2=1467318&view=diff
==============================================================================
--- 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Leaf.java
 (original)
+++ 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/main/java/org/apache/mavibot/btree/Leaf.java
 Fri Apr 12 15:44:46 2013
@@ -26,6 +26,7 @@ import java.util.LinkedList;
 
 import org.apache.mavibot.btree.exception.EndOfFileExceededException;
 import org.apache.mavibot.btree.exception.KeyNotFoundException;
+import static org.apache.mavibot.btree.InternalUtil.*;
 
 
 /**
@@ -598,7 +599,7 @@ import org.apache.mavibot.btree.exceptio
 
             // The first element has been found. Create the cursor
             ParentPos<K, V> parentPos = new ParentPos<K, V>( this, index );
-            setDupsContainer( parentPos );
+            setDupsContainer( parentPos, btree );
             stack.push( parentPos );
 
             cursor = new Cursor<K, V>( btree, transaction, stack );
@@ -609,7 +610,7 @@ import org.apache.mavibot.btree.exceptio
             if ( pos < nbElems )
             {
                 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, pos );
-                setDupsContainer( parentPos );
+                setDupsContainer( parentPos, btree );
                 stack.push( parentPos );
 
                 cursor = new Cursor<K, V>( btree, transaction, stack );
@@ -647,7 +648,7 @@ import org.apache.mavibot.btree.exceptio
             // Start at the beginning of the page
             ParentPos<K, V> parentPos = new ParentPos<K, V>( this, pos );
 
-            setDupsContainer( parentPos );
+            setDupsContainer( parentPos, btree );
 
             stack.push( parentPos );
 
@@ -965,28 +966,6 @@ import org.apache.mavibot.btree.exceptio
 
 
     /**
-     * Creates a sub-tree if the BTree accept multiple values for a key.
-     *
-     * @param parentPos The position we will add the sub-tree at
-     */
-    private void setDupsContainer( ParentPos<K, V> parentPos )
-    {
-        if ( btree.isAllowDuplicates() )
-        {
-            try
-            {
-                BTree<V, V> dupsContainer = ( BTree<V, V> ) 
values[parentPos.pos].getValue( btree );
-                parentPos.dupsContainer = dupsContainer;
-            }
-            catch ( IOException e )
-            {
-                throw new RuntimeException( e );
-            }
-        }
-    }
-
-
-    /**
      * {@inheritDoc}
      */
     public String dumpPage( String tabs )

Modified: 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/test/java/org/apache/mavibot/btree/BTreeDuplicateKeyTest.java
URL: 
http://svn.apache.org/viewvc/labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/test/java/org/apache/mavibot/btree/BTreeDuplicateKeyTest.java?rev=1467318&r1=1467317&r2=1467318&view=diff
==============================================================================
--- 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/test/java/org/apache/mavibot/btree/BTreeDuplicateKeyTest.java
 (original)
+++ 
labs/mavibot/branches/mavibot-multivalue-support/mavibot/src/test/java/org/apache/mavibot/btree/BTreeDuplicateKeyTest.java
 Fri Apr 12 15:44:46 2013
@@ -290,4 +290,186 @@ public class BTreeDuplicateKeyTest
         assertEquals( ( 'a' - 1 ) , ch );
         cursor.close();
     }
+
+    @Test
+    public void testMoveFirst() throws Exception
+    {
+        StringSerializer serializer = new StringSerializer();
+
+        BTreeConfiguration<String, String> config = new 
BTreeConfiguration<String, String>();
+        config.setAllowDuplicates( true );
+        config.setName( "master" );
+        config.setSerializers( serializer, serializer );
+        BTree<String, String> btree = new BTree<String, String>( config );
+
+        for ( char ch = 'a'; ch <= 'z'; ch++ )
+        {
+            btree.insert( String.valueOf( ch ), UUID.randomUUID().toString() );
+        }
+
+        // add one more value for 'a'
+        btree.insert( String.valueOf( 'a' ), UUID.randomUUID().toString() );
+        
+        Cursor<String, String> cursor = btree.browseFrom( "c" );
+
+        int i = 0;
+        while( cursor.hasNext() )
+        {
+            assertNotNull( cursor.next() );
+            i++;
+        }
+        assertEquals( 24, i );
+        
+        // now move the cursor first
+        cursor.beforeFirst();
+        assertTrue( cursor.hasNext() );
+        assertEquals( "c", cursor.next().getKey() );
+        
+        i = 0;
+        while( cursor.hasNext() )
+        {
+            assertNotNull( cursor.next() );
+            i++;
+        }
+        assertEquals( 23, i );
+        
+        cursor.close();
+        
+        cursor = btree.browse();
+        
+        i = 0;
+        while( cursor.hasNext() )
+        {
+            assertNotNull( cursor.next() );
+            i++;
+        }
+        assertEquals( 27, i );
+        
+        // now move the cursor first
+        cursor.beforeFirst();
+        assertTrue( cursor.hasNext() );
+        assertEquals( "a", cursor.next().getKey() );
+        
+        i = 0;
+        while( cursor.hasNext() )
+        {
+            assertNotNull( cursor.next() );
+            i++;
+        }
+        assertEquals( 26, i );
+    }
+
+
+    @Test
+    public void testMoveLast() throws Exception
+    {
+        StringSerializer serializer = new StringSerializer();
+
+        BTreeConfiguration<String, String> config = new 
BTreeConfiguration<String, String>();
+        config.setAllowDuplicates( true );
+        config.setName( "master" );
+        config.setSerializers( serializer, serializer );
+        BTree<String, String> btree = new BTree<String, String>( config );
+
+        for ( char ch = 'a'; ch <= 'z'; ch++ )
+        {
+            btree.insert( String.valueOf( ch ), UUID.randomUUID().toString() );
+        }
+        
+        btree.insert( String.valueOf( 'z' ), UUID.randomUUID().toString() );
+        
+        Cursor<String, String> cursor = btree.browseFrom( "c" );
+        cursor.afterLast();
+        
+        assertFalse( cursor.hasNext() );
+        assertTrue( cursor.hasPrev() );
+        assertEquals( "z", cursor.prev().getKey() );
+        assertEquals( "z", cursor.prev().getKey() );
+        assertEquals( "y", cursor.prev().getKey() );
+        
+        cursor.beforeFirst();
+        assertEquals( "c", cursor.next().getKey() );
+    }
+
+    
+    @Test
+    public void testMoveToNextPrevNonDuplicateKey() throws Exception
+    {
+        StringSerializer serializer = new StringSerializer();
+
+        BTreeConfiguration<String, String> config = new 
BTreeConfiguration<String, String>();
+        config.setAllowDuplicates( true );
+        config.setName( "master" );
+        config.setSerializers( serializer, serializer );
+        BTree<String, String> btree = new BTree<String, String>( config );
+
+        int i = 7;
+        for ( char ch = 'a'; ch <= 'z'; ch++ )
+        {
+            for( int k = 0; k< i; k++ )
+            {
+                btree.insert( String.valueOf( ch ), String.valueOf( k ) );
+            }
+        }
+        
+        Cursor<String, String> cursor = btree.browse();
+
+        assertTrue( cursor.hasNext() );
+        assertFalse( cursor.hasPrev() );
+        for(int k =0; k < 2; k++)
+        {
+            assertEquals( "a", cursor.next().getKey() );
+        }
+        
+        assertEquals( "a", cursor.next().getKey() );
+        
+        cursor.moveToNextNonDuplicateKey();
+        
+        assertEquals( "b", cursor.next().getKey() );
+        
+        for ( char ch = 'b'; ch < 'z'; ch++ )
+        {
+            assertEquals( String.valueOf( ch ), cursor.next().getKey() );
+            cursor.moveToNextNonDuplicateKey();
+            char t = ch;
+            assertEquals( String.valueOf( ++t ), cursor.next().getKey() );
+        }
+
+        for(int k =0; k < i-1; k++)
+        {
+            assertEquals( "z", cursor.next().getKey() );
+        }
+
+        assertFalse( cursor.hasNext() );
+        assertTrue( cursor.hasPrev() );
+        Tuple<String, String> tuple = cursor.prev();
+        assertEquals( "z", tuple.getKey() );
+        assertEquals( "6", tuple.getValue() );
+        
+        for ( char ch = 'z'; ch > 'a'; ch-- )
+        {
+            char t = ch;
+            t--;
+            
+            assertEquals( String.valueOf( ch ), cursor.prev().getKey() );
+            
+            cursor.moveToPrevNonDuplicateKey();
+
+            tuple = cursor.prev();
+            assertEquals( String.valueOf( t ), tuple.getKey() );
+        }
+        
+        for(int k =5; k >=0; k--)
+        {
+            tuple = cursor.prev();
+            assertEquals( "a", tuple.getKey() );
+            assertEquals( String.valueOf( k ), tuple.getValue() );
+        }
+
+        assertTrue( cursor.hasNext() );
+        assertFalse( cursor.hasPrev() );
+        tuple = cursor.next();
+        assertEquals( "a", tuple.getKey() );
+        assertEquals( "0", tuple.getValue() );
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to