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