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