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.concurrent.ConcurrentLinkedQueue;
27 import java.util.concurrent.locks.ReentrantLock;
28
29 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
30 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
31
32
33
34
35
36
37
38
39
40
41
42
43 {
44
45 protected long readTimeOut = DEFAULT_READ_TIMEOUT;
46
47
48 protected BTreeHeader btreeHeader;
49
50
51 protected volatile Page<K, V> rootPage;
52
53
54 protected ElementSerializer<K> keySerializer;
55
56
57 protected ElementSerializer<V> valueSerializer;
58
59
60 protected ConcurrentLinkedQueue<ReadTransaction<K, V>> readTransactions;
61
62
63 protected int writeBufferSize;
64
65
66 protected ReentrantLock writeLock;
67
68
69 private boolean allowDuplicates;
70
71
72 protected Thread readTransactionsThread;
73
74
75 private BTreeTypeEnum type;
76
77
78 protected WriteTransaction writeTransaction;
79
80
81
82
83
84
85
86
87 protected ReadTransaction<K, V> beginReadTransaction()
88 {
89 ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( rootPage, btreeHeader.getRevision() - 1,
90 System.currentTimeMillis() );
91
92 readTransactions.add( readTransaction );
93
94 return readTransaction;
95 }
96
97
98
99
100
101 public TupleCursor<K, V> browse() throws IOException
102 {
103 ReadTransaction<K, V> transaction = beginReadTransaction();
104
105
106 ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
107
108 TupleCursor<K, V> cursor = rootPage.browse( transaction, stack, 0 );
109
110
111 cursor.beforeFirst();
112
113 return cursor;
114 }
115
116
117
118
119
120 public TupleCursor<K, V> browse( long revision ) throws IOException, KeyNotFoundException
121 {
122 ReadTransaction<K, V> transaction = beginReadTransaction();
123
124
125 Page<K, V> revisionRootPage = getRootPage( revision );
126
127 ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
128
129
130 TupleCursor<K, V> cursor = revisionRootPage.browse( transaction, stack, 0 );
131
132 return cursor;
133 }
134
135
136
137
138
139 public TupleCursor<K, V> browseFrom( K key ) throws IOException
140 {
141 ReadTransaction<K, V> transaction = beginReadTransaction();
142
143
144 ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
145
146 TupleCursor<K, V> cursor = rootPage.browse( key, transaction, stack, 0 );
147
148 return cursor;
149 }
150
151
152
153
154
155 public TupleCursor<K, V> browseFrom( long revision, K key ) throws IOException, KeyNotFoundException
156 {
157 ReadTransaction<K, V> transaction = beginReadTransaction();
158
159
160 Page<K, V> revisionRootPage = getRootPage( revision );
161
162 ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
163
164
165 TupleCursor<K, V> cursor = revisionRootPage.browse( key, transaction, stack, 0 );
166
167 return cursor;
168 }
169
170
171
172
173
174 public boolean contains( K key, V value ) throws IOException
175 {
176 return rootPage.contains( key, value );
177 }
178
179
180
181
182
183 public boolean contains( long revision, K key, V value ) throws IOException, KeyNotFoundException
184 {
185
186 Page<K, V> revisionRootPage = getRootPage( revision );
187
188 return revisionRootPage.contains( key, value );
189 }
190
191
192
193
194
195 public Tuple<K, V> delete( K key ) throws IOException
196 {
197 if ( key == null )
198 {
199 throw new IllegalArgumentException( "Key must not be null" );
200 }
201
202 long revision = generateRevision();
203
204 Tuple<K, V> deleted = delete( key, revision );
205
206 return deleted;
207 }
208
209
210
211
212
213 public Tuple<K, V> delete( K key, V value ) throws IOException
214 {
215 if ( key == null )
216 {
217 throw new IllegalArgumentException( "Key must not be null" );
218 }
219
220 if ( value == null )
221 {
222 throw new IllegalArgumentException( "Value must not be null" );
223 }
224
225 long revision = generateRevision();
226
227 Tuple<K, V> deleted = delete( key, value, revision );
228
229 return deleted;
230 }
231
232
233
234
235
236
237
238
239
240
241 {
242 return delete( key, null, revision );
243 }
244
245
246
247
248
249
250
251
252 public V insert( K key, V value ) throws IOException
253 {
254 long revision = generateRevision();
255
256 V existingValue = null;
257
258 try
259 {
260 if ( writeTransaction == null )
261 {
262 writeLock.lock();
263 }
264
265 InsertResult<K, V> result = insert( key, value, revision );
266
267 if ( result instanceof ModifyResult )
268 {
269 existingValue = ( ( ModifyResult<K, V> ) result ).getModifiedValue();
270 }
271 }
272 finally
273 {
274
275 if ( writeTransaction == null )
276 {
277 writeLock.unlock();
278 }
279 }
280
281 return existingValue;
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295 public void flush() throws IOException
296 {
297 }
298
299
300
301
302
303 public V get( K key ) throws IOException, KeyNotFoundException
304 {
305 return rootPage.get( key );
306 }
307
308
309
310
311
312 public V get( long revision, K key ) throws IOException, KeyNotFoundException
313 {
314
315 Page<K, V> revisionRootPage = getRootPage( revision );
316
317 return revisionRootPage.get( key );
318 }
319
320
321
322
323
324 public Page<K, V> getRootPage()
325 {
326 return rootPage;
327 }
328
329
330
331
332
333
334 {
335 rootPage = root;
336 }
337
338
339
340
341
342 public ValueCursor<V> getValues( K key ) throws IOException, KeyNotFoundException
343 {
344 return rootPage.getValues( key );
345 }
346
347
348
349
350
351 public boolean hasKey( K key ) throws IOException
352 {
353 if ( key == null )
354 {
355 return false;
356 }
357
358 return rootPage.hasKey( key );
359 }
360
361
362
363
364
365 public boolean hasKey( long revision, K key ) throws IOException, KeyNotFoundException
366 {
367 if ( key == null )
368 {
369 return false;
370 }
371
372
373 Page<K, V> revisionRootPage = getRootPage( revision );
374
375 return revisionRootPage.hasKey( key );
376 }
377
378
379
380
381
382 public ElementSerializer<K> getKeySerializer()
383 {
384 return keySerializer;
385 }
386
387
388
389
390
391 public void setKeySerializer( ElementSerializer<K> keySerializer )
392 {
393 this.keySerializer = keySerializer;
394 btreeHeader.setKeySerializerFQCN( keySerializer.getClass().getName() );
395 }
396
397
398
399
400
401 public String getKeySerializerFQCN()
402 {
403 return btreeHeader.getKeySerializerFQCN();
404 }
405
406
407
408
409
410 public ElementSerializer<V> getValueSerializer()
411 {
412 return valueSerializer;
413 }
414
415
416
417
418
419 public void setValueSerializer( ElementSerializer<V> valueSerializer )
420 {
421 this.valueSerializer = valueSerializer;
422 btreeHeader.setValueSerializerFQCN( valueSerializer.getClass().getName() );
423 }
424
425
426
427
428
429 public String getValueSerializerFQCN()
430 {
431 return btreeHeader.getValueSerializerFQCN();
432 }
433
434
435
436
437
438 public long getRevision()
439 {
440 return btreeHeader.getRevision();
441 }
442
443
444
445
446
447
448 {
449 btreeHeader.setRevision( revision );
450 }
451
452
453
454
455
456
457
458
459 {
460 return btreeHeader.incrementRevision();
461 }
462
463
464
465
466
467 public long getReadTimeOut()
468 {
469 return readTimeOut;
470 }
471
472
473
474
475
476 public void setReadTimeOut( long readTimeOut )
477 {
478 this.readTimeOut = readTimeOut;
479 }
480
481
482
483
484
485 public long getNbElems()
486 {
487 return btreeHeader.getNbElems();
488 }
489
490
491
492
493
494
495 {
496 btreeHeader.setNbElems( nbElems );
497 }
498
499
500
501
502
503 public int getPageSize()
504 {
505 return btreeHeader.getPageSize();
506 }
507
508
509
510
511
512 public void setPageSize( int pageSize )
513 {
514 if ( pageSize <= 2 )
515 {
516 btreeHeader.setPageSize( DEFAULT_PAGE_SIZE );
517 }
518 else
519 {
520 btreeHeader.setPageSize( getPowerOf2( pageSize ) );
521 }
522 }
523
524
525
526
527
528 public String getName()
529 {
530 return btreeHeader.getName();
531 }
532
533
534
535
536
537 public void setName( String name )
538 {
539 btreeHeader.setName( name );
540 }
541
542
543
544
545
546 public Comparator<K> getComparator()
547 {
548 return keySerializer.getComparator();
549 }
550
551
552
553
554
555 public int getWriteBufferSize()
556 {
557 return writeBufferSize;
558 }
559
560
561
562
563
564 public void setWriteBufferSize( int writeBufferSize )
565 {
566 this.writeBufferSize = writeBufferSize;
567 }
568
569
570
571
572
573 public boolean isAllowDuplicates()
574 {
575 return btreeHeader.isAllowDuplicates();
576 }
577
578
579
580
581
582 public void setAllowDuplicates( boolean allowDuplicates )
583 {
584 btreeHeader.setAllowDuplicates( allowDuplicates );
585 }
586
587
588
589
590
591 public BTreeTypeEnum getType()
592 {
593 return type;
594 }
595
596
597
598
599
600 public void setType( BTreeTypeEnum type )
601 {
602 this.type = type;
603 }
604
605
606
607
608
609 private int getPowerOf2( int size )
610 {
611 int newSize = --size;
612 newSize |= newSize >> 1;
613 newSize |= newSize >> 2;
614 newSize |= newSize >> 4;
615 newSize |= newSize >> 8;
616 newSize |= newSize >> 16;
617 newSize++;
618
619 return newSize;
620 }
621
622
623
624
625
626
627
628 {
629 Runnable readTransactionTask = new Runnable()
630 {
631 public void run()
632 {
633 try
634 {
635 ReadTransaction<K, V> transaction = null;
636
637 while ( !Thread.currentThread().isInterrupted() )
638 {
639 long timeoutDate = System.currentTimeMillis() - readTimeOut;
640 long t0 = System.currentTimeMillis();
641 int nbTxns = 0;
642
643
644 while ( ( transaction = readTransactions.peek() ) != null )
645 {
646 nbTxns++;
647
648 if ( transaction.isClosed() )
649 {
650
651 readTransactions.poll();
652 continue;
653 }
654
655
656 if ( transaction.getCreationDate() < timeoutDate )
657 {
658 transaction.close();
659 readTransactions.poll();
660 continue;
661 }
662
663
664 break;
665 }
666
667 long t1 = System.currentTimeMillis();
668
669 if ( nbTxns > 0 )
670 {
671 System.out.println( "Processing old txn : " + nbTxns + ", " + ( t1 - t0 ) + "ms" );
672 }
673
674
675 Thread.sleep( readTimeOut );
676 }
677 }
678 catch ( InterruptedException ie )
679 {
680
681 }
682 catch ( Exception e )
683 {
684 throw new RuntimeException( e );
685 }
686 }
687 };
688
689 readTransactionsThread = new Thread( readTransactionTask );
690 readTransactionsThread.setDaemon( true );
691 readTransactionsThread.start();
692 }
693 }