opends/src/server/org/opends/server/controls/PersistentSearchChangeType.java
@@ -23,63 +23,47 @@ * * * Copyright 2006-2008 Sun Microsystems, Inc. * Portions Copyright 2013 ForgeRock AS */ package org.opends.server.controls; import org.opends.messages.Message; import static org.opends.messages.ProtocolMessages.*; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.opends.messages.Message; import org.opends.server.protocols.ldap.LDAPResultCode; import org.opends.server.types.LDAPException; import static org.opends.messages.ProtocolMessages.*; /** * This enumeration defines the set of possible change types that may be used in * conjunction with the persistent search control, as defined in * draft-ietf-ldapext-psearch. * <p> * It is a different type from {@link ChangeOperationType} to enforce type * safety, despite mirroring it completely. */ public enum PersistentSearchChangeType { /** * The change type that will be used for add operations. */ /** The change type that will be used for add operations. */ ADD(1), /** * The change type that will be used for delete operations. */ /** The change type that will be used for delete operations. */ DELETE(2), /** * The change type that will be used for modify operations. */ /** The change type that will be used for modify operations. */ MODIFY(4), /** * The change type that will be used for modify DN operations. */ /** The change type that will be used for modify DN operations. */ MODIFY_DN(8); // The integer value associated with this change type. /** The integer value associated with this change type. */ private int intValue; /** * Creates a new instance of a persistent search change type with the provided * integer value. @@ -111,6 +95,7 @@ * @return A string representation of this persistent search change type, or * "unknown" if it has an unknown type. */ @Override public String toString() { switch (intValue) @@ -175,7 +160,7 @@ public static Set<PersistentSearchChangeType> intToTypes(int intValue) throws LDAPException { HashSet<PersistentSearchChangeType> changeTypes = Set<PersistentSearchChangeType> changeTypes = new HashSet<PersistentSearchChangeType>(4); switch (intValue) opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -3273,13 +3273,18 @@ */ private boolean findAndRenameChild(DN entryDN, Operation conflictOp) { /* * TODO JNR Ludo thinks that: "Ideally, the operation should verify that the * entryUUID has not changed or try to use the entryUUID rather than the * DN.". entryUUID can be obtained from the caller of the current method. */ boolean conflict = false; // Find an rename child entries. try { Set<String> attrs = new LinkedHashSet<String>(1); attrs.add(ENTRYUUID_ATTRIBUTE_NAME); attrs.add(EntryHistorical.ENTRYUUID_ATTRIBUTE_NAME); attrs.add(EntryHistorical.HISTORICAL_ATTRIBUTE_NAME); InternalSearchOperation op = @@ -5595,20 +5600,26 @@ } /** * 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. * Check if the operation that just happened has cleared a conflict : Clearing * a conflict happens if the operation has freed a DN for which another entry * was in conflict. * <p> * Steps: * - get the DN freed by a DELETE or MODRDN op * - search for entries put in the conflict space (dn=entryUUID'+'....) * because the expected DN was not available (ds-sync-conflict=expected DN) * - retain the entry with the oldest conflict * - rename this entry with the freedDN as it was expected originally * <ul> * <li>get the DN freed by a DELETE or MODRDN op</li> * <li>search for entries put in the conflict space (dn=entryUUID'+'....) * because the expected DN was not available (ds-sync-conflict=expected DN) * </li> * <li>retain the entry with the oldest conflict</li> * <li>rename this entry with the freedDN as it was expected originally</li> * </ul> * * @param task the task raising this purge. * @param endDate the date to stop this task whether the job is done or not. * @throws DirectoryException when an exception happens. * * @param task * the task raising this purge. * @param endDate * the date to stop this task whether the job is done or not. * @throws DirectoryException * when an exception happens. */ public void purgeConflictsHistorical(PurgeConflictsHistoricalTask task, long endDate) opends/src/server/org/opends/server/replication/server/DraftCNDB.java
@@ -27,6 +27,9 @@ */ package org.opends.server.replication.server; import static com.sleepycat.je.LockMode.*; import static com.sleepycat.je.OperationStatus.*; import static org.opends.messages.ReplicationMessages.*; import static org.opends.server.loggers.ErrorLogger.*; import static org.opends.server.loggers.debug.DebugLogger.*; @@ -230,8 +233,7 @@ cursor = db.openCursor(null, null); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry entry = new DatabaseEntry(); OperationStatus status = cursor.getFirst(key, entry, LockMode.DEFAULT); if (status != OperationStatus.SUCCESS) if (cursor.getFirst(key, entry, LockMode.DEFAULT) != SUCCESS) { /* database is empty */ return 0; @@ -301,8 +303,7 @@ cursor = db.openCursor(null, null); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry entry = new DatabaseEntry(); OperationStatus status = cursor.getLast(key, entry, LockMode.DEFAULT); if (status != OperationStatus.SUCCESS) if (cursor.getLast(key, entry, LockMode.DEFAULT) != SUCCESS) { /* database is empty */ return 0; @@ -361,11 +362,6 @@ */ private DraftCNDBCursor(int startingDraftCN) throws Exception { // For consistency with other constructor, we'll use a local here, // even though it's always null. final Transaction localTxn = null; Cursor localCursor = null; this.key = new ReplicationDraftCNKey(startingDraftCN); this.entry = new DatabaseEntry(); @@ -374,6 +370,7 @@ // unlock it when throwing an exception. dbCloseLock.readLock().lock(); Cursor localCursor = null; try { // If the DB has been closed then create empty cursor. @@ -385,32 +382,27 @@ return; } localCursor = db.openCursor(localTxn, null); localCursor = db.openCursor(null, null); if (startingDraftCN >= 0) { if (localCursor.getSearchKey( key, entry, LockMode.DEFAULT) != OperationStatus.SUCCESS) if (localCursor.getSearchKey(key, entry, LockMode.DEFAULT) != SUCCESS) { // We could not move the cursor to the expected startingChangeNumber if (localCursor.getSearchKeyRange(key, entry, LockMode.DEFAULT) != OperationStatus.SUCCESS) if (localCursor.getSearchKeyRange(key, entry, DEFAULT) != SUCCESS) { // We could not even move the cursor closed to it => failure throw new Exception("ChangeLog Draft Change Number " + startingDraftCN + " is not available"); } if (localCursor.getPrev(key, entry, LockMode.DEFAULT) != SUCCESS) { localCursor.close(); localCursor = db.openCursor(null, null); } else { if (localCursor.getPrev(key, entry, LockMode.DEFAULT) != OperationStatus.SUCCESS) { localCursor.close(); localCursor = db.openCursor(localTxn, null); } else { seqnumData = new DraftCNData(entry.getData()); } seqnumData = new DraftCNData(entry.getData()); } } else @@ -419,7 +411,7 @@ } } this.txn = localTxn; this.txn = null; this.cursor = localCursor; } catch (Exception e) opends/src/server/org/opends/server/util/ChangeOperationType.java
@@ -26,10 +26,8 @@ */ package org.opends.server.util; /** * This enumeration defines the days of the week. * This enumeration defines the set of possible change types. */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, @@ -38,43 +36,29 @@ mayInvoke=true) public enum ChangeOperationType { /** * The change type for add operations. */ /** The change type for add operations. */ ADD("ADD", "add"), /** * The change type for delete operations. */ /** The change type for delete operations. */ DELETE("DELETE", "delete"), /** * The change type for modify operations. */ /** The change type for modify operations. */ MODIFY("MODIFY", "modify"), /** * The change type for modify DN operations. */ /** The change type for modify DN operations. */ MODIFY_DN("MODIFY_DN", "moddn"); // The name of this change type as it should appear in the "changetype" field // in LDIF records. /** * The name of this change type as it should appear in the "changetype" field * in LDIF records. */ private String ldifChangeType; // The user-friendly name given to this change type. /** The user-friendly name given to this change type. */ private String type; /** * Creates a change type with the given string value. * @@ -118,6 +102,7 @@ * * @return A string representation of this type. */ @Override public String toString() { return type; opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
@@ -630,7 +630,7 @@ /** Add an entry in the database */ private void addEntry(Entry entry) throws Exception { AddOperationBasis addOp = new AddOperationBasis(connection, AddOperation addOp = new AddOperationBasis(connection, InternalClientConnection.nextOperationID(), InternalClientConnection .nextMessageID(), null, entry.getDN(), entry.getObjectClasses(), entry.getUserAttributes(), entry.getOperationalAttributes()); @@ -804,10 +804,10 @@ publishDeleteMsgInOTest(s1test, cn, tn, 1); cn = new ChangeNumber(time++, ts++, s2test2.getServerId()); publishDeleteMsgInOTest(s2test2, cn, tn, 2); publishDeleteMsgInOTest2(s2test2, cn, tn, 2); ChangeNumber cn3 = new ChangeNumber(time++, ts++, s2test2.getServerId()); publishDeleteMsgInOTest(s2test2, cn3, tn, 3); publishDeleteMsgInOTest2(s2test2, cn3, tn, 3); cn = new ChangeNumber(time++, ts++, s1test.getServerId()); publishDeleteMsgInOTest(s1test, cn, tn, 4); @@ -1262,10 +1262,7 @@ // Publish MOD ChangeNumber cn3 = new ChangeNumber(TimeThread.getTime(), ts++, 1201); Attribute attr1 = Attributes.create("description", "new value"); Modification mod1 = new Modification(ModificationType.REPLACE, attr1); List<Modification> mods = new ArrayList<Modification>(); mods.add(mod1); List<Modification> mods = createMods("description", "new value"); ModifyMsg modMsg = new ModifyMsg(cn3, DN .decode("uid="+tn+"3," + TEST_ROOT_DN_STRING), mods, tn+"uuid3"); server01.publish(modMsg); @@ -1274,13 +1271,12 @@ // Publish modDN DN newSuperior = DN.decode(TEST_ROOT_DN_STRING2); ChangeNumber cn4 = new ChangeNumber(TimeThread.getTime(), ts++, 1201); ModifyDNOperationBasis op = new ModifyDNOperationBasis(connection, 1, 1, null, ModifyDNOperation op = new ModifyDNOperationBasis(connection, 1, 1, null, DN.decode("uid="+tn+"4," + TEST_ROOT_DN_STRING), // entryDN RDN.decode("uid="+tn+"new4"), // new rdn true, // deleteoldrdn newSuperior); op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cn4, tn+"uuid4", "newparentId")); op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cn4, tn+"uuid4", "newparentId")); LocalBackendModifyDNOperation localOp = new LocalBackendModifyDNOperation(op); ModifyDNMsg modDNMsg = new ModifyDNMsg(localOp); server01.publish(modDNMsg); @@ -2384,8 +2380,7 @@ if (createBaseEntry) { Entry e = createEntry(baseDN); memoryBackend.addEntry(e, null); memoryBackend.addEntry(createEntry(baseDN), null); } return memoryBackend; } @@ -2583,10 +2578,7 @@ // Publish MOD ChangeNumber cn3 = new ChangeNumber(TimeThread.getTime(), ts++, 1201); Attribute attr1 = Attributes.create("description", "new value"); Modification mod1 = new Modification(ModificationType.REPLACE, attr1); List<Modification> mods = new ArrayList<Modification>(); mods.add(mod1); List<Modification> mods = createMods("description", "new value"); ModifyMsg modMsg = new ModifyMsg(cn3, DN .decode("uid="+tn+"3," + TEST_ROOT_DN_STRING), mods, user1entryUUID); server01.publish(modMsg); @@ -2594,13 +2586,12 @@ // Publish modDN ChangeNumber cn4 = new ChangeNumber(TimeThread.getTime(), ts++, 1201); ModifyDNOperationBasis op = new ModifyDNOperationBasis(connection, 1, 1, null, ModifyDNOperation op = new ModifyDNOperationBasis(connection, 1, 1, null, DN.decode("uid="+tn+"4," + TEST_ROOT_DN_STRING), // entryDN RDN.decode("uid="+tn+"new4"), // new rdn true, // deleteoldrdn DN.decode(TEST_ROOT_DN_STRING2)); // new superior op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cn4, user1entryUUID, "newparentId")); op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cn4, user1entryUUID, "newparentId")); LocalBackendModifyDNOperation localOp = new LocalBackendModifyDNOperation(op); ModifyDNMsg modDNMsg = new ModifyDNMsg(localOp); server01.publish(modDNMsg); @@ -3270,7 +3261,7 @@ debugInfo(tn, "Starting test\n\n"); Backend backend2 = null; Backend backend3 = null; DeleteOperationBasis delOp =null; DeleteOperation delOp = null; LDAPReplicationDomain domain2 = null; LDAPReplicationDomain domain3 = null; LDAPReplicationDomain domain21 = null; @@ -3341,11 +3332,8 @@ sleep(1000); Entry e2 = createEntry(baseDn2); addEntry(e2); Entry e3 = createEntry(baseDn3); addEntry(e3); addEntry(createEntry(baseDn2)); addEntry(createEntry(baseDn3)); String lentry = "dn: cn=Fiona Jensen," + TEST_ROOT_DN_STRING2 + "\n" @@ -3375,29 +3363,13 @@ addEntry(uentry2); // add robert in o=test3 // mod 'sn' of fiona (o=test2) with 'sn' configured as ecl-incl-att AttributeBuilder builder = new AttributeBuilder("sn"); builder.add("newsn"); Modification mod = new Modification(ModificationType.REPLACE, builder.toAttribute()); List<Modification> mods = new ArrayList<Modification>(); mods.add(mod); ModifyOperationBasis modOpBasis = new ModifyOperationBasis(connection, 1, 1, null, uentry1.getDN(), mods); modOpBasis.run(); waitOpResult(modOpBasis, ResultCode.SUCCESS); runModifyOperation(uentry1, createMods("sn", "newsn")); // mod 'telephonenumber' of robert (o=test3) builder = new AttributeBuilder("telephonenumber"); builder.add("555555"); mod = new Modification(ModificationType.REPLACE, builder.toAttribute()); mods = new ArrayList<Modification>(); mods.add(mod); ModifyOperationBasis modOpBasis2 = new ModifyOperationBasis(connection, 1, 1, null, uentry2.getDN(), mods); modOpBasis2.run(); waitOpResult(modOpBasis2, ResultCode.SUCCESS); runModifyOperation(uentry2, createMods("telephonenumber", "555555")); // moddn robert (o=test3) to robert2 (o=test3) ModifyDNOperationBasis modDNOp = new ModifyDNOperationBasis(connection, ModifyDNOperation modDNOp = new ModifyDNOperationBasis(connection, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), null, @@ -3522,6 +3494,23 @@ debugInfo(tn, "Ending test with success"); } private void runModifyOperation(Entry entry, List<Modification> mods) throws Exception { final ModifyOperation operation = new ModifyOperationBasis(connection, 1, 1, null, entry.getDN(), mods); operation.run(); waitOpResult(operation, ResultCode.SUCCESS); } private List<Modification> createMods(String attributeName, String valueString) { Attribute attr = Attributes.create(attributeName, valueString); List<Modification> mods = new ArrayList<Modification>(); mods.add(new Modification(ModificationType.REPLACE, attr)); return mods; } private Entry parseIncludedAttributes(SearchResultEntry resultEntry, String targetdn) throws Exception {