JCR-5095: retry token creation on concurrent modification of the token parent - #368
Open
slachiewicz wants to merge 1 commit into
Open
JCR-5095: retry token creation on concurrent modification of the token parent#368slachiewicz wants to merge 1 commit into
slachiewicz wants to merge 1 commit into
Conversation
…n parent Concurrent logins of the same user each use their own session but add their token node below the same .tokens parent. A concurrent commit below that parent can invalidate this session's pending changes, so that the token node can neither be saved (InvalidItemStateException from validateTransientItems) nor resolved afterwards (ItemNotFoundException while building its path). Either one failed the whole login. Wrap the token node creation in a bounded retry that discards the doomed transient state via session.refresh(false) and re-reads the token parent, mirroring the conflict handling that getTokenParent already performs for the concurrent creation of the token store itself. The original exception is rethrown once the attempts are exhausted, so behaviour on persistent failures is unchanged. This makes token creation tolerate the conflict but does not remove the underlying race in the transient state handling.
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.
Retry token node creation when a concurrent login invalidates the pending changes.
Problem
TokenBasedLoginTestfails intermittently on CI (JCR-5095, open since 2024-08). Two symptoms, both from the same race:Cause
Concurrent logins of the same user each get their own session (
DefaultLoginModule.commit) but add their token node below the same.tokensparent. When another session commits below that parent, this session's view of the parent can lose the child entry for its own pending token node. The failure then surfaces either while saving (InvalidItemStateExceptionfromItemSaveOperation.validateTransientItems) or right after, while resolving the new node's path (ItemNotFoundExceptionfromHierarchyManagerImpl).getTokenParentalready handles exactly this kind of conflict for the concurrent creation of the token store itself — it refreshes the session and re-reads the parent. The creation of the token node below that parent had no such handling, so a single conflict failed the whole login.Change
Wrap the token node creation in a bounded retry (3 attempts) that discards the doomed transient state with
session.refresh(false)and re-reads the token parent, mirroring the existing idiom ingetTokenParent. The body of the old method is extracted unchanged intocreateTokenNode. After the last attempt the original exception is rethrown, so behaviour on persistent failures is unchanged.This makes token creation tolerate the conflict; it does not remove the underlying core race in transient state handling, which is why JCR-5095 should stay open.
Verification
TokenBasedLoginTestrun repeatedly on a clean repository, macOS / JDK 24:One run in the "after" set failed with an error I did not manage to capture, and it did not recur in 30 further runs, so I cannot say what it was. The baseline showed unrelated environment errors ("Failed to get Repository instance", stale repository lock) at a comparable rate.
mvn test -Dtest='org.apache.jackrabbit.core.security.authentication.**'— 114 tests, all passing.Note for reviewers:
session.refresh(false)discards all transient changes on the session. That is safe forDefaultLoginModule, which creates a dedicated session for token creation, butTokenBasedAuthentication.createTokenis public and accepts a caller-supplied session. The pre-existinggetTokenParentconflict path already callssession.refresh(false)on the same session, so this is not a new hazard, but it now applies to a second code path — happy to scope it differently if you prefer.