From 7c6dff1723be6ac0e0faeff0b9bc9747a18b98b5 Mon Sep 17 00:00:00 2001
From: pgamba <pgamba@localhost>
Date: Wed, 17 Jan 2007 11:01:32 +0000
Subject: [PATCH] Fix Issue 783 synchronization does not detect that the parent is renamed during add operations
---
opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java | 100 +++++++++++++++++++++++++++++++++
opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java | 26 ++++++++
2 files changed, 124 insertions(+), 2 deletions(-)
diff --git a/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java b/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
index 825ab82..cfcde54 100644
--- a/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
+++ b/opends/src/server/org/opends/server/synchronization/plugin/SynchronizationDomain.java
@@ -532,6 +532,30 @@
addOperation.setResultCode(ResultCode.SUCCESS);
return new SynchronizationProviderResult(false);
}
+
+ /* The parent entry may have been renamed here since the change was done
+ * on the first server, and another entry have taken the former dn
+ * of the parent entry
+ */
+
+ // There is a potential of perfs improvement here
+ // if we could avoid the following parent entry retrieval
+ DN parentDnFromCtx = findEntryDN(ctx.getParentUid());
+
+ if (parentDnFromCtx != null)
+ {
+ DN entryDN = addOperation.getEntryDN();
+ DN parentDnFromEntryDn = entryDN.getParentDNInSuffix();
+ if ((parentDnFromEntryDn != null)
+ && (!parentDnFromCtx.equals(parentDnFromEntryDn)))
+ {
+ // parentEntry has been renamed
+ // Synchronization name conflict resolution is expected to fix that
+ // later in the flow
+ addOperation.setResultCode(ResultCode.NO_SUCH_OBJECT);
+ return new SynchronizationProviderResult(false);
+ }
+ }
}
return new SynchronizationProviderResult(true);
}
@@ -1397,7 +1421,7 @@
* Solve a conflict detected when replaying a ADD operation.
*
* @param op The operation that triggered the conflict detection.
- * @param msg The operation that triggered the conflict detection.
+ * @param msg The message that triggered the conflict detection.
* @return true if the process is completed, false if it must continue.
* @throws Exception When the operation is not valid.
*/
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
index dffa201..f76d76c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/synchronization/UpdateOperationTest.java
@@ -31,8 +31,11 @@
import static org.testng.Assert.*;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.locks.Lock;
import org.opends.server.TestCaseUtils;
@@ -41,6 +44,7 @@
import org.opends.server.schema.IntegerSyntax;
import org.opends.server.synchronization.common.ChangeNumberGenerator;
import org.opends.server.synchronization.plugin.ChangelogBroker;
+import org.opends.server.synchronization.plugin.Historical;
import org.opends.server.synchronization.protocol.AddMsg;
import org.opends.server.synchronization.protocol.DeleteMsg;
import org.opends.server.synchronization.protocol.ModifyDNMsg;
@@ -52,6 +56,7 @@
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.Operation;
+import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
@@ -539,6 +544,99 @@
// check that the delete operation has been applied
assertNull(resultEntry,
"The DELETE synchronization message was not replayed");
+
+ /*
+ * When replaying add operations it is possible that the parent entry has
+ * been renamed before and that another entry have taken the former dn of
+ * the parent entry. In such case the synchronization replay code should
+ * detect that the parent has been renamed and should add the entry below
+ * the new dn of the parent (thus changing the original dn with which the
+ * entry had been created)
+ *
+ * Steps
+ * - create parent entry 1 with baseDn1
+ * - create Add Msg for user1 with parent entry 1 UUID
+ * - MODDN parent entry 1 to baseDn2 in the LDAP server
+ * - add new parent entry 2 with baseDn1
+ * - publish msg
+ * - check that the Dn has been changed to baseDn2 in the msg received
+ */
+
+ // - create parent entry 1 with baseDn1
+ String[] topEntries = new String[1];
+ topEntries[0] = "dn: ou=baseDn1,"+baseDn+"\n" + "objectClass: top\n"
+ + "objectClass: organizationalUnit\n"
+ + "entryUUID: 55555555-5555-5555-5555-555555555555\n";
+ Entry entry;
+ for (int i = 0; i < topEntries.length; i++)
+ {
+ entry = TestCaseUtils.entryFromLdifString(topEntries[i]);
+ AddOperation addOp = new AddOperation(connection,
+ InternalClientConnection.nextOperationID(), InternalClientConnection
+ .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
+ entry.getUserAttributes(), entry.getOperationalAttributes());
+ addOp.setInternalOperation(true);
+ addOp.run();
+ entryList.add(entry.getDN());
+ }
+ resultEntry = getEntry(
+ DN.decode("ou=baseDn1,"+baseDn), 10000, true);
+ assertNotNull(resultEntry,
+ "Entry not added: ou=baseDn1,"+baseDn);
+
+ // - create Add Msg for user1 with parent entry 1 UUID
+ addMsg = new AddMsg(gen.NewChangeNumber(),
+ "uid=new person,ou=baseDn1,"+baseDn,
+ user1entryUUID,
+ getEntryUUID(DN.decode("ou=baseDn1,"+baseDn)),
+ personWithUUIDEntry.getObjectClassAttribute(),
+ personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
+
+ // - MODDN parent entry 1 to baseDn2 in the LDAP server
+ ModifyDNOperation modDNOp = new ModifyDNOperation(connection,
+ InternalClientConnection.nextOperationID(), InternalClientConnection
+ .nextMessageID(), null,
+ DN.decode("ou=baseDn1,"+baseDn),
+ RDN.decode("ou=baseDn2"), true,
+ baseDn);
+ modDNOp.run();
+ entryList.add(DN.decode("ou=baseDn2,"+baseDn));
+
+ resultEntry = getEntry(
+ DN.decode("ou=baseDn2,"+baseDn), 10000, true);
+ assertNotNull(resultEntry,
+ "Entry not moved from ou=baseDn1,"+baseDn+" to ou=baseDn2,"+baseDn);
+
+ // - add new parent entry 2 with baseDn1
+ String p2 = new String("dn: ou=baseDn1,"+baseDn+"\n" + "objectClass: top\n"
+ + "objectClass: organizationalUnit\n"
+ + "entryUUID: 66666666-6666-6666-6666-666666666666\n");
+ entry = TestCaseUtils.entryFromLdifString(p2);
+ AddOperation addOp = new AddOperation(connection,
+ InternalClientConnection.nextOperationID(), InternalClientConnection
+ .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
+ entry.getUserAttributes(), entry.getOperationalAttributes());
+ addOp.setInternalOperation(true);
+ addOp.run();
+ entryList.add(entry.getDN());
+
+
+ // - publish msg
+ broker.publish(addMsg);
+
+ // - check that the Dn has been changed to baseDn2
+ resultEntry = getEntry(
+ DN.decode("uid=new person,ou=baseDn1,"+baseDn), 10000, true);
+ assertNull(resultEntry,
+ "The ADD synchronization message was applied under ou=baseDn1,"+baseDn);
+
+ resultEntry = getEntry(
+ DN.decode("uid=new person,ou=baseDn2,"+baseDn), 10000, true);
+ assertNotNull(resultEntry,
+ "The ADD synchronization message was NOT applied under ou=baseDn2,"+baseDn);
+ entryList.add(resultEntry.getDN());
+
+
broker.stop();
}
@@ -690,7 +788,7 @@
*/
Entry resultEntry = getEntry(personWithUUIDEntry.getDN(), 10000, true);
assertNotNull(resultEntry,
- "The send ADD synchronization message was not applied");
+ "The send ADD synchronization message was not applied for "+personWithUUIDEntry.getDN().toString());
entryList.add(resultEntry.getDN());
/*
--
Gitblit v1.10.0