opends/src/server/org/opends/server/replication/plugin/Historical.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.replication.plugin; @@ -433,6 +433,26 @@ return builder.toAttribute(); } /** * Indicates if the Entry was renamed or added after the ChangeNumber * that is given as a parameter. * * @param cn The ChangeNumber with which the ADD or Rename date must be * compared. * * @return A boolean indicating if the Entry was renamed or added after * the ChangeNumber that is given as a parameter. */ public boolean AddedOrRenamedAfter(ChangeNumber cn) { if (cn.older(ADDDate) || cn.older(MODDNDate)) { return true; } else return false; } /** * read the historical information from the entry attribute and opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -64,6 +64,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.CheckedOutputStream; import java.util.zip.DataFormatException; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.server.admin.server.ConfigurationChangeListener; @@ -75,6 +76,7 @@ import org.opends.server.api.SynchronizationProvider; import org.opends.server.backends.jeb.BackendImpl; import org.opends.server.config.ConfigException; import org.opends.server.controls.SubtreeDeleteControl; import org.opends.server.core.AddOperation; import org.opends.server.core.DeleteOperation; import org.opends.server.core.DirectoryServer; @@ -1069,6 +1071,8 @@ * different operation. */ op = msg.createOperation(conn); if (op instanceof DeleteOperation) op.addRequestControl(new SubtreeDeleteControl()); } } else @@ -1407,9 +1411,11 @@ * The action taken here must be consistent with the actions * done in the solveNamingConflict(AddOperation) method * when we are adding an entry whose parent entry has already been deleted. * */ findAndRenameChild(entryUid, op.getEntryDN(), op); if (findAndRenameChild(entryUid, op.getEntryDN(), op)) numUnresolvedNamingConflicts.incrementAndGet(); return false; } else @@ -1652,17 +1658,25 @@ * @param entryDN The DN of the entry whose child must be renamed. * @param conflictOp The Operation that generated the conflict. */ private void findAndRenameChild( private boolean findAndRenameChild( String entryUid, DN entryDN, Operation conflictOp) { boolean conflict = false; // Find an rename child entries. InternalClientConnection conn = InternalClientConnection.getRootConnection(); DeleteContext ctx = (DeleteContext) conflictOp.getAttachment(SYNCHROCONTEXT); ChangeNumber cn = null; if (ctx != null) cn = ctx.getChangeNumber(); try { LinkedHashSet<String> attrs = new LinkedHashSet<String>(1); attrs.add(ENTRYUIDNAME); attrs.add(Historical.HISTORICALATTRIBUTENAME); SearchFilter ALLMATCH; ALLMATCH = SearchFilter.createFilterFromString("(objectClass=*)"); @@ -1678,12 +1692,25 @@ { for (SearchResultEntry entry : entries) { /* * Check the ADD and ModRDN date of the child entry. If it is after * the delete date then keep the entry as a conflicting entry, * otherwise delete the entry with the operation. */ if (cn != null) { Historical hist = Historical.load(entry); if (hist.AddedOrRenamedAfter(cn)) { conflict = true; markConflictEntry(conflictOp, entry.getDN(), entryDN); renameConflictEntry(conflictOp, entry.getDN(), Historical.getEntryUuid(entry)); } } } } } else { // log error and information for the REPAIR tool. @@ -1708,6 +1735,8 @@ mb.append(e.getLocalizedMessage()); logError(mb.toMessage()); } return conflict; } opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.replication; @@ -1120,6 +1120,8 @@ // add domain1 entry with 2 children : domain2 and domain3 addEntry(domain1); ChangeNumber olderCn = gen.newChangeNumber(); Thread.sleep(1000); domain1uid = getEntryUUID(DN.decode(domain1dn)); addEntry(domain2); domain2uid = getEntryUUID(DN.decode(domain2dn)); @@ -1134,7 +1136,7 @@ AlertCount = DummyAlertHandler.getAlertCount(); // delete domain1 delMsg = new DeleteMsg(domain1dn, gen.newChangeNumber(), domain1uid); delMsg = new DeleteMsg(domain1dn, olderCn, domain1uid); broker.publish(delMsg); // check that the domain1 has correctly been deleted @@ -1167,6 +1169,36 @@ delEntry(conflictDomain3dn); // // Check that when a delete is replayed over an entry which has child // those child are also deleted // // add domain1 entry with 2 children : domain2 and domain3 addEntry(domain1); domain1uid = getEntryUUID(DN.decode(domain1dn)); addEntry(domain2); domain2uid = getEntryUUID(DN.decode(domain2dn)); addEntry(domain3); domain3uid = getEntryUUID(DN.decode(domain3dn)); updateMonitorCount(baseDn, unresolvedMonitorAttr); AlertCount = DummyAlertHandler.getAlertCount(); // delete domain1 delMsg = new DeleteMsg(domain1dn, gen.newChangeNumber(), domain1uid); broker.publish(delMsg); // check that the domain1 has correctly been deleted assertNull(getEntry(DN.decode(domain1dn), 10000, false), "The DELETE replication message was not replayed"); // check that domain2 and domain3 have not been renamed as conflicting assertNull(getEntry(conflictDomain2dn, 1000, true), "The conflicting entries were not created"); assertNull(getEntry(conflictDomain3dn, 1000, true), "The conflicting entries were not created"); // // Check that when an entry is added on one master below an entry // that is currently deleted on another master, the replay of the // add on the second master cause the added entry to be renamed opends/tests/unit-tests-testng/src/server/org/opends/server/replication/service/ReplicationDomainTest.java
@@ -41,6 +41,7 @@ import org.opends.server.replication.ReplicationTestCase; import org.opends.server.replication.common.DSInfo; import org.opends.server.replication.common.RSInfo; import org.opends.server.replication.common.ServerStatus; import org.opends.server.replication.protocol.UpdateMsg; import org.opends.server.replication.server.ReplServerFakeConfiguration; import org.opends.server.replication.server.ReplicationServer; @@ -128,6 +129,11 @@ assertTrue(replServerInfo.getGenerationId() == 1); } for (DSInfo serverInfo : domain1.getDsList()) { assertTrue(serverInfo.getStatus() == ServerStatus.NORMAL_STATUS); } domain1.setGenerationID(2); domain1.resetReplicationLog(); @@ -138,6 +144,28 @@ // The generation Id of the remote should now be 2 assertTrue(replServerInfo.getGenerationId() == 2); } for (DSInfo serverInfo : domain1.getDsList()) { if (serverInfo.getDsId() == 2) assertTrue(serverInfo.getStatus() == ServerStatus.BAD_GEN_ID_STATUS); else { assertTrue(serverInfo.getDsId() == 1); assertTrue(serverInfo.getStatus() == ServerStatus.NORMAL_STATUS); } } for (DSInfo serverInfo : domain2.getDsList()) { if (serverInfo.getDsId() == 2) assertTrue(serverInfo.getStatus() == ServerStatus.BAD_GEN_ID_STATUS); else { assertTrue(serverInfo.getDsId() == 1); assertTrue(serverInfo.getStatus() == ServerStatus.NORMAL_STATUS); } } } finally {