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.FilenameFilter;
25 import java.io.IOException;
26 import java.net.URI;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Set;
32
33 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
34 import org.apache.directory.api.ldap.model.cursor.Cursor;
35 import org.apache.directory.api.ldap.model.cursor.Tuple;
36 import org.apache.directory.api.ldap.model.entry.Attribute;
37 import org.apache.directory.api.ldap.model.entry.Entry;
38 import org.apache.directory.api.ldap.model.entry.Value;
39 import org.apache.directory.api.ldap.model.exception.LdapException;
40 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
41 import org.apache.directory.api.ldap.model.schema.AttributeType;
42 import org.apache.directory.api.ldap.model.schema.SchemaManager;
43 import org.apache.directory.api.util.exception.MultiException;
44 import org.apache.directory.mavibot.btree.RecordManager;
45 import org.apache.directory.server.constants.ApacheSchemaConstants;
46 import org.apache.directory.server.core.api.DnFactory;
47 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
48 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
49 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
50 import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
51 import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
52 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
53 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
54 import org.apache.directory.server.core.api.partition.Partition;
55 import org.apache.directory.server.core.api.partition.PartitionReadTxn;
56 import org.apache.directory.server.core.api.partition.PartitionTxn;
57 import org.apache.directory.server.core.api.partition.PartitionWriteTxn;
58 import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
59 import org.apache.directory.server.i18n.I18n;
60 import org.apache.directory.server.xdbm.Index;
61 import org.apache.directory.server.xdbm.search.impl.CursorBuilder;
62 import org.apache.directory.server.xdbm.search.impl.DefaultOptimizer;
63 import org.apache.directory.server.xdbm.search.impl.DefaultSearchEngine;
64 import org.apache.directory.server.xdbm.search.impl.EvaluatorBuilder;
65 import org.apache.directory.server.xdbm.search.impl.NoOpOptimizer;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 import com.github.benmanes.caffeine.cache.Cache;
70 import com.github.benmanes.caffeine.cache.Caffeine;
71
72
73
74
75
76
77
78 public class MavibotPartition extends AbstractBTreePartition
79 {
80
81 private static final Logger LOG = LoggerFactory.getLogger( MavibotPartition.class );
82
83 private static final String MAVIBOT_DB_FILE_EXTN = ".data";
84
85 private static final FilenameFilter DB_FILTER = new FilenameFilter()
86 {
87
88 public boolean accept( File dir, String name )
89 {
90
91 return ( name.endsWith( MAVIBOT_DB_FILE_EXTN ) && !name.startsWith( "master." ) );
92 }
93 };
94
95 private RecordManager recordMan;
96
97
98 private Cache< String, Entry > entryCache;
99
100
101 public MavibotPartition( SchemaManager schemaManager, DnFactory dnFactory )
102 {
103 super( schemaManager, dnFactory );
104
105 MavibotEntrySerializer.setSchemaManager( schemaManager );
106
107
108 if ( cacheSize < 0 )
109 {
110 cacheSize = DEFAULT_CACHE_SIZE;
111 LOG.debug( "Using the default entry cache size of {} for {} partition", cacheSize, id );
112 }
113 else
114 {
115 LOG.debug( "Using the custom configured cache size of {} for {} partition", cacheSize, id );
116 }
117 }
118
119
120
121
122
123 @Override
124 protected void doRepair() throws LdapException
125 {
126
127 }
128
129
130
131
132
133 @Override
134 protected void doInit() throws LdapException
135 {
136 if ( !initialized )
137 {
138
139 if ( !isOptimizerEnabled() )
140 {
141 setOptimizer( new NoOpOptimizer() );
142 }
143 else
144 {
145 setOptimizer( new DefaultOptimizer( this ) );
146 }
147
148 EvaluatorBuildersearch/impl/EvaluatorBuilder.html#EvaluatorBuilder">EvaluatorBuilder evaluatorBuilder = new EvaluatorBuilder( this, schemaManager );
149 CursorBuilder/xdbm/search/impl/CursorBuilder.html#CursorBuilder">CursorBuilder cursorBuilder = new CursorBuilder( this, evaluatorBuilder );
150
151 setSearchEngine( new DefaultSearchEngine( this, cursorBuilder, evaluatorBuilder, getOptimizer() ) );
152
153
154 File partitionDir = new File( getPartitionPath() );
155
156 if ( !partitionDir.exists() && !partitionDir.mkdirs() )
157 {
158 throw new LdapOtherException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECTORY, partitionDir ) );
159 }
160
161 if ( cacheSize < 0 )
162 {
163 cacheSize = DEFAULT_CACHE_SIZE;
164 LOG.debug( "Using the default entry cache size of {} for {} partition", cacheSize, id );
165 }
166 else
167 {
168 LOG.debug( "Using the custom configured cache size of {} for {} partition", cacheSize, id );
169 }
170
171 recordMan = new RecordManager( partitionDir.getPath() );
172
173
174 super.doInit();
175
176
177
178 try
179 {
180 master = new MavibotMasterTable( recordMan, schemaManager, "master", cacheSize );
181 }
182 catch ( IOException ioe )
183 {
184 throw new LdapOtherException( ioe.getMessage(), ioe );
185 }
186
187
188 File[] allIndexDbFiles = partitionDir.listFiles( DB_FILTER );
189
190
191 List<String> indexDbFileNameList = Arrays.asList( partitionDir.list( DB_FILTER ) );
192
193
194 List<String> allIndices = new ArrayList<>();
195
196 for ( Index<?, String> index : systemIndices.values() )
197 {
198 allIndices.add( index.getAttribute().getOid() );
199 }
200
201 List<Index<?, String>> indexToBuild = new ArrayList<>();
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 entryCache = Caffeine.newBuilder().maximumSize( cacheSize ).build();
233
234
235 initialized = true;
236 }
237 }
238
239
240 @Override
241 protected Index<?, String> convertAndInit( Index<?, String> index ) throws LdapException
242 {
243 MavibotIndex<?> mavibotIndex;
244
245 if ( index instanceof MavibotRdnIndex )
246 {
247 mavibotIndex = ( MavibotRdnIndex ) index;
248 }
249 else if ( index instanceof MavibotDnIndex )
250 {
251 mavibotIndex = ( MavibotDnIndex ) index;
252 }
253 else if ( index instanceof MavibotIndex<?> )
254 {
255 mavibotIndex = ( MavibotIndex<?> ) index;
256
257 if ( mavibotIndex.getWkDirPath() == null )
258 {
259 mavibotIndex.setWkDirPath( partitionPath );
260 }
261 }
262 else
263 {
264 LOG.debug( "Supplied index {} is not a MavibotIndex. "
265 + "Will create new MavibotIndex using copied configuration parameters.", index );
266 mavibotIndex = new MavibotIndex( index.getAttributeId(), true );
267 mavibotIndex.setCacheSize( index.getCacheSize() );
268 mavibotIndex.setWkDirPath( index.getWkDirPath() );
269 }
270
271 mavibotIndex.setRecordManager( recordMan );
272
273 try
274 {
275 mavibotIndex.init( schemaManager, schemaManager.lookupAttributeTypeRegistry( index.getAttributeId() ) );
276 }
277 catch ( IOException ioe )
278 {
279 throw new LdapOtherException( ioe.getMessage(), ioe );
280 }
281
282 return mavibotIndex;
283 }
284
285
286
287
288
289 @Override
290 protected synchronized void doDestroy( PartitionTxn partitionTxn ) throws LdapException
291 {
292 MultiException errors = new MultiException( I18n.err( I18n.ERR_577 ) );
293
294 if ( !initialized )
295 {
296 return;
297 }
298
299 try
300 {
301 super.doDestroy( partitionTxn );
302 }
303 catch ( Exception e )
304 {
305 errors.addThrowable( e );
306 }
307
308
309 try
310 {
311 recordMan.close();
312 LOG.debug( "Closed record manager for {} partition.", suffixDn );
313 }
314 catch ( Throwable t )
315 {
316 LOG.error( I18n.err( I18n.ERR_127 ), t );
317 errors.addThrowable( t );
318 }
319 finally
320 {
321 if ( entryCache != null )
322 {
323 entryCache.invalidateAll();
324 }
325 }
326
327 if ( errors.size() > 0 )
328 {
329 throw new LdapOtherException( errors.getMessage(), errors );
330 }
331 }
332
333
334 @Override
335 protected Index createSystemIndex( String indexOid, URI path, boolean withReverse ) throws LdapException
336 {
337 LOG.debug( "Supplied index {} is not a MavibotIndex. "
338 + "Will create new MavibotIndex using copied configuration parameters." );
339 MavibotIndex<?> mavibotIndex;
340
341 if ( indexOid.equals( ApacheSchemaConstants.APACHE_RDN_AT_OID ) )
342 {
343 mavibotIndex = new MavibotRdnIndex();
344 mavibotIndex.setAttributeId( ApacheSchemaConstants.APACHE_RDN_AT_OID );
345 }
346 else if ( indexOid.equals( ApacheSchemaConstants.APACHE_ALIAS_AT_OID ) )
347 {
348 mavibotIndex = new MavibotDnIndex( ApacheSchemaConstants.APACHE_ALIAS_AT_OID );
349 mavibotIndex.setAttributeId( ApacheSchemaConstants.APACHE_ALIAS_AT_OID );
350 }
351 else
352 {
353 mavibotIndex = new MavibotIndex( indexOid, withReverse );
354 }
355
356 mavibotIndex.setWkDirPath( path );
357
358 return mavibotIndex;
359 }
360
361
362
363
364
365
366 private void deleteUnusedIndexFiles( List<String> allIndices, File[] dbFiles )
367 {
368
369 }
370
371
372
373
374
375
376
377
378 private void buildUserIndex( PartitionTxn partitionTxn, List<Index<?, String>> userIndexes ) throws Exception
379 {
380 Cursor<Tuple<String, Entry>> cursor = master.cursor();
381 cursor.beforeFirst();
382
383 while ( cursor.next() )
384 {
385 for ( Index index : userIndexes )
386 {
387 AttributeType atType = index.getAttribute();
388
389 String attributeOid = index.getAttribute().getOid();
390
391 LOG.info( "building the index for attribute type {}", atType );
392
393 Tuple<String, Entry> tuple = cursor.get();
394
395 String id = tuple.getKey();
396 Entry entry = tuple.getValue();
397
398 Attribute entryAttr = entry.get( atType );
399
400 if ( entryAttr != null )
401 {
402 for ( Value value : entryAttr )
403 {
404 index.add( partitionTxn, value.getString(), id );
405 }
406
407
408 presenceIdx.add( partitionTxn, attributeOid, id );
409 }
410 }
411 }
412
413 cursor.close();
414 }
415
416
417
418
419
420 public String getDefaultId()
421 {
422 return Partition.DEFAULT_ID;
423 }
424
425
426
427
428
429 public String getRootId()
430 {
431 return Partition.ROOT_ID;
432 }
433
434
435 public RecordManager getRecordMan()
436 {
437 return recordMan;
438 }
439
440
441
442
443
444 @Override
445 public Entry lookupCache( String id )
446 {
447 return ( entryCache != null ) ? entryCache.getIfPresent( id ) : null;
448 }
449
450
451 @Override
452 public void addToCache( String id, Entry entry )
453 {
454 if ( entryCache == null )
455 {
456 return;
457 }
458
459 if ( entry instanceof ClonedServerEntry )
460 {
461 entry = ( ( ClonedServerEntry ) entry ).getOriginalEntry();
462 }
463
464 entryCache.put( id, entry );
465 }
466
467
468 @Override
469 public void updateCache( OperationContext opCtx )
470 {
471 if ( entryCache == null )
472 {
473 return;
474 }
475
476 try
477 {
478 if ( opCtx instanceof ModifyOperationContext )
479 {
480
481 ModifyOperationContext/../../../org/apache/directory/server/core/api/interceptor/context/ModifyOperationContext.html#ModifyOperationContext">ModifyOperationContext modCtx = ( ModifyOperationContext ) opCtx;
482 Entry entry = modCtx.getAlteredEntry();
483 String id = entry.get( SchemaConstants.ENTRY_UUID_AT ).getString();
484
485 if ( entry instanceof ClonedServerEntry )
486 {
487 entry = ( ( ClonedServerEntry ) entry ).getOriginalEntry();
488 }
489
490 entryCache.put( id, entry );
491 }
492 else if ( ( opCtx instanceof MoveOperationContext ) || ( opCtx instanceof MoveAndRenameOperationContext )
493 || ( opCtx instanceof RenameOperationContext ) )
494 {
495
496 entryCache.invalidateAll();
497 }
498 else if ( opCtx instanceof DeleteOperationContext )
499 {
500
501 DeleteOperationContext/../../../org/apache/directory/server/core/api/interceptor/context/DeleteOperationContext.html#DeleteOperationContext">DeleteOperationContext delCtx = ( DeleteOperationContext ) opCtx;
502 entryCache.invalidate( delCtx.getEntry().get( SchemaConstants.ENTRY_UUID_AT ).getString() );
503 }
504 }
505 catch ( LdapException e )
506 {
507 LOG.warn( "Failed to update entry cache", e );
508 }
509 }
510
511
512
513
514
515 public Set<Index<?, String>> getAllIndices()
516 {
517 Set<Index<?, String>> all = new HashSet<>( systemIndices.values() );
518 all.addAll( userIndices.values() );
519
520 return all;
521 }
522
523
524 @Override
525 public PartitionReadTxn beginReadTransaction()
526 {
527 return new PartitionReadTxn();
528 }
529
530
531 @Override
532 public PartitionWriteTxn beginWriteTransaction()
533 {
534 return new PartitionWriteTxn();
535 }
536 }