mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
yesterday f3076a0a7b60fa444dbaea5a69f40ab423562765
[#955] Answer a ModifyDN whose entry is gone before the new superior is looked up (#965)
2 files modified
66 ■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java 26 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/NamingConflictTest.java 40 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -3629,6 +3629,21 @@
  // get the current DN of this entry in the database.
  DN currentDN = findEntryDN(entryUUID);
  if (currentDN == null)
  {
    /*
     * The entry targeted by the Modify DN is not in the database anymore.
     * This is a conflict between a delete and this modify DN.
     * The entry has been deleted, we can safely assume that the operation is completed.
     *
     * This is answered before the new superior is looked up, and before the branch which
     * marks the entry as conflicting: an entry which is not in the database can not be
     * marked, and the delete has already settled what this Modify DN was trying to do.
     */
    numResolvedNamingConflicts.incrementAndGet();
    return ConflictResolution.NOTHING_TO_DO;
  }
  // Construct the new DN to use for the entry.
  DN entryDN = op.getEntryDN();
  DN newSuperior;
@@ -3657,17 +3672,6 @@
  DN newDN = newSuperior.child(newRDN);
  if (currentDN == null)
  {
    // The entry targeted by the Modify DN is not in the database
    // anymore.
    // This is a conflict between a delete and this modify DN.
    // The entry has been deleted, we can safely assume
    // that the operation is completed.
    numResolvedNamingConflicts.incrementAndGet();
    return ConflictResolution.NOTHING_TO_DO;
  }
  // if the newDN and the current DN match then the operation
  // is a no-op (this was probably a second replay)
  // don't do anything.
opendj-server-legacy/src/test/java/org/opends/server/replication/plugin/NamingConflictTest.java
@@ -205,6 +205,46 @@
  }
  /**
   * Test case for [Issue 955]: a ModifyDN whose entry and whose new superior are both
   * gone from this replica is a conflict between a delete and this ModifyDN, and it is
   * solved as such rather than left to be delivered again until this replica gives up on
   * it.
   * <p>
   * Neither entryUUID the message carries resolves to a DN here, so conflict resolution
   * has no new superior to move the entry under - and no entry to move either. The entry
   * having been deleted settles what the ModifyDN was trying to do, which is what makes
   * the change resolved: an entry which is not in the database can not be marked as
   * conflicting, and marking it is what used to be attempted first, on the DN of an entry
   * which is not there.
   */
  @Test
  public void modifyDnOnAnEntryAndANewSuperiorWhichAreBothGone() throws Exception
  {
    final Entry entry = createAndAddEntry("modDnOnEntryAndNewSuperiorBothGone");
    final String entryUUID = getEntryUUID(entry.getName());
    final Entry newSuperior = TestCaseUtils.addEntry(
        "dn: ou=newSuperiorBothGone," + TEST_ROOT_DN_STRING,
        "objectClass: top",
        "objectClass: organizationalUnit",
        "ou: newSuperiorBothGone");
    final String newSuperiorUUID = getEntryUUID(newSuperior.getName());
    // Both entries are deleted on this replica while the ModifyDN is on its way.
    TestCaseUtils.deleteEntry(newSuperior.getName());
    TestCaseUtils.deleteEntry(entry.getName());
    final CSN csn = gen.newCSN();
    replayMsg(new ModifyDNMsg(entry.getName(), csn, entryUUID, newSuperiorUUID, false,
        newSuperior.getName().toString(), entry.getName().rdn().toString()));
    assertFalse(entryExists(entry.getName()),
        "the deleted entry was brought back by the replayed ModifyDN");
    assertTrue(domain.getServerState().cover(csn),
        "a ModifyDN which the delete of its entry has settled must be recorded as replayed");
  }
  /**
   * 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.