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.util.NoSuchElementException;
25
26 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
27
28
29
30
31
32
33
34
35
36
37
38
39 public class KeyCursor<K>
40 {
41
42 private static final int BEFORE_FIRST = -1;
43
44
45 private static final int AFTER_LAST = -2;
46
47
48 protected ParentPos<K, K>[] stack;
49
50
51 protected int depth = 0;
52
53
54 protected ReadTransaction<K, K> transaction;
55
56
57
58
59
60 protected KeyCursor()
61 {
62 }
63
64
65
66
67
68
69
70
71 public KeyCursor( ReadTransaction<K, K> transaction, ParentPos<K, K>[] stack, int depth )
72 {
73 this.transaction = transaction;
74 this.stack = stack;
75 this.depth = depth;
76 }
77
78
79
80
81
82 public void afterLast() throws IOException
83 {
84
85 if ( ( stack == null ) || ( stack.length == 0 ) )
86 {
87 return;
88 }
89
90 Page<K, K> child = null;
91
92 for ( int i = 0; i < depth; i++ )
93 {
94 ParentPos<K, K> parentPos = stack[i];
95
96 if ( child != null )
97 {
98 parentPos.page = child;
99 parentPos.pos = child.getNbElems();
100 }
101 else
102 {
103
104 parentPos.pos = parentPos.page.getNbElems();
105 }
106
107 child = ( ( AbstractPage<K, K> ) parentPos.page ).getPage( parentPos.pos );
108 }
109
110
111 ParentPos<K, K> parentPos = stack[depth];
112
113 if ( child == null )
114 {
115 parentPos.pos = parentPos.page.getNbElems() - 1;
116 }
117 else
118 {
119 parentPos.page = child;
120 parentPos.pos = child.getNbElems() - 1;
121 }
122
123 parentPos.pos = AFTER_LAST;
124 }
125
126
127
128
129
130 public void beforeFirst() throws IOException
131 {
132
133 if ( ( stack == null ) || ( stack.length == 0 ) )
134 {
135 return;
136 }
137
138 Page<K, K> child = null;
139
140 for ( int i = 0; i < depth; i++ )
141 {
142 ParentPos<K, K> parentPos = stack[i];
143 parentPos.pos = 0;
144
145 if ( child != null )
146 {
147 parentPos.page = child;
148 }
149
150 child = ( ( AbstractPage<K, K> ) parentPos.page ).getPage( 0 );
151 }
152
153
154 ParentPos<K, K> parentPos = stack[depth];
155 parentPos.pos = BEFORE_FIRST;
156
157 if ( child != null )
158 {
159 parentPos.page = child;
160 }
161 }
162
163
164
165
166
167
168
169
170
171 public boolean hasNext() throws EndOfFileExceededException, IOException
172 {
173
174 if ( ( stack == null ) || ( stack.length == 0 ) )
175 {
176 return false;
177 }
178
179
180 ParentPos<K, K> parentPos = stack[depth];
181
182 if ( parentPos.page == null )
183 {
184
185 return false;
186 }
187
188 if ( parentPos.pos == AFTER_LAST )
189 {
190 return false;
191 }
192
193 if ( parentPos.pos == BEFORE_FIRST )
194 {
195 return true;
196 }
197
198 if ( parentPos.pos < parentPos.page.getNbElems() - 1 )
199 {
200
201 return true;
202 }
203 else
204 {
205
206
207 int currentDepth = depth - 1;
208
209 while ( currentDepth >= 0 )
210 {
211 parentPos = stack[currentDepth];
212
213 if ( parentPos.pos < parentPos.page.getNbElems() )
214 {
215
216 return true;
217 }
218 else
219 {
220 currentDepth--;
221 }
222 }
223
224
225 return false;
226 }
227 }
228
229
230
231
232
233
234
235
236
237 public K next() throws EndOfFileExceededException, IOException
238 {
239
240 if ( ( stack == null ) || ( stack.length == 0 ) )
241 {
242 throw new NoSuchElementException( "No Key is present" );
243 }
244
245 ParentPos<K, K> parentPos = stack[depth];
246
247 if ( ( parentPos.page == null ) || ( parentPos.pos == AFTER_LAST ) )
248 {
249
250 throw new NoSuchElementException( "No more keys present" );
251 }
252
253 if ( parentPos.pos == parentPos.page.getNbElems() )
254 {
255
256
257 parentPos = findNextParentPos();
258
259
260
261 if ( ( parentPos == null ) || ( parentPos.page == null ) )
262 {
263
264 throw new NoSuchElementException( "No more keys present" );
265 }
266 }
267
268
269 if ( parentPos.pos == BEFORE_FIRST )
270 {
271 parentPos.pos++;
272 }
273 else
274 {
275 if ( parentPos.pos == parentPos.page.getNbElems() - 1 )
276 {
277 parentPos = findNextParentPos();
278
279 if ( ( parentPos == null ) || ( parentPos.page == null ) )
280 {
281
282 throw new NoSuchElementException( "No more keys present" );
283 }
284 }
285 else
286 {
287 parentPos.pos++;
288 }
289 }
290
291 AbstractPage<K, K> leaf = ( AbstractPage<K, K> ) ( parentPos.page );
292
293 return leaf.getKey( parentPos.pos );
294 }
295
296
297
298
299
300 public K nextKey() throws EndOfFileExceededException, IOException
301 {
302 return next();
303 }
304
305
306
307
308
309
310
311
312
313 public boolean hasNextKey() throws EndOfFileExceededException, IOException
314 {
315
316 if ( ( stack == null ) || ( stack.length == 0 ) )
317 {
318
319 return false;
320 }
321
322 ParentPos<K, K> parentPos = stack[depth];
323
324 if ( parentPos.page == null )
325 {
326
327 return false;
328 }
329
330 if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) )
331 {
332
333
334 return hasNextParentPos();
335 }
336 else
337 {
338 return true;
339 }
340 }
341
342
343
344
345
346
347
348
349
350 public boolean hasPrev() throws EndOfFileExceededException, IOException
351 {
352
353 if ( ( stack == null ) || ( stack.length == 0 ) )
354 {
355 return false;
356 }
357
358
359 ParentPos<K, K> parentPos = stack[depth];
360
361 if ( parentPos.page == null )
362 {
363
364 return false;
365 }
366
367 if ( parentPos.pos > 0 )
368 {
369
370 return true;
371 }
372 else
373 {
374
375 if ( parentPos.pos == BEFORE_FIRST )
376 {
377 return false;
378 }
379
380 if ( parentPos.pos == AFTER_LAST )
381 {
382 return true;
383 }
384
385
386
387 int currentDepth = depth - 1;
388
389 while ( currentDepth >= 0 )
390 {
391 parentPos = stack[currentDepth];
392
393 if ( parentPos.pos > 0 )
394 {
395
396 return true;
397 }
398 else
399 {
400 currentDepth--;
401 }
402 }
403
404 return false;
405 }
406 }
407
408
409
410
411
412
413
414
415
416 public K prev() throws EndOfFileExceededException, IOException
417 {
418
419 if ( ( stack == null ) || ( stack.length == 0 ) )
420 {
421 throw new NoSuchElementException( "No more keys present" );
422 }
423
424 ParentPos<K, K> parentPos = stack[depth];
425
426 if ( ( parentPos.page == null ) || ( parentPos.pos == BEFORE_FIRST ) )
427 {
428
429 throw new NoSuchElementException( "No more keys present" );
430 }
431
432
433 if ( parentPos.pos == AFTER_LAST )
434 {
435 parentPos.pos = parentPos.page.getNbElems() - 1;
436 }
437 else
438 {
439 if ( parentPos.pos == 0 )
440 {
441 parentPos = findPrevParentPos();
442
443 if ( ( parentPos == null ) || ( parentPos.page == null ) )
444 {
445
446 throw new NoSuchElementException( "No more keys present" );
447 }
448 }
449 else
450 {
451 parentPos.pos--;
452 }
453 }
454
455 AbstractPage<K, K> leaf = ( AbstractPage<K, K> ) ( parentPos.page );
456
457 return leaf.getKey( parentPos.pos );
458 }
459
460
461
462
463
464
465
466
467
468 public K prevKey() throws EndOfFileExceededException, IOException
469 {
470 return prev();
471 }
472
473
474
475
476
477
478
479
480
481 public boolean hasPrevKey() throws EndOfFileExceededException, IOException
482 {
483
484 if ( ( stack == null ) || ( stack.length == 0 ) )
485 {
486
487 return false;
488 }
489
490 ParentPos<K, K> parentPos = stack[depth];
491
492 if ( parentPos.page == null )
493 {
494
495 return false;
496 }
497
498 switch ( parentPos.pos )
499 {
500 case 0 :
501
502
503 return hasPrevParentPos();
504
505 case -1 :
506
507 return false;
508
509 default :
510
511 return true;
512 }
513 }
514
515
516
517
518
519
520
521
522
523 private boolean hasNextParentPos() throws EndOfFileExceededException, IOException
524 {
525 if ( depth == 0 )
526 {
527
528 return false;
529 }
530
531 int currentDepth = depth - 1;
532 Page<K, K> child = null;
533
534
535 while ( currentDepth >= 0 )
536 {
537
538
539 ParentPos<K, K> parentPos = stack[currentDepth];
540
541 if ( parentPos.pos + 1 > parentPos.page.getNbElems() )
542 {
543
544 currentDepth--;
545 }
546 else
547 {
548
549 child = ( ( AbstractPage<K, K> ) parentPos.page ).getPage( parentPos.pos + 1 );
550
551
552 while ( currentDepth < depth - 1 )
553 {
554 currentDepth++;
555 child = ( ( AbstractPage<K, K> ) child ).getPage( 0 );
556 }
557
558 return true;
559 }
560 }
561
562 return false;
563 }
564
565
566
567
568
569
570
571
572
573 private ParentPos<K, K> findNextParentPos() throws EndOfFileExceededException, IOException
574 {
575 if ( depth == 0 )
576 {
577
578 return null;
579 }
580
581 int currentDepth = depth - 1;
582 Page<K, K> child = null;
583
584
585 while ( currentDepth >= 0 )
586 {
587
588
589 ParentPos<K, K> parentPos = stack[currentDepth];
590
591 if ( parentPos.pos + 1 > parentPos.page.getNbElems() )
592 {
593
594 currentDepth--;
595 }
596 else
597 {
598
599 parentPos.pos++;
600 child = ( ( AbstractPage<K, K> ) parentPos.page ).getPage( parentPos.pos );
601
602
603 while ( currentDepth < depth - 1 )
604 {
605 currentDepth++;
606 parentPos = stack[currentDepth];
607 parentPos.pos = 0;
608 parentPos.page = child;
609 child = ( ( AbstractPage<K, K> ) child ).getPage( 0 );
610 }
611
612
613 parentPos = stack[depth];
614 parentPos.page = child;
615 parentPos.pos = 0;
616
617 return parentPos;
618 }
619 }
620
621 return null;
622 }
623
624
625
626
627
628
629
630
631
632 private ParentPos<K, K> findPrevParentPos() throws EndOfFileExceededException, IOException
633 {
634 if ( depth == 0 )
635 {
636
637 return null;
638 }
639
640 int currentDepth = depth - 1;
641 Page<K, K> child = null;
642
643
644 while ( currentDepth >= 0 )
645 {
646
647
648 ParentPos<K, K> parentPos = stack[currentDepth];
649
650 if ( parentPos.pos == 0 )
651 {
652
653 currentDepth--;
654 }
655 else
656 {
657
658 parentPos.pos--;
659 child = ( ( AbstractPage<K, K> ) parentPos.page ).getPage( parentPos.pos );
660
661
662 while ( currentDepth < depth - 1 )
663 {
664 currentDepth++;
665 parentPos = stack[currentDepth];
666 parentPos.pos = child.getNbElems();
667 parentPos.page = child;
668 child = ( ( AbstractPage<K, K> ) parentPos.page ).getPage( parentPos.page.getNbElems() );
669 }
670
671
672 parentPos = stack[depth];
673 parentPos.pos = child.getNbElems() - 1;
674 parentPos.page = child;
675
676 return parentPos;
677 }
678 }
679
680 return null;
681 }
682
683
684
685
686
687
688
689
690
691 private boolean hasPrevParentPos() throws EndOfFileExceededException, IOException
692 {
693 if ( depth == 0 )
694 {
695
696 return false;
697 }
698
699 int currentDepth = depth - 1;
700 Page<K, K> child = null;
701
702
703 while ( currentDepth >= 0 )
704 {
705
706
707 ParentPos<K, K> parentPos = stack[currentDepth];
708
709 if ( parentPos.pos == 0 )
710 {
711
712 currentDepth--;
713 }
714 else
715 {
716
717 child = ( ( AbstractPage<K, K> ) parentPos.page ).getPage( parentPos.pos - 1 );
718
719
720 while ( currentDepth < depth - 1 )
721 {
722 currentDepth++;
723 child = ( ( AbstractPage<K, K> ) child ).getPage( child.getNbElems() );
724 }
725
726 return true;
727 }
728 }
729
730 return false;
731 }
732
733
734
735
736
737 public void close()
738 {
739 transaction.close();
740 }
741
742
743
744
745
746
747 public long getCreationDate()
748 {
749 return transaction.getCreationDate();
750 }
751
752
753
754
755
756
757
758 public long getRevision()
759 {
760 return transaction.getRevision();
761 }
762
763
764 public String toString()
765 {
766 StringBuilder sb = new StringBuilder();
767
768 sb.append( "KeyCursor, depth = " ).append( depth ).append( "\n" );
769
770 for ( int i = 0; i <= depth; i++ )
771 {
772 sb.append( " " ).append( stack[i] ).append( "\n" );
773 }
774
775 return sb.toString();
776 }
777 }