Repository navigation
[#955] Answer a ModifyDN whose entry is gone before the new superior is looked up - #965
Merged
vharseko merged 1 commit intoSep 10, 2026
Conversation
…re the new superior is looked up
maximthomas
approved these changes
Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #955.
solveNamingConflict(ModifyDNOperation)dereferencedcurrentDNin the branch which handles a missing new parent, seven lines above the check which sayscurrentDNcan be null:A replayed ModifyDN carrying a
newSuperior, where this replica has since deleted both the entry being moved and the entry it is being moved under, resolves neither entryUUID:findEntryDN()returns null for both, andcurrentDN.parent()throws.Nothing upstream of it answers that case: the pre-operation plugin does not run when the target entry is not there - the core returns
NO_SUCH_OBJECTbefore the plugins - andcheckDependencies(ModifyDNMsg)only defers a change while an Add or a Delete on the same DNs is still in flight, which deletes applied long ago are not.What it cost
The NPE did not escape -
replay()caught it, loggedERR_EXCEPTION_REPLAYING_OPERATIONand left the change out of the ServerState, which is right as far as it goes. But nothing on the replica changes between two deliveries, so every one of them threw in the same place: the change restarted the session each time, burned the wholeREPLAY_GIVE_UP_DELAY_IN_MSbudget and ended inERR_REPLAY_SKIPPING_CHANGEand the alert which tells the administrator this replica has diverged and must be reinitialized - for a case the check at the bottom of the method answers in one step.markConflictEntry()was meaningless in that state anyway: it runs an internal modify againstcurrentDNto putds-sync-conflicton the entry, and there is no entry at that DN to mark.The change
The
currentDN == nullcheck is answered first, right after the entryUUID is resolved - above the lookup of the new superior as well, so a search which can not change the outcome is not run either. An entry which is not in the database can not be marked as conflicting and does not need to be: the delete has already settled what the ModifyDN was trying to do, which is what the comment on that check says.newDNis only built after thenewSuperior == nullbranch, so nothing between the two checks depended on the order.This is what the other conflict resolution methods already do:
solveNamingConflict(ModifyOperation)andsolveNamingConflict(DeleteOperation)both answer "the entry is gone - resolved, nothing to do" before anything else. The ModifyDN one was the only outlier.The second form of the same branch -
newSuperiorID == nullwithentryDN.parent()null - needs the entry DN to be the root DN, so it is not reachable in practice; the check closes it all the same.Test
NamingConflictTest.modifyDnOnAnEntryAndANewSuperiorWhichAreBothGone()deletes both the entry and its new superior on this replica and replays a ModifyDN carrying their entryUUIDs. Before the change it failed on the ServerState assertion, withNullPointerException: Cannot invoke "org.forgerock.opendj.ldap.DN.parent()" because "currentDN" is nullatLDAPReplicationDomain.java:3530in the log; now the change is resolved and recorded as replayed on the first delivery.Verified:
NamingConflictTest,DependencyTestandUpdateOperationTest(26 tests), and the wholeorg.opends.server.replication.pluginpackage (185 tests) - all pass.