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;
21
22
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.net.URI;
26 import java.time.Duration;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import java.util.concurrent.Semaphore;
35 import java.util.concurrent.atomic.AtomicBoolean;
36 import java.util.concurrent.locks.ReadWriteLock;
37 import java.util.concurrent.locks.ReentrantReadWriteLock;
38
39 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
40 import org.apache.directory.api.ldap.model.cursor.Cursor;
41 import org.apache.directory.api.ldap.model.cursor.CursorException;
42 import org.apache.directory.api.ldap.model.entry.Attribute;
43 import org.apache.directory.api.ldap.model.entry.Entry;
44 import org.apache.directory.api.ldap.model.entry.Modification;
45 import org.apache.directory.api.ldap.model.entry.Value;
46 import org.apache.directory.api.ldap.model.exception.LdapAliasDereferencingException;
47 import org.apache.directory.api.ldap.model.exception.LdapAliasException;
48 import org.apache.directory.api.ldap.model.exception.LdapContextNotEmptyException;
49 import org.apache.directory.api.ldap.model.exception.LdapEntryAlreadyExistsException;
50 import org.apache.directory.api.ldap.model.exception.LdapException;
51 import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
52 import org.apache.directory.api.ldap.model.exception.LdapNoSuchAttributeException;
53 import org.apache.directory.api.ldap.model.exception.LdapNoSuchObjectException;
54 import org.apache.directory.api.ldap.model.exception.LdapOperationErrorException;
55 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
56 import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
57 import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
58 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
59 import org.apache.directory.api.ldap.model.name.Ava;
60 import org.apache.directory.api.ldap.model.name.Dn;
61 import org.apache.directory.api.ldap.model.name.Rdn;
62 import org.apache.directory.api.ldap.model.schema.AttributeType;
63 import org.apache.directory.api.ldap.model.schema.MatchingRule;
64 import org.apache.directory.api.ldap.model.schema.Normalizer;
65 import org.apache.directory.api.ldap.model.schema.SchemaManager;
66 import org.apache.directory.api.util.Strings;
67 import org.apache.directory.api.util.exception.MultiException;
68 import org.apache.directory.server.constants.ApacheSchemaConstants;
69 import org.apache.directory.server.core.api.DnFactory;
70 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
71 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
72 import org.apache.directory.server.core.api.filtering.EntryFilteringCursorImpl;
73 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
74 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
75 import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext;
76 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
77 import org.apache.directory.server.core.api.interceptor.context.ModDnAva;
78 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
79 import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
80 import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
81 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
82 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
83 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
84 import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext;
85 import org.apache.directory.server.core.api.partition.AbstractPartition;
86 import org.apache.directory.server.core.api.partition.Partition;
87 import org.apache.directory.server.core.api.partition.PartitionTxn;
88 import org.apache.directory.server.core.api.partition.PartitionWriteTxn;
89 import org.apache.directory.server.core.api.partition.Subordinates;
90 import org.apache.directory.server.i18n.I18n;
91 import org.apache.directory.server.xdbm.Index;
92 import org.apache.directory.server.xdbm.IndexEntry;
93 import org.apache.directory.server.xdbm.IndexNotFoundException;
94 import org.apache.directory.server.xdbm.MasterTable;
95 import org.apache.directory.server.xdbm.ParentIdAndRdn;
96 import org.apache.directory.server.xdbm.Store;
97 import org.apache.directory.server.xdbm.search.Optimizer;
98 import org.apache.directory.server.xdbm.search.PartitionSearchResult;
99 import org.apache.directory.server.xdbm.search.SearchEngine;
100 import org.slf4j.Logger;
101 import org.slf4j.LoggerFactory;
102
103 import com.github.benmanes.caffeine.cache.Cache;
104 import com.github.benmanes.caffeine.cache.Caffeine;
105
106
107
108
109
110
111
112 public abstract class AbstractBTreePartition extends AbstractPartition implements Store
113 {
114
115 private static final Logger LOG = LoggerFactory.getLogger( AbstractBTreePartition.class );
116
117
118 private SearchEngine searchEngine;
119
120
121 private Optimizer optimizer;
122
123
124 protected boolean optimizerEnabled = true;
125
126
127 public static final int DEFAULT_CACHE_SIZE = 10000;
128
129
130 protected int cacheSize = DEFAULT_CACHE_SIZE;
131
132
133 protected Cache<String, Dn> aliasCache;
134
135
136 protected Cache<String, ParentIdAndRdn> piarCache;
137
138
139 protected AtomicBoolean isSyncOnWrite = new AtomicBoolean( true );
140
141
142 private volatile String suffixId;
143
144
145 protected URI partitionPath;
146
147
148 private Set<Index<?, String>> indexedAttributes;
149
150
151 protected MasterTable master;
152
153
154 protected Map<String, Index<?, String>> userIndices = new HashMap<>();
155
156
157 protected Map<String, Index<?, String>> systemIndices = new HashMap<>();
158
159
160 protected Index<ParentIdAndRdn, String> rdnIdx;
161
162
163 protected Index<String, String> objectClassIdx;
164
165
166 protected Index<String, String> presenceIdx;
167
168
169 protected Index<String, String> entryCsnIdx;
170
171
172 protected Index<Dn, String> aliasIdx;
173
174
175 protected Index<String, String> subAliasIdx;
176
177
178 protected Index<String, String> oneAliasIdx;
179
180
181 protected Index<String, String> adminRoleIdx;
182
183
184 protected AttributeType objectClassAT;
185 private Normalizer objectClassNormalizer;
186 protected AttributeType presenceAT;
187 private Normalizer presenceNormalizer;
188 protected AttributeType entryCsnAT;
189 protected AttributeType entryDnAT;
190 protected AttributeType entryUuidAT;
191 protected AttributeType aliasedObjectNameAT;
192 protected AttributeType administrativeRoleAT;
193 protected AttributeType contextCsnAT;
194
195
196 private Value topOCValue;
197
198 private static final boolean NO_REVERSE = Boolean.FALSE;
199 private static final boolean WITH_REVERSE = Boolean.TRUE;
200
201 private static final boolean ADD_CACHE = Boolean.TRUE;
202 private static final boolean DEL_CACHE = Boolean.FALSE;
203
204 protected static final boolean ADD_CHILD = true;
205 protected static final boolean REMOVE_CHILD = false;
206
207
208 private ReadWriteLock rwLock;
209
210
211 private Cache<String, Dn> entryDnCache;
212
213
214 private Semaphore ctxCsnSemaphore = new Semaphore( 1 );
215
216
217
218
219
220
221
222
223
224
225 protected AbstractBTreePartition( SchemaManager schemaManager )
226 {
227 this.schemaManager = schemaManager;
228
229 initInstance();
230 }
231
232
233
234
235
236
237
238
239 protected AbstractBTreePartition( SchemaManager schemaManager, DnFactory dnFactory )
240 {
241 this.schemaManager = schemaManager;
242 this.dnFactory = dnFactory;
243
244 initInstance();
245 }
246
247
248
249
250
251 private void initInstance()
252 {
253 indexedAttributes = new HashSet<>();
254
255
256 objectClassAT = schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
257 objectClassNormalizer = objectClassAT.getEquality().getNormalizer();
258 presenceAT = schemaManager.getAttributeType( ApacheSchemaConstants.APACHE_PRESENCE_AT );
259 presenceNormalizer = presenceAT.getEquality().getNormalizer();
260 aliasedObjectNameAT = schemaManager.getAttributeType( SchemaConstants.ALIASED_OBJECT_NAME_AT );
261 entryCsnAT = schemaManager.getAttributeType( SchemaConstants.ENTRY_CSN_AT );
262 entryDnAT = schemaManager.getAttributeType( SchemaConstants.ENTRY_DN_AT );
263 entryUuidAT = schemaManager.getAttributeType( SchemaConstants.ENTRY_UUID_AT );
264 administrativeRoleAT = schemaManager.getAttributeType( SchemaConstants.ADMINISTRATIVE_ROLE_AT );
265 contextCsnAT = schemaManager.getAttributeType( SchemaConstants.CONTEXT_CSN_AT );
266
267
268 try
269 {
270 topOCValue = new Value( schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT_OID ), SchemaConstants.TOP_OC_OID );
271 }
272 catch ( LdapInvalidAttributeValueException e )
273 {
274
275 }
276
277
278 entryDnAT.setRelaxed( true );
279 }
280
281
282
283
284
285
286
287
288
289
290 @Override
291 public int getCacheSize()
292 {
293 return cacheSize;
294 }
295
296
297
298
299
300
301
302
303
304 @Override
305 public void setCacheSize( int cacheSize )
306 {
307 this.cacheSize = cacheSize;
308 }
309
310
311
312
313
314
315 public boolean isOptimizerEnabled()
316 {
317 return optimizerEnabled;
318 }
319
320
321
322
323
324
325 public void setOptimizerEnabled( boolean optimizerEnabled )
326 {
327 this.optimizerEnabled = optimizerEnabled;
328 }
329
330
331
332
333
334
335
336
337 @Override
338 public void setPartitionPath( URI partitionPath )
339 {
340 checkInitialized( "partitionPath" );
341 this.partitionPath = partitionPath;
342 }
343
344
345
346
347
348 @Override
349 public boolean isSyncOnWrite()
350 {
351 return isSyncOnWrite.get();
352 }
353
354
355
356
357
358 @Override
359 public void setSyncOnWrite( boolean isSyncOnWrite )
360 {
361 checkInitialized( "syncOnWrite" );
362 this.isSyncOnWrite.set( isSyncOnWrite );
363 }
364
365
366
367
368
369
370
371 @SuppressWarnings("unchecked")
372 protected void setupSystemIndices() throws LdapException
373 {
374
375 if ( getPresenceIndex() == null )
376 {
377 Index<String, String> index = createSystemIndex( ApacheSchemaConstants.APACHE_PRESENCE_AT_OID,
378 partitionPath, NO_REVERSE );
379 addIndex( index );
380 }
381
382 if ( getRdnIndex() == null )
383 {
384 Index<ParentIdAndRdn, String> index = createSystemIndex(
385 ApacheSchemaConstants.APACHE_RDN_AT_OID,
386 partitionPath, WITH_REVERSE );
387 addIndex( index );
388 }
389
390 if ( getAliasIndex() == null )
391 {
392 Index<Dn, String> index = createSystemIndex( ApacheSchemaConstants.APACHE_ALIAS_AT_OID,
393 partitionPath, WITH_REVERSE );
394 addIndex( index );
395 }
396
397 if ( getOneAliasIndex() == null )
398 {
399 Index<String, String> index = createSystemIndex( ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID,
400 partitionPath, NO_REVERSE );
401 addIndex( index );
402 }
403
404 if ( getSubAliasIndex() == null )
405 {
406 Index<String, String> index = createSystemIndex( ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID,
407 partitionPath, NO_REVERSE );
408 addIndex( index );
409 }
410
411 if ( getObjectClassIndex() == null )
412 {
413 Index<String, String> index = createSystemIndex( SchemaConstants.OBJECT_CLASS_AT_OID, partitionPath,
414 NO_REVERSE );
415 addIndex( index );
416 }
417
418 if ( getEntryCsnIndex() == null )
419 {
420 Index<String, String> index = createSystemIndex( SchemaConstants.ENTRY_CSN_AT_OID, partitionPath,
421 NO_REVERSE );
422 addIndex( index );
423 }
424
425 if ( getAdministrativeRoleIndex() == null )
426 {
427 Index<String, String> index = createSystemIndex( SchemaConstants.ADMINISTRATIVE_ROLE_AT_OID,
428 partitionPath,
429 NO_REVERSE );
430 addIndex( index );
431 }
432
433
434 for ( Map.Entry<String, Index<?, String>> elem : systemIndices.entrySet() )
435 {
436 Index<?, String> index = elem.getValue();
437 index = convertAndInit( index );
438 systemIndices.put( elem.getKey(), index );
439 }
440
441
442 rdnIdx = ( Index<ParentIdAndRdn, String> ) systemIndices
443 .get( ApacheSchemaConstants.APACHE_RDN_AT_OID );
444 presenceIdx = ( Index<String, String> ) systemIndices.get( ApacheSchemaConstants.APACHE_PRESENCE_AT_OID );
445 aliasIdx = ( Index<Dn, String> ) systemIndices.get( ApacheSchemaConstants.APACHE_ALIAS_AT_OID );
446 oneAliasIdx = ( Index<String, String> ) systemIndices
447 .get( ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID );
448 subAliasIdx = ( Index<String, String> ) systemIndices
449 .get( ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID );
450 objectClassIdx = ( Index<String, String> ) systemIndices.get( SchemaConstants.OBJECT_CLASS_AT_OID );
451 entryCsnIdx = ( Index<String, String> ) systemIndices.get( SchemaConstants.ENTRY_CSN_AT_OID );
452 adminRoleIdx = ( Index<String, String> ) systemIndices.get( SchemaConstants.ADMINISTRATIVE_ROLE_AT_OID );
453 }
454
455
456
457
458
459
460
461 protected void setupUserIndices() throws LdapException
462 {
463
464 Map<String, Index<?, String>> tmp = new HashMap<>();
465
466 for ( Map.Entry<String, Index<?, String>> elem : userIndices.entrySet() )
467 {
468 String oid = elem.getKey();
469
470
471 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
472 MatchingRule mr = attributeType.getEquality();
473
474 if ( mr != null )
475 {
476 Index<?, String> index = elem.getValue();
477 index = convertAndInit( index );
478 tmp.put( oid, index );
479 }
480 else
481 {
482 LOG.error( I18n.err( I18n.ERR_4, attributeType.getName() ) );
483 }
484 }
485
486 userIndices = tmp;
487 }
488
489
490
491
492
493
494
495
496 public SearchEngine getSearchEngine()
497 {
498 return searchEngine;
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512 protected abstract Index<?, String> convertAndInit( Index<?, String> index ) throws LdapException;
513
514
515
516
517
518
519
520 @Override
521 public URI getPartitionPath()
522 {
523 return partitionPath;
524 }
525
526
527
528
529
530
531
532
533 @Override
534 protected void doDestroy( PartitionTxn partitionTxn ) throws LdapException
535 {
536 LOG.debug( "destroy() called on store for {}", this.suffixDn );
537
538 if ( !initialized )
539 {
540 return;
541 }
542
543
544 initialized = false;
545
546 aliasCache.invalidateAll();
547 piarCache.invalidateAll();
548 entryDnCache.invalidateAll();
549
550 MultiException errors = new MultiException( I18n.err( I18n.ERR_577 ) );
551
552 for ( Index<?, String> index : userIndices.values() )
553 {
554 try
555 {
556 index.close( partitionTxn );
557 LOG.debug( "Closed {} user index for {} partition.", index.getAttributeId(), suffixDn );
558 }
559 catch ( Throwable t )
560 {
561 LOG.error( I18n.err( I18n.ERR_124 ), t );
562 errors.addThrowable( t );
563 }
564 }
565
566 for ( Index<?, String> index : systemIndices.values() )
567 {
568 try
569 {
570 index.close( partitionTxn );
571 LOG.debug( "Closed {} system index for {} partition.", index.getAttributeId(), suffixDn );
572 }
573 catch ( Throwable t )
574 {
575 LOG.error( I18n.err( I18n.ERR_124 ), t );
576 errors.addThrowable( t );
577 }
578 }
579
580 try
581 {
582 master.close( partitionTxn );
583
584 if ( LOG.isDebugEnabled() )
585 {
586 LOG.debug( I18n.err( I18n.ERR_125, suffixDn ) );
587 }
588 }
589 catch ( Throwable t )
590 {
591 LOG.error( I18n.err( I18n.ERR_126 ), t );
592 errors.addThrowable( t );
593 }
594
595 if ( errors.size() > 0 )
596 {
597 throw new LdapOtherException( errors.getMessage(), errors );
598 }
599 }
600
601
602
603
604
605 @Override
606 public void repair() throws LdapException
607 {
608
609 doRepair();
610 }
611
612
613
614
615
616 @Override
617 protected void doInit() throws LdapException
618 {
619
620 if ( ( indexedAttributes != null ) && ( !indexedAttributes.isEmpty() ) )
621 {
622 for ( Index index : indexedAttributes )
623 {
624 addIndex( index );
625 }
626 }
627
628
629 setupSystemIndices();
630 setupUserIndices();
631
632 aliasCache = Caffeine.newBuilder().maximumSize( cacheSize ).expireAfterAccess( Duration.ofMinutes( 20 ) )
633 .build();
634
635 piarCache = Caffeine.newBuilder().maximumSize( cacheSize * 3L )
636 .expireAfterAccess( Duration.ofMinutes( 20 ) ).build();
637
638 entryDnCache = Caffeine.newBuilder().maximumSize( cacheSize ).expireAfterAccess( Duration.ofMinutes( 20 ) )
639 .build();
640 }
641
642
643 private void dumpAllRdnIdx( PartitionTxn partitionTxn ) throws LdapException, CursorException, IOException
644 {
645 if ( LOG.isDebugEnabled() )
646 {
647 dumpRdnIdx( partitionTxn, Partition.ROOT_ID, "" );
648 System.out.println( "-----------------------------" );
649 }
650 }
651
652
653 private void dumpRdnIdx( PartitionTxn partitionTxn ) throws LdapException, CursorException, IOException
654 {
655 if ( LOG.isDebugEnabled() )
656 {
657 dumpRdnIdx( partitionTxn, Partition.ROOT_ID, 1, "" );
658 System.out.println( "-----------------------------" );
659 }
660 }
661
662
663
664
665
666
667
668
669
670
671
672
673 public void dumpRdnIdx( PartitionTxn partitionTxn, String id, String tabs ) throws LdapException, CursorException, IOException
674 {
675
676 Cursor<IndexEntry<ParentIdAndRdn, String>> cursor = rdnIdx.forwardCursor( partitionTxn );
677
678 IndexEntry<ParentIdAndRdn, String> startingPos = new IndexEntry<>();
679 startingPos.setKey( new ParentIdAndRdn( id, ( Rdn[] ) null ) );
680 cursor.before( startingPos );
681
682 while ( cursor.next() )
683 {
684 IndexEntry<ParentIdAndRdn, String> entry = cursor.get();
685 System.out.println( tabs + entry );
686 }
687
688 cursor.close();
689 }
690
691
692 private void dumpRdnIdx( PartitionTxn partitionTxn, String id, int nbSibbling, String tabs )
693 throws LdapException, CursorException, IOException
694 {
695
696 Cursor<IndexEntry<ParentIdAndRdn, String>> cursor = rdnIdx.forwardCursor( partitionTxn );
697
698 IndexEntry<ParentIdAndRdn, String> startingPos = new IndexEntry<>();
699 startingPos.setKey( new ParentIdAndRdn( id, ( Rdn[] ) null ) );
700 cursor.before( startingPos );
701 int countChildren = 0;
702
703 while ( cursor.next() && ( countChildren < nbSibbling ) )
704 {
705 IndexEntry<ParentIdAndRdn, String> entry = cursor.get();
706 System.out.println( tabs + entry );
707 countChildren++;
708
709
710 int nbChildren = entry.getKey().getNbChildren();
711
712 if ( nbChildren > 0 )
713 {
714 dumpRdnIdx( partitionTxn, entry.getId(), nbChildren, tabs + " " );
715 }
716 }
717
718 cursor.close();
719 }
720
721
722
723
724
725 private ParentIdAndRdn getParentId( PartitionTxn partitionTxn, Dn entryDn ) throws LdapException
726 {
727 ParentIdAndRdn key;
728
729 if ( entryDn.getNormName().equals( suffixDn.getNormName() ) )
730 {
731 key = new ParentIdAndRdn( Partition.ROOT_ID, suffixDn.getRdns() );
732 }
733 else
734 {
735 String parentId = null;
736 Dn parentDn = entryDn.getParent();
737
738 lockRead();
739
740 try
741 {
742 parentId = getEntryId( partitionTxn, parentDn );
743 }
744 finally
745 {
746 unlockRead();
747 }
748
749 if ( parentId == null )
750 {
751 return null;
752 }
753
754 key = new ParentIdAndRdn( parentId, entryDn.getRdn() );
755 }
756
757 return key;
758 }
759
760
761
762
763
764 @Override
765 public void add( AddOperationContext addContext ) throws LdapException
766 {
767 PartitionTxn partitionTxn = addContext.getTransaction();
768
769 assert ( partitionTxn != null );
770 assert ( partitionTxn instanceof PartitionWriteTxn );
771
772 try
773 {
774 setRWLock( addContext );
775 Entry entry = ( ( ClonedServerEntry ) addContext.getEntry() ).getClonedEntry();
776
777 Dn entryDn = entry.getDn();
778
779
780 ParentIdAndRdn parentIdAndRdn = getParentId( partitionTxn, entryDn );
781
782
783 if ( parentIdAndRdn == null )
784 {
785 throw new LdapNoSuchObjectException( I18n.err( I18n.ERR_216_ID_FOR_PARENT_NOT_FOUND,
786 parentIdAndRdn ) );
787 }
788
789 String parentId = parentIdAndRdn.getParentId();
790
791 lockRead();
792
793 try
794 {
795 if ( rdnIdx.forwardLookup( partitionTxn, parentIdAndRdn ) != null )
796 {
797 throw new LdapEntryAlreadyExistsException(
798 I18n.err( I18n.ERR_250_ENTRY_ALREADY_EXISTS, entryDn.getName() ) );
799 }
800 }
801 finally
802 {
803 unlockRead();
804 }
805
806
807 Attribute entryUUID = entry.get( entryUuidAT );
808
809 String id;
810
811 if ( entryUUID == null )
812 {
813 id = master.getNextId( entry );
814 }
815 else
816 {
817 id = entryUUID.getString();
818 }
819
820 if ( entryDn.getNormName().equals( suffixDn.getNormName() ) )
821 {
822 suffixId = id;
823 }
824
825
826 Attribute objectClass = entry.get( objectClassAT );
827
828 if ( objectClass == null )
829 {
830 String msg = I18n.err( I18n.ERR_217, entryDn.getName(), entry );
831 ResultCodeEnum rc = ResultCodeEnum.OBJECT_CLASS_VIOLATION;
832
833 throw new LdapSchemaViolationException( rc, msg );
834 }
835
836 for ( Value value : objectClass )
837 {
838 if ( value.equals( topOCValue ) )
839 {
840 continue;
841 }
842
843 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
844
845 objectClassIdx.add( partitionTxn, normalizedOc, id );
846 }
847
848 if ( objectClass.contains( SchemaConstants.ALIAS_OC ) )
849 {
850 Attribute aliasAttr = entry.get( aliasedObjectNameAT );
851
852 addAliasIndices( partitionTxn, id, entryDn, new Dn( schemaManager, aliasAttr.getString() ) );
853 }
854
855
856 Attribute entryCsn = entry.get( entryCsnAT );
857
858 if ( entryCsn == null )
859 {
860 String msg = I18n.err( I18n.ERR_219, entryDn.getName(), entry );
861 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, msg );
862 }
863
864 entryCsnIdx.add( partitionTxn, entryCsn.getString(), id );
865
866
867 if ( entry.containsAttribute( administrativeRoleAT ) )
868 {
869
870 Attribute adminRoles = entry.get( administrativeRoleAT );
871
872 for ( Value value : adminRoles )
873 {
874 adminRoleIdx.add( partitionTxn, value.getString(), id );
875 }
876
877
878 presenceIdx.add( partitionTxn, administrativeRoleAT.getOid(), id );
879 }
880
881
882 for ( Attribute attribute : entry )
883 {
884 AttributeType attributeType = attribute.getAttributeType();
885 String attributeOid = attributeType.getOid();
886
887 if ( hasUserIndexOn( attributeType ) )
888 {
889 Index<Object, String> userIndex = ( Index<Object, String> ) getUserIndex( attributeType );
890
891
892
893
894 for ( Value value : attribute )
895 {
896 String normalized = value.getNormalized();
897 userIndex.add( partitionTxn, normalized, id );
898 }
899
900
901 presenceIdx.add( partitionTxn, attributeOid, id );
902 }
903 }
904
905
906 entry.put( ApacheSchemaConstants.ENTRY_PARENT_ID_AT, parentId );
907
908 lockWrite();
909
910 try
911 {
912
913 rdnIdx.add( partitionTxn, parentIdAndRdn, id );
914
915
916 updatePiarCache( parentIdAndRdn, id, ADD_CACHE );
917
918
919 if ( parentId != Partition.ROOT_ID )
920 {
921 updateRdnIdx( partitionTxn, parentId, ADD_CHILD, 0 );
922 }
923
924
925 entry.removeAttributes( entryDnAT );
926
927 Attribute at = entry.get( SchemaConstants.ENTRY_CSN_AT );
928 setContextCsn( at.getString() );
929
930
931 master.put( partitionTxn, id, entry );
932 }
933 finally
934 {
935 unlockWrite();
936 }
937 }
938 catch ( LdapException le )
939 {
940 throw le;
941 }
942 catch ( Exception e )
943 {
944 throw new LdapException( e );
945 }
946 }
947
948
949
950
951
952
953
954
955 @Override
956 public Entry delete( DeleteOperationContext deleteContext ) throws LdapException
957 {
958 PartitionTxn partitionTxn = deleteContext.getTransaction();
959
960 assert ( partitionTxn != null );
961 assert ( partitionTxn instanceof PartitionWriteTxn );
962
963 setRWLock( deleteContext );
964 Dn dn = deleteContext.getDn();
965 String id = null;
966
967 lockRead();
968
969 try
970 {
971 id = getEntryId( partitionTxn, dn );
972 }
973 finally
974 {
975 unlockRead();
976 }
977
978
979 if ( id == null )
980 {
981 throw new LdapNoSuchObjectException( I18n.err( I18n.ERR_699, dn ) );
982 }
983
984 long childCount = getChildCount( partitionTxn, id );
985
986 if ( childCount > 0 )
987 {
988 throw new LdapContextNotEmptyException( I18n.err( I18n.ERR_700, dn ) );
989 }
990
991
992 Entry deletedEntry = delete( partitionTxn, id );
993
994 updateCache( deleteContext );
995
996 return deletedEntry;
997 }
998
999
1000 protected void updateRdnIdx( PartitionTxn partitionTxn, String parentId, boolean addRemove, int nbDescendant ) throws LdapException
1001 {
1002 boolean isFirst = true;
1003
1004 if ( parentId.equals( Partition.ROOT_ID ) )
1005 {
1006 return;
1007 }
1008
1009 ParentIdAndRdn parent = rdnIdx.reverseLookup( partitionTxn, parentId );
1010
1011 while ( parent != null )
1012 {
1013 rdnIdx.drop( partitionTxn, parentId );
1014
1015 if ( isFirst )
1016 {
1017 if ( addRemove == ADD_CHILD )
1018 {
1019 parent.setNbChildren( parent.getNbChildren() + 1 );
1020 }
1021 else
1022 {
1023 parent.setNbChildren( parent.getNbChildren() - 1 );
1024 }
1025
1026 isFirst = false;
1027 }
1028
1029 if ( addRemove == ADD_CHILD )
1030 {
1031 parent.setNbDescendants( parent.getNbDescendants() + ( nbDescendant + 1 ) );
1032 }
1033 else
1034 {
1035 parent.setNbDescendants( parent.getNbDescendants() - ( nbDescendant + 1 ) );
1036 }
1037
1038
1039 rdnIdx.add( partitionTxn, parent, parentId );
1040
1041
1042
1043 parentId = parent.getParentId();
1044 parent = rdnIdx.reverseLookup( partitionTxn, parentId );
1045 }
1046 }
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057 @Override
1058 public Entry delete( PartitionTxn partitionTxn, String id ) throws LdapException
1059 {
1060 try
1061 {
1062
1063 Entry entry = null;
1064
1065 lockRead();
1066
1067 try
1068 {
1069 entry = master.get( partitionTxn, id );
1070 }
1071 finally
1072 {
1073 unlockRead();
1074 }
1075
1076 if ( entry == null )
1077 {
1078
1079 throw new LdapNoSuchObjectException( "Cannot find an entry for UUID " + id );
1080 }
1081
1082 Attribute objectClass = entry.get( objectClassAT );
1083
1084 if ( objectClass.contains( SchemaConstants.ALIAS_OC ) )
1085 {
1086 dropAliasIndices( partitionTxn, id );
1087 }
1088
1089
1090 for ( Value value : objectClass )
1091 {
1092 if ( value.equals( topOCValue ) )
1093 {
1094 continue;
1095 }
1096
1097 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1098
1099 objectClassIdx.drop( partitionTxn, normalizedOc, id );
1100 }
1101
1102
1103 ParentIdAndRdn parent = rdnIdx.reverseLookup( partitionTxn, id );
1104 updateRdnIdx( partitionTxn, parent.getParentId(), REMOVE_CHILD, 0 );
1105
1106
1107 entryCsnIdx.drop( partitionTxn, entry.get( entryCsnAT ).getString(), id );
1108
1109
1110 if ( entry.containsAttribute( administrativeRoleAT ) )
1111 {
1112
1113 Attribute adminRoles = entry.get( administrativeRoleAT );
1114
1115 for ( Value value : adminRoles )
1116 {
1117 adminRoleIdx.drop( partitionTxn, value.getString(), id );
1118 }
1119
1120
1121 presenceIdx.drop( partitionTxn, administrativeRoleAT.getOid(), id );
1122 }
1123
1124
1125 for ( Attribute attribute : entry )
1126 {
1127 AttributeType attributeType = attribute.getAttributeType();
1128 String attributeOid = attributeType.getOid();
1129
1130 if ( hasUserIndexOn( attributeType ) )
1131 {
1132 Index<?, String> userIndex = getUserIndex( attributeType );
1133
1134
1135
1136 for ( Value value : attribute )
1137 {
1138 String normalized = value.getNormalized();
1139 ( ( Index ) userIndex ).drop( partitionTxn, normalized, id );
1140 }
1141
1142 presenceIdx.drop( partitionTxn, attributeOid, id );
1143 }
1144 }
1145
1146 lockWrite();
1147
1148 try
1149 {
1150 rdnIdx.drop( partitionTxn, id );
1151
1152 updatePiarCache( parent, id, DEL_CACHE );
1153
1154 entryDnCache.invalidate( id );
1155
1156 Attribute csn = entry.get( entryCsnAT );
1157
1158 if ( csn != null )
1159 {
1160 setContextCsn( csn.getString() );
1161 }
1162
1163 master.remove( partitionTxn, id );
1164 }
1165 finally
1166 {
1167 unlockWrite();
1168 }
1169
1170 if ( isSyncOnWrite.get() )
1171 {
1172 sync();
1173 }
1174
1175 return entry;
1176 }
1177 catch ( Exception e )
1178 {
1179 throw new LdapOperationErrorException( e.getMessage(), e );
1180 }
1181 }
1182
1183
1184
1185
1186
1187
1188
1189
1190 @Override
1191 public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException
1192 {
1193 PartitionTxn partitionTxn = searchContext.getTransaction();
1194
1195 assert ( partitionTxn != null );
1196
1197 try
1198 {
1199 setRWLock( searchContext );
1200
1201 if ( ctxCsnChanged && getSuffixDn().equals( searchContext.getDn() ) )
1202 {
1203 try
1204 {
1205 ctxCsnSemaphore.acquire();
1206 saveContextCsn( partitionTxn );
1207 ctxCsnChanged = false;
1208 }
1209 catch ( Exception e )
1210 {
1211 throw new LdapOperationErrorException( e.getMessage(), e );
1212 }
1213 finally
1214 {
1215 ctxCsnSemaphore.release();
1216 }
1217 }
1218
1219 PartitionSearchResult searchResult = searchEngine.computeResult( partitionTxn, schemaManager, searchContext );
1220
1221 Cursor<Entry> result = new EntryCursorAdaptor( partitionTxn, this, searchResult );
1222
1223 return new EntryFilteringCursorImpl( result, searchContext, schemaManager );
1224 }
1225 catch ( LdapException le )
1226 {
1227
1228 throw le;
1229 }
1230 catch ( Exception e )
1231 {
1232 throw new LdapOperationErrorException( e.getMessage(), e );
1233 }
1234 }
1235
1236
1237
1238
1239
1240
1241
1242
1243 @Override
1244 public Entry lookup( LookupOperationContext lookupContext ) throws LdapException
1245 {
1246 PartitionTxn partitionTxn = lookupContext.getTransaction();
1247
1248 assert ( partitionTxn != null );
1249
1250 try
1251 {
1252 setRWLock( lookupContext );
1253 String id = getEntryId( partitionTxn, lookupContext.getDn() );
1254
1255 if ( id == null )
1256 {
1257 return null;
1258 }
1259
1260 if ( ctxCsnChanged && getSuffixDn().getNormName().equals( lookupContext.getDn().getNormName() ) )
1261 {
1262 try
1263 {
1264 ctxCsnSemaphore.acquire();
1265 saveContextCsn( partitionTxn );
1266 }
1267 catch ( Exception e )
1268 {
1269 throw new LdapOperationErrorException( e.getMessage(), e );
1270 }
1271 finally
1272 {
1273 ctxCsnSemaphore.release();
1274 }
1275 }
1276
1277 return fetch( partitionTxn, id, lookupContext.getDn() );
1278 }
1279 catch ( Exception e )
1280 {
1281 throw new LdapOperationErrorException( e.getMessage() );
1282 }
1283 }
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294 @Override
1295 public Entry fetch( PartitionTxn partitionTxn, String id ) throws LdapException
1296 {
1297 try
1298 {
1299 rwLock.readLock().lock();
1300
1301 if ( id == null )
1302 {
1303 id = "";
1304 }
1305
1306 Dn dn = buildEntryDn( partitionTxn, id );
1307
1308 return fetch( partitionTxn, id, dn );
1309 }
1310 catch ( Exception e )
1311 {
1312 throw new LdapOperationErrorException( e.getMessage(), e );
1313 }
1314 finally
1315 {
1316 rwLock.readLock().unlock();
1317 }
1318 }
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329 @Override
1330 public Entry fetch( PartitionTxn partitionTxn, String id, Dn dn ) throws LdapException
1331 {
1332 try
1333 {
1334 Entry entry = lookupCache( id );
1335
1336 if ( entry != null )
1337 {
1338 entry.setDn( dn );
1339
1340 entry = new ClonedServerEntry( entry );
1341
1342
1343 Attribute entryDnAt = entry.get( entryDnAT );
1344 Value dnValue = new Value( entryDnAT, dn.getName(), dn.getNormName() );
1345
1346 if ( entryDnAt == null )
1347 {
1348 entry.add( entryDnAT, dnValue );
1349 }
1350 else
1351 {
1352 entryDnAt.clear();
1353 entryDnAt.add( dnValue );
1354 }
1355
1356 return entry;
1357 }
1358
1359 try
1360 {
1361 rwLock.readLock().lock();
1362 entry = master.get( partitionTxn, id );
1363 }
1364 finally
1365 {
1366 rwLock.readLock().unlock();
1367 }
1368
1369 if ( entry != null )
1370 {
1371
1372 entry.setDn( dn );
1373
1374
1375 addToCache( id, entry );
1376
1377 entry = new ClonedServerEntry( entry );
1378
1379 if ( !entry.containsAttribute( entryDnAT ) )
1380 {
1381 entry.add( entryDnAT, dn.getName() );
1382 }
1383
1384 return entry;
1385 }
1386
1387 return null;
1388 }
1389 catch ( Exception e )
1390 {
1391 throw new LdapOperationErrorException( e.getMessage(), e );
1392 }
1393 }
1394
1395
1396
1397
1398
1399
1400
1401
1402 @Override
1403 public void modify( ModifyOperationContext modifyContext ) throws LdapException
1404 {
1405 PartitionTxn partitionTxn = modifyContext.getTransaction();
1406
1407 assert ( partitionTxn != null );
1408 assert ( partitionTxn instanceof PartitionWriteTxn );
1409
1410 try
1411 {
1412 setRWLock( modifyContext );
1413
1414 Entry modifiedEntry = modify( partitionTxn, modifyContext.getDn(),
1415 modifyContext.getModItems().toArray( new Modification[]
1416 {} ) );
1417
1418 modifyContext.setAlteredEntry( modifiedEntry );
1419
1420 updateCache( modifyContext );
1421 }
1422 catch ( Exception e )
1423 {
1424 throw new LdapOperationErrorException( e.getMessage(), e );
1425 }
1426 }
1427
1428
1429
1430
1431
1432 @Override
1433 public final synchronized Entry modify( PartitionTxn partitionTxn, Dn dn, Modification... mods ) throws LdapException
1434 {
1435 String id = getEntryId( partitionTxn, dn );
1436 Entry entry = master.get( partitionTxn, id );
1437
1438 for ( Modification mod : mods )
1439 {
1440 Attribute attrMods = mod.getAttribute();
1441
1442 try
1443 {
1444 switch ( mod.getOperation() )
1445 {
1446 case ADD_ATTRIBUTE:
1447 modifyAdd( partitionTxn, id, entry, attrMods );
1448 break;
1449
1450 case REMOVE_ATTRIBUTE:
1451 modifyRemove( partitionTxn, id, entry, attrMods );
1452 break;
1453
1454 case REPLACE_ATTRIBUTE:
1455 modifyReplace( partitionTxn, id, entry, attrMods );
1456 break;
1457
1458 case INCREMENT_ATTRIBUTE:
1459 modifyIncrement( partitionTxn, id, entry, attrMods );
1460 break;
1461
1462 default:
1463 throw new LdapException( I18n.err( I18n.ERR_221 ) );
1464 }
1465 }
1466 catch ( IndexNotFoundException infe )
1467 {
1468 throw new LdapOtherException( infe.getMessage(), infe );
1469 }
1470 }
1471
1472 updateCsnIndex( partitionTxn, entry, id );
1473
1474
1475 entry.removeAttributes( entryDnAT );
1476
1477 setContextCsn( entry.get( entryCsnAT ).getString() );
1478
1479 master.put( partitionTxn, id, entry );
1480
1481 return entry;
1482 }
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496 @SuppressWarnings("unchecked")
1497 private void modifyAdd( PartitionTxn partitionTxn, String id, Entry entry, Attribute mods )
1498 throws LdapException, IndexNotFoundException
1499 {
1500 if ( entry instanceof ClonedServerEntry )
1501 {
1502 throw new LdapOtherException( I18n.err( I18n.ERR_215_CANNOT_STORE_CLONED_SERVER_ENTRY ) );
1503 }
1504
1505 String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() );
1506 String normalizedModsOid = presenceNormalizer.normalize( modsOid );
1507
1508 AttributeType attributeType = mods.getAttributeType();
1509
1510
1511 if ( modsOid.equals( SchemaConstants.OBJECT_CLASS_AT_OID ) )
1512 {
1513 for ( Value value : mods )
1514 {
1515 if ( value.equals( topOCValue ) )
1516 {
1517 continue;
1518 }
1519
1520 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1521
1522 objectClassIdx.add( partitionTxn, normalizedOc, id );
1523 }
1524 }
1525 else if ( hasUserIndexOn( attributeType ) )
1526 {
1527 Index<?, String> userIndex = getUserIndex( attributeType );
1528
1529 if ( mods.size() > 0 )
1530 {
1531 for ( Value value : mods )
1532 {
1533 String normalized = value.getNormalized();
1534 ( ( Index ) userIndex ).add( partitionTxn, normalized, id );
1535 }
1536 }
1537 else
1538 {
1539
1540 ( ( Index ) userIndex ).add( partitionTxn, null, id );
1541 }
1542
1543
1544 if ( !presenceIdx.forward( partitionTxn, normalizedModsOid, id ) )
1545 {
1546 presenceIdx.add( partitionTxn, normalizedModsOid, id );
1547 }
1548 }
1549
1550 else if ( modsOid.equals( SchemaConstants.ADMINISTRATIVE_ROLE_AT_OID ) )
1551 {
1552
1553 for ( Value value : mods )
1554 {
1555 adminRoleIdx.add( partitionTxn, value.getString(), id );
1556 }
1557
1558
1559 if ( !presenceIdx.forward( partitionTxn, normalizedModsOid, id ) )
1560 {
1561 presenceIdx.add( partitionTxn, normalizedModsOid, id );
1562 }
1563 }
1564
1565
1566 if ( mods.size() > 0 )
1567 {
1568 for ( Value value : mods )
1569 {
1570 entry.add( mods.getAttributeType(), value );
1571 }
1572 }
1573 else
1574 {
1575
1576 if ( mods.getAttributeType().getSyntax().isHumanReadable() )
1577 {
1578 entry.add( mods.getAttributeType(), new Value( mods.getAttributeType(), ( String ) null ) );
1579 }
1580 else
1581 {
1582 entry.add( mods.getAttributeType(), new Value( mods.getAttributeType(), ( byte[] ) null ) );
1583 }
1584 }
1585
1586 if ( modsOid.equals( SchemaConstants.ALIASED_OBJECT_NAME_AT_OID ) )
1587 {
1588 Dn ndn = getEntryDn( partitionTxn, id );
1589 addAliasIndices( partitionTxn, id, ndn, new Dn( schemaManager, mods.getString() ) );
1590 }
1591 }
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607 @SuppressWarnings("unchecked")
1608 private void modifyReplace( PartitionTxn partitionTxn, String id, Entry entry, Attribute mods )
1609 throws LdapException, IndexNotFoundException
1610 {
1611 if ( entry instanceof ClonedServerEntry )
1612 {
1613 throw new LdapOtherException( I18n.err( I18n.ERR_215_CANNOT_STORE_CLONED_SERVER_ENTRY ) );
1614 }
1615
1616 String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() );
1617 AttributeType attributeType = mods.getAttributeType();
1618
1619
1620 if ( attributeType.equals( objectClassAT ) )
1621 {
1622
1623
1624 for ( Value value : entry.get( objectClassAT ) )
1625 {
1626 if ( value.equals( topOCValue ) )
1627 {
1628 continue;
1629 }
1630
1631 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1632
1633 objectClassIdx.drop( partitionTxn, normalizedOc, id );
1634 }
1635
1636 for ( Value value : mods )
1637 {
1638 if ( value.equals( topOCValue ) )
1639 {
1640 continue;
1641 }
1642
1643 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1644
1645 objectClassIdx.add( partitionTxn, normalizedOc, id );
1646 }
1647 }
1648 else if ( hasUserIndexOn( attributeType ) )
1649 {
1650 Index<?, String> userIndex = getUserIndex( attributeType );
1651
1652
1653 Attribute oldAttribute = entry.get( mods.getAttributeType() );
1654
1655 if ( oldAttribute != null )
1656 {
1657 for ( Value value : oldAttribute )
1658 {
1659 String normalized = value.getNormalized();
1660 ( ( Index<Object, String> ) userIndex ).drop( partitionTxn, normalized, id );
1661 }
1662 }
1663
1664
1665 for ( Value value : mods )
1666 {
1667 String normalized = value.getNormalized();
1668 ( ( Index ) userIndex ).add( partitionTxn, normalized, id );
1669 }
1670
1671
1672
1673
1674 if ( mods.size() == 0 )
1675 {
1676 presenceIdx.drop( partitionTxn, modsOid, id );
1677 }
1678 }
1679
1680 else if ( attributeType.equals( administrativeRoleAT ) )
1681 {
1682
1683 for ( Value value : entry.get( administrativeRoleAT ) )
1684 {
1685 if ( value.equals( topOCValue ) )
1686 {
1687 continue;
1688 }
1689
1690 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1691
1692 objectClassIdx.drop( partitionTxn, normalizedOc, id );
1693 }
1694
1695
1696 for ( Value value : mods )
1697 {
1698 String valueStr = value.getString();
1699
1700 if ( valueStr.equals( topOCValue ) )
1701 {
1702 continue;
1703 }
1704
1705 adminRoleIdx.add( partitionTxn, valueStr, id );
1706 }
1707 }
1708
1709 String aliasAttributeOid = schemaManager.getAttributeTypeRegistry().getOidByName(
1710 SchemaConstants.ALIASED_OBJECT_NAME_AT );
1711
1712 if ( mods.getAttributeType().equals( aliasedObjectNameAT ) )
1713 {
1714 dropAliasIndices( partitionTxn, id );
1715 }
1716
1717
1718 if ( mods.size() > 0 )
1719 {
1720 entry.put( mods );
1721 }
1722 else
1723
1724 {
1725 entry.remove( mods );
1726 }
1727
1728 if ( modsOid.equals( aliasAttributeOid ) && mods.size() > 0 )
1729 {
1730 Dn entryDn = getEntryDn( partitionTxn, id );
1731 addAliasIndices( partitionTxn, id, entryDn, new Dn( schemaManager, mods.getString() ) );
1732 }
1733 }
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749 @SuppressWarnings("unchecked")
1750 private void modifyIncrement( PartitionTxn partitionTxn, String id, Entry entry, Attribute mods )
1751 throws LdapException, IndexNotFoundException
1752 {
1753 if ( entry instanceof ClonedServerEntry )
1754 {
1755 throw new LdapOtherException( I18n.err( I18n.ERR_215_CANNOT_STORE_CLONED_SERVER_ENTRY ) );
1756 }
1757
1758 String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() );
1759 AttributeType attributeType = mods.getAttributeType();
1760
1761
1762 if ( attributeType.equals( objectClassAT ) )
1763 {
1764
1765
1766 for ( Value value : entry.get( objectClassAT ) )
1767 {
1768 if ( value.equals( topOCValue ) )
1769 {
1770 continue;
1771 }
1772
1773 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1774
1775 objectClassIdx.drop( partitionTxn, normalizedOc, id );
1776 }
1777
1778 for ( Value value : mods )
1779 {
1780 if ( value.equals( topOCValue ) )
1781 {
1782 continue;
1783 }
1784
1785 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1786
1787 objectClassIdx.add( partitionTxn, normalizedOc, id );
1788 }
1789 }
1790 else if ( hasUserIndexOn( attributeType ) )
1791 {
1792 Index<?, String> userIndex = getUserIndex( attributeType );
1793
1794
1795 Attribute oldAttribute = entry.get( mods.getAttributeType() );
1796
1797 if ( oldAttribute != null )
1798 {
1799 for ( Value value : oldAttribute )
1800 {
1801 String normalized = value.getNormalized();
1802 ( ( Index<Object, String> ) userIndex ).drop( partitionTxn, normalized, id );
1803 }
1804 }
1805
1806
1807 for ( Value value : mods )
1808 {
1809 String normalized = value.getNormalized();
1810 ( ( Index ) userIndex ).add( partitionTxn, normalized, id );
1811 }
1812
1813
1814
1815
1816 if ( mods.size() == 0 )
1817 {
1818 presenceIdx.drop( partitionTxn, modsOid, id );
1819 }
1820 }
1821
1822 else if ( attributeType.equals( administrativeRoleAT ) )
1823 {
1824
1825 for ( Value value : entry.get( administrativeRoleAT ) )
1826 {
1827 if ( value.equals( topOCValue ) )
1828 {
1829 continue;
1830 }
1831
1832 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1833
1834 objectClassIdx.drop( partitionTxn, normalizedOc, id );
1835 }
1836
1837
1838 for ( Value value : mods )
1839 {
1840 String valueStr = value.getString();
1841
1842 if ( valueStr.equals( topOCValue ) )
1843 {
1844 continue;
1845 }
1846
1847 adminRoleIdx.add( partitionTxn, valueStr, id );
1848 }
1849 }
1850
1851 String aliasAttributeOid = schemaManager.getAttributeTypeRegistry().getOidByName(
1852 SchemaConstants.ALIASED_OBJECT_NAME_AT );
1853
1854 if ( mods.getAttributeType().equals( aliasedObjectNameAT ) )
1855 {
1856 dropAliasIndices( partitionTxn, id );
1857 }
1858
1859
1860 Attribute attribute = entry.get( mods.getAttributeType() );
1861 Value[] newValues = new Value[ attribute.size() ];
1862 int increment = 1;
1863 int i = 0;
1864
1865 if ( mods.size() != 0 )
1866 {
1867 increment = Integer.parseInt( mods.getString() );
1868 }
1869
1870 for ( Value value : attribute )
1871 {
1872 int intValue = Integer.parseInt( value.getNormalized() );
1873
1874 if ( intValue >= Integer.MAX_VALUE - increment )
1875 {
1876 throw new IllegalArgumentException( "Increment operation overflow for attribute"
1877 + attributeType );
1878 }
1879
1880 newValues[i++] = new Value( Integer.toString( intValue + increment ) );
1881 attribute.remove( value );
1882 }
1883
1884 attribute.add( newValues );
1885
1886 if ( modsOid.equals( aliasAttributeOid ) && mods.size() > 0 )
1887 {
1888 Dn entryDn = getEntryDn( partitionTxn, id );
1889 addAliasIndices( partitionTxn, id, entryDn, new Dn( schemaManager, mods.getString() ) );
1890 }
1891 }
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908 @SuppressWarnings("unchecked")
1909 private void modifyRemove( PartitionTxn partitionTxn, String id, Entry entry, Attribute mods )
1910 throws LdapException, IndexNotFoundException
1911 {
1912 if ( entry instanceof ClonedServerEntry )
1913 {
1914 throw new LdapOtherException( I18n.err( I18n.ERR_215_CANNOT_STORE_CLONED_SERVER_ENTRY ) );
1915 }
1916
1917 String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() );
1918 AttributeType attributeType = mods.getAttributeType();
1919
1920
1921 if ( attributeType.equals( objectClassAT ) )
1922 {
1923
1924
1925
1926
1927
1928 if ( mods.size() == 0 )
1929 {
1930 for ( Value value : entry.get( objectClassAT ) )
1931 {
1932 if ( value.equals( topOCValue ) )
1933 {
1934 continue;
1935 }
1936
1937 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1938
1939 objectClassIdx.drop( partitionTxn, normalizedOc, id );
1940 }
1941 }
1942 else
1943 {
1944 for ( Value value : mods )
1945 {
1946 if ( value.equals( topOCValue ) )
1947 {
1948 continue;
1949 }
1950
1951 String normalizedOc = objectClassNormalizer.normalize( value.getString() );
1952
1953 objectClassIdx.drop( partitionTxn, normalizedOc, id );
1954 }
1955 }
1956 }
1957 else if ( hasUserIndexOn( attributeType ) )
1958 {
1959 Index<?, String> userIndex = getUserIndex( attributeType );
1960
1961 Attribute attribute = entry.get( attributeType ).clone();
1962 int nbValues = 0;
1963
1964 if ( attribute != null )
1965 {
1966 nbValues = attribute.size();
1967 }
1968
1969
1970
1971
1972
1973
1974 if ( mods.size() == 0 )
1975 {
1976 ( ( Index ) userIndex ).drop( partitionTxn, id );
1977 nbValues = 0;
1978 }
1979 else if ( nbValues > 0 )
1980 {
1981 for ( Value value : mods )
1982 {
1983 if ( attribute.contains( value ) )
1984 {
1985 nbValues--;
1986 attribute.remove( value );
1987 }
1988
1989 String normalized = value.getNormalized();
1990 ( ( Index ) userIndex ).drop( partitionTxn, normalized, id );
1991 }
1992 }
1993
1994
1995
1996
1997
1998 if ( nbValues == 0 )
1999 {
2000 presenceIdx.drop( partitionTxn, modsOid, id );
2001 }
2002 }
2003
2004 else if ( modsOid.equals( SchemaConstants.ADMINISTRATIVE_ROLE_AT_OID ) )
2005 {
2006
2007 for ( Value value : mods )
2008 {
2009 adminRoleIdx.drop( partitionTxn, value.getString(), id );
2010 }
2011
2012
2013
2014
2015
2016 if ( null == adminRoleIdx.reverseLookup( partitionTxn, id ) )
2017 {
2018 presenceIdx.drop( partitionTxn, modsOid, id );
2019 }
2020 }
2021
2022
2023
2024
2025
2026
2027
2028 if ( mods.size() == 0 )
2029 {
2030 entry.removeAttributes( mods.getAttributeType() );
2031 }
2032 else
2033 {
2034 Attribute entryAttr = entry.get( mods.getAttributeType() );
2035
2036
2037 if ( entryAttr != null )
2038 {
2039 for ( Value value : mods )
2040 {
2041 entryAttr.remove( value );
2042 }
2043
2044
2045 if ( entryAttr.size() == 0 )
2046 {
2047 entry.removeAttributes( entryAttr.getId() );
2048 }
2049 }
2050 }
2051
2052
2053 if ( mods.getAttributeType().equals( aliasedObjectNameAT ) )
2054 {
2055 dropAliasIndices( partitionTxn, id );
2056 }
2057 }
2058
2059
2060
2061
2062
2063
2064
2065
2066 @Override
2067 public void move( MoveOperationContext moveContext ) throws LdapException
2068 {
2069 if ( moveContext.getNewSuperior().isDescendantOf( moveContext.getDn() ) )
2070 {
2071 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
2072 "cannot place an entry below itself" );
2073 }
2074
2075 PartitionTxn partitionTxn = moveContext.getTransaction();
2076
2077 assert ( partitionTxn != null );
2078 assert ( partitionTxn instanceof PartitionWriteTxn );
2079
2080 try
2081 {
2082 setRWLock( moveContext );
2083 Dn oldDn = moveContext.getDn();
2084 Dn newSuperior = moveContext.getNewSuperior();
2085 Dn newDn = moveContext.getNewDn();
2086 Entry modifiedEntry = moveContext.getModifiedEntry();
2087
2088 move( partitionTxn, oldDn, newSuperior, newDn, modifiedEntry );
2089 updateCache( moveContext );
2090 }
2091 catch ( Exception e )
2092 {
2093 throw new LdapOperationErrorException( e.getMessage(), e );
2094 }
2095 }
2096
2097
2098
2099
2100
2101 @Override
2102 public final synchronized void move( PartitionTxn partitionTxn, Dn oldDn, Dn newSuperiorDn, Dn newDn, Entry modifiedEntry )
2103 throws LdapException
2104 {
2105
2106 String newParentId = getEntryId( partitionTxn, newSuperiorDn );
2107
2108 if ( newParentId == null )
2109 {
2110
2111 throw new LdapEntryAlreadyExistsException(
2112 I18n.err( I18n.ERR_256_NO_SUCH_OBJECT, newSuperiorDn.getName() ) );
2113 }
2114
2115
2116 String newId = getEntryId( partitionTxn, newDn );
2117
2118 if ( newId != null )
2119 {
2120
2121
2122 throw new LdapEntryAlreadyExistsException(
2123 I18n.err( I18n.ERR_250_ENTRY_ALREADY_EXISTS, newSuperiorDn.getName() ) );
2124 }
2125
2126
2127 String entryId = getEntryId( partitionTxn, oldDn );
2128 String oldParentId = getParentId( partitionTxn, entryId );
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138 dropMovedAliasIndices( partitionTxn, oldDn );
2139
2140
2141
2142 ParentIdAndRdn movedEntry = rdnIdx.reverseLookup( partitionTxn, entryId );
2143
2144 updateRdnIdx( partitionTxn, oldParentId, REMOVE_CHILD, movedEntry.getNbDescendants() );
2145
2146 rdnIdx.drop( partitionTxn, entryId );
2147 updatePiarCache( movedEntry, entryId, DEL_CACHE );
2148
2149
2150 movedEntry.setParentId( newParentId );
2151 rdnIdx.add( partitionTxn, movedEntry, entryId );
2152 updatePiarCache( movedEntry, entryId, ADD_CACHE );
2153
2154 updateRdnIdx( partitionTxn, newParentId, ADD_CHILD, movedEntry.getNbDescendants() );
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166 Dn aliasTarget = aliasIdx.reverseLookup( partitionTxn, entryId );
2167
2168 if ( null != aliasTarget )
2169 {
2170 if ( !aliasTarget.isSchemaAware() )
2171 {
2172 aliasTarget = new Dn( schemaManager, aliasTarget );
2173 }
2174
2175
2176 addAliasIndices( partitionTxn, entryId, buildEntryDn( partitionTxn, entryId ), aliasTarget );
2177 }
2178
2179
2180
2181
2182 if ( modifiedEntry == null )
2183 {
2184 modifiedEntry = fetch( partitionTxn, entryId );
2185 }
2186
2187
2188 modifiedEntry.put( ApacheSchemaConstants.ENTRY_PARENT_ID_AT, newParentId );
2189
2190
2191 modifiedEntry.removeAttributes( entryDnAT );
2192
2193 entryDnCache.invalidateAll();
2194
2195 setContextCsn( modifiedEntry.get( entryCsnAT ).getString() );
2196
2197 master.put( partitionTxn, entryId, modifiedEntry );
2198
2199 if ( isSyncOnWrite.get() )
2200 {
2201 sync();
2202 }
2203 }
2204
2205
2206
2207
2208
2209
2210
2211
2212 @Override
2213 public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
2214 {
2215 if ( moveAndRenameContext.getNewSuperiorDn().isDescendantOf( moveAndRenameContext.getDn() ) )
2216 {
2217 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
2218 "cannot place an entry below itself" );
2219 }
2220
2221 PartitionTxn partitionTxn = moveAndRenameContext.getTransaction();
2222
2223 assert ( partitionTxn != null );
2224 assert ( partitionTxn instanceof PartitionWriteTxn );
2225
2226 try
2227 {
2228 setRWLock( moveAndRenameContext );
2229 Dn oldDn = moveAndRenameContext.getDn();
2230 Dn newSuperiorDn = moveAndRenameContext.getNewSuperiorDn();
2231 Rdn newRdn = moveAndRenameContext.getNewRdn();
2232 Entry modifiedEntry = moveAndRenameContext.getModifiedEntry();
2233 Map<String, List<ModDnAva>> modAvas = moveAndRenameContext.getModifiedAvas();
2234
2235 moveAndRename( partitionTxn, oldDn, newSuperiorDn, newRdn, modAvas, modifiedEntry );
2236 updateCache( moveAndRenameContext );
2237 }
2238 catch ( LdapException le )
2239 {
2240
2241
2242 throw le;
2243 }
2244 catch ( Exception e )
2245 {
2246 throw new LdapOperationErrorException( e.getMessage(), e );
2247 }
2248 }
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267 @Override
2268 public void moveAndRename( PartitionTxn partitionTxn, Dn oldDn, Dn newSuperiorDn, Rdn newRdn, Map<String,
2269 List<ModDnAva>> modAvas, Entry modifiedEntry ) throws LdapException
2270 {
2271
2272 Attribute entryIdAt = modifiedEntry.get( SchemaConstants.ENTRY_UUID_AT );
2273 String entryId;
2274
2275 if ( entryIdAt == null )
2276 {
2277 entryId = getEntryId( partitionTxn, modifiedEntry.getDn() );
2278 }
2279 else
2280 {
2281 entryId = modifiedEntry.get( SchemaConstants.ENTRY_UUID_AT ).getString();
2282 }
2283
2284 Attribute oldParentIdAt = modifiedEntry.get( ApacheSchemaConstants.ENTRY_PARENT_ID_AT );
2285 String oldParentId;
2286
2287 if ( oldParentIdAt == null )
2288 {
2289 oldParentId = getEntryId( partitionTxn, oldDn.getParent() );
2290 }
2291 else
2292 {
2293 oldParentId = oldParentIdAt.getString();
2294 }
2295
2296 String newParentId = getEntryId( partitionTxn, newSuperiorDn );
2297
2298
2299 ParentIdAndRdn movedEntry = rdnIdx.reverseLookup( partitionTxn, entryId );
2300
2301
2302 rdnIdx.drop( partitionTxn, entryId );
2303 updatePiarCache( movedEntry, entryId, DEL_CACHE );
2304
2305
2306
2307
2308
2309
2310
2311 updateRdnIdx( partitionTxn, oldParentId, REMOVE_CHILD, movedEntry.getNbDescendants() );
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321 dropMovedAliasIndices( partitionTxn, oldDn );
2322
2323
2324
2325 movedEntry.setParentId( newParentId );
2326 movedEntry.setRdns( new Rdn[]
2327 { newRdn } );
2328 rdnIdx.add( partitionTxn, movedEntry, entryId );
2329 updatePiarCache( movedEntry, entryId, ADD_CACHE );
2330
2331 updateRdnIdx( partitionTxn, newParentId, ADD_CHILD, movedEntry.getNbDescendants() );
2332
2333
2334 try
2335 {
2336 processModifiedAvas( partitionTxn, modAvas, entryId );
2337 }
2338 catch ( IndexNotFoundException infe )
2339 {
2340 throw new LdapOtherException( infe.getMessage(), infe );
2341 }
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353 Dn aliasTarget = aliasIdx.reverseLookup( partitionTxn, entryId );
2354
2355 if ( null != aliasTarget )
2356 {
2357 if ( !aliasTarget.isSchemaAware() )
2358 {
2359 aliasTarget = new Dn( schemaManager, aliasTarget );
2360 }
2361
2362 addAliasIndices( partitionTxn, entryId, buildEntryDn( partitionTxn, entryId ), aliasTarget );
2363 }
2364
2365
2366 modifiedEntry.removeAttributes( entryDnAT );
2367
2368
2369 modifiedEntry.removeAttributes( ApacheSchemaConstants.ENTRY_PARENT_ID_OID );
2370 modifiedEntry.add( ApacheSchemaConstants.ENTRY_PARENT_ID_OID, newParentId );
2371
2372
2373 entryDnCache.invalidateAll();
2374
2375 setContextCsn( modifiedEntry.get( entryCsnAT ).getString() );
2376
2377
2378 master.put( partitionTxn, entryId, modifiedEntry );
2379 }
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391 private void processModifiedAvas( PartitionTxn partitionTxn, Map<String, List<ModDnAva>> modAvas, String entryId )
2392 throws LdapException, IndexNotFoundException
2393 {
2394 for ( List<ModDnAva> modDnAvas : modAvas.values() )
2395 {
2396 for ( ModDnAva modDnAva : modDnAvas )
2397 {
2398 AttributeType attributeType = modDnAva.getAva().getAttributeType();
2399
2400 if ( !hasIndexOn( attributeType ) )
2401 {
2402 break;
2403 }
2404
2405 Index<?, String> index = getUserIndex( attributeType );
2406
2407 switch ( modDnAva.getType() )
2408 {
2409 case ADD :
2410 case UPDATE_ADD :
2411
2412 ( ( Index ) index ).add( partitionTxn, modDnAva.getAva().getValue().getNormalized(), entryId );
2413
2414
2415
2416
2417
2418 if ( null == index.reverseLookup( partitionTxn, entryId ) )
2419 {
2420 presenceIdx.add( partitionTxn, attributeType.getOid(), entryId );
2421 }
2422
2423 break;
2424
2425 case DELETE :
2426 case UPDATE_DELETE :
2427 ( ( Index ) index ).drop( partitionTxn, modDnAva.getAva().getValue().getNormalized(), entryId );
2428
2429
2430
2431
2432
2433 if ( null == index.reverseLookup( partitionTxn, entryId ) )
2434 {
2435 presenceIdx.drop( partitionTxn, attributeType.getOid(), entryId );
2436 }
2437
2438 break;
2439
2440 default :
2441 break;
2442 }
2443 }
2444 }
2445 }
2446
2447
2448
2449
2450
2451
2452
2453
2454 @Override
2455 public void rename( RenameOperationContext renameContext ) throws LdapException
2456 {
2457 PartitionTxn partitionTxn = renameContext.getTransaction();
2458
2459 assert ( partitionTxn != null );
2460 assert ( partitionTxn instanceof PartitionWriteTxn );
2461
2462 try
2463 {
2464 setRWLock( renameContext );
2465 Dn oldDn = renameContext.getDn();
2466 Rdn newRdn = renameContext.getNewRdn();
2467 boolean deleteOldRdn = renameContext.getDeleteOldRdn();
2468
2469 if ( renameContext.getEntry() != null )
2470 {
2471 Entry modifiedEntry = renameContext.getModifiedEntry();
2472 rename( partitionTxn, oldDn, newRdn, deleteOldRdn, modifiedEntry );
2473 }
2474 else
2475 {
2476 rename( partitionTxn, oldDn, newRdn, deleteOldRdn, null );
2477 }
2478
2479 updateCache( renameContext );
2480 }
2481 catch ( Exception e )
2482 {
2483 throw new LdapOperationErrorException( e.getMessage(), e );
2484 }
2485 }
2486
2487
2488
2489
2490
2491
2492
2493
2494 private void rename( PartitionTxn partitionTxn, String oldId, Rdn newRdn, boolean deleteOldRdn, Entry entry )
2495 throws LdapException, IndexNotFoundException
2496 {
2497 if ( entry == null )
2498 {
2499 entry = master.get( partitionTxn, oldId );
2500 }
2501
2502 Dn updn = entry.getDn();
2503
2504 if ( !newRdn.isSchemaAware() )
2505 {
2506 newRdn = new Rdn( schemaManager, newRdn );
2507 }
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519 for ( Ava newAtav : newRdn )
2520 {
2521 String newNormType = newAtav.getNormType();
2522 Object newNormValue = newAtav.getValue().getString();
2523
2524 AttributeType newRdnAttrType = schemaManager.lookupAttributeTypeRegistry( newNormType );
2525
2526 if ( newRdnAttrType.isSingleValued() && entry.containsAttribute( newRdnAttrType ) )
2527 {
2528 Attribute oldAttribute = entry.get( newRdnAttrType );
2529 AttributeType oldAttributeType = oldAttribute.getAttributeType();
2530
2531
2532 entry.removeAttributes( newRdnAttrType );
2533
2534
2535 if ( hasUserIndexOn( newRdnAttrType ) )
2536 {
2537 Index<?, String> userIndex = getUserIndex( newRdnAttrType );
2538
2539 String normalized = oldAttributeType.getEquality().getNormalizer().normalize( oldAttribute.get().getString() );
2540 ( ( Index ) userIndex ).drop( partitionTxn, normalized, id );
2541
2542
2543
2544
2545
2546 if ( null == userIndex.reverseLookup( partitionTxn, oldId ) )
2547 {
2548 presenceIdx.drop( partitionTxn, newRdnAttrType.getOid(), oldId );
2549 }
2550 }
2551 }
2552
2553 if ( newRdnAttrType.getSyntax().isHumanReadable() )
2554 {
2555 entry.add( newRdnAttrType, newAtav.getValue().getString() );
2556 }
2557 else
2558 {
2559 entry.add( newRdnAttrType, newAtav.getValue().getBytes() );
2560 }
2561
2562 if ( hasUserIndexOn( newRdnAttrType ) )
2563 {
2564 Index<?, String> userIndex = getUserIndex( newRdnAttrType );
2565
2566 String normalized = newRdnAttrType.getEquality().getNormalizer().normalize( ( String ) newNormValue );
2567 ( ( Index ) userIndex ).add( partitionTxn, normalized, oldId );
2568
2569
2570 String normTypeOid = presenceNormalizer.normalize( newNormType );
2571
2572 if ( !presenceIdx.forward( partitionTxn, normTypeOid, oldId ) )
2573 {
2574 presenceIdx.add( partitionTxn, normTypeOid, oldId );
2575 }
2576 }
2577 }
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596 if ( deleteOldRdn )
2597 {
2598 Rdn oldRdn = updn.getRdn();
2599
2600 for ( Ava oldAtav : oldRdn )
2601 {
2602
2603
2604 boolean mustRemove = true;
2605
2606 for ( Ava newAtav : newRdn )
2607 {
2608 if ( oldAtav.equals( newAtav ) )
2609 {
2610 mustRemove = false;
2611 break;
2612 }
2613 }
2614
2615 if ( mustRemove )
2616 {
2617 String oldNormType = oldAtav.getNormType();
2618 String oldNormValue = oldAtav.getValue().getString();
2619 AttributeType oldRdnAttrType = schemaManager.lookupAttributeTypeRegistry( oldNormType );
2620 entry.remove( oldRdnAttrType, oldNormValue );
2621
2622 if ( hasUserIndexOn( oldRdnAttrType ) )
2623 {
2624 Index<?, String> userIndex = getUserIndex( oldRdnAttrType );
2625
2626 String normalized = oldRdnAttrType.getEquality().getNormalizer().normalize( oldNormValue );
2627 ( ( Index ) userIndex ).drop( partitionTxn, normalized, id );
2628
2629
2630
2631
2632
2633 if ( null == userIndex.reverseLookup( partitionTxn, oldId ) )
2634 {
2635 String oldNormTypeOid = presenceNormalizer.normalize( oldNormType );
2636 presenceIdx.drop( partitionTxn, oldNormTypeOid, oldId );
2637 }
2638 }
2639 }
2640 }
2641 }
2642
2643
2644 entry.removeAttributes( entryDnAT );
2645
2646 setContextCsn( entry.get( entryCsnAT ).getString() );
2647
2648
2649 master.put( partitionTxn, oldId, entry );
2650 }
2651
2652
2653
2654
2655
2656 @SuppressWarnings("unchecked")
2657 @Override
2658 public final synchronized void rename( PartitionTxn partitionTxn, Dn dn, Rdn newRdn, boolean deleteOldRdn, Entry entry )
2659 throws LdapException
2660 {
2661 String oldId = getEntryId( partitionTxn, dn );
2662
2663 try
2664 {
2665 rename( partitionTxn, oldId, newRdn, deleteOldRdn, entry );
2666 }
2667 catch ( IndexNotFoundException infe )
2668 {
2669 throw new LdapOtherException( infe.getMessage(), infe );
2670 }
2671
2672
2673
2674
2675
2676
2677
2678 String parentId = getParentId( partitionTxn, oldId );
2679
2680
2681 ParentIdAndRdn parentIdAndRdn = rdnIdx.reverseLookup( partitionTxn, oldId );
2682
2683
2684 rdnIdx.drop( partitionTxn, oldId );
2685
2686 updatePiarCache( parentIdAndRdn, oldId, DEL_CACHE );
2687
2688
2689 parentIdAndRdn.setParentId( parentId );
2690 parentIdAndRdn.setRdns( newRdn );
2691
2692 rdnIdx.add( partitionTxn, parentIdAndRdn, oldId );
2693
2694 updatePiarCache( parentIdAndRdn, oldId, ADD_CACHE );
2695
2696 entryDnCache.invalidateAll();
2697
2698 if ( isSyncOnWrite.get() )
2699 {
2700 sync();
2701 }
2702 }
2703
2704
2705
2706
2707
2708
2709
2710
2711 @Override
2712 public final void unbind( UnbindOperationContext unbindContext ) throws LdapException
2713 {
2714
2715 }
2716
2717
2718
2719
2720
2721
2722
2723 @Override
2724 public boolean hasEntry( HasEntryOperationContext entryContext ) throws LdapException
2725 {
2726 PartitionTxn partitionTxn = entryContext.getTransaction();
2727
2728 assert ( partitionTxn != null );
2729
2730 try
2731 {
2732 setRWLock( entryContext );
2733
2734 String id = getEntryId( partitionTxn, entryContext.getDn() );
2735
2736 Entry entry = fetch( partitionTxn, id, entryContext.getDn() );
2737
2738 return entry != null;
2739 }
2740 catch ( LdapException e )
2741 {
2742 return false;
2743 }
2744 }
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758 private void updateCsnIndex( PartitionTxn partitionTxn, Entry entry, String id ) throws LdapException
2759 {
2760 String entryCsn = entry.get( SchemaConstants.ENTRY_CSN_AT ).getString();
2761 entryCsnIdx.drop( partitionTxn, id );
2762 entryCsnIdx.add( partitionTxn, entryCsn, id );
2763 }
2764
2765
2766
2767
2768
2769 private void updatePiarCache( ParentIdAndRdn piar, String id, boolean add )
2770 {
2771 if ( add == ADD_CACHE )
2772 {
2773 piarCache.put( id, piar );
2774 }
2775 else
2776 {
2777 piarCache.invalidate( id );
2778 }
2779 }
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793 protected Dn buildEntryDn( PartitionTxn partitionTxn, String id ) throws LdapException
2794 {
2795 String parentId = id;
2796 String rootId = Partition.ROOT_ID;
2797
2798
2799 Rdn[] rdnArray = new Rdn[10];
2800 int pos = 0;
2801
2802 Dn dn = null;
2803
2804 try
2805 {
2806 rwLock.readLock().lock();
2807
2808 if ( entryDnCache != null )
2809 {
2810 Dn cachedDn = entryDnCache.getIfPresent( id );
2811
2812 if ( cachedDn != null )
2813 {
2814 return cachedDn;
2815 }
2816 }
2817
2818 do
2819 {
2820 ParentIdAndRdn cur;
2821
2822 if ( piarCache != null )
2823 {
2824 cur = piarCache.getIfPresent( parentId );
2825
2826 if ( cur == null )
2827 {
2828 cur = rdnIdx.reverseLookup( partitionTxn, parentId );
2829
2830 if ( cur == null )
2831 {
2832 return null;
2833 }
2834
2835 piarCache.put( parentId, cur );
2836 }
2837 }
2838 else
2839 {
2840 cur = rdnIdx.reverseLookup( partitionTxn, parentId );
2841
2842 if ( cur == null )
2843 {
2844 return null;
2845 }
2846 }
2847
2848 Rdn[] rdns = cur.getRdns();
2849
2850 for ( Rdn rdn : rdns )
2851 {
2852 if ( ( pos > 0 ) && ( pos % 10 == 0 ) )
2853 {
2854
2855 Rdn[] newRdnArray = new Rdn[pos + 10];
2856 System.arraycopy( rdnArray, 0, newRdnArray, 0, pos );
2857 rdnArray = newRdnArray;
2858 }
2859
2860 rdnArray[pos++] = rdn;
2861 }
2862
2863 parentId = cur.getParentId();
2864 }
2865 while ( !parentId.equals( rootId ) );
2866
2867 dn = new Dn( schemaManager, Arrays.copyOf( rdnArray, pos ) );
2868
2869 entryDnCache.put( id, dn );
2870 return dn;
2871 }
2872 finally
2873 {
2874 rwLock.readLock().unlock();
2875 }
2876 }
2877
2878
2879
2880
2881
2882 @Override
2883 public long count( PartitionTxn partitionTxn ) throws LdapException
2884 {
2885 return master.count( partitionTxn );
2886 }
2887
2888
2889
2890
2891
2892 @Override
2893 public final long getChildCount( PartitionTxn partitionTxn, String id ) throws LdapException
2894 {
2895 try
2896 {
2897 ParentIdAndRdn parentIdAndRdn = rdnIdx.reverseLookup( partitionTxn, id );
2898
2899 return parentIdAndRdn.getNbChildren();
2900 }
2901 catch ( Exception e )
2902 {
2903 throw new LdapOperationErrorException( e.getMessage(), e );
2904 }
2905 }
2906
2907
2908
2909
2910
2911 @Override
2912 public final Dn getEntryDn( PartitionTxn partitionTxn, String id ) throws LdapException
2913 {
2914 return buildEntryDn( partitionTxn, id );
2915 }
2916
2917
2918
2919
2920
2921 @Override
2922 public final String getEntryId( PartitionTxn partitionTxn, Dn dn ) throws LdapException
2923 {
2924 try
2925 {
2926 if ( Dn.isNullOrEmpty( dn ) )
2927 {
2928 return Partition.ROOT_ID;
2929 }
2930
2931 ParentIdAndRdn/xdbm/ParentIdAndRdn.html#ParentIdAndRdn">ParentIdAndRdn suffixKey = new ParentIdAndRdn( Partition.ROOT_ID, suffixDn.getRdns() );
2932
2933
2934 try
2935 {
2936 rwLock.readLock().lock();
2937 String currentId = rdnIdx.forwardLookup( partitionTxn, suffixKey );
2938
2939 for ( int i = dn.size() - suffixDn.size(); i > 0; i-- )
2940 {
2941 Rdn rdn = dn.getRdn( i - 1 );
2942 ParentIdAndRdnxdbm/ParentIdAndRdn.html#ParentIdAndRdn">ParentIdAndRdn currentRdn = new ParentIdAndRdn( currentId, rdn );
2943
2944 currentId = rdnIdx.forwardLookup( partitionTxn, currentRdn );
2945
2946 if ( currentId == null )
2947 {
2948 break;
2949 }
2950 }
2951
2952 return currentId;
2953 }
2954 finally
2955 {
2956 rwLock.readLock().unlock();
2957 }
2958 }
2959 catch ( Exception e )
2960 {
2961 throw new LdapException( e.getMessage(), e );
2962 }
2963 }
2964
2965
2966
2967
2968
2969 @Override
2970 public String getParentId( PartitionTxn partitionTxn, String childId ) throws LdapException
2971 {
2972 try
2973 {
2974 rwLock.readLock().lock();
2975 ParentIdAndRdn key = rdnIdx.reverseLookup( partitionTxn, childId );
2976
2977 if ( key == null )
2978 {
2979 return null;
2980 }
2981
2982 return key.getParentId();
2983 }
2984 finally
2985 {
2986 rwLock.readLock().unlock();
2987 }
2988 }
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998 public String getSuffixId( PartitionTxn partitionTxn ) throws LdapException
2999 {
3000 if ( suffixId == null )
3001 {
3002 ParentIdAndRdnserver/xdbm/ParentIdAndRdn.html#ParentIdAndRdn">ParentIdAndRdn key = new ParentIdAndRdn( Partition.ROOT_ID, suffixDn.getRdns() );
3003
3004 try
3005 {
3006 rwLock.readLock().lock();
3007 suffixId = rdnIdx.forwardLookup( partitionTxn, key );
3008 }
3009 finally
3010 {
3011 rwLock.readLock().unlock();
3012 }
3013 }
3014
3015 return suffixId;
3016 }
3017
3018
3019
3020
3021
3022
3023
3024
3025 @Override
3026 public void addIndex( Index<?, String> index ) throws LdapException
3027 {
3028 checkInitialized( "addIndex" );
3029
3030
3031 AttributeType attributeType = null;
3032
3033 try
3034 {
3035 attributeType = schemaManager.lookupAttributeTypeRegistry( index.getAttributeId() );
3036 }
3037 catch ( LdapNoSuchAttributeException lnsae )
3038 {
3039 LOG.error( "Cannot initialize the index for AttributeType {}, this value does not exist",
3040 index.getAttributeId() );
3041
3042 return;
3043 }
3044
3045 String oid = attributeType.getOid();
3046
3047 if ( SYS_INDEX_OIDS.contains( oid ) )
3048 {
3049 if ( !systemIndices.containsKey( oid ) )
3050 {
3051 systemIndices.put( oid, index );
3052 }
3053 }
3054 else
3055 {
3056 if ( !userIndices.containsKey( oid ) )
3057 {
3058 userIndices.put( oid, index );
3059 }
3060 }
3061 }
3062
3063
3064
3065
3066
3067
3068 public void addIndexedAttributes( Index<?, String>... indexes )
3069 {
3070 for ( Index<?, String> index : indexes )
3071 {
3072 indexedAttributes.add( index );
3073 }
3074 }
3075
3076
3077
3078
3079
3080
3081 public void setIndexedAttributes( Set<Index<?, String>> indexedAttributes )
3082 {
3083 this.indexedAttributes = indexedAttributes;
3084 }
3085
3086
3087
3088
3089
3090 public Set<Index<?, String>> getIndexedAttributes()
3091 {
3092 return indexedAttributes;
3093 }
3094
3095
3096
3097
3098
3099 @Override
3100 public Iterator<String> getUserIndices()
3101 {
3102 return userIndices.keySet().iterator();
3103 }
3104
3105
3106
3107
3108
3109 @Override
3110 public Iterator<String> getSystemIndices()
3111 {
3112 return systemIndices.keySet().iterator();
3113 }
3114
3115
3116
3117
3118
3119 @Override
3120 public Index<?, String> getIndex( AttributeType attributeType ) throws IndexNotFoundException
3121 {
3122 String id = attributeType.getOid();
3123
3124 if ( userIndices.containsKey( id ) )
3125 {
3126 return userIndices.get( id );
3127 }
3128
3129 if ( systemIndices.containsKey( id ) )
3130 {
3131 return systemIndices.get( id );
3132 }
3133
3134 throw new IndexNotFoundException( I18n.err( I18n.ERR_3, id, id ) );
3135 }
3136
3137
3138
3139
3140
3141 @Override
3142 public Index<?, String> getUserIndex( AttributeType attributeType ) throws IndexNotFoundException
3143 {
3144 if ( attributeType == null )
3145 {
3146 throw new IndexNotFoundException( I18n.err( I18n.ERR_3, attributeType, attributeType ) );
3147 }
3148
3149 String oid = attributeType.getOid();
3150
3151 if ( userIndices.containsKey( oid ) )
3152 {
3153 return userIndices.get( oid );
3154 }
3155
3156 throw new IndexNotFoundException( I18n.err( I18n.ERR_3, attributeType, attributeType ) );
3157 }
3158
3159
3160
3161
3162
3163 @Override
3164 public Index<?, String> getSystemIndex( AttributeType attributeType ) throws IndexNotFoundException
3165 {
3166 if ( attributeType == null )
3167 {
3168 throw new IndexNotFoundException( I18n.err( I18n.ERR_2, attributeType, attributeType ) );
3169 }
3170
3171 String oid = attributeType.getOid();
3172
3173 if ( systemIndices.containsKey( oid ) )
3174 {
3175 return systemIndices.get( oid );
3176 }
3177
3178 throw new IndexNotFoundException( I18n.err( I18n.ERR_2, attributeType, attributeType ) );
3179 }
3180
3181
3182
3183
3184
3185 @SuppressWarnings("unchecked")
3186 @Override
3187 public Index<Dn, String> getAliasIndex()
3188 {
3189 return ( Index<Dn, String> ) systemIndices.get( ApacheSchemaConstants.APACHE_ALIAS_AT_OID );
3190 }
3191
3192
3193
3194
3195
3196 @SuppressWarnings("unchecked")
3197 @Override
3198 public Index<String, String> getOneAliasIndex()
3199 {
3200 return ( Index<String, String> ) systemIndices.get( ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID );
3201 }
3202
3203
3204
3205
3206
3207 @SuppressWarnings("unchecked")
3208 @Override
3209 public Index<String, String> getSubAliasIndex()
3210 {
3211 return ( Index<String, String> ) systemIndices.get( ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID );
3212 }
3213
3214
3215
3216
3217
3218 @SuppressWarnings("unchecked")
3219 @Override
3220 public Index<String, String> getObjectClassIndex()
3221 {
3222 return ( Index<String, String> ) systemIndices.get( SchemaConstants.OBJECT_CLASS_AT_OID );
3223 }
3224
3225
3226
3227
3228
3229 @SuppressWarnings("unchecked")
3230 @Override
3231 public Index<String, String> getEntryCsnIndex()
3232 {
3233 return ( Index<String, String> ) systemIndices.get( SchemaConstants.ENTRY_CSN_AT_OID );
3234 }
3235
3236
3237
3238
3239
3240 @SuppressWarnings("unchecked")
3241 public Index<String, String> getAdministrativeRoleIndex()
3242 {
3243 return ( Index<String, String> ) systemIndices.get( SchemaConstants.ADMINISTRATIVE_ROLE_AT_OID );
3244 }
3245
3246
3247
3248
3249
3250 @SuppressWarnings("unchecked")
3251 @Override
3252 public Index<String, String> getPresenceIndex()
3253 {
3254 return ( Index<String, String> ) systemIndices.get( ApacheSchemaConstants.APACHE_PRESENCE_AT_OID );
3255 }
3256
3257
3258
3259
3260
3261 @SuppressWarnings("unchecked")
3262 @Override
3263 public Index<ParentIdAndRdn, String> getRdnIndex()
3264 {
3265 return ( Index<ParentIdAndRdn, String> ) systemIndices.get( ApacheSchemaConstants.APACHE_RDN_AT_OID );
3266 }
3267
3268
3269
3270
3271
3272 @Override
3273 public boolean hasUserIndexOn( AttributeType attributeType ) throws LdapException
3274 {
3275 String oid = attributeType.getOid();
3276 return userIndices.containsKey( oid );
3277 }
3278
3279
3280
3281
3282
3283 @Override
3284 public boolean hasSystemIndexOn( AttributeType attributeType ) throws LdapException
3285 {
3286 return systemIndices.containsKey( attributeType.getOid() );
3287 }
3288
3289
3290
3291
3292
3293 @Override
3294 public boolean hasIndexOn( AttributeType attributeType ) throws LdapException
3295 {
3296 return hasUserIndexOn( attributeType ) || hasSystemIndexOn( attributeType );
3297 }
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315 protected void addAliasIndices( PartitionTxn partitionTxn, String aliasId, Dn aliasDn, Dn aliasTarget )
3316 throws LdapException
3317 {
3318 String targetId;
3319 Dn ancestorDn;
3320 String ancestorId;
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330 if ( !aliasTarget.isDescendantOf( suffixDn ) )
3331 {
3332 String msg = I18n.err( I18n.ERR_225, suffixDn.getName() );
3333 throw new LdapAliasDereferencingException( msg );
3334 }
3335
3336
3337 targetId = getEntryId( partitionTxn, aliasTarget );
3338
3339
3340
3341
3342
3343
3344
3345 if ( null == targetId )
3346 {
3347
3348 String msg = I18n.err( I18n.ERR_581, aliasDn.getName(), aliasTarget );
3349 throw new LdapAliasException( msg );
3350 }
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362 if ( null != aliasIdx.reverseLookup( partitionTxn, targetId ) )
3363 {
3364 String msg = I18n.err( I18n.ERR_227 );
3365 throw new LdapAliasDereferencingException( msg );
3366 }
3367
3368
3369 aliasIdx.add( partitionTxn, aliasTarget, aliasId );
3370
3371 if ( aliasCache != null )
3372 {
3373 aliasCache.put( aliasId, aliasTarget );
3374 }
3375
3376
3377
3378
3379
3380
3381
3382
3383 ancestorDn = aliasDn.getParent();
3384 ancestorId = getEntryId( partitionTxn, ancestorDn );
3385
3386
3387 Dn normalizedAliasTargetParentDn = aliasTarget.getParent();
3388
3389 if ( !aliasDn.isDescendantOf( normalizedAliasTargetParentDn ) )
3390 {
3391 oneAliasIdx.add( partitionTxn, ancestorId, targetId );
3392 }
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404 while ( !ancestorDn.equals( suffixDn ) && null != ancestorId )
3405 {
3406 if ( !aliasTarget.isDescendantOf( ancestorDn ) )
3407 {
3408 subAliasIdx.add( partitionTxn, ancestorId, targetId );
3409 }
3410
3411 ancestorDn = ancestorDn.getParent();
3412 ancestorId = getEntryId( partitionTxn, ancestorDn );
3413 }
3414 }
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427 protected void dropAliasIndices( PartitionTxn partitionTxn, String aliasId ) throws LdapException
3428 {
3429 Dn targetDn = aliasIdx.reverseLookup( partitionTxn, aliasId );
3430
3431 if ( !targetDn.isSchemaAware() )
3432 {
3433 targetDn = new Dn( schemaManager, targetDn );
3434 }
3435
3436 String targetId = getEntryId( partitionTxn, targetDn );
3437
3438 if ( targetId == null )
3439 {
3440
3441
3442 return;
3443 }
3444
3445 Dn aliasDn = getEntryDn( partitionTxn, aliasId );
3446
3447 Dn ancestorDn = aliasDn.getParent();
3448 String ancestorId = getEntryId( partitionTxn, ancestorDn );
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461 oneAliasIdx.drop( partitionTxn, ancestorId, targetId );
3462 subAliasIdx.drop( partitionTxn, ancestorId, targetId );
3463
3464 while ( !ancestorDn.equals( suffixDn ) && ancestorDn.size() > suffixDn.size() )
3465 {
3466 ancestorDn = ancestorDn.getParent();
3467 ancestorId = getEntryId( partitionTxn, ancestorDn );
3468
3469 subAliasIdx.drop( partitionTxn, ancestorId, targetId );
3470 }
3471
3472
3473 aliasIdx.drop( partitionTxn, aliasId );
3474
3475 if ( aliasCache != null )
3476 {
3477 aliasCache.invalidate( aliasId );
3478 }
3479 }
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491 protected void dropMovedAliasIndices( PartitionTxn partitionTxn, Dn movedBase ) throws LdapException
3492 {
3493 String movedBaseId = getEntryId( partitionTxn, movedBase );
3494
3495 Dn targetDn = aliasIdx.reverseLookup( partitionTxn, movedBaseId );
3496
3497 if ( targetDn != null )
3498 {
3499 if ( !targetDn.isSchemaAware() )
3500 {
3501 targetDn = new Dn( schemaManager, targetDn );
3502 }
3503
3504 String targetId = getEntryId( partitionTxn, targetDn );
3505 Dn aliasDn = getEntryDn( partitionTxn, movedBaseId );
3506
3507
3508
3509
3510
3511 Dn ancestorDn = movedBase.getParent();
3512 String ancestorId = getEntryId( partitionTxn, ancestorDn );
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526 if ( aliasDn.equals( movedBase ) )
3527 {
3528 oneAliasIdx.drop( partitionTxn, ancestorId, targetId );
3529 }
3530
3531 subAliasIdx.drop( partitionTxn, ancestorId, targetId );
3532
3533 while ( !ancestorDn.equals( suffixDn ) )
3534 {
3535 ancestorDn = ancestorDn.getParent();
3536 ancestorId = getEntryId( partitionTxn, ancestorDn );
3537
3538 subAliasIdx.drop( partitionTxn, ancestorId, targetId );
3539 }
3540 }
3541 }
3542
3543
3544
3545
3546
3547 private void dumpIndex( PartitionTxn partitionTxn, OutputStream stream, Index<?, String> index )
3548 {
3549 try
3550 {
3551 Cursor<IndexEntry<?, String>> cursor = ( Cursor ) index.forwardCursor( partitionTxn );
3552
3553 while ( cursor.next() )
3554 {
3555 IndexEntry<?, String> entry = cursor.get();
3556
3557 System.out.println( entry );
3558 }
3559 }
3560 catch ( Exception e )
3561 {
3562
3563 }
3564 }
3565
3566
3567
3568
3569
3570 @Override
3571 public void dumpIndex( PartitionTxn partitionTxn, OutputStream stream, String name ) throws IOException
3572 {
3573 try
3574 {
3575 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( name );
3576
3577 if ( attributeType == null )
3578 {
3579 stream.write( Strings.getBytesUtf8( "Cannot find an index for AttributeType names " + name ) );
3580
3581 return;
3582 }
3583
3584 if ( attributeType.getOid().equals( ApacheSchemaConstants.APACHE_RDN_AT_OID ) )
3585 {
3586 dumpIndex( partitionTxn, stream, rdnIdx );
3587 }
3588 }
3589 catch ( LdapException le )
3590 {
3591 stream.write( Strings.getBytesUtf8( "Cannot find an index for AttributeType names " + name ) );
3592 }
3593 }
3594
3595
3596
3597
3598
3599 @Override
3600 public String toString()
3601 {
3602 return "Partition<" + id + ">";
3603 }
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615 protected abstract Index createSystemIndex( String indexOid, URI path, boolean withReverse ) throws LdapException;
3616
3617
3618
3619
3620
3621 @Override
3622 public MasterTable getMasterTable()
3623 {
3624 return master;
3625 }
3626
3627
3628
3629
3630
3631 private void lockRead()
3632 {
3633 rwLock.readLock().lock();
3634 }
3635
3636
3637
3638
3639
3640 private void unlockRead()
3641 {
3642 rwLock.readLock().unlock();
3643 }
3644
3645
3646
3647
3648
3649 private void lockWrite()
3650 {
3651 rwLock.writeLock().lock();
3652 }
3653
3654
3655
3656
3657
3658 private void unlockWrite()
3659 {
3660 rwLock.writeLock().unlock();
3661 }
3662
3663
3664
3665
3666
3667
3668
3669 public void updateCache( OperationContext opCtx )
3670 {
3671
3672 }
3673
3674
3675
3676
3677
3678
3679
3680
3681 public Entry lookupCache( String id )
3682 {
3683 return null;
3684 }
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696 public void addToCache( String id, Entry entry )
3697 {
3698 }
3699
3700
3701
3702
3703
3704 public Optimizer getOptimizer()
3705 {
3706 return optimizer;
3707 }
3708
3709
3710
3711
3712
3713 public void setOptimizer( Optimizer optimizer )
3714 {
3715 this.optimizer = optimizer;
3716 }
3717
3718
3719
3720
3721
3722 public void setSearchEngine( SearchEngine searchEngine )
3723 {
3724 this.searchEngine = searchEngine;
3725 }
3726
3727
3728
3729
3730
3731
3732
3733 private void setRWLock( OperationContext operationContext )
3734 {
3735 if ( operationContext.getSession() != null )
3736 {
3737 rwLock = operationContext.getSession().getDirectoryService().getOperationManager().getRWLock();
3738 }
3739 else
3740 {
3741 if ( rwLock == null )
3742 {
3743
3744 rwLock = new ReentrantReadWriteLock();
3745 }
3746 }
3747 }
3748
3749
3750
3751
3752
3753 @Override
3754 public ReadWriteLock getReadWriteLock()
3755 {
3756 return rwLock;
3757 }
3758
3759
3760
3761
3762
3763 @Override
3764 public Cache<String, Dn> getAliasCache()
3765 {
3766 return aliasCache;
3767 }
3768
3769
3770
3771
3772
3773 @Override
3774 public String getContextCsn( PartitionTxn partitionTxn )
3775 {
3776 if ( super.getContextCsn( partitionTxn ) == null )
3777 {
3778 loadContextCsn( partitionTxn );
3779 }
3780
3781 return super.getContextCsn( partitionTxn );
3782 }
3783
3784
3785
3786
3787
3788
3789
3790 protected void loadContextCsn( PartitionTxn partitionTxn )
3791 {
3792 try
3793 {
3794 if ( rwLock == null )
3795 {
3796
3797 rwLock = new ReentrantReadWriteLock();
3798 }
3799
3800
3801 String contextEntryId = getEntryId( partitionTxn, getSuffixDn() );
3802
3803 if ( contextEntryId == null )
3804 {
3805 return;
3806 }
3807
3808 Entry entry = fetch( partitionTxn, contextEntryId );
3809
3810 Attribute ctxCsnAt = entry.get( contextCsnAT );
3811
3812 if ( ctxCsnAt != null )
3813 {
3814 setContextCsn( ctxCsnAt.getString() );
3815 ctxCsnChanged = false;
3816 }
3817 }
3818 catch ( LdapException e )
3819 {
3820 throw new RuntimeException( e );
3821 }
3822 }
3823
3824
3825
3826
3827
3828
3829
3830 @Override
3831 public void saveContextCsn( PartitionTxn partitionTxn ) throws LdapException
3832 {
3833 if ( !ctxCsnChanged )
3834 {
3835 return;
3836 }
3837
3838 String contextCsn = super.getContextCsn( partitionTxn );
3839
3840 if ( contextCsn == null )
3841 {
3842 return;
3843 }
3844
3845 try
3846 {
3847
3848
3849
3850
3851 String contextEntryId = getEntryId( partitionTxn, getSuffixDn() );
3852 Entry origEntry = fetch( partitionTxn, contextEntryId );
3853
3854
3855 if ( origEntry == null )
3856 {
3857 return;
3858 }
3859
3860 origEntry = ( ( ClonedServerEntry ) origEntry ).getOriginalEntry();
3861
3862 origEntry.removeAttributes( contextCsnAT, entryDnAT );
3863
3864 origEntry.add( contextCsnAT, contextCsn );
3865
3866 master.put( partitionTxn, contextEntryId, origEntry );
3867
3868 ctxCsnChanged = false;
3869
3870 LOG.debug( "Saved context CSN {} for the partition {}", contextCsn, suffixDn );
3871 }
3872 catch ( Exception e )
3873 {
3874 throw new LdapOperationErrorException( e.getMessage(), e );
3875 }
3876 }
3877
3878
3879
3880
3881
3882 @Override
3883 public Subordinates getSubordinates( PartitionTxn partitionTxn, Entry entry ) throws LdapException
3884 {
3885 Subordinatescore/api/partition/Subordinates.html#Subordinates">Subordinates subordinates = new Subordinates();
3886
3887 try
3888 {
3889
3890 try
3891 {
3892 rwLock.readLock().lock();
3893 ParentIdAndRdn parentIdAndRdn = rdnIdx.reverseLookup( partitionTxn, entry.get( SchemaConstants.ENTRY_UUID_AT ).getString() );
3894
3895 subordinates.setNbChildren( parentIdAndRdn.getNbChildren() );
3896 subordinates.setNbSubordinates( parentIdAndRdn.getNbDescendants() );
3897 }
3898 finally
3899 {
3900 rwLock.readLock().unlock();
3901 }
3902 }
3903 catch ( Exception e )
3904 {
3905 throw new LdapException( e.getMessage(), e );
3906 }
3907
3908 return subordinates;
3909 }
3910 }