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