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