1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.assertNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29
30 import java.io.File;
31 import java.io.IOException;
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.DuplicateValueNotAllowedException;
38 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
39 import org.apache.directory.mavibot.btree.serializer.IntSerializer;
40 import org.apache.directory.mavibot.btree.serializer.LongSerializer;
41 import org.apache.directory.mavibot.btree.serializer.StringSerializer;
42 import org.junit.After;
43 import org.junit.Before;
44 import org.junit.Ignore;
45 import org.junit.Rule;
46 import org.junit.Test;
47 import org.junit.rules.TemporaryFolder;
48
49
50
51
52
53
54
55 public class PersistedBTreeDuplicateKeyTest
56 {
57 private BTree<Long, String> btree = null;
58
59 private RecordManager recordManager1 = null;
60
61 @Rule
62 public TemporaryFolder tempFolder = new TemporaryFolder();
63
64 private File dataDir = null;
65
66
67 @Before
68 public void createBTree() throws IOException
69 {
70 dataDir = tempFolder.newFolder( UUID.randomUUID().toString() );
71
72 openRecordManagerAndBtree();
73
74 try
75 {
76
77 btree = recordManager1.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE,
78 BTree.ALLOW_DUPLICATES );
79 }
80 catch ( Exception e )
81 {
82 throw new RuntimeException( e );
83 }
84 }
85
86
87 @After
88 public void cleanup() throws IOException
89 {
90 dataDir = new File( System.getProperty( "java.io.tmpdir" ) + "/recordman" );
91
92 btree.close();
93
94 if ( dataDir.exists() )
95 {
96 FileUtils.deleteDirectory( dataDir );
97 }
98
99 recordManager1.close();
100 assertTrue( recordManager1.isContextOk() );
101 }
102
103
104 private void openRecordManagerAndBtree()
105 {
106 try
107 {
108 if ( recordManager1 != null )
109 {
110 recordManager1.close();
111 }
112
113
114 recordManager1 = new RecordManager( dataDir.getAbsolutePath() );
115
116
117 if ( btree != null )
118 {
119 btree = recordManager1.getManagedTree( btree.getName() );
120 }
121 }
122 catch ( Exception e )
123 {
124 throw new RuntimeException( e );
125 }
126 }
127
128
129 @Test
130 public void testInsertNullValue() throws IOException, KeyNotFoundException
131 {
132 btree.insert( 1L, null );
133
134 TupleCursor<Long, String> cursor = btree.browse();
135 assertTrue( cursor.hasNext() );
136
137 Tuple<Long, String> t = cursor.next();
138
139 assertEquals( Long.valueOf( 1 ), t.getKey() );
140 assertEquals( null, t.getValue() );
141
142 cursor.close();
143
144 btree.close();
145 }
146
147
148 @Test
149 public void testBrowseEmptyTree() throws IOException, KeyNotFoundException, BTreeAlreadyManagedException
150 {
151 IntSerializer serializer = IntSerializer.INSTANCE;
152
153 BTree<Integer, Integer> btree = BTreeFactory.createPersistedBTree( "master", serializer, serializer );
154
155
156 recordManager1.manage( btree );
157
158 TupleCursor<Integer, Integer> cursor = btree.browse();
159 assertFalse( cursor.hasNext() );
160 assertFalse( cursor.hasPrev() );
161
162 try
163 {
164 cursor.next();
165 fail( "Should not reach here" );
166 }
167 catch ( NoSuchElementException e )
168 {
169 assertTrue( true );
170 }
171
172 try
173 {
174 cursor.prev();
175 fail( "Should not reach here" );
176 }
177 catch ( NoSuchElementException e )
178 {
179 assertTrue( true );
180 }
181
182 cursor.close();
183 btree.close();
184 }
185
186
187 @Test
188 public void testDuplicateKey() throws IOException, KeyNotFoundException
189 {
190 btree.insert( 1L, "1" );
191 btree.insert( 1L, "2" );
192
193 TupleCursor<Long, String> cursor = btree.browse();
194 assertTrue( cursor.hasNext() );
195
196 Tuple<Long, String> t = cursor.next();
197
198 assertEquals( Long.valueOf( 1 ), t.getKey() );
199 assertEquals( "1", t.getValue() );
200
201 assertTrue( cursor.hasNext() );
202
203 t = cursor.next();
204
205 assertEquals( Long.valueOf( 1 ), t.getKey() );
206 assertEquals( "2", t.getValue() );
207
208 assertFalse( cursor.hasNext() );
209
210
211 assertTrue( cursor.hasPrev() );
212
213 t = cursor.prev();
214
215 assertEquals( Long.valueOf( 1 ), t.getKey() );
216 assertEquals( "1", t.getValue() );
217
218 assertFalse( cursor.hasPrev() );
219
220
221 assertTrue( cursor.hasNext() );
222
223 t = cursor.next();
224
225 assertEquals( Long.valueOf( 1 ), t.getKey() );
226 assertEquals( "2", t.getValue() );
227
228 assertFalse( cursor.hasNext() );
229
230 cursor.close();
231 btree.close();
232 }
233
234
235 @Test
236 public void testGetDuplicateKey() throws Exception
237 {
238 String retVal = btree.insert( 1L, "1" );
239 assertNull( retVal );
240
241 retVal = btree.insert( 1L, "2" );
242 assertNull( retVal );
243
244
245 retVal = btree.insert( 1L, "2" );
246 assertEquals( "2", retVal );
247
248 assertEquals( "1", btree.get( 1L ) );
249 assertTrue( btree.contains( 1L, "1" ) );
250 assertTrue( btree.contains( 1L, "2" ) );
251
252 assertFalse( btree.contains( 1L, "0" ) );
253 assertFalse( btree.contains( 0L, "1" ) );
254 assertFalse( btree.contains( 0L, "0" ) );
255 assertFalse( btree.contains( null, "0" ) );
256 assertFalse( btree.contains( 0L, null ) );
257 assertFalse( btree.contains( null, null ) );
258 btree.close();
259 }
260
261
262 @Test
263 public void testRemoveDuplicateKey() throws Exception
264 {
265 btree.insert( 1L, "1" );
266 btree.insert( 1L, "2" );
267
268 assertEquals( 2, btree.getNbElems() );
269
270 Tuple<Long, String> t = btree.delete( 1L, "1" );
271 assertEquals( Long.valueOf( 1 ), t.getKey() );
272 assertEquals( "1", t.getValue() );
273
274 assertEquals( 1l, btree.getNbElems() );
275
276 t = btree.delete( 1L, "2" );
277 assertEquals( Long.valueOf( 1 ), t.getKey() );
278 assertEquals( "2", t.getValue() );
279
280 assertEquals( 0l, btree.getNbElems() );
281
282 t = btree.delete( 1L, "2" );
283 assertNull( t );
284 btree.close();
285 }
286
287
288 @Test
289 public void testFullPage() throws Exception
290 {
291 int i = 7;
292 for ( char ch = 'a'; ch <= 'z'; ch++ )
293 {
294 for ( int k = 0; k < i; k++ )
295 {
296 String val = ch + Integer.toString( k );
297 btree.insert( Long.valueOf( ch ), val );
298 }
299 }
300
301 TupleCursor<Long, String> cursor = btree.browse();
302
303 char ch = 'a';
304 int k = 0;
305
306 while ( cursor.hasNext() )
307 {
308 Tuple<Long, String> t = cursor.next();
309 assertEquals( Long.valueOf( ch ), t.getKey() );
310 k++;
311
312 if ( ( k % i ) == 0 )
313 {
314 ch++;
315 }
316 }
317
318 assertEquals( ( 'z' + 1 ), ch );
319
320 ch = 'z';
321 cursor.afterLast();
322
323 while ( cursor.hasPrev() )
324 {
325 Tuple<Long, String> t = cursor.prev();
326 assertEquals( Long.valueOf( ch ), t.getKey() );
327 k--;
328
329 if ( ( k % i ) == 0 )
330 {
331 ch--;
332 }
333 }
334
335 assertEquals( ( 'a' - 1 ), ch );
336 cursor.close();
337 }
338
339
340 @Test
341 public void testMoveFirst() throws Exception
342 {
343 for ( char ch = 'a'; ch <= 'z'; ch++ )
344 {
345 String val = Character.toString( ch );
346 btree.insert( Long.valueOf( ch ), val );
347 }
348
349 assertEquals( 26, btree.getNbElems() );
350
351
352 btree.insert( Long.valueOf( 'a' ), "val" );
353
354 assertEquals( 27, btree.getNbElems() );
355
356
357 TupleCursor<Long, String> cursor = btree.browseFrom( Long.valueOf( 'c' ) );
358
359 int i = 0;
360
361 while ( cursor.hasNext() )
362 {
363 Tuple<Long, String> tuple = cursor.next();
364 assertNotNull( tuple );
365 i++;
366 }
367
368 assertEquals( 24, i );
369
370
371 cursor.beforeFirst();
372 assertTrue( cursor.hasNext() );
373 Tuple<Long, String> tuple = cursor.next();
374
375
376 assertEquals( Long.valueOf( 'a' ), tuple.getKey() );
377
378
379 i = 0;
380
381 while ( cursor.hasNext() )
382 {
383 tuple = cursor.next();
384 assertNotNull( tuple );
385 i++;
386 }
387
388 assertEquals( 26, i );
389
390 cursor.close();
391
392
393 cursor = btree.browse();
394
395 i = 0;
396
397 while ( cursor.hasNext() )
398 {
399 assertNotNull( cursor.next() );
400 i++;
401 }
402
403
404 assertEquals( 27, i );
405
406
407 cursor.beforeFirst();
408 assertTrue( cursor.hasNextKey() );
409 assertEquals( Long.valueOf( 'a' ), cursor.nextKey().getKey() );
410
411 i = 0;
412
413 while ( cursor.hasNextKey() )
414 {
415 tuple = cursor.nextKey();
416 long key = tuple.getKey();
417 assertNotNull( key );
418 i++;
419 }
420
421
422 assertEquals( 25, i );
423 }
424
425
426 @Test
427 public void testMoveLast() throws Exception
428 {
429 for ( char ch = 'a'; ch <= 'z'; ch++ )
430 {
431 String val = Character.toString( ch );
432 btree.insert( Long.valueOf( ch ), val );
433 }
434
435 assertEquals( 26, btree.getNbElems() );
436
437
438 btree.insert( Long.valueOf( 'z' ), "val" );
439
440 assertEquals( 27, btree.getNbElems() );
441
442
443 TupleCursor<Long, String> cursor = btree.browseFrom( Long.valueOf( 'x' ) );
444
445 int i = 0;
446
447 while ( cursor.hasPrev() )
448 {
449 Tuple<Long, String> tuple = cursor.prev();
450 assertNotNull( tuple );
451 i++;
452 }
453
454 assertEquals( 23, i );
455
456
457 cursor.afterLast();
458 assertTrue( cursor.hasPrev() );
459 Tuple<Long, String> tuple = cursor.prev();
460
461
462 assertEquals( Long.valueOf( 'z' ), tuple.getKey() );
463
464
465 i = 0;
466
467 while ( cursor.hasPrev() )
468 {
469 tuple = cursor.prev();
470 assertNotNull( tuple );
471 i++;
472 }
473
474 assertEquals( 26, i );
475
476 cursor.close();
477
478
479 cursor = btree.browse();
480 cursor.afterLast();
481
482 i = 0;
483
484 while ( cursor.hasPrev() )
485 {
486 assertNotNull( cursor.prev() );
487 i++;
488 }
489
490
491 assertEquals( 27, i );
492
493
494 cursor.afterLast();
495 assertTrue( cursor.hasPrevKey() );
496 assertEquals( Long.valueOf( 'z' ), cursor.prevKey().getKey() );
497
498 i = 0;
499
500 while ( cursor.hasPrevKey() )
501 {
502 tuple = cursor.prevKey();
503 long key = tuple.getKey();
504 assertNotNull( key );
505 i++;
506 }
507
508
509 assertEquals( 25, i );
510 }
511
512
513 @Test(expected = NoSuchElementException.class)
514 public void testMoveLast2() throws Exception
515 {
516 for ( char ch = 'a'; ch <= 'z'; ch++ )
517 {
518 btree.insert( Long.valueOf( ch ), UUID.randomUUID().toString() );
519 }
520
521 btree.insert( Long.valueOf( 'z' ), UUID.randomUUID().toString() );
522
523 TupleCursor<Long, String> cursor = btree.browseFrom( Long.valueOf( 'c' ) );
524 cursor.afterLast();
525
526 assertFalse( cursor.hasNext() );
527 assertTrue( cursor.hasPrev() );
528 assertEquals( Long.valueOf( 'z' ), cursor.prev().getKey() );
529
530 assertEquals( Long.valueOf( 'z' ), cursor.prev().getKey() );
531 assertEquals( Long.valueOf( 'y' ), cursor.prev().getKey() );
532
533 cursor.beforeFirst();
534 assertEquals( Long.valueOf( 'a' ), cursor.next().getKey() );
535
536 cursor.afterLast();
537 assertFalse( cursor.hasNext() );
538
539 cursor.next();
540 }
541
542
543 @Test(expected = NoSuchElementException.class)
544 public void testNextPrevKey() throws Exception
545 {
546 int i = 7;
547
548
549 for ( char ch = 'a'; ch <= 'z'; ch++ )
550 {
551 for ( int k = 0; k < i; k++ )
552 {
553 btree.insert( Long.valueOf( ch ), String.valueOf( k ) );
554 }
555 }
556
557 TupleCursor<Long, String> cursor = btree.browse();
558
559 assertTrue( cursor.hasNext() );
560 assertFalse( cursor.hasPrev() );
561
562 for ( int k = 0; k < 2; k++ )
563 {
564 assertEquals( Long.valueOf( 'a' ), cursor.next().getKey() );
565 }
566
567 assertEquals( Long.valueOf( 'a' ), cursor.next().getKey() );
568
569 Tuple<Long, String> tuple = cursor.nextKey();
570
571 assertEquals( Long.valueOf( 'b' ), tuple.getKey() );
572
573 for ( char ch = 'b'; ch < 'z'; ch++ )
574 {
575 assertEquals( Long.valueOf( ch ), cursor.next().getKey() );
576 tuple = cursor.nextKey();
577 char t = ch;
578 assertEquals( Long.valueOf( ++t ), tuple.getKey() );
579 }
580
581 for ( int k = 0; k < i; k++ )
582 {
583 assertEquals( Long.valueOf( 'z' ), cursor.next().getKey() );
584 }
585
586 assertFalse( cursor.hasNextKey() );
587 assertTrue( cursor.hasPrevKey() );
588 tuple = cursor.prev();
589 assertEquals( Long.valueOf( 'z' ), tuple.getKey() );
590 assertEquals( "6", tuple.getValue() );
591
592 for ( char ch = 'z'; ch > 'a'; ch-- )
593 {
594 char t = ch;
595 t--;
596
597 assertEquals( Long.valueOf( ch ), cursor.prev().getKey() );
598
599 tuple = cursor.prevKey();
600
601 assertEquals( Long.valueOf( t ), tuple.getKey() );
602 }
603
604 for ( int k = 5; k >= 0; k-- )
605 {
606 tuple = cursor.prev();
607 assertEquals( Long.valueOf( 'a' ), tuple.getKey() );
608 assertEquals( String.valueOf( k ), tuple.getValue() );
609 }
610
611 assertTrue( cursor.hasNext() );
612 assertFalse( cursor.hasPrev() );
613 tuple = cursor.next();
614 assertEquals( Long.valueOf( 'a' ), tuple.getKey() );
615 assertEquals( "0", tuple.getValue() );
616
617 cursor.close();
618
619 cursor = btree.browseFrom( Long.valueOf( 'y' ) );
620 tuple = cursor.prevKey();
621 assertNotNull( tuple );
622 assertEquals( Long.valueOf( 'y' ), tuple.getKey() );
623 assertEquals( "6", tuple.getValue() );
624 cursor.close();
625
626 cursor = btree.browse();
627 cursor.beforeFirst();
628 assertFalse( cursor.hasPrev() );
629
630 cursor.prev();
631 }
632
633
634
635
636
637
638
639
640 @Test
641 public void testMoveToNextAndPrevWithPageBoundaries() throws Exception
642 {
643 int i = 32;
644 for ( int k = 0; k < i; k++ )
645 {
646 btree.insert( ( long ) k, Long.toString( k ) );
647 }
648
649
650
651 TupleCursor<Long, String> cursor = btree.browseFrom( 15L );
652 Tuple<Long, String> tuple = cursor.nextKey();
653
654 assertNotNull( tuple );
655 assertEquals( Long.valueOf( 16 ), tuple.getKey() );
656 assertEquals( "16", tuple.getValue() );
657 cursor.close();
658
659
660 cursor = btree.browseFrom( 16L );
661 tuple = cursor.prevKey();
662
663 assertNotNull( tuple );
664 assertEquals( Long.valueOf( 15 ), tuple.getKey() );
665 assertEquals( "15", tuple.getValue() );
666 cursor.close();
667
668
669 cursor = btree.browseFrom( 16L );
670 tuple = cursor.prevKey();
671
672 assertNotNull( tuple );
673 assertEquals( Long.valueOf( 15 ), tuple.getKey() );
674 assertEquals( "15", tuple.getValue() );
675
676
677 assertTrue( cursor.hasNext() );
678 tuple = cursor.next();
679 assertEquals( Long.valueOf( 16 ), tuple.getKey() );
680 assertEquals( "16", tuple.getValue() );
681 cursor.close();
682
683
684 cursor = btree.browseFrom( 30L );
685 tuple = cursor.nextKey();
686 assertFalse( cursor.hasNext() );
687 assertTrue( cursor.hasPrev() );
688
689 assertEquals( Long.valueOf( 31 ), tuple.getKey() );
690 assertEquals( "31", tuple.getValue() );
691 cursor.close();
692
693 cursor = btree.browse();
694 assertTrue( cursor.hasNext() );
695 assertFalse( cursor.hasPrev() );
696
697 tuple = cursor.nextKey();
698 assertEquals( Long.valueOf( 0 ), tuple.getKey() );
699 assertEquals( "0", tuple.getValue() );
700 cursor.close();
701 }
702
703
704 @Test
705 public void testNextAfterPrev() throws Exception
706 {
707 int i = 32;
708
709 for ( int k = 0; k < i; k++ )
710 {
711 btree.insert( ( long ) k, String.valueOf( k ) );
712 }
713
714
715 TupleCursor<Long, String> cursor = btree.browseFrom( 16L );
716
717 assertTrue( cursor.hasNext() );
718 Tuple<Long, String> tuple = cursor.next();
719 assertEquals( Long.valueOf( 16 ), tuple.getKey() );
720 assertEquals( "16", tuple.getValue() );
721
722 assertTrue( cursor.hasPrev() );
723 tuple = cursor.prev();
724 assertEquals( Long.valueOf( 15 ), tuple.getKey() );
725 assertEquals( "15", tuple.getValue() );
726
727 assertTrue( cursor.hasNext() );
728 tuple = cursor.next();
729 assertEquals( Long.valueOf( 16 ), tuple.getKey() );
730 assertEquals( "16", tuple.getValue() );
731 cursor.close();
732
733 }
734
735
736
737
738
739
740
741 @Test
742 public void testMoveToNextAndTraverseBackward() throws Exception
743 {
744 int i = 5;
745
746 for ( int k = 0; k < i; k++ )
747 {
748 btree.insert( ( long ) k, Long.toString( k ) );
749 }
750
751
752 TupleCursor<Long, String> cursor = btree.browseFrom( 4L );
753 cursor.nextKey();
754
755 long currentKey = 4L;
756
757 while ( cursor.hasPrev() )
758 {
759 assertEquals( Long.valueOf( currentKey ), cursor.prev().getKey() );
760 currentKey--;
761 }
762
763 cursor.close();
764 }
765
766
767
768
769
770
771
772 @Test
773 public void testMoveToPrevAndTraverseForward() throws Exception
774 {
775 int i = 5;
776
777 for ( int k = 0; k < i; k++ )
778 {
779 btree.insert( ( long ) k, Long.toString( k ) );
780 }
781
782
783 TupleCursor<Long, String> cursor = btree.browseFrom( 0L );
784
785 long currentKey = 0L;
786
787 while ( cursor.hasNext() )
788 {
789 assertEquals( Long.valueOf( currentKey ), cursor.next().getKey() );
790 currentKey++;
791 }
792
793 cursor.close();
794 }
795
796
797 @Test
798 public void testFindLeftAndRightMosetInSubBTree() throws Exception
799 {
800 PersistedBTreeConfiguration<Integer, Integer> config = new PersistedBTreeConfiguration<Integer, Integer>();
801
802 config.setName( "test" );
803 config.setKeySerializer( IntSerializer.INSTANCE );
804 config.setValueSerializer( IntSerializer.INSTANCE );
805 config.setAllowDuplicates( false );
806 config.setBtreeType( BTreeTypeEnum.PERSISTED_SUB );
807
808 PersistedBTree<Integer, Integer> subBtree = new PersistedBTree<Integer, Integer>( config );
809
810 subBtree.setRecordManager( recordManager1 );
811
812 subBtree.insert( 1, 1 );
813 subBtree.insert( 2, 2 );
814 subBtree.insert( 3, 3 );
815 subBtree.insert( 4, 4 );
816 subBtree.insert( 5, 5 );
817
818 Tuple<Integer, Integer> t = subBtree.getRootPage().findLeftMost();
819 assertEquals( Integer.valueOf( 1 ), t.getKey() );
820
821 t = subBtree.getRootPage().findRightMost();
822 assertEquals( Integer.valueOf( 5 ), t.getKey() );
823 }
824
825
826
827
828 @Test(expected = DuplicateValueNotAllowedException.class)
829 @Ignore("this condition is removed")
830 public void testBTreeForbidDups() throws IOException, BTreeAlreadyManagedException
831 {
832 BTree<Long, String> singleValueBtree = recordManager1.addBTree( "test2", LongSerializer.INSTANCE,
833 StringSerializer.INSTANCE, BTree.FORBID_DUPLICATES );
834
835 for ( long i = 0; i < 64; i++ )
836 {
837 singleValueBtree.insert( i, Long.toString( i ) );
838 }
839
840 try
841 {
842 singleValueBtree.insert( 18L, "Duplicate" );
843 fail();
844 }
845 finally
846 {
847 singleValueBtree.close();
848 }
849 }
850 }