o Fix for DIRSERVER_1974 (the piar Cache is updated for each operation
that impacts the Rdn index : add, delete, move, rename, moveAndRename)
o Minor refactoring (commented code removal)
diff --git a/server-integ/src/test/java/org/apache/directory/server/operations/modifydn/DIRSERVER_1974_IT.java b/server-integ/src/test/java/org/apache/directory/server/operations/modifydn/DIRSERVER_1974_IT.java
index 1fe942c..a74fd17 100755
--- a/server-integ/src/test/java/org/apache/directory/server/operations/modifydn/DIRSERVER_1974_IT.java
+++ b/server-integ/src/test/java/org/apache/directory/server/operations/modifydn/DIRSERVER_1974_IT.java
@@ -27,6 +27,10 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.io.IOException;
+
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.exception.LdapException;
@@ -36,7 +40,9 @@
import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.api.ldap.model.name.Dn;
import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.Network;
import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.directory.ldap.client.api.search.FilterBuilder;
import org.apache.directory.ldap.client.template.ConnectionCallback;
import org.apache.directory.ldap.client.template.EntryMapper;
@@ -52,12 +58,11 @@
import org.apache.directory.server.core.annotations.CreatePartition;
import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
import org.apache.directory.server.core.integ.CreateLdapConnectionPoolRule;
-import org.apache.directory.server.core.partition.impl.btree.mavibot.MavibotIndex;
-import org.apache.directory.server.core.partition.impl.btree.mavibot.MavibotPartition;
+import org.apache.directory.server.core.integ.FrameworkRunner;
import org.apache.directory.server.integ.ServerIntegrationUtils;
-import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -75,14 +80,11 @@
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
-@CreateLdapServer(
- transports = {
- @CreateTransport( protocol = "LDAP" )
- } )
+@RunWith(FrameworkRunner.class)
@CreateDS( name = "classDS",
partitions = {
@CreatePartition(
- type = MavibotPartition.class,
+ //type = MavibotPartition.class,
name = "example",
suffix = "dc=example,dc=com",
contextEntry = @ContextEntry(
@@ -94,24 +96,24 @@
),
indexes = {
@CreateIndex(
- type = MavibotIndex.class,
attribute = "objectClass"
),
@CreateIndex(
- type = MavibotIndex.class,
attribute = "dc"
),
@CreateIndex(
- type = MavibotIndex.class,
attribute = "ou"
),
@CreateIndex(
- type = MavibotIndex.class,
attribute = "uid"
)
}
)
} )
+@CreateLdapServer(
+ transports = {
+ @CreateTransport( protocol = "LDAP" )
+ } )
@CreateLdapConnectionPool(
maxActive = 4,
maxIdle = 2,
@@ -131,14 +133,128 @@
}
};
- @ClassRule
- public static CreateLdapConnectionPoolRule classCreateDsRule =
- new CreateLdapConnectionPoolRule();
-
-
@Test
+ public void testRenameWithALotOfDummiesAndSomeCustomAttributesAPI() throws LdapException, CursorException, IOException
+ {
+ LdapConnection connection = new LdapNetworkConnection( Network.LOOPBACK_HOSTNAME, getLdapServer().getPort() );
+ connection.bind( "uid=admin, ou=system", "secret" );
+
+ Dn peopleDn = new Dn( "ou=people," + BASE );
+
+ // Add the root entry
+ connection.add(
+ new DefaultEntry( peopleDn,
+ "objectClass: top",
+ "objectClass: organizationalUnit",
+ "ou: people" ) );
+
+ // Add 1000 children
+ int dummyCount = 1000;
+
+ for ( int i = 0; i < dummyCount; i++ )
+ {
+ String dn = "uid=uid-" + i + "," + peopleDn;
+
+ connection.add( new DefaultEntry( dn,
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "uid", "uid-" + i,
+ "cn", "cn-" + i,
+ "sn", "sn-" + i,
+ "description", i + " is a person." ) );
+
+ if ( i % 50 == 0 )
+ {
+ logger.debug( "Added person {}", i );
+ }
+ }
+
+ EntryCursor cursor;
+ int count = 0;
+
+ // Now test the rename
+ for ( int i = 0; i < 100; i++ )
+ {
+ String oldDnString = "uid=myra-ellen-amos, " + peopleDn.getName();
+ String newDnString = "uid=tory-amos, " + peopleDn.getName();
+
+ // Add an entry
+ connection.add( new DefaultEntry( oldDnString,
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalPerson",
+ "objectClass: inetOrgPerson",
+ "objectClass: portalPerson",
+ "uid: myra-ellen-amos",
+ "cn: Myra Ellen Amo",
+ "sn: Amos",
+ "active", Boolean.TRUE.toString(),
+ "affiliation: Unknown",
+ "timeZone: America/New_York",
+ "description: Myra Ellen Amos is a person." ) );
+
+ // Check it has been added
+ Entry result = connection.lookup( oldDnString );
+
+ assertNotNull (result );
+
+ // Search for it
+ cursor = connection.search( peopleDn, "(sn=amos)", SearchScope.ONELEVEL );
+ count = 0;
+
+ while ( cursor.next() )
+ {
+ Entry amos = cursor.get();
+ assertEquals( "myra-ellen-amos", amos.get( "uid" ).getString() );
+ assertEquals( "uid=myra-ellen-amos", amos.getDn().getRdn().getName() );
+
+ count++;
+ }
+
+ assertEquals( 1, count );
+
+ cursor.close();
+
+ // Rename it
+ connection.rename( oldDnString, "uid=tory-amos" );
+
+ // Search for the old and renalme entry
+ assertNull( connection.lookup( oldDnString ) );
+ result = connection.lookup( newDnString );
+ assertNotNull( result );
+
+ // Search for the new entry
+ cursor = connection.search( peopleDn, "(sn=amos)", SearchScope.ONELEVEL );
+ count = 0;
+
+ while ( cursor.next() )
+ {
+ Entry amos = cursor.get();
+ assertEquals( "tory-amos", amos.get( "uid" ).getString() );
+ assertEquals( "uid=tory-amos", amos.getDn().getRdn().getName() );
+
+ count++;
+ }
+
+ assertEquals( 1, count );
+
+ cursor.close();
+
+ // Finally delete the new entry
+ connection.delete( newDnString );
+ }
+
+ connection.close();
+ }
+
+
+ @Test
+ @Ignore
public void testRenameWithALotOfDummiesAndSomeCustomAttributes() {
- LdapConnectionTemplate template = classCreateDsRule.getLdapConnectionTemplate();
+ CreateLdapConnectionPoolRule connectionPool = new CreateLdapConnectionPoolRule();
+ LdapConnectionTemplate template = connectionPool.getLdapConnectionTemplate();
AddResponse response = null;
final String peopleOu = "people";
@@ -215,6 +331,7 @@
Entry found = template.searchFirst( peopleDn, FilterBuilder.equal( "sn", "amos" ),
SearchScope.ONELEVEL, DEFAULT_ENTRY_MAPPER );
+
assertNotNull( found );
Rdn foundRdn = found.getDn().getRdn();
assertEquals( "uid", foundRdn.getType() );
@@ -239,6 +356,8 @@
foundRdn = found.getDn().getRdn();
assertEquals( "uid", foundRdn.getType() );
assertEquals( newUid, foundRdn.getValue() );
+
+
template.delete( newDn );
}
@@ -249,7 +368,6 @@
* Modify Rdn of an entry, delete its old rdn value and search before and
* after rename.
*/
- @Ignore
@Test
public void testModifyRdnWithLotsOfDummies() throws Exception
{
diff --git a/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java b/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java
index f4e918b..9164f1b 100644
--- a/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java
+++ b/xdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/AbstractBTreePartition.java
@@ -197,6 +197,9 @@
private static final boolean NO_REVERSE = Boolean.FALSE;
private static final boolean WITH_REVERSE = Boolean.TRUE;
+
+ private static final boolean ADD_CACHE = Boolean.TRUE;
+ private static final boolean DEL_CACHE = Boolean.FALSE;
protected static final boolean ADD_CHILD = true;
protected static final boolean REMOVE_CHILD = false;
@@ -908,6 +911,9 @@
{
// Update the RDN index
rdnIdx.add( partitionTxn, parentIdAndRdn, id );
+
+ // Update the PIAR cache at the same time
+ updatePiarCache( parentIdAndRdn, id, ADD_CACHE );
// Update the parent's nbChildren and nbDescendants values
if ( parentId != Partition.ROOT_ID )
@@ -1005,7 +1011,6 @@
while ( parent != null )
{
rdnIdx.drop( partitionTxn, parentId );
- ////dumpRdnIdx();
if ( isFirst )
{
@@ -1144,7 +1149,7 @@
{
rdnIdx.drop( partitionTxn, id );
- ////dumpRdnIdx();
+ updatePiarCache( parent, id, DEL_CACHE );
entryDnCache.invalidate( id );
@@ -2139,10 +2144,12 @@
updateRdnIdx( partitionTxn, oldParentId, REMOVE_CHILD, movedEntry.getNbDescendants() );
rdnIdx.drop( partitionTxn, entryId );
+ updatePiarCache( movedEntry, entryId, DEL_CACHE );
// Now, add the new entry at the right position
movedEntry.setParentId( newParentId );
rdnIdx.add( partitionTxn, movedEntry, entryId );
+ updatePiarCache( movedEntry, entryId, ADD_CACHE );
updateRdnIdx( partitionTxn, newParentId, ADD_CHILD, movedEntry.getNbDescendants() );
@@ -2293,6 +2300,7 @@
// First drop the moved entry from the rdn index
rdnIdx.drop( partitionTxn, entryId );
+ updatePiarCache( movedEntry, entryId, DEL_CACHE );
//
// The update the Rdn index. We will remove the ParentIdAndRdn associated with the
@@ -2318,6 +2326,7 @@
movedEntry.setRdns( new Rdn[]
{ newRdn } );
rdnIdx.add( partitionTxn, movedEntry, entryId );
+ updatePiarCache( movedEntry, entryId, ADD_CACHE );
updateRdnIdx( partitionTxn, newParentId, ADD_CHILD, movedEntry.getNbDescendants() );
@@ -2538,7 +2547,6 @@
{
presenceIdx.drop( partitionTxn, newRdnAttrType.getOid(), oldId );
}
-
}
}
@@ -2555,20 +2563,8 @@
{
Index<?, String> userIndex = getUserIndex( newRdnAttrType );
- /*
- if ( oldRemoved )
- {
- String normalized = newRdnAttrType.getEquality().getNormalizer().normalize( newNormValue );
- ( ( Index ) userIndex ).add( normalized, id );
- ( ( Index ) index ).drop( newNormValue, oldId );
- }
- */
-
String normalized = newRdnAttrType.getEquality().getNormalizer().normalize( ( String ) newNormValue );
( ( Index ) userIndex ).add( partitionTxn, normalized, oldId );
-
-
- //( ( Index ) index ).add( newNormValue, oldId );
// Make sure the altered entry shows the existence of the new attrib
String normTypeOid = presenceNormalizer.normalize( newNormType );
@@ -2686,6 +2682,8 @@
// Now we can drop it
rdnIdx.drop( partitionTxn, oldId );
+
+ updatePiarCache( parentIdAndRdn, oldId, DEL_CACHE );
// Update the descendants
parentIdAndRdn.setParentId( parentId );
@@ -2693,6 +2691,8 @@
rdnIdx.add( partitionTxn, parentIdAndRdn, oldId );
+ updatePiarCache( parentIdAndRdn, oldId, ADD_CACHE );
+
entryDnCache.invalidateAll();
if ( isSyncOnWrite.get() )
@@ -2761,6 +2761,22 @@
entryCsnIdx.drop( partitionTxn, id );
entryCsnIdx.add( partitionTxn, entryCsn, id );
}
+
+
+ /**
+ * Update the ParentIdAndRdn cache, by adding or removing an element
+ */
+ private void updatePiarCache( ParentIdAndRdn piar, String id, boolean add )
+ {
+ if ( add == ADD_CACHE )
+ {
+ piarCache.put( id, piar );
+ }
+ else
+ {
+ piarCache.invalidate( id );
+ }
+ }
// ------------------------------------------------------------------------