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.RecordManager;
24 import jdbm.helper.MRU;
25 import jdbm.recman.BaseRecordManager;
26 import jdbm.recman.CacheRecordManager;
27 import org.apache.directory.server.core.partition.impl.btree.*;
28 import org.apache.directory.server.core.cursor.Cursor;
29 import org.apache.directory.server.schema.SerializableComparator;
30 import org.apache.directory.server.xdbm.Index;
31 import org.apache.directory.server.xdbm.Tuple;
32 import org.apache.directory.server.xdbm.IndexCursor;
33 import org.apache.directory.shared.ldap.schema.AttributeType;
34 import org.apache.directory.shared.ldap.util.SynchronizedLRUMap;
35
36 import javax.naming.NamingException;
37 import java.io.File;
38 import java.io.IOException;
39
40
41
42
43
44
45
46
47
48
49 public class JdbmIndex<K,O> implements Index<K,O>
50 {
51
52
53
54 public static final int DEFAULT_DUPLICATE_LIMIT = 512;
55
56
57 public static final String FORWARD_BTREE = "_forward";
58
59 public static final String REVERSE_BTREE = "_reverse";
60
61
62 private AttributeType attribute;
63
64
65
66
67
68 protected JdbmTable<K, Long> forward;
69
70
71
72
73
74 protected JdbmTable<Long,K> reverse;
75
76
77
78 protected RecordManager recMan;
79
80
81
82
83
84 protected SynchronizedLRUMap keyCache;
85
86 protected int cacheSize = DEFAULT_INDEX_CACHE_SIZE;
87
88
89
90 protected int numDupLimit = DEFAULT_DUPLICATE_LIMIT;
91
92
93
94
95 private String attributeId;
96
97 protected boolean initialized;
98
99 protected File wkDirPath;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public JdbmIndex()
125 {
126 initialized = false;
127 }
128
129
130 public JdbmIndex( String attributeId )
131 {
132 initialized = false;
133 setAttributeId( attributeId );
134 }
135
136
137 public void init( AttributeType attributeType, File wkDirPath ) throws IOException
138 {
139 this.keyCache = new SynchronizedLRUMap( cacheSize );
140 this.attribute = attributeType;
141
142 if ( attributeId == null )
143 {
144 setAttributeId( attribute.getName() );
145 }
146
147 if ( this.wkDirPath == null )
148 {
149 this.wkDirPath = wkDirPath;
150 }
151
152 File file = new File( this.wkDirPath.getPath() + File.separator + attribute.getName() );
153 String path = file.getAbsolutePath();
154 BaseRecordManager base = new BaseRecordManager( path );
155 base.disableTransactions();
156 this.recMan = new CacheRecordManager( base, new MRU( cacheSize ) );
157
158 initTables();
159 initialized = true;
160 }
161
162
163
164
165
166
167
168
169 private void initTables() throws IOException
170 {
171 SerializableComparator<K> comp;
172
173 try
174 {
175 comp = new SerializableComparator<K>( attribute.getEquality().getOid() );
176 }
177 catch ( NamingException e )
178 {
179 IOException ioe = new IOException( "Failed to find an equality matching rule for attribute type" );
180 ioe.initCause( e );
181 throw ioe;
182 }
183
184
185
186
187
188
189 forward = new JdbmTable<K, Long>(
190 attribute.getName() + FORWARD_BTREE,
191 numDupLimit,
192 recMan,
193 comp, LongComparator.INSTANCE,
194 null, LongSerializer.INSTANCE );
195
196
197
198
199
200
201
202 if ( attribute.isSingleValue() )
203 {
204 reverse = new JdbmTable<Long,K>(
205 attribute.getName() + REVERSE_BTREE,
206 recMan,
207 LongComparator.INSTANCE,
208 LongSerializer.INSTANCE,
209 null );
210 }
211 else
212 {
213 reverse = new JdbmTable<Long,K>(
214 attribute.getName() + REVERSE_BTREE,
215 numDupLimit,
216 recMan,
217 LongComparator.INSTANCE, comp,
218 LongSerializer.INSTANCE, null );
219 }
220 }
221
222
223
224
225
226 public AttributeType getAttribute()
227 {
228 return attribute;
229 }
230
231
232
233
234
235
236
237
238
239
240
241 private void protect( String property )
242 {
243 if ( initialized )
244 {
245 throw new IllegalStateException( "The " + property
246 + " property for an index cannot be set after it has been initialized." );
247 }
248 }
249
250
251 public boolean isCountExact()
252 {
253 return false;
254 }
255
256
257
258
259
260
261
262
263 public String getAttributeId()
264 {
265 return attributeId;
266 }
267
268
269
270
271
272
273
274
275 public void setAttributeId( String attributeId )
276 {
277 protect( "attributeId" );
278 this.attributeId = attributeId;
279 }
280
281
282
283
284
285
286
287
288 public int getNumDupLimit()
289 {
290 return numDupLimit;
291 }
292
293
294
295
296
297
298
299
300 public void setNumDupLimit( int numDupLimit )
301 {
302 protect( "numDupLimit" );
303 this.numDupLimit = numDupLimit;
304 }
305
306
307
308
309
310
311
312 public int getCacheSize()
313 {
314 return cacheSize;
315 }
316
317
318
319
320
321
322
323 public void setCacheSize( int cacheSize )
324 {
325 protect( "cacheSize" );
326 this.cacheSize = cacheSize;
327 }
328
329
330
331
332
333
334
335
336 public void setWkDirPath( File wkDirPath )
337 {
338 protect( "wkDirPath" );
339 this.wkDirPath = wkDirPath;
340 }
341
342
343
344
345
346
347
348
349 public File getWkDirPath()
350 {
351 return wkDirPath;
352 }
353
354
355
356
357
358
359
360
361
362
363 public int count() throws IOException
364 {
365 return forward.count();
366 }
367
368
369
370
371
372 public int count( K attrVal ) throws Exception
373 {
374 return forward.count( getNormalized( attrVal ) );
375 }
376
377
378 public int greaterThanCount( K attrVal ) throws Exception
379 {
380 return forward.greaterThanCount( getNormalized( attrVal ) );
381 }
382
383
384
385
386
387 public int lessThanCount( K attrVal ) throws Exception
388 {
389 return forward.lessThanCount( getNormalized( attrVal ) );
390 }
391
392
393
394
395
396
397
398
399
400
401 public Long forwardLookup( K attrVal ) throws Exception
402 {
403 return forward.get( getNormalized( attrVal ) );
404 }
405
406
407
408
409
410 public K reverseLookup( Long id ) throws Exception
411 {
412 return reverse.get( id );
413 }
414
415
416
417
418
419
420
421
422
423
424 public synchronized void add( K attrVal, Long id ) throws Exception
425 {
426 forward.put( getNormalized( attrVal ), id );
427 reverse.put( id, getNormalized( attrVal ) );
428 }
429
430
431
432
433
434 public synchronized void drop( K attrVal, Long id ) throws Exception
435 {
436 forward.remove( getNormalized( attrVal ), id );
437 reverse.remove( id, getNormalized( attrVal ) );
438 }
439
440
441
442
443
444 public void drop( Long id ) throws Exception
445 {
446 Cursor<Tuple<Long,K>> values = reverse.cursor();
447 Tuple<Long,K> tuple = new Tuple<Long,K>( id, null );
448 values.before( tuple );
449
450 while ( values.next() )
451 {
452 forward.remove( values.get().getValue(), id );
453 }
454
455 reverse.remove( id );
456 }
457
458
459
460
461
462
463
464 @SuppressWarnings("unchecked")
465 public IndexCursor<K, O> reverseCursor() throws Exception
466 {
467 return new IndexCursorAdaptor<K, O>( ( Cursor ) reverse.cursor(), false );
468 }
469
470
471 @SuppressWarnings("unchecked")
472 public IndexCursor<K, O> forwardCursor() throws Exception
473 {
474 return new IndexCursorAdaptor<K, O>( ( Cursor ) forward.cursor(), true );
475 }
476
477
478 @SuppressWarnings("unchecked")
479 public IndexCursor<K, O> reverseCursor( Long id ) throws Exception
480 {
481 return new IndexCursorAdaptor<K, O>( ( Cursor ) reverse.cursor( id ), false );
482 }
483
484
485 @SuppressWarnings("unchecked")
486 public IndexCursor<K, O> forwardCursor( K key ) throws Exception
487 {
488 return new IndexCursorAdaptor<K, O>( ( Cursor ) forward.cursor( key ), true );
489 }
490
491
492 public Cursor<K> reverseValueCursor( Long id ) throws Exception
493 {
494 return reverse.valueCursor( id );
495 }
496
497
498 public Cursor<Long> forwardValueCursor( K key ) throws Exception
499 {
500 return forward.valueCursor( key );
501 }
502
503
504
505
506
507
508
509
510
511
512 public boolean forward( K attrVal ) throws Exception
513 {
514 return forward.has( getNormalized( attrVal ) );
515 }
516
517
518
519
520
521 public boolean forward( K attrVal, Long id ) throws Exception
522 {
523 return forward.has( getNormalized( attrVal ), id );
524 }
525
526
527
528
529 public boolean reverse( Long id ) throws Exception
530 {
531 return reverse.has( id );
532 }
533
534
535
536
537
538 public boolean reverse( Long id, K attrVal ) throws Exception
539 {
540 return forward.has( getNormalized( attrVal ), id );
541 }
542
543
544
545
546
547 public boolean forwardGreaterOrEq( K attrVal ) throws Exception
548 {
549 return forward.hasGreaterOrEqual( getNormalized( attrVal ) );
550 }
551
552
553
554
555
556 public boolean forwardGreaterOrEq( K attrVal, Long id ) throws Exception
557 {
558 return forward.hasGreaterOrEqual( getNormalized( attrVal ), id );
559 }
560
561
562
563
564
565 public boolean forwardLessOrEq( K attrVal ) throws Exception
566 {
567 return forward.hasLessOrEqual( getNormalized( attrVal ) );
568 }
569
570
571
572
573
574 public boolean forwardLessOrEq( K attrVal, Long id ) throws Exception
575 {
576 return forward.hasLessOrEqual( getNormalized( attrVal ), id );
577 }
578
579
580
581
582
583 public boolean reverseGreaterOrEq( Long id ) throws Exception
584 {
585 return reverse.hasGreaterOrEqual( id );
586 }
587
588
589
590
591
592 public boolean reverseGreaterOrEq( Long id, K attrVal ) throws Exception
593 {
594 return reverse.hasGreaterOrEqual( id, getNormalized( attrVal ) );
595 }
596
597
598
599
600
601 public boolean reverseLessOrEq( Long id ) throws Exception
602 {
603 return reverse.hasLessOrEqual( id );
604 }
605
606
607
608
609
610 public boolean reverseLessOrEq( Long id, K attrVal ) throws Exception
611 {
612 return reverse.hasLessOrEqual( id, getNormalized( attrVal ) );
613 }
614
615
616
617
618
619
620
621
622
623
624 public synchronized void close() throws IOException
625 {
626 forward.close();
627 reverse.close();
628 recMan.commit();
629 recMan.close();
630 }
631
632
633
634
635
636 public synchronized void sync() throws IOException
637 {
638 recMan.commit();
639 }
640
641
642
643
644
645
646 @SuppressWarnings("unchecked")
647 public K getNormalized( K attrVal ) throws Exception
648 {
649 if ( attrVal instanceof Long )
650 {
651 return attrVal;
652 }
653
654 K normalized = ( K ) keyCache.get( attrVal );
655
656 if ( null == normalized )
657 {
658 normalized = ( K ) attribute.getEquality().getNormalizer().normalize( attrVal );
659
660
661
662
663 keyCache.put( attrVal, normalized );
664 keyCache.put( normalized, normalized );
665 }
666
667 return normalized;
668 }
669
670
671
672
673
674 public String toString()
675 {
676 return "Index<" + attributeId +">";
677 }
678 }