Skip to content

Commit a402494

Browse files
authored
Use ClassLoaderValues to track class-loader state (#10075)
1 parent 47898ce commit a402494

File tree

4 files changed

+41
-23
lines changed

4 files changed

+41
-23
lines changed

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import datadog.environment.OperatingSystem;
2323
import datadog.environment.SystemProperties;
2424
import datadog.instrument.classinject.ClassInjector;
25+
import datadog.instrument.utils.ClassLoaderValue;
2526
import datadog.trace.api.Config;
2627
import datadog.trace.api.Platform;
2728
import datadog.trace.api.StatsDClientManager;
@@ -102,6 +103,8 @@ public class Agent {
102103

103104
private static final int DEFAULT_JMX_START_DELAY = 15; // seconds
104105

106+
private static final long CLASSLOADER_CLEAN_FREQUENCY_SECONDS = 30;
107+
105108
private static final Logger log;
106109

107110
private enum AgentFeature {
@@ -327,6 +330,7 @@ public static void start(
327330
startCrashTracking();
328331
StaticEventLogger.end("crashtracking");
329332
}
333+
330334
startDatadogAgent(initTelemetry, inst);
331335

332336
final EnumSet<Library> libraries = detectLibraries(log);
@@ -410,6 +414,15 @@ public static void start(
410414
StaticEventLogger.end("Profiling");
411415
}
412416

417+
// This task removes stale ClassLoaderValue entries where the class-loader is gone
418+
// It only runs a couple of times a minute since class-loaders are rarely unloaded
419+
AgentTaskScheduler.get()
420+
.scheduleAtFixedRate(
421+
ClassLoaderValue::removeStaleEntries,
422+
CLASSLOADER_CLEAN_FREQUENCY_SECONDS,
423+
CLASSLOADER_CLEAN_FREQUENCY_SECONDS,
424+
TimeUnit.SECONDS);
425+
413426
StaticEventLogger.end("Agent.start");
414427
}
415428

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/InstrumenterState.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package datadog.trace.agent.tooling;
22

3-
import datadog.trace.api.cache.DDCache;
4-
import datadog.trace.api.cache.DDCaches;
3+
import datadog.instrument.utils.ClassLoaderValue;
54
import java.util.Arrays;
65
import java.util.concurrent.atomic.AtomicLongArray;
76
import org.slf4j.Logger;
@@ -38,8 +37,13 @@ public interface Observer {
3837
private static long[] defaultState = {};
3938

4039
/** Tracks which instrumentations were applied (per-class-loader) and which were blocked. */
41-
private static final DDCache<ClassLoader, AtomicLongArray> classLoaderStates =
42-
DDCaches.newFixedSizeWeakKeyCache(512);
40+
private static final ClassLoaderValue<AtomicLongArray> classLoaderStates =
41+
new ClassLoaderValue<AtomicLongArray>() {
42+
@Override
43+
protected AtomicLongArray computeValue(ClassLoader cl) {
44+
return new AtomicLongArray(defaultState);
45+
}
46+
};
4347

4448
private static Observer observer;
4549

@@ -146,13 +150,7 @@ private static void updateState(ClassLoader classLoader, int instrumentationId,
146150
}
147151

148152
private static AtomicLongArray classLoaderState(ClassLoader classLoader) {
149-
return classLoaderStates.computeIfAbsent(
150-
null != classLoader ? classLoader : Utils.getBootstrapProxy(),
151-
InstrumenterState::buildClassLoaderState);
152-
}
153-
154-
private static AtomicLongArray buildClassLoaderState(ClassLoader classLoader) {
155-
return new AtomicLongArray(defaultState);
153+
return classLoaderStates.get(classLoader);
156154
}
157155

158156
private static int currentState(AtomicLongArray state, int bitIndex) {
@@ -173,7 +171,7 @@ public static String summary() {
173171
StringBuilder summary = new StringBuilder();
174172
classLoaderStates.visit(
175173
(loader, state) -> {
176-
summary.append(loader.getClass().getName());
174+
summary.append(loader != null ? loader.getClass().getName() : "<bootstrap>");
177175
summarizeState(summary, state);
178176
summary.append("\n\n");
179177
});

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/ClassFileLocators.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
import static datadog.trace.bootstrap.AgentClassLoading.LOCATING_CLASS;
44
import static datadog.trace.util.Strings.getResourceName;
55

6+
import datadog.instrument.utils.ClassLoaderValue;
67
import datadog.trace.agent.tooling.InstrumenterMetrics;
78
import datadog.trace.agent.tooling.Utils;
89
import datadog.trace.api.InstrumenterConfig;
9-
import datadog.trace.api.cache.DDCache;
10-
import datadog.trace.api.cache.DDCaches;
1110
import java.io.IOException;
1211
import java.io.InputStream;
1312
import java.lang.ref.WeakReference;
@@ -23,8 +22,13 @@
2322
* cannot find the desired resource, check up the classloader hierarchy until a resource is found.
2423
*/
2524
public final class ClassFileLocators {
26-
private static final DDCache<ClassLoader, DDClassFileLocator> classFileLocators =
27-
DDCaches.newFixedSizeWeakKeyCache(64);
25+
private static final ClassLoaderValue<DDClassFileLocator> classFileLocators =
26+
new ClassLoaderValue<DDClassFileLocator>() {
27+
@Override
28+
protected DDClassFileLocator computeValue(ClassLoader cl) {
29+
return new DDClassFileLocator(cl);
30+
}
31+
};
2832

2933
private static final ClassFileLocator bootClassFileLocator =
3034
new ClassFileLocator() {
@@ -49,9 +53,7 @@ public void close() {
4953
};
5054

5155
public static ClassFileLocator classFileLocator(final ClassLoader classLoader) {
52-
return null != classLoader
53-
? classFileLocators.computeIfAbsent(classLoader, DDClassFileLocator::new)
54-
: bootClassFileLocator;
56+
return null != classLoader ? classFileLocators.get(classLoader) : bootClassFileLocator;
5557
}
5658

5759
static final class DDClassFileLocator extends WeakReference<ClassLoader>

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/ClassLoaderMatchers.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import static datadog.trace.bootstrap.AgentClassLoading.PROBING_CLASSLOADER;
44
import static net.bytebuddy.matcher.ElementMatchers.any;
55

6+
import datadog.instrument.utils.ClassLoaderValue;
67
import datadog.trace.api.InstrumenterConfig;
78
import datadog.trace.api.Tracer;
8-
import datadog.trace.api.cache.DDCache;
9-
import datadog.trace.api.cache.DDCaches;
109
import datadog.trace.bootstrap.PatchLogger;
1110
import datadog.trace.util.Strings;
1211
import java.util.ArrayList;
@@ -140,15 +139,21 @@ private static boolean loadsExpectedClass(
140139
static final List<String> hasClassResourceNames = new ArrayList<>();
141140

142141
/** Cache of classloader-instance -> has-class mask. */
143-
static final DDCache<ClassLoader, BitSet> hasClassCache = DDCaches.newFixedSizeWeakKeyCache(512);
142+
static final ClassLoaderValue<BitSet> hasClassCache =
143+
new ClassLoaderValue<BitSet>() {
144+
@Override
145+
protected BitSet computeValue(ClassLoader cl) {
146+
return buildHasClassMask(cl);
147+
}
148+
};
144149

145150
/** Distinct result used to mark an incompatible classloader that the tracer should skip. */
146151
static final BitSet INCOMPATIBLE_CLASS_LOADER = new BitSet();
147152

148153
static final BitSet NO_CLASS_NAME_MATCHES = new BitSet();
149154

150155
static BitSet hasClassMask(ClassLoader loader) {
151-
return hasClassCache.computeIfAbsent(loader, ClassLoaderMatchers::buildHasClassMask);
156+
return hasClassCache.get(loader);
152157
}
153158

154159
static BitSet buildHasClassMask(ClassLoader loader) {

0 commit comments

Comments
 (0)