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