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.memory;
21
22
23 import static org.apache.directory.mavibot.btree.memory.InternalUtil.changeNextDupsContainer;
24 import static org.apache.directory.mavibot.btree.memory.InternalUtil.changePrevDupsContainer;
25 import static org.apache.directory.mavibot.btree.memory.InternalUtil.setDupsContainer;
26
27 import java.io.IOException;
28 import java.util.LinkedList;
29 import java.util.NoSuchElementException;
30
31 import org.apache.directory.mavibot.btree.Tuple;
32 import org.apache.directory.mavibot.btree.TupleCursor;
33 import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class CursorImpl<K, V> implements TupleCursor<K, V>
48 {
49
50 private Transaction<K, V> transaction;
51
52
53 private Tuple<K, V> tuple = new Tuple<K, V>();
54
55
56 private LinkedList<ParentPos<K, V>> stack;
57
58
59 private BTree<K, V> btree;
60
61 private boolean allowDuplicates;
62
63
64 private LinkedList<ParentPos<K, V>> _initialStack;
65
66
67
68
69
70
71
72
73 CursorImpl( BTree<K, V> btree, Transaction<K, V> transaction, LinkedList<ParentPos<K, V>> stack )
74 {
75 this.transaction = transaction;
76 this.stack = stack;
77 this.btree = btree;
78 this.allowDuplicates = btree.isAllowDuplicates();
79
80 _initialStack = new LinkedList<ParentPos<K, V>>();
81
82 cloneStack( stack, _initialStack );
83 }
84
85
86
87
88
89
90
91
92
93 public Tuple<K, V> next() throws EndOfFileExceededException, IOException
94 {
95 ParentPos<K, V> parentPos = stack.getFirst();
96
97 if ( parentPos.page == null )
98 {
99
100 throw new NoSuchElementException( "No more tuples present" );
101 }
102
103 if ( parentPos.pos == parentPos.page.getNbElems() )
104 {
105
106
107 parentPos = findNextParentPos();
108
109
110
111 if ( parentPos.page == null || ( parentPos.page instanceof Node ) )
112 {
113
114 throw new NoSuchElementException( "No more tuples present" );
115 }
116 }
117
118
119 if ( parentPos.pos < 0 )
120 {
121 parentPos.pos = 0;
122 }
123
124 Leaf<K, V> leaf = ( Leaf<K, V> ) ( parentPos.page );
125 tuple.setKey( leaf.keys[parentPos.pos] );
126
127 if ( allowDuplicates )
128 {
129 MultipleMemoryHolder<K, V> mvHolder = ( MultipleMemoryHolder<K, V> ) leaf.values[parentPos.pos];
130
131 if ( mvHolder.isSingleValue() )
132 {
133 tuple.setValue( mvHolder.getValue( btree ) );
134 parentPos.pos++;
135 }
136 else
137 {
138 setDupsContainer( parentPos, btree );
139
140
141 if ( parentPos.dupPos < 0 )
142 {
143 parentPos.dupPos = 0;
144 }
145
146 tuple.setValue( parentPos.dupsContainer.rootPage.getKey( parentPos.dupPos ) );
147 parentPos.dupPos++;
148
149 if ( parentPos.dupsContainer.getNbElems() == parentPos.dupPos )
150 {
151 parentPos.pos++;
152 changeNextDupsContainer( parentPos, btree );
153 }
154 }
155 }
156 else
157 {
158 tuple.setValue( leaf.values[parentPos.pos].getValue( btree ) );
159 parentPos.pos++;
160 }
161
162 return tuple;
163 }
164
165
166
167
168
169
170
171
172
173 private ParentPos<K, V> findNextParentPos() throws EndOfFileExceededException, IOException
174 {
175 ParentPos<K, V> lastParentPos = null;
176
177 while ( true )
178 {
179
180
181 ParentPos<K, V> parentPos = stack.peek();
182
183 if ( parentPos == null )
184 {
185 stack.push( lastParentPos );
186 return lastParentPos;
187 }
188
189 if ( parentPos.pos == parentPos.page.getNbElems() )
190 {
191 lastParentPos = stack.pop();
192 continue;
193 }
194 else
195 {
196
197 int newPos = ++parentPos.pos;
198 ParentPos<K, V> newParentPos = parentPos;
199
200 while ( newParentPos.page instanceof Node )
201 {
202 Node<K, V> node = ( Node<K, V> ) newParentPos.page;
203
204 newParentPos = new ParentPos<K, V>( node.children[newPos].getValue( btree ), 0 );
205
206 stack.push( newParentPos );
207
208 newPos = 0;
209 }
210
211 if ( allowDuplicates )
212 {
213 changeNextDupsContainer( newParentPos, btree );
214 }
215
216 return newParentPos;
217 }
218 }
219 }
220
221
222
223
224
225
226
227
228
229 private ParentPos<K, V> findPreviousParentPos() throws EndOfFileExceededException, IOException
230 {
231 ParentPos<K, V> lastParentPos = null;
232
233 while ( true )
234 {
235
236
237 ParentPos<K, V> parentPos = stack.peek();
238
239 if ( parentPos == null )
240 {
241 stack.push( lastParentPos );
242 return lastParentPos;
243 }
244
245 if ( parentPos.pos == 0 )
246 {
247 lastParentPos = stack.pop();
248 continue;
249 }
250 else
251 {
252
253 int newPos = --parentPos.pos;
254 ParentPos<K, V> newParentPos = parentPos;
255
256 while ( newParentPos.page instanceof Node )
257 {
258 Node<K, V> node = ( Node<K, V> ) newParentPos.page;
259
260 newParentPos = new ParentPos<K, V>( node.children[newPos].getValue( btree ), node.children[newPos]
261 .getValue( btree ).getNbElems() );
262
263 stack.push( newParentPos );
264
265 newPos = node.getNbElems();
266 }
267
268 if ( allowDuplicates )
269 {
270 changePrevDupsContainer( newParentPos, btree );
271 }
272
273 return newParentPos;
274 }
275 }
276 }
277
278
279
280
281
282
283
284
285
286 public Tuple<K, V> prev() throws EndOfFileExceededException, IOException
287 {
288 ParentPos<K, V> parentPos = stack.peek();
289
290 if ( parentPos.page == null )
291 {
292
293 throw new NoSuchElementException( "No more tuples present" );
294 }
295
296 if ( parentPos.pos == 0 && parentPos.dupPos == 0 )
297 {
298
299
300 parentPos = findPreviousParentPos();
301
302
303
304 if ( parentPos.page == null || ( parentPos.page instanceof Node ) )
305 {
306
307 throw new NoSuchElementException( "No more tuples present" );
308 }
309 }
310
311 Leaf<K, V> leaf = ( Leaf<K, V> ) ( parentPos.page );
312
313 if ( allowDuplicates )
314 {
315 boolean posDecremented = false;
316
317
318 if ( parentPos.pos == parentPos.page.getNbElems() )
319 {
320 parentPos.pos--;
321 posDecremented = true;
322 }
323
324 MultipleMemoryHolder<K, V> mvHolder = ( MultipleMemoryHolder<K, V> ) leaf.values[parentPos.pos];
325
326 boolean prevHasSubtree = false;
327
328 if ( mvHolder.isSingleValue() )
329 {
330 if ( !posDecremented )
331 {
332 parentPos.pos--;
333 mvHolder = ( MultipleMemoryHolder<K, V> ) leaf.values[parentPos.pos];
334 posDecremented = true;
335 }
336
337 if ( mvHolder.isSingleValue() )
338 {
339 tuple.setKey( leaf.keys[parentPos.pos] );
340 tuple.setValue( mvHolder.getValue( btree ) );
341 }
342 else
343 {
344 prevHasSubtree = true;
345 }
346 }
347 else
348 {
349 prevHasSubtree = true;
350 }
351
352 if ( prevHasSubtree )
353 {
354 setDupsContainer( parentPos, btree );
355
356 if ( parentPos.dupPos == parentPos.dupsContainer.getNbElems() )
357 {
358 parentPos.dupPos--;
359 }
360 else if ( parentPos.dupPos == 0 )
361 {
362 changePrevDupsContainer( parentPos, btree );
363 parentPos.pos--;
364
365 if ( parentPos.dupsContainer != null )
366 {
367 parentPos.dupPos--;
368 }
369 }
370 else
371 {
372 parentPos.dupPos--;
373 }
374
375 tuple.setKey( leaf.keys[parentPos.pos] );
376
377 if ( parentPos.dupsContainer != null )
378 {
379 tuple.setValue( parentPos.dupsContainer.rootPage.getKey( parentPos.dupPos ) );
380 }
381 else
382 {
383 tuple.setValue( leaf.values[parentPos.pos].getValue( btree ) );
384 }
385 }
386 }
387 else
388 {
389 parentPos.pos--;
390 tuple.setKey( leaf.keys[parentPos.pos] );
391 tuple.setValue( leaf.values[parentPos.pos].getValue( btree ) );
392 }
393
394 return tuple;
395 }
396
397
398
399
400
401
402
403
404 public boolean hasNext() throws EndOfFileExceededException, IOException
405 {
406 ParentPos<K, V> parentPos = stack.peek();
407
408 if ( parentPos.page == null )
409 {
410 return false;
411 }
412
413 for ( ParentPos<K, V> p : stack )
414 {
415 if ( allowDuplicates && ( p.page instanceof Leaf ) )
416 {
417 if ( ( p.dupsContainer == null ) && ( p.pos != p.page.getNbElems() ) )
418 {
419 return true;
420 }
421 else if ( ( p.dupsContainer != null ) && ( p.dupPos != p.dupsContainer.getNbElems() )
422 && ( p.pos != p.page.getNbElems() ) )
423 {
424 return true;
425 }
426 }
427 else if ( p.pos != p.page.getNbElems() )
428 {
429 return true;
430 }
431 }
432
433 return false;
434 }
435
436
437
438
439
440
441
442
443 public boolean hasPrev() throws EndOfFileExceededException, IOException
444 {
445 ParentPos<K, V> parentPos = stack.peek();
446
447 if ( parentPos.page == null )
448 {
449 return false;
450 }
451
452 for ( ParentPos<K, V> p : stack )
453 {
454 if ( allowDuplicates && ( p.page instanceof Leaf ) )
455 {
456 if ( ( p.dupsContainer == null ) && ( p.pos != 0 ) )
457 {
458 return true;
459 }
460 else if ( ( p.dupsContainer != null ) &&
461 ( ( p.dupPos != 0 ) || ( p.pos != 0 ) ) )
462 {
463 return true;
464 }
465 }
466 else if ( p.pos != 0 )
467 {
468 return true;
469 }
470 }
471
472 return false;
473 }
474
475
476
477
478
479 public void close()
480 {
481 transaction.close();
482 }
483
484
485
486
487
488 public long getRevision()
489 {
490 return transaction.getRevision();
491 }
492
493
494
495
496
497 public long getCreationDate()
498 {
499 return transaction.getCreationDate();
500 }
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520 public void moveToNextNonDuplicateKey() throws EndOfFileExceededException, IOException
521 {
522 ParentPos<K, V> parentPos = stack.getFirst();
523
524 if ( parentPos.page == null )
525 {
526 return;
527 }
528
529 if ( parentPos.pos == ( parentPos.page.getNbElems() - 1 ) )
530 {
531
532
533
534 parentPos.pos++;
535 ParentPos<K, V> nextPos = findNextParentPos();
536
537
538
539
540 if ( ( nextPos.page instanceof Node ) || ( nextPos == parentPos ) )
541 {
542 afterLast();
543 }
544 else
545 {
546 parentPos = nextPos;
547 }
548 }
549 else
550 {
551 parentPos.pos++;
552 changeNextDupsContainer( parentPos, btree );
553 }
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573 public void moveToPrevNonDuplicateKey() throws EndOfFileExceededException, IOException
574 {
575 ParentPos<K, V> parentPos = stack.peek();
576
577 if ( parentPos.page == null )
578 {
579
580 return;
581 }
582
583 if ( parentPos.pos == 0 )
584 {
585
586
587 parentPos = findPreviousParentPos();
588
589
590
591 if ( parentPos.page instanceof Node )
592 {
593 beforeFirst();
594 }
595 }
596 else
597 {
598 changePrevDupsContainer( parentPos, btree );
599 parentPos.pos--;
600 }
601 }
602
603
604
605
606
607
608
609
610
611
612
613 public void beforeFirst() throws IOException
614 {
615 cloneStack( _initialStack, stack );
616 }
617
618
619
620
621
622
623
624 public void afterLast() throws IOException
625 {
626 stack.clear();
627 stack = BTreeFactory.getPathToRightMostLeaf( btree );
628 }
629
630
631
632
633
634
635
636
637 private void cloneStack( LinkedList<ParentPos<K, V>> original, LinkedList<ParentPos<K, V>> clone )
638 {
639 clone.clear();
640
641
642 for ( ParentPos<K, V> o : original )
643 {
644 ParentPos<K, V> tmp = new ParentPos<K, V>( o.page, o.pos );
645 tmp.dupPos = o.dupPos;
646 tmp.dupsContainer = o.dupsContainer;
647 clone.add( tmp );
648 }
649 }
650
651 }