View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.mavibot.btree;
21  
22  
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertNotNull;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  import java.io.File;
30  import java.io.IOException;
31  import java.util.NoSuchElementException;
32  import java.util.UUID;
33  
34  import org.apache.commons.io.FileUtils;
35  import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
36  import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
37  import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
38  import org.apache.directory.mavibot.btree.serializer.LongSerializer;
39  import org.apache.directory.mavibot.btree.serializer.StringSerializer;
40  import org.junit.After;
41  import org.junit.Before;
42  import org.junit.Ignore;
43  import org.junit.Rule;
44  import org.junit.Test;
45  import org.junit.rules.TemporaryFolder;
46  
47  
48  /**
49   * Tests the browse methods on a managed BTree
50   *
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   */
53  public class PersistedBTreeBrowseTest
54  {
55      private BTree<Long, String> btree = null;
56  
57      private RecordManager recordManager1 = null;
58  
59      @Rule
60      public TemporaryFolder tempFolder = new TemporaryFolder();
61  
62      private File dataDir = null;
63  
64  
65      /**
66       * Create a BTree for this test
67       */
68      @Before
69      public void createBTree() throws IOException
70      {
71          dataDir = tempFolder.newFolder( UUID.randomUUID().toString() );
72  
73          openRecordManagerAndBtree();
74  
75          try
76          {
77              // Create a new BTree which allows duplicate values
78              btree = recordManager1.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE, true );
79              //btree.setPageSize( 4 );
80          }
81          catch ( Exception e )
82          {
83              throw new RuntimeException( e );
84          }
85      }
86  
87  
88      @After
89      public void cleanup() throws IOException
90      {
91          dataDir = new File( System.getProperty( "java.io.tmpdir" ) + "/recordman" );
92  
93          btree.close();
94  
95          if ( dataDir.exists() )
96          {
97              FileUtils.deleteDirectory( dataDir );
98          }
99          
100         recordManager1.close();
101         assertTrue( recordManager1.isContextOk() );
102     }
103 
104 
105     /**
106      * Reload the BTree into a new record manager
107      */
108     private void openRecordManagerAndBtree()
109     {
110         try
111         {
112             if ( recordManager1 != null )
113             {
114                 recordManager1.close();
115             }
116 
117             // Now, try to reload the file back
118             recordManager1 = new RecordManager( dataDir.getAbsolutePath() );
119 
120             // load the last created btree
121             if ( btree != null )
122             {
123                 btree = recordManager1.getManagedTree( btree.getName() );
124             }
125         }
126         catch ( Exception e )
127         {
128             throw new RuntimeException( e );
129         }
130     }
131 
132 
133     /**
134      * Check a tuple
135      */
136     private void checkTuple( Tuple<Long, String> tuple, long key, String value ) throws EndOfFileExceededException,
137         IOException
138     {
139         assertNotNull( tuple );
140         assertEquals( key, ( long ) tuple.getKey() );
141         assertEquals( value, tuple.getValue() );
142     }
143 
144 
145     /**
146      * Check a next() call
147      */
148     private void checkNext( TupleCursor<Long, String> cursor, long key, String value, boolean next, boolean prev )
149         throws EndOfFileExceededException, IOException
150     {
151         Tuple<Long, String> tuple = cursor.next();
152 
153         checkTuple( tuple, key, value );
154         assertEquals( next, cursor.hasNext() );
155         assertEquals( prev, cursor.hasPrev() );
156     }
157 
158 
159     /**
160      * Check a prev() call
161      */
162     private void checkPrev( TupleCursor<Long, String> cursor, long key, String value, boolean next, boolean prev )
163         throws EndOfFileExceededException, IOException
164     {
165         Tuple<Long, String> tuple = cursor.prev();
166         assertNotNull( tuple );
167         assertEquals( key, ( long ) tuple.getKey() );
168         assertEquals( value, tuple.getValue() );
169         assertEquals( next, cursor.hasNext() );
170         assertEquals( prev, cursor.hasPrev() );
171     }
172 
173 
174     /**
175      * Construct a String representation of a number padded with 0 on the left
176      */
177     private String toString( long value, int size )
178     {
179         String valueStr = Long.toString( value );
180 
181         StringBuilder sb = new StringBuilder();
182 
183         if ( size > valueStr.length() )
184         {
185             for ( int i = valueStr.length(); i < size; i++ )
186             {
187                 sb.append( "0" );
188             }
189         }
190 
191         sb.append( valueStr );
192 
193         return sb.toString();
194     }
195 
196 
197     //----------------------------------------------------------------------------------------
198     // The Browse tests
199     //----------------------------------------------------------------------------------------
200     /**
201      * Test the browse methods on an empty btree
202      * @throws KeyNotFoundException 
203      */
204     @Test
205     public void testBrowseEmptyBTree() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
206     {
207         TupleCursor<Long, String> cursor = btree.browse();
208 
209         assertFalse( cursor.hasNext() );
210         assertFalse( cursor.hasPrev() );
211 
212         try
213         {
214             cursor.next();
215             fail();
216         }
217         catch ( NoSuchElementException nsee )
218         {
219             // Expected
220         }
221 
222         try
223         {
224             cursor.prev();
225             fail();
226         }
227         catch ( NoSuchElementException nsee )
228         {
229             // Expected
230         }
231 
232         assertEquals( 0L, cursor.getRevision() );
233     }
234 
235 
236     /**
237      * Test the browse methods on a btree containing just a leaf
238      */
239     @Test
240     public void testBrowseBTreeLeafNext() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
241     {
242         // Inject some data
243         btree.insert( 1L, "1" );
244         btree.insert( 4L, "4" );
245         btree.insert( 2L, "2" );
246         btree.insert( 3L, "3" );
247         btree.insert( 5L, "5" );
248 
249         // Create the cursor
250         TupleCursor<Long, String> cursor = btree.browse();
251 
252         // Move forward
253         cursor.beforeFirst();
254 
255         assertFalse( cursor.hasPrev() );
256         assertTrue( cursor.hasNext() );
257 
258         checkNext( cursor, 1L, "1", true, false );
259         checkNext( cursor, 2L, "2", true, true );
260         checkNext( cursor, 3L, "3", true, true );
261         checkNext( cursor, 4L, "4", true, true );
262         checkNext( cursor, 5L, "5", false, true );
263     }
264 
265 
266     /**
267      * Test the browse methods on a btree containing just a leaf
268      */
269     @Test
270     public void testBrowseBTreeLeafPrev() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
271     {
272         // Inject some data
273         btree.insert( 1L, "1" );
274         btree.insert( 4L, "4" );
275         btree.insert( 2L, "2" );
276         btree.insert( 3L, "3" );
277         btree.insert( 5L, "5" );
278 
279         // Create the cursor
280         TupleCursor<Long, String> cursor = btree.browse();
281 
282         // Move backward
283         cursor.afterLast();
284 
285         checkPrev( cursor, 5L, "5", false, true );
286         checkPrev( cursor, 4L, "4", true, true );
287         checkPrev( cursor, 3L, "3", true, true );
288         checkPrev( cursor, 2L, "2", true, true );
289         checkPrev( cursor, 1L, "1", true, false );
290     }
291 
292 
293     /**
294      * Test the browse methods on a btree containing just a leaf and see if we can
295      * move at the end or at the beginning
296      */
297     @Test
298     public void testBrowseBTreeLeafFirstLast() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
299     {
300         // Inject some data
301         btree.insert( 1L, "1" );
302         btree.insert( 4L, "4" );
303         btree.insert( 2L, "2" );
304         btree.insert( 3L, "3" );
305         btree.insert( 5L, "5" );
306 
307         // Create the cursor
308         TupleCursor<Long, String> cursor = btree.browse();
309 
310         // We should not be able to move backward
311         try
312         {
313             cursor.prev();
314             fail();
315         }
316         catch ( NoSuchElementException nsee )
317         {
318             // Expected
319         }
320 
321         // Start browsing three elements
322         assertFalse( cursor.hasPrev() );
323         assertTrue( cursor.hasNext() );
324         Tuple<Long, String> tuple = cursor.next();
325         tuple = cursor.next();
326         tuple = cursor.next();
327 
328         // We should be at 3 now
329         assertTrue( cursor.hasPrev() );
330         assertTrue( cursor.hasNext() );
331         assertEquals( 3L, ( long ) tuple.getKey() );
332         assertEquals( "3", tuple.getValue() );
333 
334         // Move to the end
335         cursor.afterLast();
336 
337         assertTrue( cursor.hasPrev() );
338         assertFalse( cursor.hasNext() );
339 
340         // We should not be able to move forward
341         try
342         {
343             cursor.next();
344             fail();
345         }
346         catch ( NoSuchElementException nsee )
347         {
348             // Expected
349         }
350 
351         // We should be at 5
352         tuple = cursor.prev();
353         assertEquals( 5L, ( long ) tuple.getKey() );
354         assertEquals( "5", tuple.getValue() );
355 
356         assertTrue( cursor.hasPrev() );
357         assertFalse( cursor.hasNext() );
358 
359         // Move back to the origin
360         cursor.beforeFirst();
361 
362         assertFalse( cursor.hasPrev() );
363         assertTrue( cursor.hasNext() );
364 
365         // We should be at 1
366         tuple = cursor.next();
367         assertEquals( 1L, ( long ) tuple.getKey() );
368         assertEquals( "1", tuple.getValue() );
369 
370         assertFalse( cursor.hasPrev() );
371         assertTrue( cursor.hasNext() );
372     }
373 
374 
375     /**
376      * Test the browse methods on a btree containing just a leaf and see if we can
377      * move back and forth
378      */
379     @Test
380     public void testBrowseBTreeLeafNextPrev() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
381     {
382         // Inject some data
383         btree.insert( 1L, "1" );
384         btree.insert( 4L, "4" );
385         btree.insert( 2L, "2" );
386         btree.insert( 3L, "3" );
387         btree.insert( 5L, "5" );
388 
389         // Create the cursor
390         TupleCursor<Long, String> cursor = btree.browse();
391 
392         // We should not be able to move backward
393         try
394         {
395             cursor.prev();
396             fail();
397         }
398         catch ( NoSuchElementException nsee )
399         {
400             // Expected
401         }
402 
403         // Start browsing three elements
404         assertFalse( cursor.hasPrev() );
405         assertTrue( cursor.hasNext() );
406         Tuple<Long, String> tuple = cursor.next();
407         tuple = cursor.next();
408         tuple = cursor.next();
409 
410         // We should be at 3 now
411         assertTrue( cursor.hasPrev() );
412         assertTrue( cursor.hasNext() );
413         assertEquals( 3L, ( long ) tuple.getKey() );
414         assertEquals( "3", tuple.getValue() );
415 
416         // Now, move to the prev value
417         cursor.prev();
418         assertEquals( 2L, ( long ) tuple.getKey() );
419         assertEquals( "2", tuple.getValue() );
420 
421         // And to the next value
422         cursor.next();
423         assertEquals( 3L, ( long ) tuple.getKey() );
424         assertEquals( "3", tuple.getValue() );
425     }
426 
427 
428     /**
429      * Test the browse methods on a btree containing many nodes
430      */
431     @Test
432     public void testBrowseBTreeNodesNext() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
433     {
434         // Inject some data
435         for ( long i = 1; i < 1000L; i++ )
436         {
437             btree.insert( i, Long.toString( i ) );
438         }
439 
440         // Create the cursor
441         TupleCursor<Long, String> cursor = btree.browse();
442 
443         // Move forward
444         cursor.beforeFirst();
445 
446         assertFalse( cursor.hasPrev() );
447         assertTrue( cursor.hasNext() );
448 
449         checkNext( cursor, 1L, "1", true, false );
450 
451         for ( long i = 2L; i < 999L; i++ )
452         {
453             checkNext( cursor, i, Long.toString( i ), true, true );
454         }
455 
456         checkNext( cursor, 999L, "999", false, true );
457     }
458 
459 
460     /**
461      * Test the browse methods on a btree containing many nodes
462      */
463     @Test
464     public void testBrowseBTreeNodesPrev() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
465     {
466         // Inject some data
467         for ( long i = 1; i < 1000L; i++ )
468         {
469             btree.insert( i, Long.toString( i ) );
470         }
471 
472         // Create the cursor
473         TupleCursor<Long, String> cursor = btree.browse();
474 
475         // Move backward
476         cursor.afterLast();
477 
478         assertTrue( cursor.hasPrev() );
479         assertFalse( cursor.hasNext() );
480 
481         checkPrev( cursor, 999L, "999", false, true );
482 
483         for ( long i = 998L; i > 1L; i-- )
484         {
485             checkPrev( cursor, i, Long.toString( i ), true, true );
486         }
487 
488         checkPrev( cursor, 1L, "1", true, false );
489     }
490 
491 
492     /**
493      * Test the browse methods on a btree containing just a leaf with duplicate values
494      */
495     @Test
496     public void testBrowseBTreeLeafNextDups1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
497     {
498         // Inject some duplicate data
499         btree.insert( 1L, "1" );
500         btree.insert( 1L, "4" );
501         btree.insert( 1L, "2" );
502         btree.insert( 1L, "3" );
503         btree.insert( 1L, "5" );
504 
505         // Create the cursor
506         TupleCursor<Long, String> cursor = btree.browse();
507 
508         // Move forward
509         cursor.beforeFirst();
510 
511         assertFalse( cursor.hasPrev() );
512         assertTrue( cursor.hasNext() );
513 
514         checkNext( cursor, 1L, "1", true, false );
515         checkNext( cursor, 1L, "2", true, true );
516         checkNext( cursor, 1L, "3", true, true );
517         checkNext( cursor, 1L, "4", true, true );
518         checkNext( cursor, 1L, "5", false, true );
519     }
520 
521 
522     /**
523      * Test the browse methods on a btree containing just a leaf with duplicate values
524      */
525     @Test
526     public void testBrowseBTreeLeafNextDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
527     {
528         // Inject some duplicate data
529         btree.insert( 1L, "1" );
530         btree.insert( 1L, "4" );
531         btree.insert( 1L, "2" );
532         btree.insert( 2L, "3" );
533         btree.insert( 3L, "5" );
534         btree.insert( 3L, "7" );
535         btree.insert( 3L, "6" );
536 
537         // Create the cursor
538         TupleCursor<Long, String> cursor = btree.browse();
539 
540         // Move forward
541         cursor.beforeFirst();
542 
543         assertFalse( cursor.hasPrev() );
544         assertTrue( cursor.hasNext() );
545 
546         checkNext( cursor, 1L, "1", true, false );
547         checkNext( cursor, 1L, "2", true, true );
548         checkNext( cursor, 1L, "4", true, true );
549         checkNext( cursor, 2L, "3", true, true );
550         checkNext( cursor, 3L, "5", true, true );
551         checkNext( cursor, 3L, "6", true, true );
552         checkNext( cursor, 3L, "7", false, true );
553     }
554 
555 
556     /**
557      * Test the browse methods on a btree containing just a leaf with duplicate values
558      */
559     @Test
560     public void testBrowseBTreeLeafPrevDups1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
561     {
562         // Inject some duplicate data
563         btree.insert( 1L, "1" );
564         btree.insert( 1L, "4" );
565         btree.insert( 1L, "2" );
566         btree.insert( 1L, "3" );
567         btree.insert( 1L, "5" );
568 
569         // Create the cursor
570         TupleCursor<Long, String> cursor = btree.browse();
571 
572         // Move backward
573         cursor.afterLast();
574 
575         assertTrue( cursor.hasPrev() );
576         assertFalse( cursor.hasNext() );
577 
578         checkPrev( cursor, 1L, "5", false, true );
579         checkPrev( cursor, 1L, "4", true, true );
580         checkPrev( cursor, 1L, "3", true, true );
581         checkPrev( cursor, 1L, "2", true, true );
582         checkPrev( cursor, 1L, "1", true, false );
583     }
584 
585 
586     /**
587      * Test the browse methods on a btree containing just a leaf with duplicate values
588      */
589     @Test
590     public void testBrowseBTreeLeafPrevDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
591     {
592         // Inject some duplicate data
593         btree.insert( 1L, "1" );
594         btree.insert( 1L, "4" );
595         btree.insert( 1L, "2" );
596         btree.insert( 2L, "3" );
597         btree.insert( 3L, "5" );
598         btree.insert( 3L, "7" );
599         btree.insert( 3L, "6" );
600 
601         // Create the cursor
602         TupleCursor<Long, String> cursor = btree.browse();
603 
604         // Move backward
605         cursor.afterLast();
606 
607         assertTrue( cursor.hasPrev() );
608         assertFalse( cursor.hasNext() );
609 
610         checkPrev( cursor, 3L, "7", false, true );
611         checkPrev( cursor, 3L, "6", true, true );
612         checkPrev( cursor, 3L, "5", true, true );
613         checkPrev( cursor, 2L, "3", true, true );
614         checkPrev( cursor, 1L, "4", true, true );
615         checkPrev( cursor, 1L, "2", true, true );
616         checkPrev( cursor, 1L, "1", true, false );
617     }
618 
619 
620     /**
621      * Test the browse methods on a btree containing nodes with duplicate values
622      */
623     @Test
624     public void testBrowseBTreeNodesNextDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
625     {
626         // Inject some data
627         for ( long i = 1; i < 1000L; i++ )
628         {
629             for ( long j = 1; j < 10; j++ )
630             {
631                 btree.insert( i, Long.toString( j ) );
632             }
633         }
634 
635         // Create the cursor
636         TupleCursor<Long, String> cursor = btree.browse();
637 
638         // Move backward
639         cursor.beforeFirst();
640 
641         assertFalse( cursor.hasPrev() );
642         assertTrue( cursor.hasNext() );
643         boolean next = true;
644         boolean prev = false;
645 
646         for ( long i = 1L; i < 1000L; i++ )
647         {
648             for ( long j = 1L; j < 10L; j++ )
649             {
650                 checkNext( cursor, i, Long.toString( j ), next, prev );
651 
652                 if ( ( i == 1L ) && ( j == 1L ) )
653                 {
654                     prev = true;
655                 }
656 
657                 if ( ( i == 999L ) && ( j == 8L ) )
658                 {
659                     next = false;
660                 }
661             }
662         }
663     }
664 
665 
666     /**
667      * Test the browse methods on a btree containing nodes with duplicate values
668      */
669     @Test
670     public void testBrowseBTreeNodesPrevDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
671     {
672         // Inject some data
673         for ( long i = 1; i < 1000L; i++ )
674         {
675             for ( int j = 1; j < 10; j++ )
676             {
677                 btree.insert( i, Long.toString( j ) );
678             }
679         }
680 
681         // Create the cursor
682         TupleCursor<Long, String> cursor = btree.browse();
683 
684         // Move backward
685         cursor.afterLast();
686 
687         assertTrue( cursor.hasPrev() );
688         assertFalse( cursor.hasNext() );
689         boolean next = false;
690         boolean prev = true;
691 
692         for ( long i = 999L; i > 0L; i-- )
693         {
694             for ( long j = 9L; j > 0L; j-- )
695             {
696                 checkPrev( cursor, i, Long.toString( j ), next, prev );
697 
698                 if ( ( i == 1L ) && ( j == 2L ) )
699                 {
700                     prev = false;
701                 }
702 
703                 if ( ( i == 999L ) && ( j == 9L ) )
704                 {
705                     next = true;
706                 }
707             }
708         }
709     }
710 
711 
712     /**
713      * Test the browse methods on a btree containing just a leaf with duplicate values
714      * stored into a sub btree
715      */
716     @Test
717     public void testBrowseBTreeLeafNextDupsSubBTree1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
718     {
719         // Inject some duplicate data which will be stored into a sub btree
720         for ( long i = 1L; i < 32L; i++ )
721         {
722             btree.insert( 1L, toString( i, 2 ) );
723         }
724 
725         // Create the cursor
726         TupleCursor<Long, String> cursor = btree.browse();
727 
728         // Move forward
729         cursor.beforeFirst();
730 
731         assertFalse( cursor.hasPrev() );
732         assertTrue( cursor.hasNext() );
733 
734         checkNext( cursor, 1L, "01", true, false );
735 
736         for ( long i = 2L; i < 31L; i++ )
737         {
738             checkNext( cursor, 1L, toString( i, 2 ), true, true );
739         }
740 
741         checkNext( cursor, 1L, "31", false, true );
742     }
743 
744 
745     /**
746      * Test the browse methods on a btree containing just a leaf with duplicate values
747      */
748     @Test
749     public void testBrowseBTreeLeafPrevDupsSubBTree1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
750     {
751         // Inject some duplicate data which will be stored into a sub btree
752         for ( long i = 1L; i < 32L; i++ )
753         {
754             btree.insert( 1L, toString( i, 2 ) );
755         }
756 
757         // Create the cursor
758         TupleCursor<Long, String> cursor = btree.browse();
759 
760         // Move backward
761         cursor.afterLast();
762 
763         assertTrue( cursor.hasPrev() );
764         assertFalse( cursor.hasNext() );
765 
766         checkPrev( cursor, 1L, "31", false, true );
767 
768         for ( long i = 30L; i > 1L; i-- )
769         {
770             checkPrev( cursor, 1L, toString( i, 2 ), true, true );
771         }
772 
773         checkPrev( cursor, 1L, "01", true, false );
774     }
775 
776 
777     //----------------------------------------------------------------------------------------
778     // The BrowseFrom tests
779     //----------------------------------------------------------------------------------------
780     /**
781      * Test the browseFrom method on an empty tree
782      */
783     @Test
784     public void testBrowseFromEmptyBTree() throws IOException, BTreeAlreadyManagedException
785     {
786         TupleCursor<Long, String> cursor = btree.browseFrom( 1L );
787 
788         assertFalse( cursor.hasNext() );
789         assertFalse( cursor.hasPrev() );
790 
791         try
792         {
793             cursor.next();
794             fail();
795         }
796         catch ( NoSuchElementException nsee )
797         {
798             // Expected
799         }
800 
801         try
802         {
803             cursor.prev();
804             fail();
805         }
806         catch ( NoSuchElementException nsee )
807         {
808             // Expected
809         }
810 
811         assertEquals( 0L, cursor.getRevision() );
812     }
813 
814 
815     /**
816      * Test the browseFrom methods on a btree containing just a leaf
817      */
818     @Test
819     public void testBrowseFromBTreeLeaf() throws IOException, BTreeAlreadyManagedException
820     {
821         // Inject some data
822         btree.insert( 1L, "1" );
823         btree.insert( 7L, "7" );
824         btree.insert( 3L, "3" );
825         btree.insert( 5L, "5" );
826         btree.insert( 9L, "9" );
827 
828         // Create the cursor, starting at 5
829         TupleCursor<Long, String> cursor = btree.browseFrom( 5L );
830 
831         assertTrue( cursor.hasPrev() );
832         assertTrue( cursor.hasNext() );
833 
834         // Move forward
835         checkNext( cursor, 5L, "5", true, true );
836         checkNext( cursor, 7L, "7", true, true );
837         checkNext( cursor, 9L, "9", false, true );
838 
839         cursor.close();
840 
841         // now, start at 5 and move backward
842         cursor = btree.browseFrom( 5L );
843 
844         assertTrue( cursor.hasPrev() );
845         assertTrue( cursor.hasNext() );
846 
847         // Move backward
848         checkPrev( cursor, 3L, "3", true, true );
849         checkPrev( cursor, 1L, "1", true, false );
850         cursor.close();
851 
852         // Start at the first key
853         cursor = btree.browseFrom( 1L );
854         assertFalse( cursor.hasPrev() );
855         assertTrue( cursor.hasNext() );
856 
857         checkNext( cursor, 1L, "1", true, false );
858         checkNext( cursor, 3L, "3", true, true );
859 
860         // Start before the first key
861         cursor = btree.browseFrom( 0L );
862         assertFalse( cursor.hasPrev() );
863         assertTrue( cursor.hasNext() );
864 
865         checkNext( cursor, 1L, "1", true, false );
866         checkNext( cursor, 3L, "3", true, true );
867 
868         // Start at the last key
869         cursor = btree.browseFrom( 9L );
870         assertTrue( cursor.hasPrev() );
871         assertTrue( cursor.hasNext() );
872 
873         checkNext( cursor, 9L, "9", false, true );
874         checkPrev( cursor, 7L, "7", true, true );
875 
876         // Start after the last key
877         cursor = btree.browseFrom( 10L );
878         assertTrue( cursor.hasPrev() );
879         assertFalse( cursor.hasNext() );
880 
881         checkPrev( cursor, 9L, "9", false, true );
882         checkPrev( cursor, 7L, "7", true, true );
883 
884         // Start in the middle with a non existent key
885         cursor = btree.browseFrom( 4L );
886         assertTrue( cursor.hasPrev() );
887         assertTrue( cursor.hasNext() );
888 
889         checkNext( cursor, 5L, "5", true, true );
890 
891         // Start in the middle with a non existent key
892         cursor = btree.browseFrom( 4L );
893 
894         checkPrev( cursor, 3L, "3", true, true );
895     }
896 
897 
898     /**
899      * Test the browseFrom method on a btree with a non existing key
900      */
901     @Test
902     public void testBrowseFromBTreeNodesNotExistingKey() throws IOException, BTreeAlreadyManagedException
903     {
904         // Inject some data
905         for ( long i = 0; i <= 1000L; i += 2 )
906         {
907             btree.insert( i, Long.toString( i ) );
908         }
909 
910         // Create the cursor
911         TupleCursor<Long, String> cursor = btree.browseFrom( 1500L );
912         
913         assertFalse( cursor.hasNext() );
914         assertTrue( cursor.hasPrev() );
915         assertEquals( 1000L, cursor.prev().getKey().longValue() );
916     }
917 
918 
919     /**
920      * Test the browseFrom method on a btree containing nodes with duplicate values
921      */
922     @Test
923     public void testBrowseFromBTreeNodesPrevDupsN() throws IOException, BTreeAlreadyManagedException
924     {
925         // Inject some data
926         for ( long i = 1; i < 1000L; i += 2 )
927         {
928             for ( int j = 1; j < 10; j++ )
929             {
930                 btree.insert( i, Long.toString( j ) );
931             }
932         }
933 
934         // Create the cursor
935         TupleCursor<Long, String> cursor = btree.browseFrom( 500L );
936 
937         // Move forward
938 
939         assertTrue( cursor.hasPrev() );
940         assertTrue( cursor.hasNext() );
941         boolean next = true;
942         boolean prev = true;
943 
944         for ( long i = 501L; i < 1000L; i += 2 )
945         {
946             for ( long j = 1L; j < 10L; j++ )
947             {
948                 if ( ( i == 999L ) && ( j == 9L ) )
949                 {
950                     next = false;
951                 }
952 
953                 checkNext( cursor, i, Long.toString( j ), next, prev );
954             }
955         }
956     }
957 
958 
959     //----------------------------------------------------------------------------------------
960     // The TupleCursor.moveToNext/PrevNonDuplicateKey method tests
961     //----------------------------------------------------------------------------------------
962     /**
963       * Test the TupleCursor.nextKey method on a btree containing nodes
964       * with duplicate values.
965       */
966     @Test
967     public void testNextKey() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
968     {
969         // Inject some data
970         for ( long i = 1; i < 1000L; i++ )
971         {
972             for ( long j = 1; j < 10; j++ )
973             {
974                 btree.insert( i, Long.toString( j ) );
975             }
976         }
977 
978         // Create the cursor
979         TupleCursor<Long, String> cursor = btree.browse();
980 
981         // Move forward
982         cursor.beforeFirst();
983 
984         assertFalse( cursor.hasPrev() );
985         assertTrue( cursor.hasNext() );
986         boolean next = true;
987         boolean prev = false;
988 
989         for ( long i = 1L; i < 999L; i++ )
990         {
991             Tuple<Long, String> tuple = cursor.nextKey();
992 
993             checkTuple( tuple, i, "1" );
994 
995             if ( i == 999L )
996             {
997                 next = false;
998             }
999 
1000             assertEquals( next, cursor.hasNext() );
1001             assertEquals( prev, cursor.hasPrev() );
1002 
1003             if ( i == 1L )
1004             {
1005                 prev = true;
1006             }
1007         }
1008     }
1009 
1010     
1011     /**
1012      * Test the TupleCursor.nextKey method on a btree containing nodes
1013      * with duplicate values.
1014      */
1015    @Test
1016    @Ignore
1017    public void testNextKeyDups() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
1018    {
1019        // Inject some data
1020        //for ( long i = 1; i < 3; i++ )
1021        {
1022            for ( long j = 1; j < 9; j++ )
1023            {
1024                btree.insert( 1L, Long.toString( j ) );
1025            }
1026        }
1027 
1028        btree.insert( 1L, "10" );
1029 
1030        // Create the cursor
1031        TupleCursor<Long, String> cursor = btree.browse();
1032 
1033        // Move forward
1034        cursor.beforeFirst();
1035 
1036        assertFalse( cursor.hasPrevKey() );
1037        assertTrue( cursor.hasNextKey() );
1038 
1039        Tuple<Long, String> tuple = cursor.nextKey();
1040 
1041        checkTuple( tuple, 1L, "1" );
1042        
1043        cursor.beforeFirst();
1044        long val = 1L;
1045        
1046        while ( cursor.hasNext() )
1047        {
1048            tuple = cursor.next();
1049            
1050            assertEquals( Long.valueOf( 1L ), tuple.getKey() );
1051            assertEquals( Long.toString( val ), tuple.getValue() );
1052            
1053            val++;
1054        }
1055        
1056        assertFalse( cursor.hasNextKey() );
1057        assertFalse( cursor.hasPrevKey() );
1058    }
1059 
1060 
1061     /**
1062      * Test the TupleCursor.moveToPrevNonDuplicateKey method on a btree containing nodes
1063      * with duplicate values.
1064      */
1065     @Test
1066     public void testPrevKey() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
1067     {
1068         // Inject some data
1069         for ( long i = 1; i < 1000L; i++ )
1070         {
1071             for ( long j = 1; j < 10; j++ )
1072             {
1073                 btree.insert( i, Long.toString( j ) );
1074             }
1075         }
1076 
1077         // Create the cursor
1078         TupleCursor<Long, String> cursor = btree.browse();
1079 
1080         // Move backward
1081         cursor.afterLast();
1082 
1083         assertTrue( cursor.hasPrev() );
1084         assertFalse( cursor.hasNext() );
1085         boolean next = true;
1086         boolean prev = true;
1087 
1088         for ( long i = 999L; i > 0L; i-- )
1089         {
1090             Tuple<Long, String> tuple = cursor.prevKey();
1091 
1092             if ( i == 1L )
1093             {
1094                 prev = false;
1095             }
1096 
1097             checkTuple( tuple, i, "1" );
1098             assertEquals( next, cursor.hasNext() );
1099             assertEquals( prev, cursor.hasPrev() );
1100 
1101             if ( i == 999L )
1102             {
1103                 next = true;
1104             }
1105         }
1106     }
1107     
1108     
1109     /*
1110     @Test
1111     public void testAdd20Random() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
1112     {
1113         long [] values = new long[]
1114             { 
1115                 14,  7, 43, 37, 49,  3, 20, 26, 17, 29, 
1116                 40, 33, 21, 18,  9, 30, 45, 36, 12,  8
1117             };
1118     
1119         // Inject some data
1120         for ( long value : values )
1121         {
1122             btree.insert( value, Long.toString( value ) );
1123             System.out.println( btree );
1124         }
1125 
1126 
1127         BTree copiedPagesBtree = recordManager1.copiedPageBtree;
1128         
1129         System.out.println( copiedPagesBtree );
1130         
1131         TupleCursor<Long, String> cursor = btree.browse();
1132         
1133         while ( cursor.hasNext() )
1134         {
1135             System.out.println( cursor.nextKey() );
1136         }
1137     }
1138     */
1139 }