From 48ec7f1c881437922a90a50572129c1004e22915 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Fri, 7 Mar 2025 13:51:10 +0100 Subject: [PATCH 1/2] Reduce footprint of SourceFile tracking classNamesBySourceFile map used for SourceFile tracking can have a lot of entries (different SourceFiles) and for each entry we have a list (If any inner classe or non-public top-level classes). Compacting to a comma-separated list reduce the footprint of this map. As the usage is very unfrequent we can pay the price to "deserialize" the list to go through the classname that we need to retransform as a dependency --- .../agent/ClassesToRetransformFinder.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java index acfa54c889e..cc92360c7ab 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ClassesToRetransformFinder.java @@ -9,9 +9,11 @@ import com.datadog.debugger.instrumentation.InstrumentationResult; import com.datadog.debugger.probe.ProbeDefinition; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.slf4j.Logger; @@ -19,21 +21,20 @@ public class ClassesToRetransformFinder { private static final Logger LOGGER = LoggerFactory.getLogger(ClassesToRetransformFinder.class); + private static final Pattern COMMA_PATTERN = Pattern.compile(","); - private final ConcurrentMap> classNamesBySourceFile = - new ConcurrentHashMap<>(); + private final ConcurrentMap classNamesBySourceFile = new ConcurrentHashMap<>(); public void register(String sourceFile, String className) { // store only the class name that are different from SourceFile name // (Inner or non-public Top-Level classes) classNamesBySourceFile.compute( sourceFile, - (key, list) -> { - if (list == null) { - list = new ArrayList<>(); + (key, classNames) -> { + if (classNames == null) { + return className; } - list.add(className); - return list; + return classNames + "," + className; }); } @@ -89,13 +90,11 @@ Trie getAllChangedClasses(ConfigurationComparer comparer) { private void processAdditionalClasses(String sourceFile, Trie changedClasses) { sourceFile = stripPackagePath(sourceFile); - // need to clone the list to avoid concurrent modification during iteration - List additionalClasses = - classNamesBySourceFile.computeIfPresent( - sourceFile, (k, classNames) -> new ArrayList<>(classNames)); - if (additionalClasses == null) { + String classNames = classNamesBySourceFile.get(sourceFile); + if (classNames == null) { return; } + List additionalClasses = Arrays.asList(COMMA_PATTERN.split(classNames)); for (String additionalClass : additionalClasses) { additionalClass = normalizeFilePath(additionalClass); changedClasses.insert(reverseStr(additionalClass)); From d5357806281c0ec01c1cdbe9e3974ac3dcbe3035 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Fri, 7 Mar 2025 14:26:40 +0100 Subject: [PATCH 2/2] add test --- .../com/datadog/debugger/agent/InnerHelper.java | 2 ++ .../agent/SourceFileTrackingTransformerTest.java | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/InnerHelper.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/InnerHelper.java index 28e788e3832..a693a988cef 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/InnerHelper.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/InnerHelper.java @@ -3,4 +3,6 @@ public class InnerHelper { public static class MyInner {} + + public static class MySecondInner {} } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java index 0a2a5b7968e..e9a4586b3a0 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/SourceFileTrackingTransformerTest.java @@ -58,12 +58,22 @@ void transformInner() throws IllegalClassFormatException { null, null, getClassFileBytes(InnerHelper.MyInner.class)); + sourceFileTrackingTransformer.transform( + null, + getInternalName(InnerHelper.MySecondInner.class), + null, + null, + getClassFileBytes(InnerHelper.MySecondInner.class)); changedClasses = finder.getAllLoadedChangedClasses( - new Class[] {InnerHelper.class, InnerHelper.MyInner.class}, comparer); - assertEquals(2, changedClasses.size()); + new Class[] { + InnerHelper.class, InnerHelper.MyInner.class, InnerHelper.MySecondInner.class + }, + comparer); + assertEquals(3, changedClasses.size()); assertEquals(InnerHelper.class, changedClasses.get(0)); assertEquals(InnerHelper.MyInner.class, changedClasses.get(1)); + assertEquals(InnerHelper.MySecondInner.class, changedClasses.get(2)); } private ConfigurationComparer createComparer(String sourceFile) {