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