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.mavibot;
21
22
23 import java.io.IOException;
24
25 import org.apache.directory.api.ldap.model.cursor.Cursor;
26 import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
27 import org.apache.directory.api.ldap.model.cursor.SingletonCursor;
28 import org.apache.directory.api.ldap.model.cursor.Tuple;
29 import org.apache.directory.api.ldap.model.exception.LdapException;
30 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
31 import org.apache.directory.api.ldap.model.schema.SchemaManager;
32 import org.apache.directory.mavibot.btree.BTree;
33 import org.apache.directory.mavibot.btree.BTreeFactory;
34 import org.apache.directory.mavibot.btree.RecordManager;
35 import org.apache.directory.mavibot.btree.TupleCursor;
36 import org.apache.directory.mavibot.btree.ValueCursor;
37 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
38 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
39 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
40 import org.apache.directory.server.core.api.partition.PartitionTxn;
41 import org.apache.directory.server.core.avltree.ArrayMarshaller;
42 import org.apache.directory.server.core.avltree.ArrayTree;
43 import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
44 import org.apache.directory.server.i18n.I18n;
45 import org.apache.directory.server.xdbm.AbstractTable;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49
50
51
52
53
54
55 public class MavibotTable<K, V> extends AbstractTable<K, V>
56 {
57
58 private BTree<K, V> bt;
59
60
61 private ArrayMarshaller<V> arrayMarshaller;
62
63
64 private static final Logger LOG = LoggerFactory.getLogger( MavibotTable.class );
65
66
67 protected RecordManager recordMan;
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public MavibotTable( RecordManager recordMan, SchemaManager schemaManager, String name,
82 ElementSerializer<K> keySerializer, ElementSerializer<V> valueSerializer, boolean allowDuplicates )
83 throws IOException
84 {
85 this( recordMan, schemaManager, name, keySerializer, valueSerializer, allowDuplicates,
86 AbstractBTreePartition.DEFAULT_CACHE_SIZE );
87 }
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 public MavibotTable( RecordManager recordMan, SchemaManager schemaManager, String name,
103 ElementSerializer<K> keySerializer, ElementSerializer<V> valueSerializer, boolean allowDuplicates, int cacheSize )
104 throws IOException
105 {
106 super( schemaManager, name, keySerializer.getComparator(), valueSerializer.getComparator() );
107 this.recordMan = recordMan;
108
109 bt = recordMan.getManagedTree( name );
110
111 if ( bt == null )
112 {
113 bt = BTreeFactory.createPersistedBTree( name, keySerializer, valueSerializer, allowDuplicates, cacheSize );
114
115 try
116 {
117 recordMan.manage( bt );
118 }
119 catch ( BTreeAlreadyManagedException e )
120 {
121
122 throw new RuntimeException( e );
123 }
124 }
125 else
126 {
127
128
129 bt.setKeySerializer( keySerializer );
130 bt.setValueSerializer( valueSerializer );
131 }
132
133 this.allowsDuplicates = allowDuplicates;
134 arrayMarshaller = new ArrayMarshaller<>( valueComparator );
135
136
137 count = bt.getNbElems();
138 }
139
140
141
142
143
144 @Override
145 public boolean has( PartitionTxn partitionTxn, K key ) throws LdapException
146 {
147 try
148 {
149 return bt.hasKey( key );
150 }
151 catch ( IOException ioe )
152 {
153 throw new LdapException( ioe );
154 }
155 catch ( KeyNotFoundException knfe )
156 {
157 throw new LdapException( knfe );
158 }
159 }
160
161
162
163
164
165 @Override
166 public boolean has( PartitionTxn transaction, K key, V value ) throws LdapException
167 {
168 try
169 {
170 return bt.contains( key, value );
171 }
172 catch ( IOException e )
173 {
174 throw new LdapException( e );
175 }
176 }
177
178
179
180
181
182 @Override
183 public boolean hasGreaterOrEqual( PartitionTxn transaction, K key ) throws LdapException
184 {
185 TupleCursor<K, V> cursor = null;
186
187 try
188 {
189 cursor = bt.browseFrom( key );
190
191 return cursor.hasNext();
192 }
193 catch ( IOException ioe )
194 {
195 throw new LdapOtherException( ioe.getMessage() );
196 }
197 finally
198 {
199 if ( cursor != null )
200 {
201 cursor.close();
202 }
203 }
204 }
205
206
207
208
209
210 @Override
211 public boolean hasLessOrEqual( PartitionTxn transaction, K key ) throws LdapException
212 {
213 TupleCursor<K, V> cursor = null;
214
215 try
216 {
217 cursor = bt.browseFrom( key );
218
219 org.apache.directory.mavibot.btree.Tuple<K, V> tuple = null;
220
221 if ( cursor.hasNext() )
222 {
223 tuple = cursor.next();
224 }
225
226
227 if ( null != tuple && keyComparator.compare( tuple.getKey(), key ) == 0 )
228 {
229 return true;
230 }
231
232 if ( null == tuple )
233 {
234 return count > 0;
235 }
236 else
237 {
238 if ( cursor.hasPrev() )
239 {
240 return true;
241 }
242 }
243
244 return false;
245 }
246 catch ( Exception e )
247 {
248 throw new LdapException( e );
249 }
250 finally
251 {
252 if ( cursor != null )
253 {
254 cursor.close();
255 }
256 }
257 }
258
259
260
261
262
263 @Override
264 public boolean hasGreaterOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
265 {
266 if ( key == null )
267 {
268 return false;
269 }
270
271 if ( !allowsDuplicates )
272 {
273 throw new UnsupportedOperationException( I18n.err( I18n.ERR_593 ) );
274 }
275
276 ValueCursor<V> valueCursor = null;
277
278 try
279 {
280 if ( !bt.hasKey( key ) )
281 {
282 return false;
283 }
284
285 valueCursor = bt.getValues( key );
286
287 int equal = bt.getValueSerializer().compare( val, valueCursor.next() );
288
289 return ( equal >= 0 );
290 }
291 catch ( KeyNotFoundException | IOException e )
292 {
293 throw new LdapException( e.getMessage() );
294 }
295 finally
296 {
297 if ( valueCursor != null )
298 {
299 valueCursor.close();
300 }
301 }
302 }
303
304
305
306
307
308 @Override
309 public boolean hasLessOrEqual( PartitionTxn partitionTxn, K key, V val ) throws LdapException
310 {
311 if ( key == null )
312 {
313 return false;
314 }
315
316 if ( !allowsDuplicates )
317 {
318 throw new UnsupportedOperationException( I18n.err( I18n.ERR_593 ) );
319 }
320
321 try
322 {
323 if ( !bt.hasKey( key ) )
324 {
325 return false;
326 }
327
328 ValueCursor<V> dupHolder = bt.getValues( key );
329
330 return dupHolder.hasNext();
331 }
332 catch ( KeyNotFoundException knfe )
333 {
334 throw new LdapOtherException( knfe.getMessage(), knfe );
335 }
336 catch ( IOException ioe )
337 {
338 throw new LdapOtherException( ioe.getMessage(), ioe );
339 }
340 }
341
342
343
344
345
346 @Override
347 public V get( PartitionTxn transaction, K key ) throws LdapException
348 {
349 if ( key == null )
350 {
351 return null;
352 }
353
354 try
355 {
356 return bt.get( key );
357 }
358 catch ( KeyNotFoundException knfe )
359 {
360 return null;
361 }
362 catch ( Exception e )
363 {
364 throw new LdapException( e );
365 }
366 }
367
368
369
370
371
372 @Override
373 public void put( PartitionTxn partitionTxn, K key, V value ) throws LdapException
374 {
375 try
376 {
377 if ( ( value == null ) || ( key == null ) )
378 {
379 throw new IllegalArgumentException( I18n.err( I18n.ERR_594 ) );
380 }
381
382 V existingVal = bt.insert( key, value );
383
384 if ( existingVal == null )
385 {
386 count++;
387 }
388 }
389 catch ( IOException ioe )
390 {
391 LOG.error( I18n.err( I18n.ERR_131, key, name ), ioe );
392 throw new LdapOtherException( ioe.getMessage(), ioe );
393 }
394 }
395
396
397
398
399
400 @Override
401 public void remove( PartitionTxn partitionTxn, K key ) throws LdapException
402 {
403 try
404 {
405 if ( key == null )
406 {
407 return;
408 }
409
410
411 if ( bt.isAllowDuplicates() )
412 {
413 ValueCursor<V> valueCursor = bt.getValues( key );
414 int size = valueCursor.size();
415 valueCursor.close();
416 org.apache.directory.mavibot.btree.Tuple<K, V> returned = bt.delete( key );
417
418 if ( null == returned )
419 {
420 return;
421 }
422
423 count -= size;
424 }
425 else
426 {
427 org.apache.directory.mavibot.btree.Tuple<K, V> returned = bt.delete( key );
428
429 if ( null == returned )
430 {
431 return;
432 }
433
434 count--;
435 }
436 }
437 catch ( IOException | KeyNotFoundException e )
438 {
439 LOG.error( I18n.err( I18n.ERR_133, key, name ), e );
440
441 throw new LdapOtherException( e.getMessage(), e );
442 }
443 }
444
445
446
447
448
449 @Override
450 public void remove( PartitionTxn partitionTxn, K key, V value ) throws LdapException
451 {
452 try
453 {
454 if ( key == null )
455 {
456 return;
457 }
458
459 org.apache.directory.mavibot.btree.Tuple<K, V> tuple = bt.delete( key, value );
460
461
462 if ( tuple != null )
463 {
464 count--;
465 }
466 }
467 catch ( Exception e )
468 {
469 LOG.error( I18n.err( I18n.ERR_132, key, value, name ), e );
470 }
471 }
472
473
474
475
476
477 @Override
478 public Cursor<Tuple<K, V>> cursor()
479 {
480 return new MavibotCursor<>( this );
481 }
482
483
484
485
486
487 @Override
488 public Cursor<Tuple<K, V>> cursor( PartitionTxn partitionTxn, K key ) throws LdapException
489 {
490 if ( key == null )
491 {
492 return new EmptyCursor<>();
493 }
494
495 try
496 {
497 if ( !allowsDuplicates )
498 {
499 V val = bt.get( key );
500
501 return new SingletonCursor<>( new Tuple<K, V>( key, val ) );
502 }
503 else
504 {
505 ValueCursor<V> dupHolder = bt.getValues( key );
506
507 return new KeyTupleValueCursor<>( dupHolder, key );
508 }
509 }
510 catch ( KeyNotFoundException knfe )
511 {
512 return new EmptyCursor<>();
513 }
514 catch ( Exception e )
515 {
516 throw new LdapException( e );
517 }
518 }
519
520
521
522
523
524 @Override
525 public Cursor<V> valueCursor( PartitionTxn transaction, K key ) throws LdapException
526 {
527 if ( key == null )
528 {
529 return new EmptyCursor<>();
530 }
531
532 try
533 {
534 if ( !allowsDuplicates )
535 {
536 V val = bt.get( key );
537
538 return new SingletonCursor<>( val );
539 }
540 else
541 {
542 ValueCursor<V> dupCursor = bt.getValues( key );
543
544 return new ValueTreeCursor<>( dupCursor );
545 }
546 }
547 catch ( KeyNotFoundException knfe )
548 {
549 return new EmptyCursor<>();
550 }
551 catch ( Exception e )
552 {
553 throw new LdapException( e );
554 }
555 }
556
557
558
559
560
561 @Override
562 public synchronized void close( PartitionTxn transaction ) throws LdapException
563 {
564 try
565 {
566 sync();
567 }
568 catch ( IOException ioe )
569 {
570 throw new LdapOtherException( ioe.getMessage() );
571 }
572 }
573
574
575
576
577
578 @Override
579 public long count( PartitionTxn transaction, K key ) throws LdapException
580 {
581 if ( key == null )
582 {
583 return 0;
584 }
585
586 try
587 {
588 if ( bt.isAllowDuplicates() )
589 {
590 ValueCursor<V> dupHolder = bt.getValues( key );
591 int size = dupHolder.size();
592 dupHolder.close();
593
594 return size;
595 }
596 else
597 {
598 if ( bt.hasKey( key ) )
599 {
600 return 1;
601 }
602 else
603 {
604 return 0;
605 }
606 }
607 }
608 catch ( KeyNotFoundException knfe )
609 {
610
611 return 0;
612 }
613 catch ( IOException ioe )
614 {
615 throw new LdapOtherException( ioe.getMessage() );
616 }
617 }
618
619
620
621
622
623 public ArrayTree<V> getDupsContainer( byte[] serialized ) throws IOException
624 {
625 if ( serialized == null )
626 {
627 return new ArrayTree<>( valueComparator );
628 }
629
630 return arrayMarshaller.deserialize( serialized );
631 }
632
633
634
635
636
637 protected BTree<K, V> getBTree()
638 {
639 return bt;
640 }
641
642
643
644
645
646
647
648 public synchronized void sync() throws IOException
649 {
650 }
651
652
653
654
655
656 @Override
657 public String toString()
658 {
659 StringBuilder sb = new StringBuilder();
660
661 sb.append( "Mavibot table :\n" ).append( super.toString() );
662
663 return sb.toString();
664 }
665 }