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