diff --git a/communication/src/main/java/datadog/communication/serialization/GenerationalUtf8Cache.java b/communication/src/main/java/datadog/communication/serialization/GenerationalUtf8Cache.java index 099ff56e0e0..9dd1c3b2818 100644 --- a/communication/src/main/java/datadog/communication/serialization/GenerationalUtf8Cache.java +++ b/communication/src/main/java/datadog/communication/serialization/GenerationalUtf8Cache.java @@ -1,5 +1,6 @@ package datadog.communication.serialization; +import datadog.trace.api.function.BackgroundOnly; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.nio.charset.StandardCharsets; import javax.annotation.concurrent.ThreadSafe; @@ -15,6 +16,11 @@ * String#getBytes(java.nio.charset.Charset)}. * *
The cache is thread safe. + * + *
{@link BackgroundOnly}: the eden/tenured promotion and recalibration bookkeeping costs more + * than the {@code getBytes} call it replaces, so the saving only shows up as reduced allocation/GC + * pressure on the thread that pays it -- confine it to the background serializer thread, not an + * application thread. */ /* * Cache works by using a 2-level promotion based scheme. diff --git a/communication/src/main/java/datadog/communication/serialization/SimpleUtf8Cache.java b/communication/src/main/java/datadog/communication/serialization/SimpleUtf8Cache.java index 8eb12d48465..4af30539053 100644 --- a/communication/src/main/java/datadog/communication/serialization/SimpleUtf8Cache.java +++ b/communication/src/main/java/datadog/communication/serialization/SimpleUtf8Cache.java @@ -1,5 +1,6 @@ package datadog.communication.serialization; +import datadog.trace.api.function.BackgroundOnly; import java.nio.charset.StandardCharsets; import javax.annotation.concurrent.ThreadSafe; @@ -13,6 +14,11 @@ * String#getBytes(java.nio.charset.Charset)}. * *
The cache is thread safe. + * + *
{@link BackgroundOnly}: the bookkeeping (hit counting, LFU eviction scan) costs more than the
+ * {@code getBytes} call it replaces, so the saving only shows up as reduced allocation/GC pressure
+ * on the thread that pays it -- confine it to the background serializer thread, not an application
+ * thread.
*/
/*
* Thread safety is achieved through using CacheEntry objects where the key data
diff --git a/internal-api/src/main/java/datadog/trace/api/cache/DDCache.java b/internal-api/src/main/java/datadog/trace/api/cache/DDCache.java
index d1cd8024847..17888187a83 100644
--- a/internal-api/src/main/java/datadog/trace/api/cache/DDCache.java
+++ b/internal-api/src/main/java/datadog/trace/api/cache/DDCache.java
@@ -1,8 +1,15 @@
package datadog.trace.api.cache;
+import datadog.trace.api.function.ForegroundSafe;
import java.util.function.BiConsumer;
import java.util.function.Function;
+/**
+ * {@link ForegroundSafe}: every implementation looks up a key via a small, bounded number of probes
+ * (no growth, no eviction bookkeeping beyond overwriting a slot) -- cheap enough to call from an
+ * application thread.
+ */
+@ForegroundSafe
public interface DDCache This is a documentation-and-tooling marker; it changes no behavior. It exists to telegraph the
+ * constraint to readers and to give a future checker (see {@code APMLP-1645}) something to verify
+ * -- that no {@code @BackgroundOnly} code is reachable from a foreground call site. The discipline
+ * it names is not yet enforced; hold to it by hand until the checker lands.
+ *
+ * The two markers are not symmetric -- see {@link ForegroundSafe} for why it, not this
+ * one, is the strictly stronger guarantee.
+ *
+ * On a type ({@link ElementType#TYPE}): every method of this type is background-only
+ * unless a method-level {@link ForegroundSafe} widens it.
+ *
+ * On a method ({@link ElementType#METHOD}): this method specifically is background-only,
+ * regardless of what the enclosing type declares -- a method-level marker always wins over the
+ * type-level one.
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface BackgroundOnly {}
diff --git a/internal-api/src/main/java/datadog/trace/api/function/ForegroundSafe.java b/internal-api/src/main/java/datadog/trace/api/function/ForegroundSafe.java
new file mode 100644
index 00000000000..b1c0985dc3c
--- /dev/null
+++ b/internal-api/src/main/java/datadog/trace/api/function/ForegroundSafe.java
@@ -0,0 +1,36 @@
+package datadog.trace.api.function;
+
+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 code cheap enough to call from an application thread (the foreground) -- the request or
+ * transaction thread the instrumented application itself is running, where any added cost is
+ * customer-visible latency, as opposed to a background thread the tracer owns and paces itself (see
+ * {@link BackgroundOnly}).
+ *
+ * This is a documentation-and-tooling marker; it changes no behavior. It exists to telegraph the
+ * guarantee to readers and to give a future checker (see {@code APMLP-1645}) something to verify --
+ * that no {@link BackgroundOnly} code is reachable from a foreground call site. The discipline it
+ * names is not yet enforced; hold to it by hand until the checker lands.
+ *
+ * The two markers are not symmetric. {@code @ForegroundSafe} is the strictly stronger
+ * guarantee: code cheap enough for the foreground is automatically fine to call from a background
+ * thread too, so a {@code @ForegroundSafe} type or method may be called from either. {@link
+ * BackgroundOnly} code carries no such guarantee and must never be reached from a foreground call
+ * site.
+ *
+ * On a type ({@link ElementType#TYPE}): every method of this type is foreground-safe
+ * unless a method-level {@link BackgroundOnly} narrows it.
+ *
+ * On a method ({@link ElementType#METHOD}): this method specifically is foreground-safe,
+ * regardless of what the enclosing type declares -- a method-level marker always wins over the
+ * type-level one.
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface ForegroundSafe {}