1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.partition.impl.btree.jdbm;
21
22
23 import jdbm.btree.BTree;
24
25 import org.apache.directory.server.core.avltree.AvlTree;
26 import org.apache.directory.server.core.avltree.AvlTreeCursor;
27 import org.apache.directory.server.core.cursor.Cursor;
28 import org.apache.directory.server.core.cursor.InvalidCursorPositionException;
29 import org.apache.directory.server.xdbm.Tuple;
30 import org.apache.directory.server.xdbm.AbstractTupleCursor;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35
36
37
38
39
40
41 class DupsCursor<K,V> extends AbstractTupleCursor<K,V>
42 {
43 private static final Logger LOG = LoggerFactory.getLogger( DupsCursor.class.getSimpleName() );
44
45
46
47
48 private final JdbmTable<K,V> table;
49
50
51
52
53
54
55
56 private final DupsContainerCursor<K,V> containerCursor;
57
58
59
60
61 private final Tuple<K,DupsContainer<V>> containerTuple = new Tuple<K, DupsContainer<V>>();
62
63
64
65
66
67
68
69
70 private Cursor<V> dupsCursor;
71
72
73
74
75
76
77 private final Tuple<K,V> returnedTuple = new Tuple<K,V>();
78
79
80
81
82 private boolean valueAvailable;
83
84
85 public DupsCursor( JdbmTable<K,V> table ) throws Exception
86 {
87 this.table = table;
88 this.containerCursor = new DupsContainerCursor<K,V>( table );
89 LOG.debug( "Created on table {}", table );
90 }
91
92
93 public boolean available()
94 {
95 return valueAvailable;
96 }
97
98
99 public void beforeKey( K key ) throws Exception
100 {
101 beforeValue( key, null );
102 }
103
104
105 public void beforeValue( K key, V value ) throws Exception
106 {
107 checkNotClosed( "beforeValue()" );
108 containerCursor.before( new Tuple<K,DupsContainer<V>>( key, null ) );
109
110 if ( containerCursor.next() )
111 {
112 containerTuple.setBoth( containerCursor.get() );
113 DupsContainer<V> values = containerTuple.getValue();
114
115 if ( values.isAvlTree() )
116 {
117 AvlTree<V> set = values.getAvlTree();
118 dupsCursor = new AvlTreeCursor<V>( set );
119 }
120 else
121 {
122 BTree tree = table.getBTree( values.getBTreeRedirect() );
123 dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
124 }
125
126 if ( value == null )
127 {
128 return;
129 }
130
131
132 if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
133 {
134 dupsCursor.before( value );
135 }
136
137 return;
138 }
139
140 clearValue();
141 containerTuple.setKey( null );
142 containerTuple.setValue( null );
143 }
144
145
146 public void afterKey( K key ) throws Exception
147 {
148 afterValue( key, null );
149 }
150
151
152 public void afterValue( K key, V value ) throws Exception
153 {
154 checkNotClosed( "afterValue()" );
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 if ( value == null )
177 {
178 containerCursor.after( new Tuple<K,DupsContainer<V>>( key, null ) );
179 }
180 else
181 {
182 containerCursor.before( new Tuple<K,DupsContainer<V>>( key, null ) );
183 }
184
185 if ( containerCursor.next() )
186 {
187 containerTuple.setBoth( containerCursor.get() );
188 DupsContainer<V> values = containerTuple.getValue();
189
190 if ( values.isAvlTree() )
191 {
192 AvlTree<V> set = values.getAvlTree();
193 dupsCursor = new AvlTreeCursor<V>( set );
194 }
195 else
196 {
197 BTree tree = table.getBTree( values.getBTreeRedirect() );
198 dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
199 }
200
201 if ( value == null )
202 {
203 return;
204 }
205
206
207 if ( table.getKeyComparator().compare( containerTuple.getKey(), key ) == 0 )
208 {
209 dupsCursor.after( value );
210 }
211
212 return;
213 }
214
215 clearValue();
216 containerTuple.setKey( null );
217 containerTuple.setValue( null );
218 }
219
220
221 public void before( Tuple<K,V> element ) throws Exception
222 {
223 beforeValue( element.getKey(), element.getValue() );
224 }
225
226
227 public void after( Tuple<K,V> element ) throws Exception
228 {
229 afterValue( element.getKey(), element.getValue() );
230 }
231
232
233 public void beforeFirst() throws Exception
234 {
235 checkNotClosed( "beforeFirst()" );
236 clearValue();
237 containerCursor.beforeFirst();
238 containerTuple.setKey( null );
239 containerTuple.setValue( null );
240 dupsCursor = null;
241 }
242
243
244 public void afterLast() throws Exception
245 {
246 checkNotClosed( "afterLast()" );
247 clearValue();
248 containerCursor.afterLast();
249 containerTuple.setKey( null );
250 containerTuple.setValue( null );
251 dupsCursor = null;
252 }
253
254
255 public boolean first() throws Exception
256 {
257 checkNotClosed( "first()" );
258 clearValue();
259 dupsCursor = null;
260
261 if ( containerCursor.first() )
262 {
263 containerTuple.setBoth( containerCursor.get() );
264 DupsContainer<V> values = containerTuple.getValue();
265
266 if ( containerTuple.getValue().isAvlTree() )
267 {
268 dupsCursor = new AvlTreeCursor<V>( values.getAvlTree() );
269 }
270 else
271 {
272 BTree bt = table.getBTree( values.getBTreeRedirect() );
273 dupsCursor = new KeyBTreeCursor<V>( bt, table.getValueComparator() );
274 }
275
276
277
278
279
280
281 dupsCursor.first();
282 valueAvailable = true;
283 returnedTuple.setKey( containerTuple.getKey() );
284 returnedTuple.setValue( dupsCursor.get() );
285 return true;
286 }
287
288 return false;
289 }
290
291
292 public boolean last() throws Exception
293 {
294 checkNotClosed( "last()" );
295 clearValue();
296 dupsCursor = null;
297
298 if ( containerCursor.last() )
299 {
300 containerTuple.setBoth( containerCursor.get() );
301 DupsContainer<V> values = containerTuple.getValue();
302
303 if ( values.isAvlTree() )
304 {
305 AvlTree<V> set = values.getAvlTree();
306 dupsCursor = new AvlTreeCursor<V>( set );
307 }
308 else
309 {
310 BTree tree = table.getBTree( values.getBTreeRedirect() );
311 dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
312 }
313
314
315
316
317
318
319 dupsCursor.last();
320 valueAvailable = true;
321 returnedTuple.setKey( containerTuple.getKey() );
322 returnedTuple.setValue( dupsCursor.get() );
323 return true;
324 }
325
326 return false;
327 }
328
329
330
331 private void clearValue()
332 {
333 returnedTuple.setKey( null );
334 returnedTuple.setValue( null );
335 valueAvailable = false;
336 }
337
338
339 public boolean previous() throws Exception
340 {
341 checkNotClosed( "previous()" );
342
343
344
345
346 if ( null == dupsCursor || ! dupsCursor.previous() )
347 {
348
349
350
351
352
353 if ( containerCursor.previous() )
354 {
355 containerTuple.setBoth( containerCursor.get() );
356 DupsContainer<V> values = containerTuple.getValue();
357
358 if ( values.isAvlTree() )
359 {
360 AvlTree<V> set = values.getAvlTree();
361 dupsCursor = new AvlTreeCursor<V>( set );
362 }
363 else
364 {
365 BTree tree = table.getBTree( values.getBTreeRedirect() );
366 dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
367 }
368
369
370
371
372
373
374
375 dupsCursor.afterLast();
376 dupsCursor.previous();
377 }
378 else
379 {
380 dupsCursor = null;
381 return false;
382 }
383 }
384
385 returnedTuple.setKey( containerTuple.getKey() );
386 returnedTuple.setValue( dupsCursor.get() );
387 return valueAvailable = true;
388 }
389
390
391 public boolean next() throws Exception
392 {
393 checkNotClosed( "next()" );
394
395
396
397
398 if ( null == dupsCursor || ! dupsCursor.next() )
399 {
400
401
402
403
404 if ( containerCursor.next() )
405 {
406 containerTuple.setBoth( containerCursor.get() );
407 DupsContainer<V> values = containerTuple.getValue();
408
409 if ( values.isAvlTree() )
410 {
411 AvlTree<V> set = values.getAvlTree();
412 dupsCursor = new AvlTreeCursor<V>( set );
413 }
414 else
415 {
416 BTree tree = table.getBTree( values.getBTreeRedirect() );
417 dupsCursor = new KeyBTreeCursor<V>( tree, table.getValueComparator() );
418 }
419
420
421
422
423
424
425
426 dupsCursor.beforeFirst();
427 dupsCursor.next();
428 }
429 else
430 {
431 dupsCursor = null;
432 return false;
433 }
434 }
435
436
437
438
439
440
441
442
443 returnedTuple.setKey( containerTuple.getKey() );
444 returnedTuple.setValue( dupsCursor.get() );
445 return valueAvailable = true;
446 }
447
448
449 public Tuple<K,V> get() throws Exception
450 {
451 checkNotClosed( "get()" );
452
453 if ( ! valueAvailable )
454 {
455 throw new InvalidCursorPositionException();
456 }
457
458 return returnedTuple;
459 }
460
461
462 public boolean isElementReused()
463 {
464 return true;
465 }
466 }