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