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