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]