Skip to content

Commit cfc9870

Browse files
authored
Add capping on SourceFile tracking queue (#9245)
tracks number of item put into the queue and dequeued. limits to 4096 items. Avoid using queue.size that is O(n) and keep the size in AtomicInteger dump the number of entries in the SourceFile map into tracer flare
1 parent b681823 commit cfc9870

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerAgent.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,9 @@ private static void addReportToFlare(ZipOutputStream zip) throws IOException {
478478
"SymbolDB stats:",
479479
symbolDBStats,
480480
"Exception Fingerprints:",
481-
exceptionFingerprints);
481+
exceptionFingerprints,
482+
"SourceFile tracking entries:",
483+
String.valueOf(classesToRetransformFinder.getClassNamesBySourceFile().size()));
482484
TracerFlare.addText(zip, "dynamic_instrumentation.txt", content);
483485
}
484486
}

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/SourceFileTrackingTransformer.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.datadog.debugger.util.ClassFileHelper;
77
import com.datadog.debugger.util.ClassNameFiltering;
88
import datadog.trace.api.Config;
9+
import datadog.trace.relocate.api.RatelimitedLogger;
910
import datadog.trace.util.AgentTaskScheduler;
1011
import datadog.trace.util.Strings;
1112
import java.lang.instrument.ClassFileTransformer;
@@ -14,6 +15,7 @@
1415
import java.util.Queue;
1516
import java.util.concurrent.ConcurrentLinkedQueue;
1617
import java.util.concurrent.TimeUnit;
18+
import java.util.concurrent.atomic.AtomicInteger;
1719
import org.slf4j.Logger;
1820
import org.slf4j.LoggerFactory;
1921

@@ -24,10 +26,15 @@
2426
*/
2527
public class SourceFileTrackingTransformer implements ClassFileTransformer {
2628
private static final Logger LOGGER = LoggerFactory.getLogger(SourceFileTrackingTransformer.class);
29+
private static final int MINUTES_BETWEEN_ERROR_LOG = 5;
30+
static final int MAX_QUEUE_SIZE = 4096;
2731

32+
private final RatelimitedLogger ratelimitedLogger =
33+
new RatelimitedLogger(LOGGER, MINUTES_BETWEEN_ERROR_LOG, TimeUnit.MINUTES);
2834
private final ClassesToRetransformFinder finder;
2935
private final Queue<SourceFileItem> queue = new ConcurrentLinkedQueue<>();
3036
private final AgentTaskScheduler scheduler = AgentTaskScheduler.INSTANCE;
37+
private final AtomicInteger queueSize = new AtomicInteger(0);
3138
private AgentTaskScheduler.Scheduled<Runnable> scheduled;
3239
// this field MUST only be used in flush() calling thread
3340
private ClassNameFiltering classNameFilter;
@@ -55,14 +62,23 @@ void flush() {
5562
if (queue.isEmpty()) {
5663
return;
5764
}
58-
int size = queue.size();
65+
int itemCount = 0;
5966
long start = System.nanoTime();
6067
SourceFileItem item;
6168
while ((item = queue.poll()) != null) {
69+
queueSize.decrementAndGet();
6270
registerSourceFile(item.className, item.classfileBuffer);
71+
itemCount++;
6372
}
6473
LOGGER.debug(
65-
"flushing {} source file items in {}ms", size, (System.nanoTime() - start) / 1_000_000);
74+
"flushing {} source file items in {}ms, totalentries: {}",
75+
itemCount,
76+
(System.nanoTime() - start) / 1_000_000,
77+
finder.getClassNamesBySourceFile().size());
78+
}
79+
80+
int getQueueSize() {
81+
return queueSize.get();
6682
}
6783

6884
@Override
@@ -76,7 +92,12 @@ public byte[] transform(
7692
if (className == null) {
7793
return null;
7894
}
95+
if (queueSize.get() >= MAX_QUEUE_SIZE) {
96+
ratelimitedLogger.warn("SourceFile Tracking queue full, dropping class: {}", className);
97+
return null;
98+
}
7999
queue.add(new SourceFileItem(className, classfileBuffer));
100+
queueSize.incrementAndGet();
80101
return null;
81102
}
82103

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.datadog.debugger.agent;
22

3+
import static com.datadog.debugger.agent.SourceFileTrackingTransformer.MAX_QUEUE_SIZE;
34
import static org.junit.jupiter.api.Assertions.assertEquals;
45
import static utils.TestClassFileHelper.getClassFileBytes;
56

@@ -138,6 +139,22 @@ void thirdPartyExcludes() throws IllegalClassFormatException {
138139
assertEquals(0, finder.getClassNamesBySourceFile().size());
139140
}
140141

142+
@Test
143+
void maxQueue() throws IllegalClassFormatException {
144+
ClassesToRetransformFinder finder = new ClassesToRetransformFinder();
145+
SourceFileTrackingTransformer sourceFileTrackingTransformer =
146+
new SourceFileTrackingTransformer(finder);
147+
for (int i = 0; i < MAX_QUEUE_SIZE + 10; i++) {
148+
sourceFileTrackingTransformer.transform(
149+
null,
150+
getInternalName(TopLevelHelper.class),
151+
null,
152+
null,
153+
getClassFileBytes(TopLevelHelper.class));
154+
}
155+
assertEquals(MAX_QUEUE_SIZE, sourceFileTrackingTransformer.getQueueSize());
156+
}
157+
141158
private static void replaceInByteArray(byte[] buffer, byte[] oldBytes, byte[] newBytes) {
142159
int oldIdx = 0;
143160
for (int i = 0; i < buffer.length; i++) {

0 commit comments

Comments
 (0)