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 if ( values != null )
848 {
849
850
851 int pos = 0;
852
853 for ( ValueHolder<V> valueHolder : values )
854 {
855 try
856 {
857 newLeaf.values[pos++] = valueHolder.clone();
858 }
859 catch ( CloneNotSupportedException e )
860 {
861
862 e.printStackTrace();
863 }
864
865
866 if ( pos == nbElems )
867 {
868 break;
869 }
870 }
871 }
872
873 return newLeaf;
874 }
875
876
877
878
879
880
881
882
883
884
885
886
887 private InsertResult<K, V> replaceElement( long revision, K key, V value, int pos )
888 throws IOException
889 {
890 PersistedLeaf<K, V> newLeaf = this;
891
892
893 ValueHolder<V> valueHolder = values[pos];
894
895 boolean valueExists = valueHolder.contains( value );
896
897 if ( this.revision != revision )
898 {
899
900 newLeaf = ( PersistedLeaf<K, V> ) copy( revision, nbElems );
901 }
902
903
904 valueHolder = newLeaf.values[pos];
905 V replacedValue = null;
906
907 if ( !valueExists && btree.isAllowDuplicates() )
908 {
909 valueHolder.add( value );
910 newLeaf.values[pos] = valueHolder;
911 }
912 else if ( valueExists && btree.isAllowDuplicates() )
913 {
914
915
916
917 replacedValue = valueHolder.remove( value );
918 valueHolder.add( value );
919 }
920 else if ( !btree.isAllowDuplicates() )
921 {
922 replacedValue = valueHolder.replaceValueArray( value );
923 }
924
925
926 InsertResult<K, V> result = new ModifyResult<K, V>( newLeaf, replacedValue );
927 result.addCopiedPage( this );
928
929 return result;
930 }
931
932
933
934
935
936
937
938
939
940
941
942
943 private Page<K, V> addElement( long revision, K key, V value, int pos )
944 {
945
946 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems + 1 );
947
948
949 ValueHolder<V> valueHolder = new PersistedValueHolder<V>( btree, value );
950
951
952 if ( nbElems == 0 )
953 {
954 newLeaf.keys[0] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
955
956 newLeaf.values[0] = valueHolder;
957 }
958 else
959 {
960
961 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
962 System.arraycopy( values, 0, newLeaf.values, 0, pos );
963
964
965 newLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
966 newLeaf.values[pos] = valueHolder;
967
968
969 System.arraycopy( keys, pos, newLeaf.keys, pos + 1, keys.length - pos );
970 System.arraycopy( values, pos, newLeaf.values, pos + 1, values.length - pos );
971 }
972
973 return newLeaf;
974 }
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992 private InsertResult<K, V> addAndSplit( long revision, K key, V value, int pos )
993 {
994 int middle = btree.getPageSize() >> 1;
995 PersistedLeaf<K, V> leftLeaf = null;
996 PersistedLeaf<K, V> rightLeaf = null;
997 ValueHolder<V> valueHolder = new PersistedValueHolder<V>( btree, value );
998
999
1000 if ( pos <= middle )
1001 {
1002
1003 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1004
1005
1006 System.arraycopy( keys, 0, leftLeaf.keys, 0, pos );
1007 System.arraycopy( values, 0, leftLeaf.values, 0, pos );
1008
1009
1010 leftLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1011 leftLeaf.values[pos] = valueHolder;
1012
1013
1014 System.arraycopy( keys, pos, leftLeaf.keys, pos + 1, middle - pos );
1015 System.arraycopy( values, pos, leftLeaf.values, pos + 1, middle - pos );
1016
1017
1018 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1019
1020
1021 System.arraycopy( keys, middle, rightLeaf.keys, 0, middle );
1022 System.arraycopy( values, middle, rightLeaf.values, 0, middle );
1023 }
1024 else
1025 {
1026
1027 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1028
1029
1030 System.arraycopy( keys, 0, leftLeaf.keys, 0, middle );
1031 System.arraycopy( values, 0, leftLeaf.values, 0, middle );
1032
1033
1034 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1035
1036 int rightPos = pos - middle;
1037
1038
1039 System.arraycopy( keys, middle, rightLeaf.keys, 0, rightPos );
1040 System.arraycopy( values, middle, rightLeaf.values, 0, rightPos );
1041
1042
1043 rightLeaf.keys[rightPos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1044 rightLeaf.values[rightPos] = valueHolder;
1045
1046
1047 System.arraycopy( keys, pos, rightLeaf.keys, rightPos + 1, nbElems - pos );
1048 System.arraycopy( values, pos, rightLeaf.values, rightPos + 1, nbElems - pos );
1049 }
1050
1051
1052 K pivot = rightLeaf.keys[0].getKey();
1053
1054 if ( pivot == null )
1055 {
1056 pivot = rightLeaf.keys[0].getKey();
1057 }
1058
1059
1060 InsertResult<K, V> result = new SplitResult<K, V>( pivot, leftLeaf, rightLeaf );
1061
1062 return result;
1063 }
1064
1065
1066
1067
1068
1069 public K getLeftMostKey()
1070 {
1071 if( keys.length == 0 )
1072 {
1073 System.out.println("");
1074 }
1075
1076 return keys[0].getKey();
1077 }
1078
1079
1080
1081
1082
1083 public K getRightMostKey()
1084 {
1085 return keys[nbElems - 1].getKey();
1086 }
1087
1088
1089
1090
1091
1092 public Tuple<K, V> findLeftMost() throws IOException
1093 {
1094 K key = keys[0].getKey();
1095
1096 boolean isSubTree = ( btree.getType() == PERSISTED_SUB );
1097
1098 if ( isSubTree )
1099 {
1100 return new Tuple<K, V>( key, null );
1101 }
1102
1103 ValueCursor<V> cursor = values[0].getCursor();
1104
1105 try
1106 {
1107 cursor.beforeFirst();
1108 if ( cursor.hasNext() )
1109 {
1110 return new Tuple<K, V>( key, cursor.next() );
1111 }
1112 else
1113 {
1114
1115 return new Tuple<K, V>( key, null );
1116 }
1117 }
1118 finally
1119 {
1120 cursor.close();
1121 }
1122 }
1123
1124
1125
1126
1127
1128 public Tuple<K, V> findRightMost() throws EndOfFileExceededException, IOException
1129 {
1130
1131 K key = keys[nbElems - 1].getKey();
1132
1133 boolean isSubTree = ( btree.getType() == PERSISTED_SUB );
1134
1135 if ( isSubTree )
1136 {
1137 return new Tuple<K, V>( key, null );
1138 }
1139
1140 ValueCursor<V> cursor = values[nbElems - 1].getCursor();
1141
1142 try
1143 {
1144 cursor.afterLast();
1145
1146 if ( cursor.hasPrev() )
1147 {
1148 return new Tuple<K, V>( key, cursor.prev() );
1149 }
1150 else
1151 {
1152
1153 return new Tuple<K, V>( key, null );
1154 }
1155 }
1156 finally
1157 {
1158 cursor.close();
1159 }
1160 }
1161
1162
1163
1164
1165
1166 public boolean isLeaf()
1167 {
1168 return true;
1169 }
1170
1171
1172
1173
1174
1175 public boolean isNode()
1176 {
1177 return false;
1178 }
1179
1180
1181
1182
1183
1184 public String toString()
1185 {
1186 StringBuilder sb = new StringBuilder();
1187
1188 sb.append( "Leaf[" );
1189 sb.append( super.toString() );
1190
1191 sb.append( "] -> {" );
1192
1193 if ( nbElems > 0 )
1194 {
1195 boolean isFirst = true;
1196
1197 for ( int i = 0; i < nbElems; i++ )
1198 {
1199 if ( isFirst )
1200 {
1201 isFirst = false;
1202 }
1203 else
1204 {
1205 sb.append( ", " );
1206 }
1207
1208 sb.append( "<" ).append( keys[i] ).append( "," ).append( values[i] ).append( ">" );
1209 }
1210 }
1211
1212 sb.append( "}" );
1213
1214 return sb.toString();
1215 }
1216
1217
1218
1219
1220
1221
1222 private Page<K, V> addSubTreeElement( long revision, K key, int pos )
1223 {
1224
1225 PersistedLeaf<K, V> newLeaf = new PersistedLeaf<K, V>( btree, revision, nbElems + 1 );
1226
1227
1228 if ( nbElems == 0 )
1229 {
1230 newLeaf.keys[0] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1231 }
1232 else
1233 {
1234
1235 System.arraycopy( keys, 0, newLeaf.keys, 0, pos );
1236
1237
1238 newLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1239
1240
1241 System.arraycopy( keys, pos, newLeaf.keys, pos + 1, keys.length - pos );
1242 }
1243
1244 return newLeaf;
1245 }
1246
1247
1248
1249
1250
1251
1252 private InsertResult<K, V> addAndSplitSubTree( long revision, K key, int pos )
1253 {
1254 int middle = btree.getPageSize() >> 1;
1255 PersistedLeaf<K, V> leftLeaf = null;
1256 PersistedLeaf<K, V> rightLeaf = null;
1257
1258
1259 if ( pos <= middle )
1260 {
1261
1262 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1263
1264
1265 System.arraycopy( keys, 0, leftLeaf.keys, 0, pos );
1266
1267
1268 leftLeaf.keys[pos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1269
1270
1271 System.arraycopy( keys, pos, leftLeaf.keys, pos + 1, middle - pos );
1272
1273
1274 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1275
1276
1277 System.arraycopy( keys, middle, rightLeaf.keys, 0, middle );
1278 }
1279 else
1280 {
1281
1282 leftLeaf = new PersistedLeaf<K, V>( btree, revision, middle );
1283
1284
1285 System.arraycopy( keys, 0, leftLeaf.keys, 0, middle );
1286
1287
1288 rightLeaf = new PersistedLeaf<K, V>( btree, revision, middle + 1 );
1289
1290 int rightPos = pos - middle;
1291
1292
1293 System.arraycopy( keys, middle, rightLeaf.keys, 0, rightPos );
1294
1295
1296 rightLeaf.keys[rightPos] = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
1297
1298
1299 System.arraycopy( keys, pos, rightLeaf.keys, rightPos + 1, nbElems - pos );
1300 }
1301
1302
1303 K pivot = rightLeaf.keys[0].getKey();
1304
1305 if ( pivot == null )
1306 {
1307 pivot = rightLeaf.keys[0].getKey();
1308 }
1309
1310
1311 InsertResult<K, V> result = new SplitResult<K, V>( pivot, leftLeaf, rightLeaf );
1312
1313 return result;
1314 }
1315
1316
1317
1318
1319
1320 public KeyCursor<K> browseKeys( ReadTransaction<K, K> transaction, ParentPos<K, K>[] stack, int depth )
1321 {
1322 int pos = 0;
1323 KeyCursor<K> cursor = null;
1324
1325 if ( nbElems == 0 )
1326 {
1327
1328 stack[depth] = new ParentPos<K, K>( null, -1 );
1329
1330 return new KeyCursor<K>( transaction, stack, depth );
1331 }
1332 else
1333 {
1334
1335 ParentPos<K, K> parentPos = new ParentPos( this, pos );
1336
1337 stack[depth] = parentPos;
1338
1339 cursor = new KeyCursor<K>( transaction, stack, depth );
1340 }
1341
1342 return cursor;
1343 }
1344
1345
1346
1347
1348
1349
1350 void _clearValues_()
1351 {
1352 values = null;
1353 }
1354
1355
1356
1357
1358
1359 public String dumpPage( String tabs )
1360 {
1361 StringBuilder sb = new StringBuilder();
1362
1363 sb.append( tabs );
1364
1365 if ( nbElems > 0 )
1366 {
1367 boolean isFirst = true;
1368
1369 for ( int i = 0; i < nbElems; i++ )
1370 {
1371 if ( isFirst )
1372 {
1373 isFirst = false;
1374 }
1375 else
1376 {
1377 sb.append( ", " );
1378 }
1379
1380 sb.append( "<" ).append( keys[i] ).append( "," ).append( values[i] ).append( ">" );
1381 }
1382 }
1383
1384 sb.append( "\n" );
1385
1386 return sb.toString();
1387 }
1388 }