From 2332af2513c32c82d56b6889a6b4ffe2a83894fe Mon Sep 17 00:00:00 2001 From: Bruce Bujon Date: Mon, 22 Jun 2026 18:32:52 +0200 Subject: [PATCH 1/2] refactor(context): Introduce context holder swap to deduplicate code --- .../context/ThreadLocalContextManager.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java b/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java index 9b94f578409..f3a9f8962cd 100644 --- a/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java +++ b/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java @@ -40,10 +40,7 @@ ContextScope doAttach(Context context, @Nullable ContextContinuationImpl continu return context.asScope(); // convert to scope without attaching } - ContextListener[] ls = listeners; - notifyDetach(beforeAttach, ls); - holder.current = context; - notifyAttach(context, ls); + doSwap(holder, beforeAttach, context); if (continuation == null) { return new ContextScopeImpl(context, holder, beforeAttach); @@ -61,10 +58,7 @@ public Context swap(Context context) { return beforeSwap; } - ContextListener[] ls = listeners; - notifyDetach(beforeSwap, ls); - holder.current = context; - notifyAttach(context, ls); + doSwap(holder, beforeSwap, context); return beforeSwap; } @@ -143,6 +137,14 @@ static void notifyRelease(Context context, ContextListener[] listeners) { } } + private static void doSwap(ContextHolder holder, Context before, Context after) { + // Snapshot listeners so same listeners will get the two events + ContextListener[] ls = INSTANCE.listeners; + notifyDetach(before, ls); + holder.current = after; + notifyAttach(after, ls); + } + private static class ContextScopeImpl implements ContextScope { private final Context context; @@ -166,10 +168,7 @@ public final Context context() { public void close() { // check for out-of-order close to avoid corrupting the current state if (!closed && context == holder.current) { - ContextListener[] ls = INSTANCE.listeners; - notifyDetach(context, ls); - holder.current = beforeAttach; - notifyAttach(beforeAttach, ls); + doSwap(holder, context, beforeAttach); closed = true; } } From 947f4159eae5554e1c2526e73ca56830d76e3497 Mon Sep 17 00:00:00 2001 From: Bruce Bujon Date: Mon, 22 Jun 2026 18:33:45 +0200 Subject: [PATCH 2/2] refactor(context): Introduce event dispatch to deduplicate code --- .../context/ThreadLocalContextManager.java | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java b/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java index f3a9f8962cd..3336da39ee6 100644 --- a/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java +++ b/components/context/src/main/java/datadog/context/ThreadLocalContextManager.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.function.BiConsumer; import javax.annotation.Nullable; /** {@link ContextManager} that uses a {@link ThreadLocal} to track context per thread. */ @@ -97,41 +98,31 @@ static void notifyAttach(Context context, ContextListener[] listeners) { if (context == Context.root()) { return; // don't emit attach events for the default "no context" case } - for (ContextListener l : listeners) { - try { - l.onAttach(context); - } catch (Throwable ignore) { - } - } + dispatch(context, listeners, ContextListener::onAttach); } static void notifyDetach(Context context, ContextListener[] listeners) { if (context == Context.root()) { return; // don't emit detach events for the default "no context" case } - for (ContextListener l : listeners) { - try { - l.onDetach(context); - } catch (Throwable ignore) { - } - } + dispatch(context, listeners, ContextListener::onDetach); } static void notifyCapture(Context context, ContextListener[] listeners) { // only called for non-empty continuations - for (ContextListener l : listeners) { - try { - l.onCapture(context); - } catch (Throwable ignore) { - } - } + dispatch(context, listeners, ContextListener::onCapture); } static void notifyRelease(Context context, ContextListener[] listeners) { // only called for non-empty continuations + dispatch(context, listeners, ContextListener::onRelease); + } + + private static void dispatch( + Context context, ContextListener[] listeners, BiConsumer event) { for (ContextListener l : listeners) { try { - l.onRelease(context); + event.accept(l, context); } catch (Throwable ignore) { } }