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 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Comparator;
28 import java.util.List;
29 import java.util.UUID;
30
31 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyCreatedException;
32 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
33 import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
34 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
35 import org.apache.directory.mavibot.btree.serializer.IntSerializer;
36 import org.apache.directory.mavibot.btree.serializer.LongSerializer;
37 import static org.apache.directory.mavibot.btree.BTreeFactory.*;
38
39
40
41
42
43
44
45 class PersistedValueHolder<V> extends AbstractValueHolder<V>
46 {
47
48 protected PersistedBTree<V, V> parentBtree;
49
50
51 private byte[] raw;
52
53
54 private boolean isDeserialized = false;
55
56
57 private boolean isRawUpToDate = false;
58
59
60
61
62
63
64
65
66
67
68 PersistedValueHolder( BTree<?, V> parentBtree, int nbValues, byte[] raw )
69 {
70 this.parentBtree = ( PersistedBTree<V, V> ) parentBtree;
71 this.valueSerializer = parentBtree.getValueSerializer();
72 this.raw = raw;
73 isRawUpToDate = true;
74 valueThresholdUp = PersistedBTree.valueThresholdUp;
75 valueThresholdLow = PersistedBTree.valueThresholdLow;
76
77
78
79 if ( nbValues <= valueThresholdUp )
80 {
81
82 valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), nbValues );
83 }
84 }
85
86
87
88
89
90
91
92
93
94 PersistedValueHolder( BTree<?, V> parentBtree, V... values )
95 {
96 this.parentBtree = ( PersistedBTree<V, V> ) parentBtree;
97 this.valueSerializer = parentBtree.getValueSerializer();
98 valueThresholdUp = PersistedBTree.valueThresholdUp;
99 valueThresholdLow = PersistedBTree.valueThresholdLow;
100
101 if ( values != null )
102 {
103 int nbValues = values.length;
104
105 if ( nbValues < PersistedBTree.valueThresholdUp )
106 {
107
108 valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), nbValues );
109
110 try
111 {
112 System.arraycopy( values, 0, valueArray, 0, values.length );
113 }
114 catch ( ArrayStoreException ase )
115 {
116 ase.printStackTrace();
117 throw ase;
118 }
119 }
120 else
121 {
122
123 createSubTree();
124
125
126
127
128
129
130
131
132
133
134
135
136
137 try
138 {
139 build( ( PersistedBTree<V, V> ) valueBtree, values );
140 }
141 catch( Exception e )
142 {
143 throw new RuntimeException( e );
144 }
145 }
146 }
147 else
148 {
149
150 valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), 0 );
151 }
152
153 isDeserialized = true;
154 }
155
156
157
158
159
160 public ValueCursor<V> getCursor()
161 {
162
163 checkAndDeserialize();
164
165 return super.getCursor();
166 }
167
168
169
170
171
172
173
174
175
176 byte[] getRaw()
177 {
178 if ( isRawUpToDate )
179 {
180
181 return raw;
182 }
183
184 if ( isSubBtree() )
185 {
186
187 long btreeOffset = ( ( PersistedBTree<V, V> ) valueBtree ).getBtreeOffset();
188 raw = LongSerializer.serialize( btreeOffset );
189 }
190 else
191 {
192
193 byte[][] valueBytes = new byte[valueArray.length * 2][];
194 int length = 0;
195 int pos = 0;
196
197
198 for ( V value : valueArray )
199 {
200
201 byte[] bytes = valueSerializer.serialize( value );
202 length += bytes.length;
203
204
205 byte[] sizeBytes = IntSerializer.serialize( bytes.length );
206 length += sizeBytes.length;
207
208
209 valueBytes[pos++] = sizeBytes;
210 valueBytes[pos++] = bytes;
211 }
212
213
214
215 raw = new byte[length];
216 pos = 0;
217
218 for ( byte[] bytes : valueBytes )
219 {
220 System.arraycopy( bytes, 0, raw, pos, bytes.length );
221 pos += bytes.length;
222 }
223 }
224
225
226 isRawUpToDate = true;
227
228 return raw;
229 }
230
231
232
233
234
235 public int size()
236 {
237 checkAndDeserialize();
238
239 if ( valueArray == null )
240 {
241 return ( int ) valueBtree.getNbElems();
242 }
243 else
244 {
245 return valueArray.length;
246 }
247 }
248
249
250
251
252
253 protected void createSubTree()
254 {
255 try
256 {
257 PersistedBTreeConfiguration<V, V> configuration = new PersistedBTreeConfiguration<V, V>();
258 configuration.setAllowDuplicates( false );
259 configuration.setKeySerializer( valueSerializer );
260 configuration.setName( UUID.randomUUID().toString() );
261 configuration.setValueSerializer( valueSerializer );
262 configuration.setParentBTree( parentBtree );
263 configuration.setBtreeType( BTreeTypeEnum.PERSISTED_SUB );
264
265 valueBtree = BTreeFactory.createPersistedBTree( configuration );
266
267 try
268 {
269
270 parentBtree.getRecordManager().manage( valueBtree, RecordManager.INTERNAL_BTREE );
271 raw = null;
272 }
273 catch ( BTreeAlreadyManagedException e )
274 {
275
276 throw new BTreeAlreadyCreatedException( e );
277 }
278 }
279 catch ( IOException e )
280 {
281 throw new BTreeCreationException( e );
282 }
283 }
284
285
286
287
288
289 void setSubBtree( BTree<V, V> subBtree )
290 {
291 valueBtree = subBtree;
292 raw = null;
293 valueArray = null;
294 isDeserialized = true;
295 isRawUpToDate = false;
296 }
297
298
299
300
301
302 private void checkAndDeserialize()
303 {
304 if ( !isDeserialized )
305 {
306 if ( valueArray == null )
307 {
308
309 deserializeSubBtree();
310 }
311 else
312 {
313
314 deserializeArray();
315 }
316
317
318 isDeserialized = true;
319 }
320 }
321
322
323
324
325
326 public void add( V value )
327 {
328
329 checkAndDeserialize();
330
331 super.add( value );
332
333
334 isRawUpToDate = false;
335 raw = null;
336 }
337
338
339
340
341
342 private V removeFromArray( V value )
343 {
344 checkAndDeserialize();
345
346
347 int pos = findPos( value );
348
349 if ( pos < 0 )
350 {
351
352 return null;
353 }
354
355
356
357 V[] newValueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), valueArray.length - 1 );
358
359 System.arraycopy( valueArray, 0, newValueArray, 0, pos );
360 System.arraycopy( valueArray, pos + 1, newValueArray, pos, valueArray.length - pos - 1 );
361
362
363 V removedValue = valueArray[pos];
364
365
366 valueArray = newValueArray;
367
368 return removedValue;
369 }
370
371
372
373
374
375 private V removeFromBtree( V removedValue )
376 {
377
378 checkAndDeserialize();
379
380 if ( btreeContains( removedValue ) )
381 {
382 try
383 {
384 if ( valueBtree.getNbElems() - 1 < PersistedBTree.valueThresholdLow )
385 {
386 int nbValues = ( int ) ( valueBtree.getNbElems() - 1 );
387
388
389 valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), nbValues );
390
391
392 TupleCursor<V, V> cursor = valueBtree.browse();
393 V returnedValue = null;
394 int pos = 0;
395
396 while ( cursor.hasNext() )
397 {
398 Tuple<V, V> tuple = cursor.next();
399
400 V value = tuple.getKey();
401
402 if ( valueSerializer.getComparator().compare( removedValue, value ) == 0 )
403 {
404
405 returnedValue = value;
406 }
407 else
408 {
409 valueArray[pos++] = value;
410 }
411 }
412
413 return returnedValue;
414 }
415 else
416 {
417 Tuple<V, V> removedTuple = valueBtree.delete( removedValue );
418
419 if ( removedTuple != null )
420 {
421 return removedTuple.getKey();
422 }
423 else
424 {
425 return null;
426 }
427 }
428 }
429 catch ( IOException e )
430 {
431
432 e.printStackTrace();
433 return null;
434 }
435 catch ( KeyNotFoundException knfe )
436 {
437
438 knfe.printStackTrace();
439 return null;
440 }
441 }
442 else
443 {
444 return null;
445 }
446 }
447
448
449
450
451
452 public V remove( V value )
453 {
454 V removedValue = null;
455
456 if ( valueArray != null )
457 {
458 removedValue = removeFromArray( value );
459 }
460 else
461 {
462 removedValue = removeFromBtree( value );
463 }
464
465
466 isRawUpToDate = false;
467 raw = null;
468
469 return removedValue;
470 }
471
472
473
474
475
476 public boolean contains( V checkedValue )
477 {
478
479 checkAndDeserialize();
480
481 return super.contains( checkedValue );
482 }
483
484
485
486
487
488
489
490
491
492
493 private int findPos( V value )
494 {
495 if ( valueArray.length == 0 )
496 {
497 return -1;
498 }
499
500
501 int pivot = valueArray.length / 2;
502 int low = 0;
503 int high = valueArray.length - 1;
504 Comparator<V> comparator = valueSerializer.getComparator();
505
506 while ( high > low )
507 {
508 switch ( high - low )
509 {
510 case 1:
511
512 int result = comparator.compare( value, valueArray[pivot] );
513
514 if ( result == 0 )
515 {
516 return pivot;
517 }
518
519 if ( result < 0 )
520 {
521 if ( pivot == low )
522 {
523 return -( low + 1 );
524 }
525 else
526 {
527 result = comparator.compare( value, valueArray[low] );
528
529 if ( result == 0 )
530 {
531 return low;
532 }
533
534 if ( result < 0 )
535 {
536 return -( low + 1 );
537 }
538 else
539 {
540 return -( low + 2 );
541 }
542 }
543 }
544 else
545 {
546 if ( pivot == high )
547 {
548 return -( high + 2 );
549 }
550 else
551 {
552 result = comparator.compare( value, valueArray[high] );
553
554 if ( result == 0 )
555 {
556 return high;
557 }
558
559 if ( result < 0 )
560 {
561 return -( high + 1 );
562 }
563 else
564 {
565 return -( high + 2 );
566 }
567 }
568 }
569
570 default:
571
572 result = comparator.compare( value, valueArray[pivot] );
573
574 if ( result == 0 )
575 {
576 return pivot;
577 }
578
579 if ( result < 0 )
580 {
581 high = pivot - 1;
582 }
583 else
584 {
585 low = pivot + 1;
586 }
587
588 pivot = ( high + low ) / 2;
589
590 continue;
591 }
592 }
593
594 int result = comparator.compare( value, valueArray[pivot] );
595
596 if ( result == 0 )
597 {
598 return pivot;
599 }
600
601 if ( result < 0 )
602 {
603 return -( pivot + 1 );
604 }
605 else
606 {
607 return -( pivot + 2 );
608 }
609 }
610
611
612
613
614
615 public ValueHolder<V> clone() throws CloneNotSupportedException
616 {
617 PersistedValueHolder<V> copy = ( PersistedValueHolder<V> ) super.clone();
618
619
620
621
622 if ( valueArray != null )
623 {
624 copy.valueArray = ( V[] ) Array.newInstance( valueSerializer.getType(), valueArray.length );
625 System.arraycopy( valueArray, 0, copy.valueArray, 0, valueArray.length );
626 }
627
628
629 if ( isRawUpToDate )
630 {
631 copy.raw = new byte[raw.length];
632 System.arraycopy( raw, 0, copy.raw, 0, raw.length );
633 }
634
635 return copy;
636 }
637
638
639
640
641
642 private void deserializeArray()
643 {
644
645
646 int index = 0;
647 int pos = 0;
648
649 while ( pos < raw.length )
650 {
651 try
652 {
653 int size = IntSerializer.deserialize( raw, pos );
654 pos += 4;
655
656 V value = valueSerializer.fromBytes( raw, pos );
657 pos += size;
658 valueArray[index++] = value;
659 }
660 catch ( IOException e )
661 {
662 e.printStackTrace();
663 }
664 }
665 }
666
667
668
669
670
671 private void deserializeSubBtree()
672 {
673
674 long offset = LongSerializer.deserialize( raw );
675
676
677 valueBtree = parentBtree.getRecordManager().loadDupsBtree( offset, parentBtree );
678 }
679
680
681
682
683
684 long getOffset()
685 {
686 if ( valueArray == null )
687 {
688 return ( ( PersistedBTree<V, V> ) valueBtree ).getBtreeOffset();
689 }
690 else
691 {
692 return -1L;
693 }
694 }
695
696
697
698
699
700
701
702
703
704
705 private BTree build( PersistedBTree<V, V> btree, V[] dupKeyValues ) throws Exception
706 {
707 long newRevision = btree.getRevision() + 1;
708
709 int numKeysInNode = btree.getPageSize();
710
711 RecordManager rm = btree.getRecordManager();
712
713 List<Page<V, V>> lstLeaves = new ArrayList<Page<V, V>>();
714
715 int totalTupleCount = 0;
716
717 Page<V, V> leaf1 = BTreeFactory.createLeaf( btree, newRevision, numKeysInNode );
718 lstLeaves.add( leaf1 );
719
720 int leafIndex = 0;
721
722 for ( V v : dupKeyValues )
723 {
724 setKey( btree, leaf1, leafIndex, v );
725
726 leafIndex++;
727 totalTupleCount++;
728 if ( ( totalTupleCount % numKeysInNode ) == 0 )
729 {
730 leafIndex = 0;
731
732 PageHolder<V, V> pageHolder = ( PageHolder ) rm.writePage( btree, leaf1, newRevision );
733
734 leaf1 = createLeaf( btree, newRevision, numKeysInNode );
735 lstLeaves.add( leaf1 );
736 }
737
738
739 }
740
741 if ( lstLeaves.isEmpty() )
742 {
743 return btree;
744 }
745
746
747 PersistedLeaf lastLeaf = ( PersistedLeaf ) lstLeaves.get( lstLeaves.size() - 1 );
748 for ( int i = 0; i < lastLeaf.nbElems; i++ )
749 {
750 if ( lastLeaf.keys[i] == null )
751 {
752 int n = i;
753 lastLeaf.nbElems = n;
754 KeyHolder[] keys = lastLeaf.keys;
755
756 lastLeaf.keys = ( KeyHolder[] ) Array.newInstance( KeyHolder.class, n );
757 System.arraycopy( keys, 0, lastLeaf.keys, 0, n );
758
759 PageHolder pageHolder = ( PageHolder ) rm.writePage( btree, lastLeaf, newRevision );
760
761 break;
762 }
763 }
764
765 if( lastLeaf.keys.length == 0 )
766 {
767 lstLeaves.remove( lastLeaf );
768 }
769
770
771
772 Page rootPage = attachNodes( lstLeaves, btree, numKeysInNode, rm );
773
774 Page oldRoot = btree.getRootPage();
775
776 long newRootPageOffset = ( ( AbstractPage ) rootPage ).getOffset();
777 System.out.println( "replacing old offset " + btree.getRootPageOffset() + " of the BTree " + btree.getName() + " with " + newRootPageOffset );
778
779 BTreeHeader header = btree.getBtreeHeader();
780
781 header.setRootPage( rootPage );
782 header.setRevision( newRevision );
783 header.setNbElems( totalTupleCount );
784
785 long newBtreeHeaderOffset = rm.writeBtreeHeader( btree, header );
786
787 header.setBTreeHeaderOffset( newBtreeHeaderOffset );
788
789 rm.freePages( ( BTree ) btree, btree.getRevision(), ( List ) Arrays.asList( oldRoot ) );
790
791 return btree;
792 }
793
794
795
796
797
798
799
800
801
802
803
804
805 private Page attachNodes( List<Page<V, V>> children, BTree btree, int numKeysInNode, RecordManager rm ) throws IOException
806 {
807 if ( children.size() == 1 )
808 {
809 return children.get( 0 );
810 }
811
812 List<Page<V, V>> lstNodes = new ArrayList<Page<V, V>>();
813
814 int numChildren = numKeysInNode + 1;
815
816 PersistedNode node = ( PersistedNode ) createNode( btree, btree.getRevision(), numKeysInNode );
817 lstNodes.add( node );
818 int i = 0;
819 int totalNodes = 0;
820
821 for ( Page p : children )
822 {
823 if ( i != 0 )
824 {
825 setKey( btree, node, i - 1, p.getLeftMostKey() );
826 }
827
828 node.children[i] = new PersistedPageHolder( btree, p );
829
830 i++;
831 totalNodes++;
832
833 if ( ( totalNodes % numChildren ) == 0 )
834 {
835 i = 0;
836
837 PageHolder pageHolder = ( PageHolder ) rm.writePage( btree, node, 1 );
838
839 node = ( PersistedNode ) createNode( btree, btree.getRevision(), numKeysInNode );
840 lstNodes.add( node );
841 }
842 }
843
844
845 AbstractPage lastNode = ( AbstractPage ) lstNodes.get( lstNodes.size() - 1 );
846
847 for ( int j = 0; j < lastNode.nbElems; j++ )
848 {
849 if ( lastNode.keys[j] == null )
850 {
851 int n = j;
852 lastNode.nbElems = n;
853 KeyHolder[] keys = lastNode.keys;
854
855 lastNode.keys = ( KeyHolder[] ) Array.newInstance( KeyHolder.class, n );
856 System.arraycopy( keys, 0, lastNode.keys, 0, n );
857
858 PageHolder pageHolder = ( PageHolder ) rm.writePage( btree, lastNode, 1 );
859
860 break;
861 }
862 }
863
864 if( lastNode.keys.length == 0 )
865 {
866 lstNodes.remove( lastNode );
867 }
868
869 return attachNodes( lstNodes, btree, numKeysInNode, rm );
870 }
871
872
873
874
875
876 public String toString()
877 {
878 StringBuilder sb = new StringBuilder();
879
880 sb.append( "ValueHolder[" ).append( valueSerializer.getClass().getSimpleName() );
881
882 if ( !isDeserialized )
883 {
884 sb.append( ", isRaw[" ).append( raw.length ).append( "]" );
885 }
886 else
887 {
888 if ( valueArray == null )
889 {
890 sb.append( ", SubBTree" );
891 }
892 else
893 {
894 sb.append( ", array{" );
895
896 if ( valueArray == null )
897 {
898 sb.append( "}" );
899 }
900 else
901 {
902 boolean isFirst = true;
903
904 for ( V value : valueArray )
905 {
906 if ( isFirst )
907 {
908 isFirst = false;
909 }
910 else
911 {
912 sb.append( "/" );
913 }
914
915 sb.append( value );
916 }
917
918 sb.append( "}" );
919 }
920 }
921 }
922
923 sb.append( "]" );
924
925 return sb.toString();
926 }
927 }