Repository navigation
Add @StaticLifetime and @Singleton marker annotations (AI perf review) #12646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
gh-worker-dd-mergequeue-cf854d
merged 13 commits into
master
from
dougqh/static-lifetime-singleton
Oct 8, 2026
+97
−2
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
d977186
Add @StaticLifetime and @Singleton marker annotations
dougqh 88d3229
Add Checker contract section to @Singleton javadoc
dougqh e98399f
Annotate WebFlux route cache with @StaticLifetime
dougqh 4acee82
Annotate UTF8 tag/value caches with @StaticLifetime
dougqh 982b12a
Revert "Annotate WebFlux route cache with @StaticLifetime"
dougqh 0848e09
Revert "Annotate UTF8 tag/value caches with @StaticLifetime"
dougqh c6b03bb
Close StaticLifetime checker-contract gaps: require final, static+non…
dougqh afb7349
Fix StaticLifetime's ClassValue paragraph to match its own checker co…
dougqh 9f80d9c
Merge remote-tracking branch 'origin/master' into dougqh/static-lifet…
dougqh 4ef7e11
Move StaticLifetime/Singleton into datadog.perfcontract and meta-anno…
dougqh 2ec3a99
Tighten the @Singleton Javadoc
dougqh b779f87
Restructure the @StaticLifetime Javadoc around one field rule
dougqh 5fca44d
Require final for @Singleton-held fields in the perf-review StaticLif…
dougqh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
26 changes: 26 additions & 0 deletions
26
internal-api/src/main/java/datadog/perfcontract/Singleton.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package datadog.perfcontract; | ||
|
|
||
| import java.lang.annotation.Documented; | ||
| import java.lang.annotation.ElementType; | ||
| import java.lang.annotation.Retention; | ||
| import java.lang.annotation.RetentionPolicy; | ||
| import java.lang.annotation.Target; | ||
|
|
||
| /** | ||
| * Declares that a class has one instance for the life of the process. All construction paths must | ||
| * preserve that guarantee; a static holder or DI registration alone does not prevent another | ||
| * instance from being created. | ||
| * | ||
| * <p>This marker changes no runtime behavior. Tools trust the declaration without checking | ||
| * construction sites. If the class is instantiated more than once, they may accept caches that are | ||
| * rebuilt with each instance. | ||
| * | ||
| * <p><b>Checker contract.</b> This annotation has no violation rule of its own. It allows {@link | ||
| * StaticLifetime}'s checker to accept {@code final} instance fields declared on the annotated | ||
| * class. | ||
| */ | ||
| @Documented | ||
| @PerfContract | ||
| @Retention(RetentionPolicy.CLASS) | ||
| @Target(ElementType.TYPE) | ||
| public @interface Singleton {} | ||
68 changes: 68 additions & 0 deletions
68
internal-api/src/main/java/datadog/perfcontract/StaticLifetime.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package datadog.perfcontract; | ||
|
|
||
| import java.lang.annotation.Documented; | ||
| import java.lang.annotation.ElementType; | ||
| import java.lang.annotation.Retention; | ||
| import java.lang.annotation.RetentionPolicy; | ||
| import java.lang.annotation.Target; | ||
|
|
||
| /** | ||
| * Marks a field whose value must be retained for the life of the program to share its setup cost | ||
| * across uses. A cache rebuilt with each request repeats that cost. | ||
| * | ||
| * <p>The name echoes Rust's {@code 'static} lifetime rather than the Java keyword {@code static}: | ||
| * the property is "lives for the whole program," which a {@code final} field on a {@link Singleton} | ||
| * satisfies without being {@code static}. | ||
| * | ||
| * <p>This marker changes no runtime behavior. The declaration rules below guide AI review; no | ||
| * static checker currently enforces them. | ||
| * | ||
| * <p><b>Checker contract.</b> Inspect only fields annotated {@code @StaticLifetime}: | ||
| * | ||
| * <ul> | ||
| * <li><b>Accepted:</b> a {@code static final} field, or a {@code final} instance field declared | ||
| * on a class annotated {@link Singleton}. The singleton declaration is trusted, not verified. | ||
| * <li><b>Violation:</b> any other annotated field. This includes fields without {@code final} and | ||
| * instance fields on classes without {@code @Singleton}, even if a class is constructed only | ||
| * once per session. | ||
| * <li><b>Out of scope:</b> unannotated fields, how often a value is reused, and replacement of | ||
| * state inside the referenced object. The check does not follow references through the object | ||
| * graph. | ||
| * </ul> | ||
| * | ||
| * <p>Requiring {@code final} prevents reassignment from discarding cached state and repeating | ||
| * setup. It does not prevent the referenced object from changing its own state. | ||
| * | ||
| * <p>A shared {@link java.lang.ClassValue} satisfies the same field rules. Its values are cached | ||
| * per class; computation may be repeated under races or after {@link | ||
| * java.lang.ClassValue#remove(Class) remove}. This contract covers the shared holder, not the | ||
| * lifetime of each cached value. | ||
| * | ||
| * <p>Violation examples: an instance cache on a class without {@code @Singleton}, or a static cache | ||
| * without {@code final}. | ||
| * | ||
| * <pre> | ||
| * @StaticLifetime | ||
| * private final DDCache<String, String> instanceCache = DDCaches.newFixedSizeCache(128); | ||
| * | ||
| * @StaticLifetime | ||
| * private static DDCache<String, String> staticCache = DDCaches.newFixedSizeCache(128); | ||
| * </pre> | ||
| * | ||
| * <p>Compliant examples: | ||
| * | ||
| * <pre> | ||
| * @StaticLifetime | ||
| * private static final DDCache<String, String> CACHE = DDCaches.newFixedSizeCache(128); | ||
| * | ||
| * @Singleton class Registry { | ||
| * @StaticLifetime | ||
| * private final DDCache<String, String> cache = DDCaches.newFixedSizeCache(128); | ||
| * } | ||
| * </pre> | ||
| */ | ||
|
dougqh marked this conversation as resolved.
|
||
| @Documented | ||
| @PerfContract | ||
| @Retention(RetentionPolicy.CLASS) | ||
| @Target(ElementType.FIELD) | ||
| public @interface StaticLifetime {} | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.