Repository navigation
Conversation
joker23
marked this pull request as ready for review
October 15, 2026 20:31
kinyoklion
reviewed
Oct 16, 2026
| * The SDK reads the property once, at class load. The default is off. With the default, a | ||
| * clause serializes its values exactly as received. | ||
| */ | ||
| static final String RELEASE_CLAUSE_VALUES_PROPERTY = "com.launchdarkly.sdk.server.releaseClauseValues"; |
Member
There was a problem hiding this comment.
Is there a reason we are making this opt-in?
Author
There was a problem hiding this comment.
I followed the decision in launchdarkly/go-server-sdk-evaluation#72 , though opting in with system props might not be as safe as it is in go?
UPDATE: I just surrounded the system property with a try catch and made it fallback to false.
Author
There was a problem hiding this comment.
I also think it is fine if we break from go precedence and just change the behavior outright.
Author
|
Closing as Java's collections backing is just a list of pointers so this optimization is much less impactful as the go optimization. |
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.
Summary
An
inclause with more than one value gets anImmutableSetduring preprocessing, and the clause also keeps its value list. The SDK then holds every value twice. An external report against the Go SDK measured 31.6 MB of clause value lists, about 30% of one service's live heap (launchdarkly/go-server-sdk-evaluation#69). This PR is the Java port of the Go fix (launchdarkly/go-server-sdk-evaluation#72).Two findings and one change:
Threshold: Java keeps 2. A JMH benchmark of the real match path (
EvaluatorHelpers.matchClauseWithoutSegments) shows the set lookup is faster than a list scan at every size of two or more values, hit and miss, hot and cold cache. Go raised its threshold to 8 because a Go map lookup costs about 30 ns; Java'sImmutableSet.containscosts 4-5 ns at every size, becauseStringcaches its hash code. So the existing build-at-2+ rule is already right for Java, and this PR does not change it. Results (Apple Silicon, Zulu JDK 17, ns per match):Opt-in release of the duplicate list. With the system property
com.launchdarkly.sdk.server.releaseClauseValues=true, the preprocessor drops the value list of eachinclause that has a value set, so memory holds one copy instead of two. Evaluation and JSON serialization then read the values from the set.ImmutableSetkeeps first-appearance order, so a released clause serializes its values in the original order, but a duplicate value is dropped.The default is unchanged. Without the property, the list is kept and the serialized form of a clause stays byte-for-byte identical. The release is opt-in because re-serialization (for example, to a persistent data store) would silently drop duplicate values. Other operators always keep their list: their evaluation reads values by position, and
segmentMatchreads the list as segment keys.The switch is a system property because
afterDeserialized()is a static Gson hook with no access toLDConfig. Per-client config plumbing can be follow-up work, as it was for Go.🤖 Generated with Claude Code
Note
Overview
Adds an opt-in memory optimization for
inclauses: whencom.launchdarkly.sdk.server.releaseClauseValues=true, preprocessing replaces each multi-value clause’s duplicate value list with the preprocessedImmutableSet’s list view so only one copy of the values is retained.DataModel.Clausenow allows that swap viareleaseValues()(thevaluesfield is no longerfinal). Default behavior is unchanged—without the property, lists and serialized JSON stay as received. The release applies only toinclauses that get a value set (still at 2+ values); other operators and single-valueinclauses are untouched because evaluation or serialization depends on the original list.Tests cover default vs enabled release, segment rules, serialization order/deduping, and that matching still works (including
segmentMatch).Reviewed by Cursor Bugbot for commit 25d8e2d. Bugbot is set up for automated code reviews on this repo. Configure here.