Skip to content

Commit 81cdab0

Browse files
authored
When swapping context stacks, restore full stack on original thread. (#9491)
For other threads restore shallow copy, using parent and active scopes captured when the original context stack was swapped out.
1 parent f02c1d1 commit 81cdab0

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ContinuableScopeManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ public Context swap(Context context) {
367367
ContinuableScope newScope;
368368
if (context instanceof ScopeContext) {
369369
// restore previously swapped context stack
370-
newStack = ((ScopeContext) context).restore();
370+
newStack = ((ScopeContext) context).restore(profilingContextIntegration);
371371
newScope = newStack.top;
372372
} else if (context != Context.root()) {
373373
// start a new stack and record the new context as active

dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ScopeContext.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import datadog.context.Context;
44
import datadog.context.ContextKey;
5+
import datadog.trace.bootstrap.instrumentation.api.ProfilingContextIntegration;
56
import javax.annotation.Nullable;
67

78
/** Wraps a {@link ScopeStack} as a {@link Context} so it can be swapped back later. */
89
final class ScopeContext implements Context {
910
private final Thread originalThread = Thread.currentThread();
1011
private final ScopeStack scopeStack;
12+
private final ContinuableScope parent;
13+
private final ContinuableScope active;
1114
private final Context context;
1215

1316
ScopeContext(ScopeStack scopeStack) {
@@ -16,12 +19,18 @@ final class ScopeContext implements Context {
1619

1720
private ScopeContext(ScopeStack scopeStack, Context context) {
1821
this.scopeStack = scopeStack;
22+
this.parent = scopeStack.parent();
23+
this.active = scopeStack.active();
1924
this.context = context;
2025
}
2126

22-
ScopeStack restore() {
23-
// take defensive copy of original scope stack when restoring on different thread
24-
return originalThread == Thread.currentThread() ? scopeStack : scopeStack.copy();
27+
ScopeStack restore(ProfilingContextIntegration profilingContextIntegration) {
28+
// restore full stack on original thread, for other threads restore shallow copy
29+
if (Thread.currentThread() == originalThread) {
30+
return scopeStack;
31+
} else {
32+
return new ScopeStack(profilingContextIntegration, parent, active);
33+
}
2534
}
2635

2736
@Nullable

dd-trace-core/src/main/java/datadog/trace/core/scopemanager/ScopeStack.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,27 @@ final class ScopeStack {
2424
this.profilingContextIntegration = profilingContextIntegration;
2525
}
2626

27-
ScopeStack copy() {
28-
ScopeStack copy = new ScopeStack(profilingContextIntegration);
29-
copy.stack.addAll(stack);
30-
copy.top = top;
31-
copy.overdueRootScope = overdueRootScope;
32-
return copy;
27+
/** Restore a shallow stack for async propagation purposes. */
28+
ScopeStack(
29+
ProfilingContextIntegration profilingContextIntegration,
30+
ContinuableScope parent,
31+
ContinuableScope active) {
32+
this(profilingContextIntegration);
33+
if (parent != null) {
34+
stack.push(parent);
35+
}
36+
top = active;
3337
}
3438

3539
ContinuableScope active() {
3640
// avoid attaching further spans to the root scope when it's been marked as overdue
3741
return top != overdueRootScope ? top : null;
3842
}
3943

44+
ContinuableScope parent() {
45+
return stack.peek();
46+
}
47+
4048
/** Removes and closes all scopes up to the nearest live scope */
4149
void cleanup() {
4250
ContinuableScope curScope = top;

0 commit comments

Comments
 (0)