Isolate LazyNodeset lock from evaluated object #1404
Merged
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.
Product Description
Performance improvement with no user facing impact.
Technical Summary
Years ago we ran across an issue and realized that the
synchronized
call protecting lazy nodeset evaluations was wrapping a static global object, which meant that independent LazyNodesets would be blocked from concurrent evaluation on the same runtime.This was fixed in #645 by making the evaluated member a unique object for each lazy nodeset instance. Unfortunately that was a shortsighted approach, as the Boolean object constructor was marked for deprecation in Java 9 and the current non-deprecated Boolean class has no matching semantics available to guarantee a unique object instance. #1202 unintentionally re-introduced the global locking semantics when the deprecated call was removed and replaced as per the javadoc guidance.
Recent profiling in Formplayer has surfaced clear instances where the requests are blocking on this lock, and CPU / Wall Clock time have significant drift where one thread is waiting for access to the synchronized boolean held by another thread's totally different nodset before being able to evaluate its own nodeset.
This time I'm separating the lock and outcome semantics entirely, which is what I should have done the first time rather than leaving a comment. It would be worth reviewing whether there are better available locks for this purpose, but this pattern (vanilla
Object
member) is common across our other synchronized uses so I'm not inclined to block on that for now.Safety Assurance
Safety story
I've tested this change against the test suite, and the semantics introduced are the same as were present in the period between 2017 and 2022, which was thoroughly used.
I am not introducing new tests to confirm independent locking or replicating the failure condition in regression because the previous failure was the result of overloading intent for class member. We don't generally apply a pattern to confirm that objects with synchronized locks are working as intended.
Automated test coverage
This existing code is well covered by tests, which are passing.
QA Plan
n/a
Special deploy instructions
Formplayer will need to have its head updated after this change is merged.
Rollback instructions
Review
Duplicate PR
Automatically duplicate this PR as defined in contributing.md.