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.File;
24 import java.io.IOException;
25 import java.net.URI;
26 import java.util.Comparator;
27
28 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
29 import org.apache.directory.api.ldap.model.cursor.Cursor;
30 import org.apache.directory.api.ldap.model.cursor.CursorException;
31 import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
32 import org.apache.directory.api.ldap.model.cursor.Tuple;
33 import org.apache.directory.api.ldap.model.exception.LdapException;
34 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
35 import org.apache.directory.api.ldap.model.schema.AttributeType;
36 import org.apache.directory.api.ldap.model.schema.MatchingRule;
37 import org.apache.directory.api.ldap.model.schema.SchemaManager;
38 import org.apache.directory.api.ldap.model.schema.comparators.SerializableComparator;
39 import org.apache.directory.mavibot.btree.RecordManager;
40 import org.apache.directory.mavibot.btree.serializer.ByteArraySerializer;
41 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
42 import org.apache.directory.mavibot.btree.serializer.StringSerializer;
43 import org.apache.directory.server.core.api.partition.PartitionTxn;
44 import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
45 import org.apache.directory.server.core.partition.impl.btree.IndexCursorAdaptor;
46 import org.apache.directory.server.i18n.I18n;
47 import org.apache.directory.server.xdbm.AbstractIndex;
48 import org.apache.directory.server.xdbm.IndexEntry;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52
53
54
55
56
57
58 public class MavibotIndex<K> extends AbstractIndex<K, String>
59 {
60
61 private static final Logger LOG = LoggerFactory.getLogger( MavibotIndex.class.getSimpleName() );
62
63
64 public static final String FORWARD_BTREE = "_forward";
65
66
67 public static final String REVERSE_BTREE = "_reverse";
68
69
70
71
72
73
74 protected MavibotTable<K, String> forward;
75
76
77
78
79
80
81 protected MavibotTable<String, K> reverse;
82
83
84 protected File wkDirPath;
85
86 protected RecordManager recordMan;
87
88
89
90
91
92
93
94
95
96
97
98 public MavibotIndex( String attributeId, boolean withReverse )
99 {
100 super( attributeId, withReverse );
101
102 initialized = false;
103 }
104
105
106
107
108
109
110
111
112
113
114 public void init( SchemaManager schemaManager, AttributeType attributeType ) throws LdapException, IOException
115 {
116 LOG.debug( "Initializing an Index for attribute '{}'", attributeType.getName() );
117
118
119 if ( recordMan == null )
120 {
121 throw new IllegalStateException( "No RecordManager reference was set in the index " + getAttributeId() );
122 }
123
124 this.attributeType = attributeType;
125
126 if ( attributeId == null )
127 {
128 setAttributeId( attributeType.getName() );
129 }
130
131 if ( this.wkDirPath == null )
132 {
133 throw new NullPointerException( "The index working directory has not be set" );
134 }
135
136 try
137 {
138 initTables( schemaManager );
139 }
140 catch ( IOException e )
141 {
142
143 close( null );
144 throw e;
145 }
146
147 initialized = true;
148 }
149
150
151
152
153
154
155
156
157
158 private void initTables( SchemaManager schemaManager ) throws IOException
159 {
160 MatchingRule mr = attributeType.getEquality();
161
162 if ( mr == null )
163 {
164 throw new IOException( I18n.err( I18n.ERR_574, attributeType.getName() ) );
165 }
166
167 SerializableComparator<K> comp = new SerializableComparator<>( mr.getOid() );
168 comp.setSchemaManager( schemaManager );
169
170
171
172
173
174
175
176 ElementSerializer<K> forwardKeySerializer = null;
177
178 if ( !attributeType.getSyntax().isHumanReadable() )
179 {
180 forwardKeySerializer = ( ElementSerializer<K> ) new ByteArraySerializer( ( Comparator<byte[]> ) comp );
181 }
182 else
183 {
184 forwardKeySerializer = ( ElementSerializer<K> ) new StringSerializer( ( Comparator<String> ) comp );
185 }
186
187 boolean forwardDups = true;
188
189 String oid = attributeType.getOid();
190
191 if ( oid.equals( SchemaConstants.ENTRY_CSN_AT_OID ) || oid.equals( SchemaConstants.ENTRY_UUID_AT_OID ) )
192 {
193 forwardDups = false;
194 }
195
196 String forwardTableName = attributeType.getOid() + FORWARD_BTREE;
197 forward = new MavibotTable<>( recordMan, schemaManager, forwardTableName, forwardKeySerializer,
198 StringSerializer.INSTANCE, forwardDups, AbstractBTreePartition.DEFAULT_CACHE_SIZE );
199
200
201
202
203
204
205
206 if ( withReverse )
207 {
208 String reverseTableName = attributeType.getOid() + REVERSE_BTREE;
209 reverse = new MavibotTable<>( recordMan, schemaManager, reverseTableName, StringSerializer.INSTANCE,
210 forwardKeySerializer, !attributeType.isSingleValued() );
211 }
212 }
213
214
215
216
217
218
219
220 public void setRecordManager( RecordManager rm )
221 {
222 this.recordMan = rm;
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236 public void setWkDirPath( URI wkDirPath )
237 {
238
239 protect( "wkDirPath" );
240 this.wkDirPath = new File( wkDirPath );
241 }
242
243
244
245
246
247
248
249
250 public URI getWkDirPath()
251 {
252 return wkDirPath != null ? wkDirPath.toURI() : null;
253 }
254
255
256
257
258
259
260
261
262 public long count( PartitionTxn partitionTxn ) throws LdapException
263 {
264 return forward.count( partitionTxn );
265 }
266
267
268
269
270
271 public long count( PartitionTxn partitionTxn, K attrVal ) throws LdapException
272 {
273 return forward.count( partitionTxn, attrVal );
274 }
275
276
277
278
279
280 @Override
281 public long greaterThanCount( PartitionTxn partitionTxn, K attrVal ) throws LdapException
282 {
283 return forward.greaterThanCount( partitionTxn, attrVal );
284 }
285
286
287
288
289
290 @Override
291 public long lessThanCount( PartitionTxn partitionTxn, K attrVal ) throws LdapException
292 {
293 return forward.lessThanCount( partitionTxn, attrVal );
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309 public String forwardLookup( PartitionTxn partitionTxn, K attrVal ) throws LdapException
310 {
311 return forward.get( partitionTxn, attrVal );
312 }
313
314
315
316
317
318 public K reverseLookup( PartitionTxn partitionTxn, String id ) throws LdapException
319 {
320 if ( withReverse )
321 {
322 return reverse.get( partitionTxn, id );
323 }
324 else
325 {
326 return null;
327 }
328 }
329
330
331
332
333
334
335
336
337
338 public synchronized void add( PartitionTxn partitionTxn, K attrVal, String id ) throws LdapException
339 {
340
341 forward.put( partitionTxn, attrVal, id );
342
343 if ( withReverse )
344 {
345 reverse.put( partitionTxn, id, attrVal );
346 }
347 }
348
349
350
351
352
353 @Override
354 public synchronized void drop( PartitionTxn partitionTxn, K attrVal, String id ) throws LdapException
355 {
356
357 if ( forward.has( partitionTxn, attrVal, id ) )
358 {
359 forward.remove( partitionTxn, attrVal, id );
360
361 if ( withReverse )
362 {
363 reverse.remove( partitionTxn, id, attrVal );
364 }
365 }
366 }
367
368
369
370
371
372 public void drop( PartitionTxn partitionTxn, String entryId ) throws LdapException
373 {
374 if ( withReverse )
375 {
376 if ( isDupsEnabled() )
377 {
378
379
380 Cursor<Tuple<String, K>> values = reverse.cursor( partitionTxn, entryId );
381
382 try
383 {
384 while ( values.next() )
385 {
386
387 forward.remove( partitionTxn, values.get().getValue(), entryId );
388 }
389
390 values.close();
391 }
392 catch ( CursorException | IOException e )
393 {
394 throw new LdapOtherException( e.getMessage(), e );
395 }
396 }
397 else
398 {
399 K key = reverse.get( partitionTxn, entryId );
400
401 forward.remove( partitionTxn, key );
402 }
403
404
405 reverse.remove( partitionTxn, entryId );
406 }
407 }
408
409
410
411
412
413 @SuppressWarnings("unchecked")
414 public Cursor<IndexEntry<K, String>> forwardCursor( PartitionTxn partitionTxn ) throws LdapException
415 {
416 return new IndexCursorAdaptor<>( partitionTxn, ( Cursor ) forward.cursor(), true );
417 }
418
419
420 public Cursor<IndexEntry<K, String>> forwardCursor( PartitionTxn partitionTxn, K key ) throws LdapException
421 {
422 return new IndexCursorAdaptor<>( partitionTxn, ( Cursor ) forward.cursor( partitionTxn, key ), true );
423 }
424
425
426
427
428
429 @Override
430 public Cursor<K> reverseValueCursor( PartitionTxn partitionTxn, String id ) throws LdapException
431 {
432 if ( withReverse )
433 {
434 return reverse.valueCursor( partitionTxn, id );
435 }
436 else
437 {
438 return new EmptyCursor<>();
439 }
440 }
441
442
443 public Cursor<String> forwardValueCursor( PartitionTxn partitionTxn, K key ) throws LdapException
444 {
445 return forward.valueCursor( partitionTxn, key );
446 }
447
448
449
450
451
452
453
454
455 public boolean forward( PartitionTxn partitionTxn, K attrVal ) throws LdapException
456 {
457 return forward.has( partitionTxn, attrVal );
458 }
459
460
461
462
463
464 public boolean forward( PartitionTxn partitionTxn, K attrVal, String id ) throws LdapException
465 {
466 return forward.has( partitionTxn, attrVal, id );
467 }
468
469
470
471
472
473 @Override
474 public boolean reverse( PartitionTxn partitionTxn, String id ) throws LdapException
475 {
476 if ( withReverse )
477 {
478 return reverse.has( partitionTxn, id );
479 }
480 else
481 {
482 return false;
483 }
484 }
485
486
487
488
489
490 @Override
491 public boolean reverse( PartitionTxn partitionTxn, String id, K attrVal ) throws LdapException
492 {
493 return forward.has( partitionTxn, attrVal, id );
494 }
495
496
497
498
499
500
501
502
503 @Override
504 public synchronized void close( PartitionTxn partitionTxn ) throws IOException
505 {
506 try
507 {
508 if ( forward != null )
509 {
510 forward.close( partitionTxn );
511 }
512
513 if ( reverse != null )
514 {
515 reverse.close( partitionTxn );
516 }
517 }
518 catch ( Exception e )
519 {
520 throw new IOException( e );
521 }
522 }
523
524
525
526
527
528
529
530 public synchronized void sync() throws IOException
531 {
532 forward.getBTree().flush();
533
534 if ( reverse != null )
535 {
536 reverse.getBTree().flush();
537 }
538 }
539
540
541
542
543
544 @Override
545 public boolean isDupsEnabled()
546 {
547 if ( withReverse )
548 {
549 return reverse.isDupsEnabled();
550 }
551 else
552 {
553 return false;
554 }
555 }
556
557
558
559
560
561 public String toString()
562 {
563 return "Index<" + attributeId + ">";
564 }
565 }