Skip to content

Commit ab14c85

Browse files
authored
Merge pull request #459 from DataDog/ark/gc-span-closing
gc span closing
2 parents 79a33d7 + e0837ef commit ab14c85

4 files changed

Lines changed: 32 additions & 7 deletions

File tree

dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,12 +297,17 @@ void write(final PendingTrace trace) {
297297
}
298298
}
299299
}
300-
traceCount.incrementAndGet();
300+
incrementTraceCount();
301301
if (!writtenTrace.isEmpty() && sampler.sample(writtenTrace.get(0))) {
302302
writer.write(writtenTrace);
303303
}
304304
}
305305

306+
/** Increment the reported trace count, but do not write a trace. */
307+
void incrementTraceCount() {
308+
traceCount.incrementAndGet();
309+
}
310+
306311
@Override
307312
public void close() {
308313
PendingTrace.close();

dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,20 @@ public synchronized boolean clean() {
214214
int count = 0;
215215
while ((ref = referenceQueue.poll()) != null) {
216216
weakReferences.remove(ref);
217+
if (isWritten.compareAndSet(false, true)) {
218+
SPAN_CLEANER.pendingTraces.remove(this);
219+
// preserve throughput count.
220+
// Don't report the trace because the data comes from buggy uses of the api and is suspect.
221+
tracer.incrementTraceCount();
222+
}
217223
count++;
218224
expireReference();
219225
}
220226
if (count > 0) {
221-
log.debug("{} unfinished spans garbage collected!", count);
227+
log.debug(
228+
"trace {} : {} unfinished spans garbage collected. Trace will not report.",
229+
traceId,
230+
count);
222231
}
223232
return count > 0;
224233
}

dd-trace-ot/src/test/groovy/datadog/opentracing/PendingTraceTest.groovy

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import datadog.trace.agent.test.TestUtils
44
import datadog.trace.common.writer.ListWriter
55
import spock.lang.Specification
66
import spock.lang.Subject
7+
import spock.lang.Timeout
78

89
import java.lang.ref.WeakReference
910
import java.util.concurrent.TimeUnit
@@ -94,7 +95,8 @@ class PendingTraceTest extends Specification {
9495
traceCount.get() == 1
9596
}
9697

97-
def "trace reported when unfinished child discarded"() {
98+
@Timeout(value = 60, unit = TimeUnit.SECONDS)
99+
def "trace does not report when unfinished child discarded"() {
98100
when:
99101
def child = tracer.buildSpan("child").asChildOf(rootSpan).start()
100102
rootSpan.finish()
@@ -109,15 +111,17 @@ class PendingTraceTest extends Specification {
109111
def childRef = new WeakReference<>(child)
110112
child = null
111113
TestUtils.awaitGC(childRef)
112-
while (trace.clean()) {
114+
while (trace.pendingReferenceCount.get() > 0) {
115+
trace.clean()
113116
}
114117

115118
then:
116119
trace.pendingReferenceCount.get() == 0
117120
trace.weakReferences.size() == 0
118121
trace.asList() == [rootSpan]
119-
writer == [[rootSpan]]
122+
writer == []
120123
traceCount.get() == 1
124+
!PendingTrace.SPAN_CLEANER.pendingTraces.contains(trace)
121125
}
122126

123127
def "add unfinished span to trace fails"() {

dd-trace-ot/src/test/groovy/datadog/opentracing/scopemanager/ScopeManagerTest.groovy

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import io.opentracing.Span
1010
import io.opentracing.noop.NoopSpan
1111
import spock.lang.Specification
1212
import spock.lang.Subject
13+
import spock.lang.Timeout
1314

1415
import java.lang.ref.WeakReference
16+
import java.util.concurrent.TimeUnit
1517
import java.util.concurrent.atomic.AtomicBoolean
1618
import java.util.concurrent.atomic.AtomicReference
1719

@@ -179,11 +181,13 @@ class ScopeManagerTest extends Specification {
179181
false | true
180182
}
181183

184+
@Timeout(value = 60, unit = TimeUnit.SECONDS)
182185
def "hard reference on continuation prevents trace from reporting"() {
183186
setup:
184187
def builder = tracer.buildSpan("test")
185188
def scope = (ContinuableScope) builder.startActive(false)
186189
def span = scope.span()
190+
def traceCount = ((DDSpan) span).context().tracer.traceCount
187191
scope.setAsyncPropagation(true)
188192
def continuation = scope.capture()
189193
scope.close()
@@ -199,7 +203,9 @@ class ScopeManagerTest extends Specification {
199203
def continuationRef = new WeakReference<>(continuation)
200204
continuation = null // Continuation references also hold up traces.
201205
TestUtils.awaitGC(continuationRef)
202-
writer.waitForTraces(1)
206+
while (traceCount.get() == 0) {
207+
// wait until trace count increments or timeout expires
208+
}
203209
}
204210
if (autoClose) {
205211
if (continuation != null) {
@@ -208,7 +214,8 @@ class ScopeManagerTest extends Specification {
208214
}
209215

210216
then:
211-
writer == [[span]]
217+
forceGC ? true : writer == [[span]]
218+
traceCount.get() == 1
212219

213220
where:
214221
autoClose | forceGC

0 commit comments

Comments
 (0)