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
26 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
27 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
28
29
30
31
32
33
34
35
36
37
38
39 abstract class AbstractPage<K, V> implements Page<K, V>
40 {
41
42 protected transient BTree<K, V> btree;
43
44
45 protected KeyHolder<K>[] keys;
46
47
48 protected PageHolder<K, V>[] children;
49
50
51 protected int nbElems;
52
53
54 protected long revision;
55
56
57 protected long offset = -1L;
58
59
60 protected long lastOffset = -1L;
61
62
63
64
65
66
67 protected AbstractPage( BTree<K, V> btree )
68 {
69 this.btree = btree;
70 }
71
72
73
74
75
76 @SuppressWarnings("unchecked")
77
78 protected AbstractPage( BTree<K, V> btree, long revision, int nbElems )
79 {
80 this.btree = btree;
81 this.revision = revision;
82 this.nbElems = nbElems;
83 this.keys = ( KeyHolder[] ) Array.newInstance( KeyHolder.class, nbElems );
84 }
85
86
87
88
89
90 public int getNbElems()
91 {
92 return nbElems;
93 }
94
95
96
97
98
99
100 void setNbElems( int nbElems )
101 {
102 this.nbElems = nbElems;
103 }
104
105
106
107
108
109 public K getKey( int pos )
110 {
111 if ( ( pos < nbElems ) && ( keys[pos] != null ) )
112 {
113 return keys[pos].getKey();
114 }
115 else
116 {
117 return null;
118 }
119 }
120
121
122
123
124
125 @Override
126 public boolean hasKey( K key ) throws IOException
127 {
128 int pos = findPos( key );
129
130 if ( pos < 0 )
131 {
132
133
134 return children[-pos].getValue().hasKey( key );
135 }
136 else
137 {
138 Page<K, V> page = children[pos].getValue();
139
140 if ( page == null )
141 {
142 System.out.println( "Page is null for pos = " + pos + ", children = " + children[pos] );
143 }
144
145 return page.hasKey( key );
146 }
147 }
148
149
150
151
152
153 Page<K, V> getReference( int pos ) throws IOException
154 {
155 if ( pos < nbElems + 1 )
156 {
157 return children[pos].getValue();
158 }
159 else
160 {
161 return null;
162 }
163 }
164
165
166
167
168
169 public TupleCursor<K, V> browse( K key, ReadTransaction<K, V> transaction, ParentPos<K, V>[] stack, int depth )
170 throws IOException
171 {
172 int pos = findPos( key );
173
174 if ( pos < 0 )
175 {
176 pos = -pos;
177 }
178
179
180 stack[depth++] = new ParentPos<K, V>( this, pos );
181
182 Page<K, V> page = children[pos].getValue();
183
184 return page.browse( key, transaction, stack, depth );
185 }
186
187
188
189
190
191 @Override
192 public boolean contains( K key, V value ) throws IOException
193 {
194 int pos = findPos( key );
195
196 if ( pos < 0 )
197 {
198
199
200 return children[-pos].getValue().contains( key, value );
201 }
202 else
203 {
204 return children[pos].getValue().contains( key, value );
205 }
206 }
207
208
209
210
211
212 public DeleteResult<K, V> delete( K key, V value, long revision ) throws IOException
213 {
214 return delete( key, value, revision, null, -1 );
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228
229 abstract DeleteResult<K, V> delete( K key, V value, long revision, Page<K, V> parent, int parentPos )
230 throws IOException;
231
232
233
234
235
236 public V get( K key ) throws IOException, KeyNotFoundException
237 {
238 int pos = findPos( key );
239
240 if ( pos < 0 )
241 {
242
243
244 return children[-pos].getValue().get( key );
245 }
246 else
247 {
248 return children[pos].getValue().get( key );
249 }
250 }
251
252
253
254
255
256 Page<K, V> getPage( int pos )
257 {
258 if ( ( pos >= 0 ) && ( pos < children.length ) )
259 {
260 return children[pos].getValue();
261 }
262 else
263 {
264 return null;
265 }
266 }
267
268
269
270
271
272 void setPageHolder( int pos, PageHolder<K, V> pageHolder )
273 {
274 if ( ( pos >= 0 ) && ( pos < children.length ) )
275 {
276 children[pos] = pageHolder;
277 }
278 }
279
280
281
282
283
284 @Override
285 public ValueCursor<V> getValues( K key ) throws KeyNotFoundException, IOException, IllegalArgumentException
286 {
287 int pos = findPos( key );
288
289 if ( pos < 0 )
290 {
291
292
293 return children[-pos].getValue().getValues( key );
294 }
295 else
296 {
297 return children[pos].getValue().getValues( key );
298 }
299 }
300
301
302
303
304
305 public TupleCursor<K, V> browse( ReadTransaction<K, V> transaction, ParentPos<K, V>[] stack, int depth )
306 throws IOException
307 {
308 stack[depth++] = new ParentPos<K, V>( this, 0 );
309
310 Page<K, V> page = children[0].getValue();
311
312 return page.browse( transaction, stack, depth );
313 }
314
315
316
317
318
319 public KeyCursor<K> browseKeys( ReadTransaction<K, K> transaction, ParentPos<K, K>[] stack, int depth )
320 throws IOException
321 {
322 stack[depth++] = new ParentPos( this, 0 );
323
324 Page<K, V> page = children[0].getValue();
325
326 return page.browseKeys( transaction, stack, depth );
327 }
328
329
330
331
332
333
334
335
336
337
338
339 protected int selectSibling( Page<K, V> parent, int parentPos ) throws IOException
340 {
341 if ( parentPos == 0 )
342 {
343
344
345 return 1;
346 }
347
348 if ( parentPos == parent.getNbElems() )
349 {
350
351
352 return parentPos - 1;
353 }
354
355 Page<K, V> prevPage = ( ( AbstractPage<K, V> ) parent ).getPage( parentPos - 1 );
356 Page<K, V> nextPage = ( ( AbstractPage<K, V> ) parent ).getPage( parentPos + 1 );
357
358 int prevPageSize = prevPage.getNbElems();
359 int nextPageSize = nextPage.getNbElems();
360
361 if ( prevPageSize >= nextPageSize )
362 {
363 return parentPos - 1;
364 }
365 else
366 {
367 return parentPos + 1;
368 }
369 }
370
371
372
373
374
375 public K getLeftMostKey()
376 {
377 return keys[0].getKey();
378 }
379
380
381
382
383
384 public K getRightMostKey()
385 {
386 return keys[nbElems - 1].getKey();
387 }
388
389
390
391
392
393 long getOffset()
394 {
395 return offset;
396 }
397
398
399
400
401
402 void setOffset( long offset )
403 {
404 this.offset = offset;
405 }
406
407
408
409
410
411 long getLastOffset()
412 {
413 return lastOffset;
414 }
415
416
417
418
419
420 void setLastOffset( long lastOffset )
421 {
422 this.lastOffset = lastOffset;
423 }
424
425
426
427
428
429 KeyHolder<K>[] getKeys()
430 {
431 return keys;
432 }
433
434
435
436
437
438
439
440
441 void setKey( int pos, KeyHolder<K> key )
442 {
443 keys[pos] = key;
444 }
445
446
447
448
449
450 void setKeys( KeyHolder<K>[] keys )
451 {
452 this.keys = keys;
453 }
454
455
456
457
458
459 ValueHolder<V> getValue( int pos )
460 {
461
462 return null;
463 }
464
465
466
467
468
469 public long getRevision()
470 {
471 return revision;
472 }
473
474
475
476
477
478 void setRevision( long revision )
479 {
480 this.revision = revision;
481 }
482
483
484
485
486
487
488
489
490
491
492 protected final int compare( K key1, K key2 )
493 {
494 if ( key1 == key2 )
495 {
496 return 0;
497 }
498
499 if ( key1 == null )
500 {
501 return 1;
502 }
503
504 if ( key2 == null )
505 {
506 return -1;
507 }
508
509 return btree.getComparator().compare( key1, key2 );
510 }
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549 public int findPos( K key )
550 {
551
552 if ( nbElems == 0 )
553 {
554 return 0;
555 }
556
557 int min = 0;
558 int max = nbElems - 1;
559
560
561 while ( min < max )
562 {
563 int middle = ( min + max + 1 ) >> 1;
564
565 int comp = compare( keys[middle].getKey(), key );
566
567 if ( comp < 0 )
568 {
569 min = middle + 1;
570 }
571 else if ( comp > 0 )
572 {
573 max = middle - 1;
574 }
575 else
576 {
577
578
579
580 return -( middle + 1 );
581 }
582 }
583
584
585 int comp = compare( keys[max].getKey(), key );
586
587 if ( comp == 0 )
588 {
589 return -( max + 1 );
590 }
591 else
592 {
593 if ( comp < 0 )
594 {
595 return max + 1;
596 }
597 else
598 {
599 return max;
600 }
601 }
602 }
603
604
605
606
607
608 public Tuple<K, V> findLeftMost() throws EndOfFileExceededException, IOException
609 {
610 return children[0].getValue().findLeftMost();
611 }
612
613
614
615
616
617 public Tuple<K, V> findRightMost() throws EndOfFileExceededException, IOException
618 {
619 return children[nbElems].getValue().findRightMost();
620 }
621
622
623
624
625
626 public BTree<K, V> getBtree()
627 {
628 return btree;
629 }
630
631
632
633
634
635 public String dumpPage( String tabs )
636 {
637 StringBuilder sb = new StringBuilder();
638
639 if ( nbElems > 0 )
640 {
641
642 sb.append( children[0].getValue().dumpPage( tabs + " " ) );
643
644 for ( int i = 0; i < nbElems; i++ )
645 {
646 sb.append( tabs );
647 sb.append( "<" );
648 sb.append( getKey( i ) ).append( ">\n" );
649 sb.append( children[i + 1].getValue().dumpPage( tabs + " " ) );
650 }
651 }
652
653 return sb.toString();
654 }
655
656
657
658
659
660 public String toString()
661 {
662 StringBuilder sb = new StringBuilder();
663
664 sb.append( "r" ).append( revision );
665 sb.append( ", nbElems:" ).append( nbElems );
666
667 if ( offset > 0 )
668 {
669 sb.append( ", offset:" ).append( offset );
670 }
671
672 return sb.toString();
673 }
674 }