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.apache.directory.mavibot.btree.InternalUtil.setDupsContainer;
24
25 import java.io.IOException;
26 import java.lang.reflect.Array;
27 import java.util.LinkedList;
28
29 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
30 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
31
32
33
34
35
36
37
38
39
40
41
42 {
43
44 protected ElementHolder<V, K, V>[] values;
45
46
47
48
49
50
51
52
53 {
54 super( btree );
55 }
56
57
58
59
60
61
62
63
64
65 @SuppressWarnings("unchecked")
66
67
68 {
69 super( btree, revision, nbElems );
70
71 if ( btree.isAllowDuplicates() )
72 {
73 this.values = ( DuplicateKeyMemoryHolder<K, V>[] ) Array.newInstance( DuplicateKeyMemoryHolder.class,
74 nbElems );
75 }
76 else
77 {
78 this.values = ( MemoryHolder<K, V>[] ) Array.newInstance( MemoryHolder.class, nbElems );
79 }
80 }
81
82
83
84
85
86 public InsertResult<K, V> insert( long revision, K key, V value ) throws IOException
87 {
88
89 int pos = findPos( key );
90
91 if ( pos < 0 )
92 {
93
94
95 int index = -( pos + 1 );
96
97
98 InsertResult<K, V> result = replaceElement( revision, key, value, index );
99
100 return result;
101 }
102
103
104 if ( nbElems < btree.getPageSize() )
105 {
106
107
108 Page<K, V> modifiedPage = addElement( revision, key, value, pos );
109
110 InsertResult<K, V> result = new ModifyResult<K, V>( modifiedPage, null );
111 result.addCopiedPage( this );
112
113 return result;
114 }
115 else
116 {
117
118
119 InsertResult<K, V> result = addAndSplit( revision, key, value, pos );
120 result.addCopiedPage( this );
121
122 return result;
123 }
124 }
125
126
127
128
129
130 @SuppressWarnings("unchecked")
131 public DeleteResult<K, V> delete( long revision, K key, V value, Page<K, V> parent, int parentPos )
132 throws IOException
133 {
134
135 if ( nbElems == 0 )
136 {
137
138 return NotPresentResult.NOT_PRESENT;
139 }
140
141
142 int pos = findPos( key );
143
144 if ( pos >= 0 )
145 {
146
147 return NotPresentResult.NOT_PRESENT;
148 }
149
150
151 Tuple<K, V> removedElement = null;
152
153
154 boolean keyRemoved = false;
155
156 int index = -( pos + 1 );
157
158 if ( btree.isAllowDuplicates() )
159 {
160 BTree<V, V> dups = ( BTree<V, V> ) values[index].getValue( btree );
161
162 if ( dups.hasKey( value ) )
163 {
164 dups.delete( value );
165
166 if ( dups.getNbElems() == 0 )
167 {
168 keyRemoved = true;
169 }
170
171 removedElement = new Tuple<K, V>( keys[index], value );
172 }
173 else if ( value == null )
174 {
175 removedElement = new Tuple<K, V>( keys[index], ( V ) dups );
176 keyRemoved = true;
177 }
178 else
179
180 {
181 return NotPresentResult.NOT_PRESENT;
182 }
183 }
184 else
185 {
186 V existing = values[index].getValue( btree );
187
188 if ( ( ( existing == null ) && ( value == null ) ) || ( value == null ) )
189 {
190 removedElement = new Tuple<K, V>( keys[index], existing );
191 keyRemoved = true;
192 }
193 else if ( btree.getValueSerializer().compare( value, existing ) == 0 )
194 {
195 removedElement = new Tuple<K, V>( keys[index], value );
196 keyRemoved = true;
197 }
198 else
199 {
200 return NotPresentResult.NOT_PRESENT;
201 }
202 }
203
204 Leaf<K, V> newLeaf = null;
205
206 if ( keyRemoved )
207 {
208 newLeaf = new Leaf<K, V>( btree, revision, nbElems - 1 );
209 }
210 else
211 {
212 newLeaf = new Leaf<K, V>( btree, revision, nbElems );
213 }
214
215
216 DeleteResult<K, V> defaultResult = new RemoveResult<K, V>( newLeaf, removedElement );
217
218
219 if ( parent == null )
220 {
221
222 copyAfterRemovingElement( keyRemoved, newLeaf, index );
223
224
225 defaultResult.addCopiedPage( this );
226
227 return defaultResult;
228 }
229 else if ( keyRemoved )
230 {
231
232
233 int halfSize = btree.getPageSize() / 2;
234
235 if ( nbElems == halfSize )
236 {
237
238
239
240
241 int siblingPos = selectSibling( ( Node<K, V> ) parent, parentPos );
242 Leaf<K, V> sibling = ( Leaf<K, V> ) ( ( ( Node<K, V> ) parent ).children[siblingPos].getValue( btree ) );
243
244 if ( sibling.getNbElems() == halfSize )
245 {
246
247 DeleteResult<K, V> result = mergeWithSibling( removedElement, revision, sibling,
248 ( siblingPos < parentPos ), index );
249
250 return result;
251 }
252 else
253 {
254
255 if ( siblingPos < parentPos )
256 {
257 DeleteResult<K, V> result = borrowFromLeft( removedElement, revision, sibling, index );
258
259 return result;
260 }
261 else
262 {
263
264 DeleteResult<K, V> result = borrowFromRight( removedElement, revision, sibling, index );
265
266 return result;
267 }
268 }
269 }
270 else
271 {
272
273
274
275
276 copyAfterRemovingElement( keyRemoved, newLeaf, index );
277
278
279 defaultResult.addCopiedPage( this );
280
281 return defaultResult;
282 }
283 }
284 else
285 {
286
287
288 System.arraycopy( keys, 0, newLeaf.keys, 0, nbElems );
289 System.arraycopy( values, 0, newLeaf.values, 0, nbElems );
290
291
292 defaultResult.addCopiedPage( this );
293
294 return defaultResult;
295 }
296 }
297
298
299
300
301
302
303
304
305
306
307
308
309 private DeleteResult<K, V> mergeWithSibling( Tuple<K, V> removedElement, long revision, Leaf<K, V> sibling,
310 boolean isLeft, int pos )
311 throws EndOfFileExceededException, IOException
312 {
313
314
315 Leaf<K, V> newLeaf = new Leaf<K, V>( btree, revision, btree.getPageSize() - 1 );
316
317 if ( isLeft )
318 {
319
320
321 System.arraycopy( sibling.keys, 0, newLeaf.keys, 0, sibling.nbElems );
322 System.arraycopy( sibling.values, 0, newLeaf.values, 0, sibling.nbElems );
323
324
325 System.arraycopy( keys, 0, newLeaf.keys, sibling.nbElems, pos );
326 System.arraycopy( values, 0, newLeaf.values, sibling.nbElems, pos );
327
328
329 System.arraycopy( keys, pos + 1, newLeaf.keys, sibling.nbElems + pos, nbElems - pos - 1 );
330 System.arraycopy( values, pos + 1, newLeaf.values, sibling.nbElems + pos, nbElems - pos - 1 );
331 }
332 else
333 {
334
335
336 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
337 System.arraycopy( values, 0, newLeaf.values, 0, pos );
338
339
340 System.arraycopy( keys, pos + 1, newLeaf.keys, pos, nbElems - pos - 1 );
341 System.arraycopy( values, pos + 1, newLeaf.values, pos, nbElems - pos - 1 );
342
343
344 System.arraycopy( sibling.keys, 0, newLeaf.keys, nbElems - 1, sibling.nbElems );
345 System.arraycopy( sibling.values, 0, newLeaf.values, nbElems - 1, sibling.nbElems );
346 }
347
348
349 DeleteResult<K, V> result = new MergedWithSiblingResult<K, V>( newLeaf,
350 removedElement );
351
352 result.addCopiedPage( this );
353 result.addCopiedPage( sibling );
354
355 return result;
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370 private DeleteResult<K, V> borrowFromLeft( Tuple<K, V> removedElement, long revision, Leaf<K, V> sibling, int pos )
371 throws IOException
372 {
373
374 K siblingKey = sibling.keys[sibling.getNbElems() - 1];
375 ElementHolder<V, K, V> siblingValue = sibling.values[sibling.getNbElems() - 1];
376
377
378 Leaf<K, V> newSibling = ( Leaf<K, V> ) sibling.copy( revision, sibling.getNbElems() - 1 );
379
380
381
382 Leaf<K, V> newLeaf = new Leaf<K, V>( btree, revision, nbElems );
383
384
385 newLeaf.keys[0] = siblingKey;
386 newLeaf.values[0] = siblingValue;
387
388
389 System.arraycopy( keys, 0, newLeaf.keys, 1, pos );
390 System.arraycopy( values, 0, newLeaf.values, 1, pos );
391
392
393 System.arraycopy( keys, pos + 1, newLeaf.keys, pos + 1, keys.length - pos - 1 );
394 System.arraycopy( values, pos + 1, newLeaf.values, pos + 1, values.length - pos - 1 );
395
396 DeleteResult<K, V> result = new BorrowedFromLeftResult<K, V>( newLeaf, newSibling, removedElement );
397
398
399 result.addCopiedPage( this );
400 result.addCopiedPage( sibling );
401
402 return result;
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416
417 private DeleteResult<K, V> borrowFromRight( Tuple<K, V> removedElement, long revision, Leaf<K, V> sibling, int pos )
418 throws IOException
419 {
420
421 K siblingKey = sibling.keys[0];
422 ElementHolder<V, K, V> siblingHolder = sibling.values[0];
423
424
425 Leaf<K, V> newSibling = new Leaf<K, V>( btree, revision, sibling.getNbElems() - 1 );
426
427
428 System.arraycopy( sibling.keys, 1, newSibling.keys, 0, sibling.nbElems - 1 );
429 System.arraycopy( sibling.values, 1, newSibling.values, 0, sibling.nbElems - 1 );
430
431
432
433 Leaf<K, V> newLeaf = new Leaf<K, V>( btree, revision, nbElems );
434
435
436 newLeaf.keys[nbElems - 1] = siblingKey;
437 newLeaf.values[nbElems - 1] = siblingHolder;
438
439
440 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
441 System.arraycopy( values, 0, newLeaf.values, 0, pos );
442
443
444 System.arraycopy( keys, pos + 1, newLeaf.keys, pos, keys.length - pos - 1 );
445 System.arraycopy( values, pos + 1, newLeaf.values, pos, values.length - pos - 1 );
446
447 DeleteResult<K, V> result = new BorrowedFromRightResult<K, V>( newLeaf, newSibling, removedElement );
448
449
450 result.addCopiedPage( this );
451 result.addCopiedPage( sibling );
452
453 return result;
454 }
455
456
457
458
459
460
461
462
463
464
465 private void copyAfterRemovingElement( boolean keyRemoved, Leaf<K, V> newLeaf, int pos ) throws IOException
466 {
467 if ( keyRemoved )
468 {
469
470
471 if ( nbElems == 1 )
472 {
473 return;
474 }
475
476
477 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
478 System.arraycopy( values, 0, newLeaf.values, 0, pos );
479
480
481 System.arraycopy( keys, pos + 1, newLeaf.keys, pos, keys.length - pos - 1 );
482 System.arraycopy( values, pos + 1, newLeaf.values, pos, values.length - pos - 1 );
483 }
484 else
485
486 {
487 System.arraycopy( keys, 0, newLeaf.keys, 0, nbElems );
488 System.arraycopy( values, 0, newLeaf.values, 0, nbElems );
489 }
490 }
491
492
493
494
495
496 public V get( K key ) throws KeyNotFoundException, IOException
497 {
498 int pos = findPos( key );
499
500 if ( pos < 0 )
501 {
502 V v = values[-( pos + 1 )].getValue( btree );
503
504 if ( btree.isAllowDuplicates() )
505 {
506
507 BTree<V, V> dupTree = ( ( BTree<V, V> ) v );
508 return dupTree.rootPage.getLeftMostKey();
509 }
510
511 return v;
512 }
513 else
514 {
515 throw new KeyNotFoundException( "Cannot find an entry for key " + key );
516 }
517 }
518
519
520
521
522
523 @Override
524 public BTree<V, V> getValues( K key ) throws KeyNotFoundException, IOException, IllegalArgumentException
525 {
526 if ( !btree.isAllowDuplicates() )
527 {
528 throw new IllegalArgumentException( "Duplicates are not allowed in this tree" );
529 }
530
531 int pos = findPos( key );
532
533 if ( pos < 0 )
534 {
535 V v = values[-( pos + 1 )].getValue( btree );
536
537 return ( ( BTree<V, V> ) v );
538 }
539 else
540 {
541 throw new KeyNotFoundException( "Cannot find an entry for key " + key );
542 }
543 }
544
545
546
547
548
549 public boolean hasKey( K key )
550 {
551 int pos = findPos( key );
552
553 if ( pos < 0 )
554 {
555 return true;
556 }
557
558 return false;
559 }
560
561
562 @Override
563 public boolean contains( K key, V value ) throws IOException
564 {
565 int pos = findPos( key );
566
567 if ( pos < 0 )
568 {
569 V v = values[-( pos + 1 )].getValue( btree );
570
571 if ( btree.isAllowDuplicates() )
572 {
573
574 BTree<V, V> dupTree = ( ( BTree<V, V> ) v );
575 return dupTree.hasKey( value );
576 }
577 else
578 {
579 return ( btree.getValueSerializer().compare( value, v ) == 0 );
580 }
581 }
582 else
583 {
584 return false;
585 }
586 }
587
588
589
590
591
592 public ElementHolder<V, K, V> getValue( int pos )
593 {
594 if ( pos < nbElems )
595 {
596 return values[pos];
597 }
598 else
599 {
600 return null;
601 }
602 }
603
604
605
606
607
608
609
610 public void setValue( int pos, ElementHolder<V, K, V> value )
611 {
612 values[pos] = value;
613 }
614
615
616
617
618
619 public Cursor<K, V> browse( K key, Transaction<K, V> transaction, LinkedList<ParentPos<K, V>> stack )
620 {
621 int pos = findPos( key );
622 Cursor<K, V> cursor = null;
623
624 if ( pos < 0 )
625 {
626 int index = -( pos + 1 );
627
628
629 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, index );
630 setDupsContainer( parentPos, btree );
631 stack.push( parentPos );
632
633 cursor = new Cursor<K, V>( btree, transaction, stack );
634 }
635 else
636 {
637
638 if ( pos < nbElems )
639 {
640 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, pos );
641 setDupsContainer( parentPos, btree );
642 stack.push( parentPos );
643
644 cursor = new Cursor<K, V>( btree, transaction, stack );
645 }
646 else
647 {
648
649 stack.push( new ParentPos<K, V>( null, -1 ) );
650
651 return new Cursor<K, V>( btree, transaction, stack );
652 }
653 }
654
655 return cursor;
656 }
657
658
659
660
661
662 public Cursor<K, V> browse( Transaction<K, V> transaction, LinkedList<ParentPos<K, V>> stack )
663 {
664 int pos = 0;
665 Cursor<K, V> cursor = null;
666
667 if ( nbElems == 0 )
668 {
669
670 stack.push( new ParentPos<K, V>( null, -1 ) );
671
672 return new Cursor<K, V>( btree, transaction, stack );
673 }
674 else
675 {
676
677 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, pos );
678
679 setDupsContainer( parentPos, btree );
680
681 stack.push( parentPos );
682
683 cursor = new Cursor<K, V>( btree, transaction, stack );
684 }
685
686 return cursor;
687 }
688
689
690
691
692
693
694
695
696
697 private Page<K, V> copy( long revision, int nbElems )
698 {
699 Leaf<K, V> newLeaf = new Leaf<K, V>( btree, revision, nbElems );
700
701
702 System.arraycopy( keys, 0, newLeaf.keys, 0, nbElems );
703 System.arraycopy( values, 0, newLeaf.values, 0, nbElems );
704
705 return newLeaf;
706 }
707
708
709
710
711
712
713
714
715
716
717
718
719 private InsertResult<K, V> replaceElement( long revision, K key, V value, int pos )
720 throws IOException
721 {
722 Leaf<K, V> newLeaf = this;
723
724 if ( this.revision != revision )
725 {
726
727 newLeaf = ( Leaf<K, V> ) copy( revision, nbElems );
728 }
729
730 V oldValue = null;
731
732 if ( btree.isAllowDuplicates() )
733 {
734 BTree<V, V> dupValues = ( BTree<V, V> ) newLeaf.values[pos].getValue( btree );
735
736
737 if ( !dupValues.hasKey( value ) )
738 {
739 dupValues.insert( value, null, 0 );
740 }
741 else
742 {
743 oldValue = value;
744 }
745 }
746 else
747 {
748
749 oldValue = newLeaf.values[pos].getValue( btree );
750 newLeaf.values[pos] = btree.createHolder( value );
751 }
752
753
754 InsertResult<K, V> result = new ModifyResult<K, V>( newLeaf, oldValue );
755 result.addCopiedPage( this );
756
757 return result;
758 }
759
760
761
762
763
764
765
766
767
768
769
770
771 private Page<K, V> addElement( long revision, K key, V value, int pos )
772 {
773
774 Leaf<K, V> newLeaf = new Leaf<K, V>( btree, revision, nbElems + 1 );
775
776
777
778 ElementHolder valueHolder = null;
779
780 if ( btree.isAllowDuplicates() )
781 {
782 valueHolder = new DuplicateKeyMemoryHolder<K, V>( btree, value );
783 }
784 else
785 {
786 valueHolder = new MemoryHolder<K, V>( btree, value );
787 }
788
789
790
791
792 if ( nbElems == 0 )
793 {
794 newLeaf.keys[0] = key;
795
796 newLeaf.values[0] = valueHolder;
797 }
798 else
799 {
800
801
802 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
803 System.arraycopy( values, 0, newLeaf.values, 0, pos );
804
805
806 newLeaf.keys[pos] = key;
807 newLeaf.values[pos] = valueHolder;
808
809
810 System.arraycopy( keys, pos, newLeaf.keys, pos + 1, keys.length - pos );
811 System.arraycopy( values, pos, newLeaf.values, pos + 1, values.length - pos );
812 }
813
814 return newLeaf;
815 }
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833 private InsertResult<K, V> addAndSplit( long revision, K key, V value, int pos )
834 {
835 int middle = btree.getPageSize() >> 1;
836 Leaf<K, V> leftLeaf = null;
837 Leaf<K, V> rightLeaf = null;
838 ElementHolder<V, K, V> valueHolder = btree.createHolder( value );
839
840
841 if ( pos <= middle )
842 {
843
844 leftLeaf = new Leaf<K, V>( btree, revision, middle + 1 );
845
846
847 System.arraycopy( keys, 0, leftLeaf.keys, 0, pos );
848 System.arraycopy( values, 0, leftLeaf.values, 0, pos );
849
850
851 leftLeaf.keys[pos] = key;
852 leftLeaf.values[pos] = valueHolder;
853
854
855 System.arraycopy( keys, pos, leftLeaf.keys, pos + 1, middle - pos );
856 System.arraycopy( values, pos, leftLeaf.values, pos + 1, middle - pos );
857
858
859 rightLeaf = new Leaf<K, V>( btree, revision, middle );
860
861
862 System.arraycopy( keys, middle, rightLeaf.keys, 0, middle );
863 System.arraycopy( values, middle, rightLeaf.values, 0, middle );
864 }
865 else
866 {
867
868 leftLeaf = new Leaf<K, V>( btree, revision, middle );
869
870
871 System.arraycopy( keys, 0, leftLeaf.keys, 0, middle );
872 System.arraycopy( values, 0, leftLeaf.values, 0, middle );
873
874
875 rightLeaf = new Leaf<K, V>( btree, revision, middle + 1 );
876
877 int rightPos = pos - middle;
878
879
880 System.arraycopy( keys, middle, rightLeaf.keys, 0, rightPos );
881 System.arraycopy( values, middle, rightLeaf.values, 0, rightPos );
882
883
884 rightLeaf.keys[rightPos] = key;
885 rightLeaf.values[rightPos] = valueHolder;
886
887
888 System.arraycopy( keys, pos, rightLeaf.keys, rightPos + 1, nbElems - pos );
889 System.arraycopy( values, pos, rightLeaf.values, rightPos + 1, nbElems - pos );
890 }
891
892
893 K pivot = rightLeaf.keys[0];
894
895
896 InsertResult<K, V> result = new SplitResult<K, V>( pivot, leftLeaf, rightLeaf );
897
898 return result;
899 }
900
901
902
903
904
905 public K getLeftMostKey()
906 {
907 return keys[0];
908 }
909
910
911
912
913
914 public K getRightMostKey()
915 {
916 return keys[nbElems - 1];
917 }
918
919
920
921
922
923 public Tuple<K, V> findLeftMost() throws IOException
924 {
925 V val = null;
926
927 if ( btree.isAllowDuplicates() )
928 {
929 BTree<V, V> dupTree = ( BTree<V, V> ) values[0].getValue( btree );
930 val = dupTree.rootPage.getLeftMostKey();
931 }
932 else
933 {
934 val = values[0].getValue( btree );
935 }
936
937 return new Tuple<K, V>( keys[0], val );
938 }
939
940
941
942
943
944 public Tuple<K, V> findRightMost() throws EndOfFileExceededException, IOException
945 {
946 V val = null;
947
948 if ( btree.isAllowDuplicates() )
949 {
950 BTree<V, V> dupTree = ( BTree<V, V> ) values[nbElems - 1].getValue( btree );
951 val = dupTree.rootPage.getRightMostKey();
952 }
953 else
954 {
955 val = values[nbElems - 1].getValue( btree );
956 }
957
958 return new Tuple<K, V>( keys[nbElems - 1], val );
959 }
960
961
962
963
964
965 public String toString()
966 {
967 StringBuilder sb = new StringBuilder();
968
969 sb.append( "Leaf[" );
970 sb.append( super.toString() );
971
972 sb.append( "] -> {" );
973
974 if ( nbElems > 0 )
975 {
976 boolean isFirst = true;
977
978 for ( int i = 0; i < nbElems; i++ )
979 {
980 if ( isFirst )
981 {
982 isFirst = false;
983 }
984 else
985 {
986 sb.append( ", " );
987 }
988
989 sb.append( "<" ).append( keys[i] ).append( "," ).append( values[i] ).append( ">" );
990 }
991 }
992
993 sb.append( "}" );
994
995 return sb.toString();
996 }
997
998
999
1000
1001
1002 public String dumpPage( String tabs )
1003 {
1004 StringBuilder sb = new StringBuilder();
1005
1006 sb.append( tabs );
1007
1008 if ( nbElems > 0 )
1009 {
1010 boolean isFirst = true;
1011
1012 for ( int i = 0; i < nbElems; i++ )
1013 {
1014 if ( isFirst )
1015 {
1016 isFirst = false;
1017 }
1018 else
1019 {
1020 sb.append( ", " );
1021 }
1022
1023 sb.append( "<" ).append( keys[i] ).append( "," ).append( values[i] ).append( ">" );
1024 }
1025 }
1026
1027 sb.append( "\n" );
1028
1029 return sb.toString();
1030 }
1031 }