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
40 public class TupleCursor<K, V>
41 {
42
43 private static final int BEFORE_FIRST = -1;
44
45
46 private static final int AFTER_LAST = -2;
47
48
49 protected ParentPos<K, V>[] stack;
50
51
52 protected int depth = 0;
53
54
55 protected ReadTransaction<K, V> transaction;
56
57
58 protected Tuple<K, V> tuple = new Tuple<K, V>();
59
60
61
62
63
64 protected TupleCursor()
65 {
66 }
67
68
69
70
71
72
73
74
75 public TupleCursor( ReadTransaction<K, V> transaction, ParentPos<K, V>[] stack, int depth )
76 {
77 this.transaction = transaction;
78 this.stack = stack;
79 this.depth = depth;
80 }
81
82
83
84
85
86 public void afterLast() throws IOException
87 {
88
89 if ( ( stack == null ) || ( stack.length == 0 ) )
90 {
91 return;
92 }
93
94 Page<K, V> child = null;
95
96 for ( int i = 0; i < depth; i++ )
97 {
98 ParentPos<K, V> parentPos = stack[i];
99
100 if ( child != null )
101 {
102 parentPos.page = child;
103 parentPos.pos = child.getNbElems();
104 }
105 else
106 {
107
108 parentPos.pos = parentPos.page.getNbElems();
109 }
110
111 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos );
112 }
113
114
115 ParentPos<K, V> parentPos = stack[depth];
116
117 if ( child == null )
118 {
119 parentPos.pos = parentPos.page.getNbElems() - 1;
120 }
121 else
122 {
123 parentPos.page = child;
124 parentPos.pos = child.getNbElems() - 1;
125 }
126
127 parentPos.valueCursor = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos ).getCursor();
128 parentPos.valueCursor.afterLast();
129 parentPos.pos = AFTER_LAST;
130 }
131
132
133
134
135
136 public void beforeFirst() throws IOException
137 {
138
139 if ( ( stack == null ) || ( stack.length == 0 ) )
140 {
141 return;
142 }
143
144 Page<K, V> child = null;
145
146 for ( int i = 0; i < depth; i++ )
147 {
148 ParentPos<K, V> parentPos = stack[i];
149 parentPos.pos = 0;
150
151 if ( child != null )
152 {
153 parentPos.page = child;
154 }
155
156 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( 0 );
157 }
158
159
160 ParentPos<K, V> parentPos = stack[depth];
161 parentPos.pos = BEFORE_FIRST;
162
163 if ( child != null )
164 {
165 parentPos.page = child;
166 }
167
168 if ( parentPos.valueCursor != null )
169 {
170 parentPos.valueCursor = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( 0 ).getCursor();
171 parentPos.valueCursor.beforeFirst();
172 }
173 }
174
175
176
177
178
179
180
181
182
183 public boolean hasNext() throws EndOfFileExceededException, IOException
184 {
185
186 if ( ( stack == null ) || ( stack.length == 0 ) )
187 {
188 return false;
189 }
190
191
192 ParentPos<K, V> parentPos = stack[depth];
193
194 if ( parentPos.page == null )
195 {
196
197 return false;
198 }
199
200 if ( parentPos.pos == AFTER_LAST )
201 {
202 return false;
203 }
204
205 if ( parentPos.pos < parentPos.page.getNbElems() - 1 )
206 {
207
208 return true;
209 }
210 else
211 {
212
213 if ( parentPos.valueCursor.hasNext() )
214 {
215 return true;
216 }
217
218
219
220 int currentDepth = depth - 1;
221
222 while ( currentDepth >= 0 )
223 {
224 parentPos = stack[currentDepth];
225
226 if ( parentPos.pos < parentPos.page.getNbElems() )
227 {
228
229 return true;
230 }
231 else
232 {
233 currentDepth--;
234 }
235 }
236
237
238 return false;
239 }
240 }
241
242
243
244
245
246
247
248
249
250 public Tuple<K, V> next() throws EndOfFileExceededException, IOException
251 {
252
253 if ( ( stack == null ) || ( stack.length == 0 ) )
254 {
255 throw new NoSuchElementException( "No tuple present" );
256 }
257
258 ParentPos<K, V> parentPos = stack[depth];
259
260 if ( ( parentPos.page == null ) || ( parentPos.pos == AFTER_LAST ) )
261 {
262
263 throw new NoSuchElementException( "No more tuples present" );
264 }
265
266 if ( parentPos.pos == parentPos.page.getNbElems() )
267 {
268
269
270 parentPos = findNextParentPos();
271
272
273
274 if ( ( parentPos == null ) || ( parentPos.page == null ) )
275 {
276
277 throw new NoSuchElementException( "No more tuples present" );
278 }
279 }
280
281 V value = null;
282
283 if ( parentPos.valueCursor.hasNext() )
284 {
285
286 if ( parentPos.pos == BEFORE_FIRST )
287 {
288 parentPos.pos++;
289 }
290
291 value = parentPos.valueCursor.next();
292 }
293 else
294 {
295 if ( parentPos.pos == parentPos.page.getNbElems() - 1 )
296 {
297 parentPos = findNextParentPos();
298
299 if ( ( parentPos == null ) || ( parentPos.page == null ) )
300 {
301
302 throw new NoSuchElementException( "No more tuples present" );
303 }
304 }
305 else
306 {
307 parentPos.pos++;
308 }
309
310 try
311 {
312 ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
313
314 parentPos.valueCursor = valueHolder.getCursor();
315
316 value = parentPos.valueCursor.next();
317 }
318 catch ( IllegalArgumentException e )
319 {
320 e.printStackTrace();
321 }
322 }
323
324 AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
325 tuple.setKey( leaf.getKey( parentPos.pos ) );
326 tuple.setValue( value );
327
328 return tuple;
329 }
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350 public Tuple<K, V> nextKey() throws EndOfFileExceededException, IOException
351 {
352
353 if ( ( stack == null ) || ( stack.length == 0 ) )
354 {
355
356 throw new NoSuchElementException( "No more tuples present" );
357 }
358
359 ParentPos<K, V> parentPos = stack[depth];
360
361 if ( parentPos.page == null )
362 {
363
364 throw new NoSuchElementException( "No more tuples present" );
365 }
366
367 if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) )
368 {
369
370
371 ParentPos<K, V> newParentPos = findNextParentPos();
372
373
374
375 if ( ( newParentPos == null ) || ( newParentPos.page == null ) )
376 {
377
378 AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
379 ValueHolder<V> valueHolder = leaf.getValue( parentPos.pos );
380 parentPos.pos = AFTER_LAST;
381 parentPos.valueCursor = valueHolder.getCursor();
382 parentPos.valueCursor.afterLast();
383
384 return null;
385 }
386 else
387 {
388 parentPos = newParentPos;
389 }
390 }
391 else
392 {
393
394 parentPos.pos++;
395 }
396
397
398 AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
399 tuple.setKey( leaf.getKey( parentPos.pos ) );
400
401
402 ValueHolder<V> valueHolder = leaf.getValue( parentPos.pos );
403 parentPos.valueCursor = valueHolder.getCursor();
404 V value = parentPos.valueCursor.next();
405 tuple.setValue( value );
406
407 return tuple;
408 }
409
410
411
412
413
414
415
416
417
418 public boolean hasNextKey() throws EndOfFileExceededException, IOException
419 {
420
421 if ( ( stack == null ) || ( stack.length == 0 ) )
422 {
423
424 return false;
425 }
426
427 ParentPos<K, V> parentPos = stack[depth];
428
429 if ( parentPos.page == null )
430 {
431
432 return false;
433 }
434
435 if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) )
436 {
437
438
439 return hasNextParentPos();
440 }
441 else
442 {
443 return true;
444 }
445 }
446
447
448
449
450
451
452
453
454
455 public boolean hasPrev() throws EndOfFileExceededException, IOException
456 {
457
458 if ( ( stack == null ) || ( stack.length == 0 ) )
459 {
460 return false;
461 }
462
463
464 ParentPos<K, V> parentPos = stack[depth];
465
466 if ( parentPos.page == null )
467 {
468
469 return false;
470 }
471
472 if ( parentPos.pos > 0 )
473 {
474
475 return true;
476 }
477 else
478 {
479
480 if ( parentPos.pos == BEFORE_FIRST )
481 {
482 return false;
483 }
484
485
486 if ( parentPos.valueCursor.hasPrev() )
487 {
488 return true;
489 }
490
491
492
493 int currentDepth = depth - 1;
494
495 while ( currentDepth >= 0 )
496 {
497 parentPos = stack[currentDepth];
498
499 if ( parentPos.pos > 0 )
500 {
501
502 return true;
503 }
504 else
505 {
506 currentDepth--;
507 }
508 }
509
510 return false;
511 }
512 }
513
514
515
516
517
518
519
520
521
522 public Tuple<K, V> prev() throws EndOfFileExceededException, IOException
523 {
524
525 if ( ( stack == null ) || ( stack.length == 0 ) )
526 {
527 throw new NoSuchElementException( "No more tuple present" );
528 }
529
530 ParentPos<K, V> parentPos = stack[depth];
531
532 if ( ( parentPos.page == null ) || ( parentPos.pos == BEFORE_FIRST ) )
533 {
534
535 throw new NoSuchElementException( "No more tuples present" );
536 }
537
538 if ( ( parentPos.pos == 0 ) && ( !parentPos.valueCursor.hasPrev() ) )
539 {
540
541
542 parentPos = findPrevParentPos();
543
544
545
546 if ( ( parentPos == null ) || ( parentPos.page == null ) )
547 {
548
549 throw new NoSuchElementException( "No more tuples present" );
550 }
551 }
552
553 V value = null;
554
555 if ( parentPos.valueCursor.hasPrev() )
556 {
557
558 if ( parentPos.pos == AFTER_LAST )
559 {
560 parentPos.pos = parentPos.page.getNbElems() - 1;
561 }
562
563 value = parentPos.valueCursor.prev();
564 }
565 else
566 {
567 if ( parentPos.pos == 0 )
568 {
569 parentPos = findPrevParentPos();
570
571 if ( ( parentPos == null ) || ( parentPos.page == null ) )
572 {
573
574 throw new NoSuchElementException( "No more tuples present" );
575 }
576 }
577 else
578 {
579 parentPos.pos--;
580
581 try
582 {
583 ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
584
585 parentPos.valueCursor = valueHolder.getCursor();
586 parentPos.valueCursor.afterLast();
587
588 value = parentPos.valueCursor.prev();
589 }
590 catch ( IllegalArgumentException e )
591 {
592 e.printStackTrace();
593 }
594 }
595 }
596
597 AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
598 tuple.setKey( leaf.getKey( parentPos.pos ) );
599 tuple.setValue( value );
600
601 return tuple;
602 }
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623 public Tuple<K, V> prevKey() throws EndOfFileExceededException, IOException
624 {
625
626 if ( ( stack == null ) || ( stack.length == 0 ) )
627 {
628
629 throw new NoSuchElementException( "No more tuples present" );
630 }
631
632 ParentPos<K, V> parentPos = stack[depth];
633
634 if ( parentPos.page == null )
635 {
636
637 throw new NoSuchElementException( "No more tuples present" );
638 }
639
640 if ( parentPos.pos == 0 )
641 {
642
643
644 parentPos = findPrevParentPos();
645
646 if ( ( parentPos == null ) || ( parentPos.page == null ) )
647 {
648
649 throw new NoSuchElementException( "No more tuples present" );
650 }
651 }
652 else
653 {
654 if ( parentPos.pos == AFTER_LAST )
655 {
656 parentPos.pos = parentPos.page.getNbElems() - 1;
657 }
658 else
659 {
660 parentPos.pos--;
661 }
662 }
663
664
665 AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
666
667
668 tuple.setKey( leaf.getKey( parentPos.pos ) );
669
670
671 ValueHolder<V> valueHolder = leaf.getValue( parentPos.pos );
672 parentPos.valueCursor = valueHolder.getCursor();
673 V value = parentPos.valueCursor.next();
674 tuple.setValue( value );
675
676 return tuple;
677 }
678
679
680
681
682
683
684
685
686
687 public boolean hasPrevKey() throws EndOfFileExceededException, IOException
688 {
689
690 if ( ( stack == null ) || ( stack.length == 0 ) )
691 {
692
693 return false;
694 }
695
696 ParentPos<K, V> parentPos = stack[depth];
697
698 if ( parentPos.page == null )
699 {
700
701 return false;
702 }
703
704 switch ( parentPos.pos )
705 {
706 case 0 :
707
708
709 return hasPrevParentPos();
710
711 case -1 :
712
713 return false;
714
715 default :
716
717 return true;
718 }
719 }
720
721
722
723
724
725
726
727
728
729 private boolean hasNextParentPos() throws EndOfFileExceededException, IOException
730 {
731 if ( depth == 0 )
732 {
733
734 return false;
735 }
736
737 int currentDepth = depth - 1;
738 Page<K, V> child = null;
739
740
741 while ( currentDepth >= 0 )
742 {
743
744
745 ParentPos<K, V> parentPos = stack[currentDepth];
746
747 if ( parentPos.pos + 1 > parentPos.page.getNbElems() )
748 {
749
750 currentDepth--;
751 }
752 else
753 {
754
755 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos + 1 );
756
757
758 while ( currentDepth < depth - 1 )
759 {
760 currentDepth++;
761 child = ( ( AbstractPage<K, V> ) child ).getPage( 0 );
762 }
763
764 return true;
765 }
766 }
767
768 return false;
769 }
770
771
772
773
774
775
776
777
778
779 private ParentPos<K, V> findNextParentPos() throws EndOfFileExceededException, IOException
780 {
781 if ( depth == 0 )
782 {
783
784 return null;
785 }
786
787 int currentDepth = depth - 1;
788 Page<K, V> child = null;
789
790
791 while ( currentDepth >= 0 )
792 {
793
794
795 ParentPos<K, V> parentPos = stack[currentDepth];
796
797 if ( parentPos.pos + 1 > parentPos.page.getNbElems() )
798 {
799
800 currentDepth--;
801 }
802 else
803 {
804
805 parentPos.pos++;
806 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos );
807
808
809 while ( currentDepth < depth - 1 )
810 {
811 currentDepth++;
812 parentPos = stack[currentDepth];
813 parentPos.pos = 0;
814 parentPos.page = child;
815 child = ( ( AbstractPage<K, V> ) child ).getPage( 0 );
816 }
817
818
819 parentPos = stack[depth];
820 parentPos.page = child;
821 parentPos.pos = 0;
822 parentPos.valueCursor = ( ( AbstractPage<K, V> ) child ).getValue( 0 ).getCursor();
823
824 return parentPos;
825 }
826 }
827
828 return null;
829 }
830
831
832
833
834
835
836
837
838
839 private ParentPos<K, V> findPrevParentPos() throws EndOfFileExceededException, IOException
840 {
841 if ( depth == 0 )
842 {
843
844 return null;
845 }
846
847 int currentDepth = depth - 1;
848 Page<K, V> child = null;
849
850
851 while ( currentDepth >= 0 )
852 {
853
854
855 ParentPos<K, V> parentPos = stack[currentDepth];
856
857 if ( parentPos.pos == 0 )
858 {
859
860 currentDepth--;
861 }
862 else
863 {
864
865 parentPos.pos--;
866 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos );
867
868
869 while ( currentDepth < depth - 1 )
870 {
871 currentDepth++;
872 parentPos = stack[currentDepth];
873 parentPos.pos = child.getNbElems();
874 parentPos.page = child;
875 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.page.getNbElems() );
876 }
877
878
879 parentPos = stack[depth];
880 parentPos.pos = child.getNbElems() - 1;
881 parentPos.page = child;
882 ValueHolder<V> valueHolder = ( ( AbstractPage<K, V> ) parentPos.page ).getValue( parentPos.pos );
883 parentPos.valueCursor = valueHolder.getCursor();
884 parentPos.valueCursor.afterLast();
885
886 return parentPos;
887 }
888 }
889
890 return null;
891 }
892
893
894
895
896
897
898
899
900
901 private boolean hasPrevParentPos() throws EndOfFileExceededException, IOException
902 {
903 if ( depth == 0 )
904 {
905
906 return false;
907 }
908
909 int currentDepth = depth - 1;
910 Page<K, V> child = null;
911
912
913 while ( currentDepth >= 0 )
914 {
915
916
917 ParentPos<K, V> parentPos = stack[currentDepth];
918
919 if ( parentPos.pos == 0 )
920 {
921
922 currentDepth--;
923 }
924 else
925 {
926
927 child = ( ( AbstractPage<K, V> ) parentPos.page ).getPage( parentPos.pos - 1 );
928
929
930 while ( currentDepth < depth - 1 )
931 {
932 currentDepth++;
933 child = ( ( AbstractPage<K, V> ) child ).getPage( child.getNbElems() );
934 }
935
936 return true;
937 }
938 }
939
940 return false;
941 }
942
943
944
945
946
947 public void close()
948 {
949 transaction.close();
950 }
951
952
953
954
955
956
957 public long getCreationDate()
958 {
959 return transaction.getCreationDate();
960 }
961
962
963
964
965
966
967
968 public long getRevision()
969 {
970 return transaction.getRevision();
971 }
972
973
974 public String toString()
975 {
976 StringBuilder sb = new StringBuilder();
977
978 sb.append( "TupleCursor, depth = " ).append( depth ).append( "\n" );
979
980 for ( int i = 0; i <= depth; i++ )
981 {
982 sb.append( " " ).append( stack[i] ).append( "\n" );
983 }
984
985 return sb.toString();
986 }
987 }