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 java.io.IOException;
24 import java.lang.reflect.Array;
25
26 import org.apache.directory.mavibot.btree.exception.DuplicateValueNotAllowedException;
27 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
28 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
29 import static org.apache.directory.mavibot.btree.BTreeTypeEnum.*;
30
31
32
33
34
35
36
37
38
39 class PersistedLeaf<K, V> extends AbstractPage<K, V>
40 {
41
42 protected ValueHolder<V>[] values;
43
44
45
46
47
48
49
50 PersistedLeaf( BTree<K, V> btree )
51 {
52 super( btree );
53 }
54
55
56
57
58
59
60
61
62
63 @SuppressWarnings("unchecked")
64 PersistedLeaf( BTree<K, V> btree, long revision, int nbElems )
65 {
66 super( btree, revision, nbElems );
67 if( btree.getType() != BTreeTypeEnum.PERSISTED_SUB )
68 {
69 values = ( ValueHolder<V>[] ) Array.newInstance( PersistedValueHolder.class, nbElems );
70 }
71 }
72
73
74
75
76
77 public InsertResult<K, V> insert( K key, V value, long revision ) throws IOException
78 {
79
80 int pos = findPos( key );
81
82 boolean isSubTree = ( btree.getType() == PERSISTED_SUB );
83
84 if ( pos < 0 )
85 {
86
87
88 int index = -( pos + 1 );
89
90 if( isSubTree )
91 {
92 return ExistsResult.EXISTS;
93 }
94
95
96 InsertResult<K, V> result = replaceElement( revision, key, value, index );
97
98 return result;
99 }
100
101
102 if ( nbElems < btree.getPageSize() )
103 {
104
105
106 Page<K, V> modifiedPage = null;
107
108 if ( isSubTree )
109 {
110 modifiedPage = addSubTreeElement( revision, key, pos );
111 }
112 else
113 {
114 modifiedPage = addElement( revision, key, value, pos );
115 }
116
117 InsertResult<K, V> result = new ModifyResult<K, V>( modifiedPage, null );
118 result.addCopiedPage( this );
119
120 return result;
121 }
122 else
123 {
124
125
126 InsertResult<K, V> result = null;
127
128 if( isSubTree )
129 {
130 result = addAndSplitSubTree( revision, key, pos );
131 }
132 else
133 {
134 result = addAndSplit( revision, key, value, pos );
135 }
136
137 result.addCopiedPage( this );
138
139 return result;
140 }
141 }
142
143
144
145
146
147 @SuppressWarnings("unchecked")
148 DeleteResult<K, V> delete( K key, V value, long revision, Page<K, V> parent, int parentPos )
149 throws IOException
150 {
151
152 if ( nbElems == 0 )
153 {
154
155 return NotPresentResult.NOT_PRESENT;
156 }
157
158
159 int pos = findPos( key );
160
161 if ( pos >= 0 )
162 {
163
164 return NotPresentResult.NOT_PRESENT;
165 }
166
167
168 Tuple<K, V> removedElement = null;
169
170
171 boolean keyRemoved = false;
172
173 int index = -( pos + 1 );
174
175 boolean isNotSubTree = ( btree.getType() != PERSISTED_SUB );
176
177 ValueHolder<V> valueHolder = null;
178
179 if( isNotSubTree )
180 {
181 valueHolder = values[index];
182 }
183 else
184 {
185 value = null;
186 }
187
188 if ( value == null )
189 {
190
191 removedElement = new Tuple<K, V>( keys[index].getKey(), value );
192 keyRemoved = true;
193 }
194 else
195 {
196 if ( valueHolder.contains( value ) )
197 {
198 keyRemoved = ( valueHolder.size() == 1 );
199
200 removedElement = new Tuple<K, V>( keys[index].getKey(), value );
201 }
202 else
203 {
204 return NotPresentResult.NOT_PRESENT;
205 }
206 }
207
208 PersistedLeaf<K, V> newLeaf = null;
209
210 if ( keyRemoved )
211 {
212
213 newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems - 1 );
214 }
215 else
216 {
217
218 newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems );
219 }
220
221
222 DeleteResult<K, V> defaultResult = new RemoveResult<K, V>( newLeaf, removedElement );
223
224
225 if ( parent == null )
226 {
227
228 copyAfterRemovingElement( keyRemoved, value, newLeaf, index );
229
230
231 defaultResult.addCopiedPage( this );
232
233 return defaultResult;
234 }
235 else if ( keyRemoved )
236 {
237
238
239 int halfSize = btree.getPageSize() / 2;
240
241 if ( nbElems == halfSize )
242 {
243
244
245
246
247 int siblingPos = selectSibling( parent, parentPos );
248 PersistedLeaf<K, V> sibling = ( PersistedLeaf<K, V> ) ( ( ( PersistedNode<K, V> ) parent )
249 .getPage( siblingPos ) );
250
251 if ( sibling.getNbElems() == halfSize )
252 {
253
254 DeleteResult<K, V> result = mergeWithSibling( removedElement, revision, sibling,
255 ( siblingPos < parentPos ), index );
256
257 return result;
258 }
259 else
260 {
261
262 if ( siblingPos < parentPos )
263 {
264 DeleteResult<K, V> result = borrowFromLeft( removedElement, revision, sibling, index );
265
266 return result;
267 }
268 else
269 {
270
271 DeleteResult<K, V> result = borrowFromRight( removedElement, revision, sibling, index );
272
273 return result;
274 }
275 }
276 }
277 else
278 {
279
280
281
282
283 copyAfterRemovingElement( true, value, newLeaf, index );
284
285
286 defaultResult.addCopiedPage( this );
287
288 return defaultResult;
289 }
290 }
291 else
292 {
293
294
295 System.arraycopy( keys, 0, newLeaf.keys, 0, nbElems );
296 System.arraycopy( values, 0, newLeaf.values, 0, nbElems );
297
298
299 try
300 {
301 ValueHolder<V> newValueHolder = valueHolder.clone();
302 newValueHolder.remove( value );
303
304 newLeaf.values[pos] = newValueHolder;
305 }
306 catch ( CloneNotSupportedException e )
307 {
308 throw new RuntimeException( e );
309 }
310
311
312 defaultResult.addCopiedPage( this );
313
314 return defaultResult;
315 }
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329 private DeleteResult<K, V> mergeWithSibling( Tuple<K, V> removedElement, long revision,
330 PersistedLeaf<K, V> sibling,
331 boolean isLeft, int pos )
332 throws EndOfFileExceededException, IOException
333 {
334 boolean isNotSubTree = ( btree.getType() != PERSISTED_SUB );
335
336
337
338 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, btree.getPageSize() - 1 );
339
340 if ( isLeft )
341 {
342
343
344 System.arraycopy( sibling.keys, 0, newLeaf.keys, 0, sibling.nbElems );
345 if ( isNotSubTree )
346 {
347 System.arraycopy( sibling.values, 0, newLeaf.values, 0, sibling.nbElems );
348 }
349
350
351 System.arraycopy( keys, 0, newLeaf.keys, sibling.nbElems, pos );
352 if ( isNotSubTree )
353 {
354 System.arraycopy( values, 0, newLeaf.values, sibling.nbElems, pos );
355 }
356
357
358 System.arraycopy( keys, pos + 1, newLeaf.keys, sibling.nbElems + pos, nbElems - pos - 1 );
359 if ( isNotSubTree )
360 {
361 System.arraycopy( values, pos + 1, newLeaf.values, sibling.nbElems + pos, nbElems - pos - 1 );
362 }
363 }
364 else
365 {
366
367
368 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
369 if ( isNotSubTree )
370 {
371 System.arraycopy( values, 0, newLeaf.values, 0, pos );
372 }
373
374
375 System.arraycopy( keys, pos + 1, newLeaf.keys, pos, nbElems - pos - 1 );
376 if ( isNotSubTree )
377 {
378 System.arraycopy( values, pos + 1, newLeaf.values, pos, nbElems - pos - 1 );
379 }
380
381
382 System.arraycopy( sibling.keys, 0, newLeaf.keys, nbElems - 1, sibling.nbElems );
383 if ( isNotSubTree )
384 {
385 System.arraycopy( sibling.values, 0, newLeaf.values, nbElems - 1, sibling.nbElems );
386 }
387 }
388
389
390 DeleteResult<K, V> result = new MergedWithSiblingResult<K, V>( newLeaf, removedElement );
391
392 result.addCopiedPage( this );
393 result.addCopiedPage( sibling );
394
395 return result;
396 }
397
398
399
400
401
402
403
404
405
406
407
408
409
410 private DeleteResult<K, V> borrowFromLeft( Tuple<K, V> removedElement, long revision, PersistedLeaf<K, V> sibling,
411 int pos )
412 throws IOException
413 {
414 boolean isNotSubTree = ( btree.getType() != PERSISTED_SUB );
415
416
417 K siblingKey = sibling.keys[sibling.getNbElems() - 1].getKey();
418 ValueHolder<V> siblingValue = null;
419 if ( isNotSubTree )
420 {
421 siblingValue = sibling.values[sibling.getNbElems() - 1];
422 }
423
424
425 PersistedLeaf<K, V> newSibling = ( PersistedLeaf<K, V> ) sibling.copy( revision, sibling.getNbElems() - 1 );
426
427
428
429 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems );
430
431
432 newLeaf.keys[0] = new PersistedKeyHolder<K>( btree.getKeySerializer(), siblingKey );
433 if ( isNotSubTree )
434 {
435 newLeaf.values[0] = siblingValue;
436 }
437
438
439 System.arraycopy( keys, 0, newLeaf.keys, 1, pos );
440 if ( isNotSubTree )
441 {
442 System.arraycopy( values, 0, newLeaf.values, 1, pos );
443 }
444
445
446 System.arraycopy( keys, pos + 1, newLeaf.keys, pos + 1, keys.length - pos - 1 );
447 if( isNotSubTree )
448 {
449 System.arraycopy( values, pos + 1, newLeaf.values, pos + 1, values.length - pos - 1 );
450 }
451
452 DeleteResult<K, V> result = new BorrowedFromLeftResult<K, V>( newLeaf, newSibling, removedElement );
453
454
455 result.addCopiedPage( this );
456 result.addCopiedPage( sibling );
457
458 return result;
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472
473 private DeleteResult<K, V> borrowFromRight( Tuple<K, V> removedElement, long revision, PersistedLeaf<K, V> sibling,
474 int pos )
475 throws IOException
476 {
477 boolean isNotSubTree = ( btree.getType() != PERSISTED_SUB );
478
479
480 K siblingKey = sibling.keys[0].getKey();
481 ValueHolder<V> siblingHolder = null;
482 if ( isNotSubTree )
483 {
484 siblingHolder = sibling.values[0];
485 }
486
487
488 PersistedLeaf<K, V> newSibling = new PersistedLeaf<K, V>( btree, revision, sibling.getNbElems() - 1 );
489
490
491 System.arraycopy( sibling.keys, 1, newSibling.keys, 0, sibling.nbElems - 1 );
492 if ( isNotSubTree )
493 {
494 System.arraycopy( sibling.values, 1, newSibling.values, 0, sibling.nbElems - 1 );
495 }
496
497
498
499 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems );
500
501
502 newLeaf.keys[nbElems - 1] = new PersistedKeyHolder<K>( btree.getKeySerializer(), siblingKey );
503 if ( isNotSubTree )
504 {
505 newLeaf.values[nbElems - 1] = siblingHolder;
506 }
507
508
509 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
510 if ( isNotSubTree )
511 {
512 System.arraycopy( values, 0, newLeaf.values, 0, pos );
513 }
514
515
516 System.arraycopy( keys, pos + 1, newLeaf.keys, pos, keys.length - pos - 1 );
517 if ( isNotSubTree )
518 {
519 System.arraycopy( values, pos + 1, newLeaf.values, pos, values.length - pos - 1 );
520 }
521
522 DeleteResult<K, V> result = new BorrowedFromRightResult<K, V>( newLeaf, newSibling, removedElement );
523
524
525 result.addCopiedPage( this );
526 result.addCopiedPage( sibling );
527
528 return result;
529 }
530
531
532
533
534
535
536
537
538
539
540 private void copyAfterRemovingElement( boolean keyRemoved, V removedValue, PersistedLeaf<K, V> newLeaf, int pos )
541 throws IOException
542 {
543 boolean isNotSubTree = ( btree.getType() != PERSISTED_SUB );
544
545 if ( keyRemoved )
546 {
547
548
549 if ( nbElems == 1 )
550 {
551 return;
552 }
553
554
555 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
556 if ( isNotSubTree )
557 {
558 System.arraycopy( values, 0, newLeaf.values, 0, pos );
559 }
560
561
562 System.arraycopy( keys, pos + 1, newLeaf.keys, pos, keys.length - pos - 1 );
563 if ( isNotSubTree )
564 {
565 System.arraycopy( values, pos + 1, newLeaf.values, pos, values.length - pos - 1 );
566 }
567 }
568 else
569
570 {
571 System.arraycopy( keys, 0, newLeaf.keys, 0, nbElems );
572 System.arraycopy( values, 0, newLeaf.values, 0, nbElems );
573
574
575 ValueHolder<V> valueHolder = newLeaf.values[pos];
576
577 try
578 {
579 ValueHolder<V> newValueHolder = valueHolder.clone();
580
581 newValueHolder.remove( removedValue );
582
583 newLeaf.values[pos] = newValueHolder;
584 }
585 catch ( CloneNotSupportedException e )
586 {
587
588 e.printStackTrace();
589 }
590 }
591 }
592
593
594
595
596
597 public V get( K key ) throws KeyNotFoundException, IOException
598 {
599 int pos = findPos( key );
600
601 if ( pos < 0 )
602 {
603 ValueHolder<V> valueHolder = values[-( pos + 1 )];
604
605 ValueCursor<V> cursor = valueHolder.getCursor();
606
607 cursor.beforeFirst();
608
609 if ( cursor.hasNext() )
610 {
611 V value = cursor.next();
612
613 return value;
614 }
615 else
616 {
617 return null;
618 }
619 }
620 else
621 {
622 throw KeyNotFoundException.INSTANCE;
623 }
624 }
625
626
627
628
629
630 KeyHolder<K> getKeyHolder( int pos )
631 {
632 if ( pos < nbElems )
633 {
634 return keys[pos];
635 }
636 else
637 {
638 return null;
639 }
640 }
641
642
643
644
645
646 @Override
647 public ValueCursor<V> getValues( K key ) throws KeyNotFoundException, IOException, IllegalArgumentException
648 {
649 if ( !btree.isAllowDuplicates() )
650 {
651 throw new IllegalArgumentException( "Duplicates are not allowed in this tree" );
652 }
653
654 int pos = findPos( key );
655
656 if ( pos < 0 )
657 {
658 ValueHolder<V> valueHolder = values[-( pos + 1 )];
659
660 return valueHolder.getCursor();
661 }
662 else
663 {
664 throw KeyNotFoundException.INSTANCE;
665 }
666 }
667
668
669
670
671
672 public boolean hasKey( K key )
673 {
674 int pos = findPos( key );
675
676 if ( pos < 0 )
677 {
678 return true;
679 }
680
681 return false;
682 }
683
684
685 @Override
686 public boolean contains( K key, V value ) throws IOException
687 {
688 int pos = findPos( key );
689
690 if ( pos < 0 )
691 {
692 ValueHolder<V> valueHolder = values[-( pos + 1 )];
693
694 return valueHolder.contains( value );
695 }
696 else
697 {
698 return false;
699 }
700 }
701
702
703
704
705
706 ValueHolder<V> getValue( int pos )
707 {
708 if ( pos < nbElems )
709 {
710 return values[pos];
711 }
712 else
713 {
714 return null;
715 }
716 }
717
718
719
720
721
722
723
724 void setValue( int pos, ValueHolder<V> value )
725 {
726 values[pos] = value;
727 }
728
729
730
731
732
733 public TupleCursor<K, V> browse( K key, ReadTransaction<K, V> transaction, ParentPos<K, V>[] stack, int depth )
734 {
735 int pos = findPos( key );
736 TupleCursor<K, V> cursor = null;
737
738 if ( pos < 0 )
739 {
740 pos = -( pos + 1 );
741
742
743 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, pos );
744
745
746 parentPos.valueCursor = values[pos].getCursor();
747
748 stack[depth] = parentPos;
749
750 cursor = new TupleCursor<K, V>( transaction, stack, depth );
751 }
752 else
753 {
754
755 if ( pos < nbElems )
756 {
757 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, pos );
758
759
760 parentPos.valueCursor = values[pos].getCursor();
761
762 stack[depth] = parentPos;
763
764 cursor = new TupleCursor<K, V>( transaction, stack, depth );
765 }
766 else if ( nbElems > 0 )
767 {
768
769 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, nbElems - 1 );
770
771
772 parentPos.valueCursor = values[nbElems - 1].getCursor();
773
774 stack[depth] = parentPos;
775
776 cursor = new TupleCursor<K, V>( transaction, stack, depth );
777
778 try
779 {
780 cursor.afterLast();
781 }
782 catch ( IOException e )
783 {
784
785 e.printStackTrace();
786 }
787 }
788 else
789 {
790
791 stack[depth] = null;
792
793 cursor = new TupleCursor<K, V>( transaction, null, 0 );
794 }
795 }
796
797 return cursor;
798 }
799
800
801
802
803
804 public TupleCursor<K, V> browse( ReadTransaction<K, V> transaction, ParentPos<K, V>[] stack, int depth )
805 {
806 int pos = 0;
807 TupleCursor<K, V> cursor = null;
808
809 if ( nbElems == 0 )
810 {
811
812 stack[depth] = new ParentPos<K, V>( null, -1 );
813
814 return new TupleCursor<K, V>( transaction, stack, depth );
815 }
816 else
817 {
818
819 ParentPos<K, V> parentPos = new ParentPos<K, V>( this, pos );
820
821
822 parentPos.valueCursor = values[0].getCursor();
823
824 stack[depth] = parentPos;
825
826 cursor = new TupleCursor<K, V>( transaction, stack, depth );
827 }
828
829 return cursor;
830 }
831
832
833
834
835
836
837
838
839
840 private Page<K, V> copy( long revision, int nbElems )
841 {
842 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems );
843
844
845 System.arraycopy( keys, 0, newLeaf.keys, 0, nbElems );
846
847
848
849 int pos = 0;
850
851 for ( ValueHolder<V> valueHolder : values )
852 {
853 try
854 {
855 newLeaf.values[pos++] = valueHolder.clone();
856 }
857 catch ( CloneNotSupportedException e )
858 {
859
860 e.printStackTrace();
861 }
862
863
864 if ( pos == nbElems )
865 {
866 break;
867 }
868 }
869
870 return newLeaf;
871 }
872
873
874
875
876
877
878
879
880
881
882
883
884 private InsertResult<K, V> replaceElement( long revision, K key, V value, int pos )
885 throws IOException
886 {
887 PersistedLeaf<K, V> newLeaf = this;
888
889
890 ValueHolder<V> valueHolder = values[pos];
891
892 boolean valueExists = valueHolder.contains( value );
893
894
895 if ( !valueExists && !btree.isAllowDuplicates() )
896 {
897 throw new DuplicateValueNotAllowedException( "Duplicate values are not allowed" );
898 }
899
900 if ( valueExists )
901 {
902 return ExistsResult.EXISTS;
903 }
904
905 if ( this.revision != revision )
906 {
907
908 newLeaf = ( PersistedLeaf<K, V> ) copy( revision, nbElems );
909 }
910
911
912 valueHolder = newLeaf.values[pos];
913 V replacedValue = null;
914
915 if ( !valueExists )
916 {
917 valueHolder.add( value );
918 newLeaf.values[pos] = valueHolder;
919 }
920 else
921 {
922
923
924
925
926
927
928 }
929
930
931 InsertResult<K, V> result = new ModifyResult<K, V>( newLeaf, replacedValue );
932 result.addCopiedPage( this );
933
934 return result;
935 }
936
937
938
939
940
941
942
943
944
945
946
947
948 private Page<K, V> addElement( long revision, K key, V value, int pos )
949 {
950
951 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems + 1 );
952
953
954 ValueHolder<V> valueHolder = new PersistedValueHolder<V>( btree, value );
955
956
957 if ( nbElems == 0 )
958 {
959 newLeaf.keys[0] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
960
961 newLeaf.values[0] = valueHolder;
962 }
963 else
964 {
965
966 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
967 System.arraycopy( values, 0, newLeaf.values, 0, pos );
968
969
970 newLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
971 newLeaf.values[pos] = valueHolder;
972
973
974 System.arraycopy( keys, pos, newLeaf.keys, pos + 1, keys.length - pos );
975 System.arraycopy( values, pos, newLeaf.values, pos + 1, values.length - pos );
976 }
977
978 return newLeaf;
979 }
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997 private InsertResult<K, V> addAndSplit( long revision, K key, V value, int pos )
998 {
999 int middle = btree.getPageSize() >> 1;
1000 PersistedLeaf<K, V> leftLeaf = null;
1001 PersistedLeaf<K, V> rightLeaf = null;
1002 ValueHolder<V> valueHolder = new PersistedValueHolder<V>( btree, value );
1003
1004
1005 if ( pos <= middle )
1006 {
1007
1008 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1009
1010
1011 System.arraycopy( keys, 0, leftLeaf.keys, 0, pos );
1012 System.arraycopy( values, 0, leftLeaf.values, 0, pos );
1013
1014
1015 leftLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1016 leftLeaf.values[pos] = valueHolder;
1017
1018
1019 System.arraycopy( keys, pos, leftLeaf.keys, pos + 1, middle - pos );
1020 System.arraycopy( values, pos, leftLeaf.values, pos + 1, middle - pos );
1021
1022
1023 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1024
1025
1026 System.arraycopy( keys, middle, rightLeaf.keys, 0, middle );
1027 System.arraycopy( values, middle, rightLeaf.values, 0, middle );
1028 }
1029 else
1030 {
1031
1032 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1033
1034
1035 System.arraycopy( keys, 0, leftLeaf.keys, 0, middle );
1036 System.arraycopy( values, 0, leftLeaf.values, 0, middle );
1037
1038
1039 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1040
1041 int rightPos = pos - middle;
1042
1043
1044 System.arraycopy( keys, middle, rightLeaf.keys, 0, rightPos );
1045 System.arraycopy( values, middle, rightLeaf.values, 0, rightPos );
1046
1047
1048 rightLeaf.keys[rightPos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1049 rightLeaf.values[rightPos] = valueHolder;
1050
1051
1052 System.arraycopy( keys, pos, rightLeaf.keys, rightPos + 1, nbElems - pos );
1053 System.arraycopy( values, pos, rightLeaf.values, rightPos + 1, nbElems - pos );
1054 }
1055
1056
1057 K pivot = rightLeaf.keys[0].getKey();
1058
1059 if ( pivot == null )
1060 {
1061 pivot = rightLeaf.keys[0].getKey();
1062 }
1063
1064
1065 InsertResult<K, V> result = new SplitResult<K, V>( pivot, leftLeaf, rightLeaf );
1066
1067 return result;
1068 }
1069
1070
1071
1072
1073
1074 public K getLeftMostKey()
1075 {
1076 if( keys.length == 0 )
1077 {
1078 System.out.println("");
1079 }
1080
1081 return keys[0].getKey();
1082 }
1083
1084
1085
1086
1087
1088 public K getRightMostKey()
1089 {
1090 return keys[nbElems - 1].getKey();
1091 }
1092
1093
1094
1095
1096
1097 public Tuple<K, V> findLeftMost() throws IOException
1098 {
1099 ValueCursor<V> cursor = values[0].getCursor();
1100
1101 try
1102 {
1103 cursor.beforeFirst();
1104 if ( cursor.hasNext() )
1105 {
1106 return new Tuple<K, V>( keys[0].getKey(), cursor.next() );
1107 }
1108 else
1109 {
1110
1111 return new Tuple<K, V>( keys[0].getKey(), null );
1112 }
1113 }
1114 finally
1115 {
1116 cursor.close();
1117 }
1118 }
1119
1120
1121
1122
1123
1124 public Tuple<K, V> findRightMost() throws EndOfFileExceededException, IOException
1125 {
1126 ValueCursor<V> cursor = values[nbElems - 1].getCursor();
1127
1128 try
1129 {
1130 cursor.afterLast();
1131
1132 if ( cursor.hasPrev() )
1133 {
1134 return new Tuple<K, V>( keys[nbElems - 1].getKey(), cursor.prev() );
1135 }
1136 else
1137 {
1138
1139 return new Tuple<K, V>( keys[nbElems - 1].getKey(), null );
1140 }
1141 }
1142 finally
1143 {
1144 cursor.close();
1145 }
1146 }
1147
1148
1149
1150
1151
1152 public boolean isLeaf()
1153 {
1154 return true;
1155 }
1156
1157
1158
1159
1160
1161 public boolean isNode()
1162 {
1163 return false;
1164 }
1165
1166
1167
1168
1169
1170 public String toString()
1171 {
1172 StringBuilder sb = new StringBuilder();
1173
1174 sb.append( "Leaf[" );
1175 sb.append( super.toString() );
1176
1177 sb.append( "] -> {" );
1178
1179 if ( nbElems > 0 )
1180 {
1181 boolean isFirst = true;
1182
1183 for ( int i = 0; i < nbElems; i++ )
1184 {
1185 if ( isFirst )
1186 {
1187 isFirst = false;
1188 }
1189 else
1190 {
1191 sb.append( ", " );
1192 }
1193
1194 sb.append( "<" ).append( keys[i] ).append( "," ).append( values[i] ).append( ">" );
1195 }
1196 }
1197
1198 sb.append( "}" );
1199
1200 return sb.toString();
1201 }
1202
1203
1204
1205
1206
1207
1208 private Page<K, V> addSubTreeElement( long revision, K key, int pos )
1209 {
1210
1211 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems + 1 );
1212
1213
1214 if ( nbElems == 0 )
1215 {
1216 newLeaf.keys[0] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1217 }
1218 else
1219 {
1220
1221 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
1222
1223
1224 newLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1225
1226
1227 System.arraycopy( keys, pos, newLeaf.keys, pos + 1, keys.length - pos );
1228 }
1229
1230 return newLeaf;
1231 }
1232
1233
1234
1235
1236
1237
1238 private InsertResult<K, V> addAndSplitSubTree( long revision, K key, int pos )
1239 {
1240 int middle = btree.getPageSize() >> 1;
1241 PersistedLeaf<K, V> leftLeaf = null;
1242 PersistedLeaf<K, V> rightLeaf = null;
1243
1244
1245 if ( pos <= middle )
1246 {
1247
1248 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1249
1250
1251 System.arraycopy( keys, 0, leftLeaf.keys, 0, pos );
1252
1253
1254 leftLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1255
1256
1257 System.arraycopy( keys, pos, leftLeaf.keys, pos + 1, middle - pos );
1258
1259
1260 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1261
1262
1263 System.arraycopy( keys, middle, rightLeaf.keys, 0, middle );
1264 }
1265 else
1266 {
1267
1268 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1269
1270
1271 System.arraycopy( keys, 0, leftLeaf.keys, 0, middle );
1272
1273
1274 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1275
1276 int rightPos = pos - middle;
1277
1278
1279 System.arraycopy( keys, middle, rightLeaf.keys, 0, rightPos );
1280
1281
1282 rightLeaf.keys[rightPos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1283
1284
1285 System.arraycopy( keys, pos, rightLeaf.keys, rightPos + 1, nbElems - pos );
1286 }
1287
1288
1289 K pivot = rightLeaf.keys[0].getKey();
1290
1291 if ( pivot == null )
1292 {
1293 pivot = rightLeaf.keys[0].getKey();
1294 }
1295
1296
1297 InsertResult<K, V> result = new SplitResult<K, V>( pivot, leftLeaf, rightLeaf );
1298
1299 return result;
1300 }
1301
1302
1303
1304
1305
1306 public KeyCursor<K> browseKeys( ReadTransaction<K, K> transaction, ParentPos<K, K>[] stack, int depth )
1307 {
1308 int pos = 0;
1309 KeyCursor<K> cursor = null;
1310
1311 if ( nbElems == 0 )
1312 {
1313
1314 stack[depth] = new ParentPos<K, K>( null, -1 );
1315
1316 return new KeyCursor<K>( transaction, stack, depth );
1317 }
1318 else
1319 {
1320
1321 ParentPos<K, K> parentPos = new ParentPos( this, pos );
1322
1323 stack[depth] = parentPos;
1324
1325 cursor = new KeyCursor<K>( transaction, stack, depth );
1326 }
1327
1328 return cursor;
1329 }
1330
1331
1332
1333
1334
1335
1336 void _clearValues_()
1337 {
1338 values = null;
1339 }
1340
1341
1342
1343
1344
1345 public String dumpPage( String tabs )
1346 {
1347 StringBuilder sb = new StringBuilder();
1348
1349 sb.append( tabs );
1350
1351 if ( nbElems > 0 )
1352 {
1353 boolean isFirst = true;
1354
1355 for ( int i = 0; i < nbElems; i++ )
1356 {
1357 if ( isFirst )
1358 {
1359 isFirst = false;
1360 }
1361 else
1362 {
1363 sb.append( ", " );
1364 }
1365
1366 sb.append( "<" ).append( keys[i] ).append( "," ).append( values[i] ).append( ">" );
1367 }
1368 }
1369
1370 sb.append( "\n" );
1371
1372 return sb.toString();
1373 }
1374 }