From 018234e6ccd27c399d0d1aa17981c8b4f7abbc39 Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Mon, 07 Jun 2010 09:55:29 +0000
Subject: [PATCH] Fix issue #3404. Conflicting entries are now indexed by ds-sync-conflict attribute. This index is only updated when conflicts are detected and searched on for all deletes and modDN operations. Tested successfully against performance regression.
---
opends/resource/schema/02-config.ldif | 3
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java | 201 +++++++++++++++++++++++++++-
opends/src/server/org/opends/server/replication/plugin/Historical.java | 21 ++
opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml | 8 +
opends/resource/config/config.ldif | 6
opends/src/messages/messages/replication.properties | 4
opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java | 163 ++++++++++++++++++++++-
7 files changed, 385 insertions(+), 21 deletions(-)
diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index 574a82d..c370f27 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -223,6 +223,12 @@
ds-cfg-attribute: ds-sync-hist
ds-cfg-index-type: ordering
+dn: ds-cfg-attribute=ds-sync-conflict,cn=Index,ds-cfg-backend-id=userRoot,cn=Backends,cn=config
+objectClass: top
+objectClass: ds-cfg-local-db-index
+ds-cfg-attribute: ds-sync-conflict
+ds-cfg-index-type: equality
+
dn: ds-cfg-attribute=entryUUID,cn=Index,ds-cfg-backend-id=userRoot,cn=Backends,cn=config
objectClass: top
objectClass: ds-cfg-local-db-index
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 6322ce2..2bd9523 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -1552,7 +1552,8 @@
X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.317
NAME 'ds-sync-conflict'
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ EQUALITY distinguishedNameMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
USAGE directoryOperation
X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.319
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml
index d0ae3fc..052e353 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml
@@ -84,6 +84,14 @@
<adm:value>ds-sync-hist</adm:value>
</adm:property>
</adm:default-managed-object>
+ <adm:default-managed-object name="ds-sync-conflict">
+ <adm:property name="index-type">
+ <adm:value>equality</adm:value>
+ </adm:property>
+ <adm:property name="attribute">
+ <adm:value>ds-sync-conflict</adm:value>
+ </adm:property>
+ </adm:default-managed-object>
</adm:one-to-many>
<adm:profile name="ldap">
<ldap:rdn-sequence>cn=Index</ldap:rdn-sequence>
diff --git a/opends/src/messages/messages/replication.properties b/opends/src/messages/messages/replication.properties
index 25e4416..0189c92 100644
--- a/opends/src/messages/messages/replication.properties
+++ b/opends/src/messages/messages/replication.properties
@@ -494,4 +494,6 @@
NOTICE_ERR_WHILE_TRYING_TO_DECODE_RUV_IN_STATE_200=Error while trying to \
translate RUV into state for suffix %s
SEVERE_ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN_201=Processing two different \
- changes with same changeNumber=%s. Previous msg=<%s>, New msg=<%s>
\ No newline at end of file
+ changes with same changeNumber=%s. Previous msg=<%s>, New msg=<%s>
+SEVERE_ERR_COULD_NOT_SOLVE_CONFLICT_202=Error while trying to solve conflict \
+ with DN : %s ERROR : %s
diff --git a/opends/src/server/org/opends/server/replication/plugin/Historical.java b/opends/src/server/org/opends/server/replication/plugin/Historical.java
index 0d269fd..11ef740 100644
--- a/opends/src/server/org/opends/server/replication/plugin/Historical.java
+++ b/opends/src/server/org/opends/server/replication/plugin/Historical.java
@@ -22,7 +22,7 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2009 Sun Microsystems, Inc.
+ * Copyright 2006-2010 Sun Microsystems, Inc.
*/
package org.opends.server.replication.plugin;
@@ -449,6 +449,25 @@
/**
+ * Returns the lastChangeNumber when the entry DN was modified.
+ *
+ * @return The lastChangeNumber when the entry DN was modified.
+ */
+ public ChangeNumber getDNDate()
+ {
+ if (ADDDate == null)
+ return MODDNDate;
+
+ if (MODDNDate == null)
+ return ADDDate;
+
+ if (MODDNDate.older(ADDDate))
+ return MODDNDate;
+ else
+ return ADDDate;
+ }
+
+ /**
* read the historical information from the entry attribute and
* load it into the Historical object attached to the entry.
* @param entry The entry which historical information must be loaded
diff --git a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index 04094a0..3b45c55 100644
--- a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -2411,6 +2411,148 @@
pendingChanges.pushCommittedChanges();
}
}
+
+ checkForClearedConflict(op);
+ }
+
+ /**
+ * Check if the operation that just happened has cleared a conflict :
+ * Clearing a conflict happens if the operation has free a DN that
+ * for which an other entry was in conflict.
+ */
+ private void checkForClearedConflict(PostOperationOperation op)
+ {
+ OperationType type = op.getOperationType();
+ if (op.getResultCode() != ResultCode.SUCCESS)
+ {
+ // those operations cannot have cleared a conflict
+ return;
+ }
+
+ DN targetDN;
+ if (type == OperationType.DELETE)
+ {
+ targetDN = ((PostOperationDeleteOperation) op).getEntryDN();
+ }
+ else if (type == OperationType.MODIFY_DN)
+ {
+ targetDN = ((PostOperationModifyDNOperation) op).getEntryDN();
+ }
+ else
+ {
+ return;
+ }
+
+ LDAPFilter filter = null;
+ try
+ {
+ filter = LDAPFilter.decode(
+ DS_SYNC_CONFLICT + "=" + targetDN.toNormalizedString());
+ } catch (LDAPException e)
+ {
+ // Not possible. We know the filter just above is correct.
+ }
+
+ LinkedHashSet<String> attrs = new LinkedHashSet<String>(1);
+ attrs.add(Historical.HISTORICALATTRIBUTENAME);
+ attrs.add(Historical.ENTRYUIDNAME);
+ attrs.add("*");
+ InternalSearchOperation searchOp = conn.processSearch(
+ ByteString.valueOf(baseDn.toString()),
+ SearchScope.WHOLE_SUBTREE,
+ DereferencePolicy.NEVER_DEREF_ALIASES,
+ 0, 0, false, filter,
+ attrs, null);
+
+ LinkedList<SearchResultEntry> entries = searchOp.getSearchEntries();
+ Entry entrytoRename = null;
+ ChangeNumber entrytoRenameDate = null;
+ for (SearchResultEntry entry : entries)
+ {
+ Historical history = Historical.load(entry);
+ if (entrytoRename == null)
+ {
+ entrytoRename = entry;
+ entrytoRenameDate = history.getDNDate();
+ }
+ else if (!history.AddedOrRenamedAfter(entrytoRenameDate))
+ {
+ // this conflict is older than the previous, keep it.
+ entrytoRename = entry;
+ entrytoRenameDate = history.getDNDate();
+ }
+ }
+
+ if (entrytoRename != null)
+ {
+ DN entryDN = entrytoRename.getDN();
+ ModifyDNOperationBasis newOp = renameEntry(
+ entryDN, targetDN.getRDN(), targetDN.getParent(), false);
+
+ ResultCode res = newOp.getResultCode();
+ if (res != ResultCode.SUCCESS)
+ {
+ Message message =
+ ERR_COULD_NOT_SOLVE_CONFLICT.get(entryDN.toString(), res.toString());
+ logError(message);
+ }
+ }
+ }
+
+ /**
+ * Rename an Entry Using a synchronization, non-replicated operation.
+ * This method should be used instead of the InternalConnection methods
+ * when the operation that need to be run must be local only and therefore
+ * not replicated to the RS.
+ *
+ * @param targetDN The DN of the entry to rename.
+ * @param newRDN The new RDN to be used.
+ * @param parentDN The parentDN to be used.
+ * @param markConflict A boolean indicating is this entry should be marked
+ * as a conflicting entry. In such case the
+ * DS_SYNC_CONFLICT attribute will be added to the entry
+ * with the value of its original DN.
+ * If false, the DS_SYNC_CONFLICT attribute will be
+ * cleared.
+ *
+ * @return The operation that was run to rename the entry.
+ */
+ private ModifyDNOperationBasis renameEntry(
+ DN targetDN, RDN newRDN, DN parentDN, boolean markConflict)
+ {
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ ModifyDNOperationBasis newOp =
+ new ModifyDNOperationBasis(
+ conn, InternalClientConnection.nextOperationID(),
+ InternalClientConnection.nextMessageID(), new ArrayList<Control>(0),
+ targetDN, newRDN, false,
+ parentDN);
+ newOp.setInternalOperation(true);
+ newOp.setSynchronizationOperation(true);
+ newOp.setDontSynchronize(true);
+
+ if (markConflict)
+ {
+ AttributeType attrType =
+ DirectoryServer.getAttributeType(DS_SYNC_CONFLICT, true);
+ Attribute attr = Attributes.create(attrType, AttributeValues.create(
+ attrType, targetDN.toString()));
+ Modification mod = new Modification(ModificationType.REPLACE, attr);
+ newOp.addModification(mod);
+ }
+ else
+ {
+ AttributeType attrType =
+ DirectoryServer.getAttributeType(DS_SYNC_CONFLICT, true);
+ Attribute attr = Attributes.empty(attrType);
+ Modification mod = new Modification(ModificationType.DELETE, attr);
+ newOp.addModification(mod);
+ }
+
+ newOp.run();
+ return newOp;
}
/**
@@ -3188,7 +3330,6 @@
* and keep the entry as a conflicting entry,
*/
conflict = true;
- markConflictEntry(conflictOp, entry.getDN(), entryDN);
renameConflictEntry(conflictOp, entry.getDN(),
Historical.getEntryUuid(entry));
}
@@ -3233,11 +3374,8 @@
*/
private void renameConflictEntry(Operation conflictOp, DN dn, String uid)
{
- InternalClientConnection conn =
- InternalClientConnection.getRootConnection();
-
- ModifyDNOperation newOp = conn.processModifyDN(
- dn, generateDeleteConflictDn(uid, dn),false, baseDn);
+ ModifyDNOperation newOp =
+ renameEntry(dn, generateDeleteConflictDn(uid, dn), baseDn, true);
if (newOp.getResultCode() != ResultCode.SUCCESS)
{
@@ -3275,7 +3413,18 @@
List<Modification> mods = new ArrayList<Modification>();
Modification mod = new Modification(ModificationType.REPLACE, attr);
mods.add(mod);
- ModifyOperation newOp = conn.processModify(currentDN, mods);
+
+ ModifyOperationBasis newOp =
+ new ModifyOperationBasis(
+ conn, InternalClientConnection.nextOperationID(),
+ InternalClientConnection.nextMessageID(), new ArrayList<Control>(0),
+ currentDN, mods);
+ newOp.setInternalOperation(true);
+ newOp.setSynchronizationOperation(true);
+ newOp.setDontSynchronize(true);
+
+ newOp.run();
+
if (newOp.getResultCode() != ResultCode.SUCCESS)
{
// Log information for the repair tool.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
index 1977ed7..fde1cfd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
@@ -34,6 +34,8 @@
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.ReplicationDomainCfgDefn.IsolationPolicy;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
@@ -42,9 +44,12 @@
import org.opends.server.replication.protocol.DeleteMsg;
import org.opends.server.types.Attribute;
import org.opends.server.types.DN;
+import org.opends.server.types.RDN;
import org.opends.server.types.Entry;
+import org.opends.server.types.ResultCode;
import org.testng.annotations.Test;
+
import static org.testng.Assert.*;
@@ -138,7 +143,7 @@
// and resolve conflict
domain.replay(queue.take().getUpdateMessage());
- // Expect the conflict resolution
+ // Expect the conflict resolution
assertFalse(DirectoryServer.entryExists(entry.getDN()),
"The modDN conflict was not resolved as expected.");
}
@@ -149,6 +154,181 @@
}
/**
+ * Test that when a previous conflict is resolved because
+ * a delete operation has removed one of the conflicting entries
+ * the other conflicting entry is correctly renamed to its
+ * original name.
+ *
+ * @throws Exception if the test fails.
+ */
+ @Test(enabled=true)
+ public void conflictCleaningDelete() throws Exception
+ {
+ TestCaseUtils.initializeTestBackend(true);
+
+ final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
+
+ TestSynchronousReplayQueue queue = new TestSynchronousReplayQueue();
+ DomainFakeCfg conf = new DomainFakeCfg(baseDn, 1, new TreeSet<String>());
+ conf.setIsolationPolicy(IsolationPolicy.ACCEPT_ALL_UPDATES);
+
+ LDAPReplicationDomain domain =
+ MultimasterReplication.createNewDomain(conf, queue);
+ domain.start();
+
+ try
+ {
+ /*
+ * Create a Change number generator to generate new ChangeNumbers
+ * when we need to send operations messages to the replicationServer.
+ */
+ ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
+
+ String entryldif =
+ "dn: cn=conflictCleaningDelete, "+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n" + "objectClass: person\n"
+ + "objectClass: organizationalPerson\n"
+ + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
+ + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
+ + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
+ + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
+ + "cn: Aaccf Amar\n" + "l: Rockford\n"
+ + "street: 17984 Thirteenth Street\n"
+ + "employeeNumber: 1\n"
+ + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
+ + "userPassword: password\n" + "initials: AA\n";
+ Entry entry = TestCaseUtils.entryFromLdifString(entryldif);
+
+ // Add the first entry
+ TestCaseUtils.addEntry(entry);
+ String parentUUID = getEntryUUID(DN.decode(TEST_ROOT_DN_STRING));
+
+ ChangeNumber cn1 = gen.newChangeNumber();
+
+ // Now try to add the same entry with same DN but a different
+ // unique ID though the replication
+ AddMsg addMsg =
+ new AddMsg(cn1,
+ entry.getDN().toNormalizedString(),
+ "c9cb8c3c-615a-4122-865d-50323aaaed48", parentUUID,
+ entry.getObjectClasses(), entry.getUserAttributes(),
+ null);
+
+ // Put the message in the replay queue
+ domain.processUpdate(addMsg);
+
+ // Make the domain replay the change from the replay queue
+ domain.replay(queue.take().getUpdateMessage());
+
+ // Now delete the first entry that was added at the beginning
+ TestCaseUtils.deleteEntry(entry.getDN());
+
+ // Expect the conflict resolution : the second entry should now
+ // have been renamed with the original DN.
+ Entry resultEntry = DirectoryServer.getEntry(entry.getDN());
+ assertTrue(resultEntry != null, "The conflict was not cleared");
+ assertEquals(getEntryUUID(resultEntry.getDN()),
+ "c9cb8c3c-615a-4122-865d-50323aaaed48",
+ "The wrong entry has been renamed");
+ assertNull(resultEntry.getAttribute(LDAPReplicationDomain.DS_SYNC_CONFLICT));
+ }
+ finally
+ {
+ MultimasterReplication.deleteDomain(baseDn);
+ }
+ }
+
+ /**
+ * Test that when a previous conflict is resolved because
+ * a MODDN operation has removed one of the conflicting entries
+ * the other conflicting entry is correctly renamed to its
+ * original name.
+ *
+ * @throws Exception if the test fails.
+ */
+ @Test(enabled=true)
+ public void conflictCleaningMODDN() throws Exception
+ {
+ TestCaseUtils.initializeTestBackend(true);
+
+ final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
+
+ TestSynchronousReplayQueue queue = new TestSynchronousReplayQueue();
+ DomainFakeCfg conf = new DomainFakeCfg(baseDn, 1, new TreeSet<String>());
+ conf.setIsolationPolicy(IsolationPolicy.ACCEPT_ALL_UPDATES);
+
+ LDAPReplicationDomain domain =
+ MultimasterReplication.createNewDomain(conf, queue);
+ domain.start();
+
+ try
+ {
+ /*
+ * Create a Change number generator to generate new ChangeNumbers
+ * when we need to send operations messages to the replicationServer.
+ */
+ ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
+
+ String entryldif =
+ "dn: cn=conflictCleaningDelete, "+ TEST_ROOT_DN_STRING + "\n"
+ + "objectClass: top\n" + "objectClass: person\n"
+ + "objectClass: organizationalPerson\n"
+ + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
+ + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
+ + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
+ + "$Rockford, NC 85762\n" + "mail: user.1@example.com\n"
+ + "cn: Aaccf Amar\n" + "l: Rockford\n"
+ + "street: 17984 Thirteenth Street\n"
+ + "employeeNumber: 1\n"
+ + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
+ + "userPassword: password\n" + "initials: AA\n";
+ Entry entry = TestCaseUtils.entryFromLdifString(entryldif);
+
+ // Add the first entry
+ TestCaseUtils.addEntry(entry);
+ String parentUUID = getEntryUUID(DN.decode(TEST_ROOT_DN_STRING));
+
+ ChangeNumber cn1 = gen.newChangeNumber();
+
+ // Now try to add the same entry with same DN but a different
+ // unique ID though the replication
+ AddMsg addMsg =
+ new AddMsg(cn1,
+ entry.getDN().toNormalizedString(),
+ "c9cb8c3c-615a-4122-865d-50323aaaed48", parentUUID,
+ entry.getObjectClasses(), entry.getUserAttributes(),
+ null);
+
+ // Put the message in the replay queue
+ domain.processUpdate(addMsg);
+
+ // Make the domain replay the change from the replay queue
+ domain.replay(queue.take().getUpdateMessage());
+
+ // Now delete the first entry that was added at the beginning
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ ModifyDNOperation modDNOperation =
+ conn.processModifyDN(entry.getDN(), RDN.decode("cn=foo"), false);
+ assertEquals(modDNOperation.getResultCode(), ResultCode.SUCCESS);
+
+ // Expect the conflict resolution : the second entry should now
+ // have been renamed with the original DN.
+ Entry resultEntry = DirectoryServer.getEntry(entry.getDN());
+ assertTrue(resultEntry != null, "The conflict was not cleared");
+ assertEquals(getEntryUUID(resultEntry.getDN()),
+ "c9cb8c3c-615a-4122-865d-50323aaaed48",
+ "The wrong entry has been renamed");
+ assertNull(resultEntry.getAttribute(LDAPReplicationDomain.DS_SYNC_CONFLICT));
+ }
+ finally
+ {
+ MultimasterReplication.deleteDomain(baseDn);
+ }
+ }
+
+ /**
* Tests for issue 3891
* S1 S2
* ADD uid=xx,ou=parent,... [SUBTREE] DEL ou=parent, ...
@@ -161,14 +341,14 @@
* 2/ removeParentConflict2 (on S1)
* - t1(cn1) ADD uid=xx,ou=parent,...
* - replay t2(cn2) DEL ou=parent, ....
- * => Conflict and no automatic resolution: expect
+ * => Conflict and no automatic resolution: expect
* - the child entry to be renamed under root entry
* - the parent entry to be deleted
*
* 3/ removeParentConflict3 (on S2)
* - t2(cn2) DEL or SUBTREE DEL ou=parent, ....
* - t1(cn1) replay ADD uid=xx,ou=parent,...
- * => Conflict and no automatic resolution: expect
+ * => Conflict and no automatic resolution: expect
* - the child entry to be renamed under root entry
*
*/
@@ -198,11 +378,11 @@
Entry parentEntry = TestCaseUtils.entryFromLdifString(
"dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
+ "objectClass: top\n"
- + "objectClass: organizationalUnit\n");
+ + "objectClass: organizationalUnit\n");
Entry childEntry = TestCaseUtils.entryFromLdifString(
"dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
- + "objectClass: top\n"
+ + "objectClass: top\n"
+ "objectClass: person\n"
+ "objectClass: organizationalPerson\n"
+ "objectClass: inetOrgPerson\n" + "uid: user.1\n"
@@ -219,7 +399,6 @@
TestCaseUtils.addEntry(childEntry);
String parentUUID = getEntryUUID(parentEntry.getDN());
- String childUUID = getEntryUUID(childEntry.getDN());
ChangeNumber cn2 = gen.newChangeNumber();
@@ -272,11 +451,11 @@
Entry parentEntry = TestCaseUtils.entryFromLdifString(
"dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
+ "objectClass: top\n"
- + "objectClass: organizationalUnit\n");
+ + "objectClass: organizationalUnit\n");
Entry childEntry = TestCaseUtils.entryFromLdifString(
"dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
- + "objectClass: top\n"
+ + "objectClass: top\n"
+ "objectClass: person\n"
+ "objectClass: organizationalPerson\n"
+ "objectClass: inetOrgPerson\n" + "uid: user.1\n"
@@ -357,11 +536,11 @@
Entry parentEntry = TestCaseUtils.entryFromLdifString(
"dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
+ "objectClass: top\n"
- + "objectClass: organizationalUnit\n");
+ + "objectClass: organizationalUnit\n");
Entry childEntry = TestCaseUtils.entryFromLdifString(
"dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
- + "objectClass: top\n"
+ + "objectClass: top\n"
+ "objectClass: person\n"
+ "objectClass: organizationalPerson\n"
+ "objectClass: inetOrgPerson\n" + "uid: user.1\n"
@@ -391,7 +570,7 @@
childEntry.getObjectClassAttribute(),
childEntry.getAttributes(),
new ArrayList<Attribute>());
-
+
// Put the message in the replay queue
domain.processUpdate(addMsg);
// Make the domain replay the change from the replay queue
--
Gitblit v1.10.0