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