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