From a34ba17b27293131d65a2fff433748bca99a9b66 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Thu, 29 Oct 2020 15:33:19 -0400 Subject: [PATCH 01/12] Use datadog.trace.api.Function in WeakMap --- .../java/datadog/trace/bootstrap/WeakMap.java | 15 ++++----------- .../datadog/trace/bootstrap/WeakMapTest.groovy | 5 +++-- .../trace/agent/tooling/WeakMapSuppliers.java | 5 +++-- .../instrumentation/netty40/AttributeKeys.java | 16 ++++++++-------- .../instrumentation/netty41/AttributeKeys.java | 16 ++++++++-------- 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakMap.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakMap.java index 982afee08e8..ae22b6acbdc 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakMap.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakMap.java @@ -1,5 +1,6 @@ package datadog.trace.bootstrap; +import datadog.trace.api.Function; import java.util.Collections; import java.util.Map; import java.util.WeakHashMap; @@ -18,7 +19,7 @@ public interface WeakMap { void putIfAbsent(K key, V value); - V computeIfAbsent(K key, ValueSupplier supplier); + V computeIfAbsent(K key, Function supplier); @Slf4j class Provider { @@ -58,14 +59,6 @@ public WeakMap get() { } } - /** - * Supplies the value to be stored and it is called only when a value does not exists yet in the - * registry. - */ - interface ValueSupplier { - V get(K key); - } - class MapAdapter implements WeakMap { private final Object[] locks = new Object[16]; private final Map map; @@ -111,14 +104,14 @@ public void putIfAbsent(final K key, final V value) { } @Override - public V computeIfAbsent(final K key, final ValueSupplier supplier) { + public V computeIfAbsent(final K key, final Function supplier) { // We can't use computeIfAbsent since it was added in 1.8. V value = map.get(key); if (null == value) { synchronized (locks[key.hashCode() & (locks.length - 1)]) { value = map.get(key); if (null == value) { - value = supplier.get(key); + value = supplier.apply(key); map.put(key, value); } } diff --git a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/WeakMapTest.groovy b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/WeakMapTest.groovy index 683362b94d7..d20bae664d8 100644 --- a/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/WeakMapTest.groovy +++ b/dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/WeakMapTest.groovy @@ -1,5 +1,6 @@ package datadog.trace.bootstrap +import datadog.trace.api.Function import spock.lang.Specification class WeakMapTest extends Specification { @@ -39,12 +40,12 @@ class WeakMapTest extends Specification { supplier.counter == 2 } - class CounterSupplier implements WeakMap.ValueSupplier { + class CounterSupplier implements Function { def counter = 0 @Override - Integer get(String ignored) { + Integer apply(String ignored) { counter = counter + 1 return counter } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java index f2fcc7623d7..d0360aaed6d 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java @@ -1,6 +1,7 @@ package datadog.trace.agent.tooling; import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap; +import datadog.trace.api.Function; import datadog.trace.bootstrap.WeakMap; import datadog.trace.util.AgentTaskScheduler; import datadog.trace.util.AgentTaskScheduler.Task; @@ -92,13 +93,13 @@ public void putIfAbsent(final K key, final V value) { } @Override - public V computeIfAbsent(final K key, final ValueSupplier supplier) { + public V computeIfAbsent(final K key, final Function supplier) { V value = map.get(key); if (null == value) { synchronized (locks[key.hashCode() & (locks.length - 1)]) { value = map.get(key); if (null == value) { - value = supplier.get(key); + value = supplier.apply(key); map.put(key, value); } } diff --git a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/AttributeKeys.java b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/AttributeKeys.java index ff7a098990d..068586e2453 100644 --- a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/AttributeKeys.java +++ b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/AttributeKeys.java @@ -1,5 +1,6 @@ package datadog.trace.instrumentation.netty40; +import datadog.trace.api.Function; import datadog.trace.bootstrap.WeakMap; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.context.TraceScope; @@ -12,14 +13,13 @@ public class AttributeKeys { private static final WeakMap>> map = WeakMap.Implementation.DEFAULT.get(); - private static final WeakMap.ValueSupplier>> - mapSupplier = - new WeakMap.ValueSupplier>>() { - @Override - public ConcurrentMap> get(final ClassLoader ignore) { - return new ConcurrentHashMap<>(); - } - }; + private static final Function>> mapSupplier = + new Function>>() { + @Override + public ConcurrentMap> apply(final ClassLoader ignore) { + return new ConcurrentHashMap<>(); + } + }; public static final AttributeKey PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY = diff --git a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/AttributeKeys.java b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/AttributeKeys.java index e0c18803617..052492ef15d 100644 --- a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/AttributeKeys.java +++ b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/AttributeKeys.java @@ -1,5 +1,6 @@ package datadog.trace.instrumentation.netty41; +import datadog.trace.api.Function; import datadog.trace.bootstrap.WeakMap; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.context.TraceScope; @@ -12,14 +13,13 @@ public class AttributeKeys { private static final WeakMap>> map = WeakMap.Implementation.DEFAULT.get(); - private static final WeakMap.ValueSupplier>> - mapSupplier = - new WeakMap.ValueSupplier>>() { - @Override - public ConcurrentMap> get(final ClassLoader ignore) { - return new ConcurrentHashMap<>(); - } - }; + private static final Function>> mapSupplier = + new Function>>() { + @Override + public ConcurrentMap> apply(final ClassLoader ignore) { + return new ConcurrentHashMap<>(); + } + }; public static final AttributeKey PARENT_CONNECT_CONTINUATION_ATTRIBUTE_KEY = From 2a07215492aac5f6b7d21c8199ebc6f8d3b0481f Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Thu, 29 Oct 2020 15:49:13 -0400 Subject: [PATCH 02/12] Simplify WeakCache interface --- .../main/java/datadog/trace/bootstrap/WeakCache.java | 12 ++++-------- .../datadog/trace/agent/tooling/AgentTooling.java | 3 ++- .../trace/agent/tooling/muzzle/ReferenceMatcher.java | 11 ++++++----- .../datadog/trace/agent/tooling/WeakCacheTest.groovy | 7 +++---- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakCache.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakCache.java index 4b2b0bd38a6..d354e2462e0 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakCache.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/WeakCache.java @@ -1,19 +1,15 @@ package datadog.trace.bootstrap; -import java.util.concurrent.Callable; +import datadog.trace.api.Function; public interface WeakCache { - interface Provider { - WeakCache newWeakCache(); - - WeakCache newWeakCache(final long maxSize); + interface Provider { + WeakCache newWeakCache(long maxSize); } V getIfPresent(final K key); - V getIfPresentOrCompute(final K key, final Callable loader); - - V get(final K key, final Callable loader); + V computeIfAbsent(K key, Function mappingFunction); void put(final K key, final V value); } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java index be93bac7785..e3d7e7ed0d6 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java @@ -41,13 +41,14 @@ private static Provider loadWeakCacheProvider() { throw new IllegalStateException("Can't load implementation of WeakCache.Provider"); } + private static final long DEFAULT_CACHE_CAPACITY = 32; private static final Provider weakCacheProvider = loadWeakCacheProvider(); private static final DDLocationStrategy LOCATION_STRATEGY = new DDLocationStrategy(); private static final DDCachingPoolStrategy POOL_STRATEGY = new DDCachingPoolStrategy(); public static WeakCache newWeakCache() { - return weakCacheProvider.newWeakCache(); + return newWeakCache(DEFAULT_CACHE_CAPACITY); } public static WeakCache newWeakCache(final long maxSize) { diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java index f2ddf0eed6b..aaf9aedfe44 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java @@ -6,6 +6,7 @@ import datadog.trace.agent.tooling.Utils; import datadog.trace.agent.tooling.muzzle.Reference.Mismatch; import datadog.trace.agent.tooling.muzzle.Reference.Source; +import datadog.trace.api.Function; import datadog.trace.bootstrap.WeakCache; import datadog.trace.bootstrap.instrumentation.api.Pair; import java.util.ArrayList; @@ -15,7 +16,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.Callable; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.method.MethodDescription; @@ -53,12 +53,13 @@ public boolean matches(ClassLoader loader) { loader = Utils.getBootstrapProxy(); } final ClassLoader cl = loader; - return mismatchCache.getIfPresentOrCompute( + return mismatchCache.computeIfAbsent( loader, - new Callable() { + // Can't use a function reference because of Java7 support + new Function() { @Override - public Boolean call() { - return doesMatch(cl); + public Boolean apply(ClassLoader key) { + return doesMatch(key); } }); } diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy index ad2cd655e06..df7ee9e7640 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy @@ -1,9 +1,8 @@ package datadog.trace.agent.tooling +import datadog.trace.api.Function import spock.lang.Specification -import java.util.concurrent.Callable - class WeakCacheTest extends Specification { def supplier = new CounterSupplier() @@ -68,11 +67,11 @@ class WeakCacheTest extends Specification { weakCacheFor1elem.cache.size() == 1 } - class CounterSupplier implements Callable { + class CounterSupplier implements Function { def counter = 0 @Override - Integer call() { + Integer apply(String ignored) { counter = counter + 1 return counter } From 95e08a9bcd98c84355df0515e946521b6d507ed0 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Thu, 29 Oct 2020 16:57:19 -0400 Subject: [PATCH 03/12] Add CLHMWeakCache and CaffeineWeakCache --- .../agent-tooling/agent-tooling.gradle | 7 +- .../trace/agent/tooling/AgentTooling.java | 30 ++++--- .../trace/agent/tooling/CLHMWeakCache.java | 68 ++++++++++++++ .../agent/tooling/CaffeineWeakCache.java | 51 +++++++++++ .../trace/agent/tooling/GuavaWeakCache.java | 90 ------------------- 5 files changed, 140 insertions(+), 106 deletions(-) create mode 100644 dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CLHMWeakCache.java create mode 100644 dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java delete mode 100644 dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/GuavaWeakCache.java diff --git a/dd-java-agent/agent-tooling/agent-tooling.gradle b/dd-java-agent/agent-tooling/agent-tooling.gradle index 41bc7ab71b4..5bffe813c16 100644 --- a/dd-java-agent/agent-tooling/agent-tooling.gradle +++ b/dd-java-agent/agent-tooling/agent-tooling.gradle @@ -12,14 +12,13 @@ dependencies { compile(project(':dd-java-agent:agent-bootstrap')) { exclude group: 'com.datadoghq', module: 'agent-logging' } - compile group: 'com.blogspot.mydailyjava', name: 'weak-lock-free', version: '0.15' + compile group: 'com.blogspot.mydailyjava', name: 'weak-lock-free', version: '0.17' + compile group: 'com.googlecode.concurrentlinkedhashmap', name: 'concurrentlinkedhashmap-lru', version: '1.4.2' + compile group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.8.6' compile deps.bytebuddy compile deps.bytebuddyagent compile deps.guava - annotationProcessor deps.autoserviceProcessor - compileOnly deps.autoserviceAnnotation - compile project(':dd-trace-core') compile project(':dd-trace-core:jfr-openjdk') diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java index e3d7e7ed0d6..ac6fdee3541 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java @@ -5,8 +5,6 @@ import datadog.trace.bootstrap.WeakCache; import datadog.trace.bootstrap.WeakCache.Provider; import datadog.trace.bootstrap.WeakMap; -import java.util.Iterator; -import java.util.ServiceLoader; /** * This class contains class references for objects shared by the agent installer as well as muzzle @@ -27,18 +25,26 @@ static void registerWeakMapProvider() { } } - private static Provider loadWeakCacheProvider() { - final Iterator providers = - ServiceLoader.load(Provider.class, AgentInstaller.class.getClassLoader()).iterator(); - if (providers.hasNext()) { - final Provider provider = providers.next(); - if (providers.hasNext()) { - throw new IllegalStateException( - "Only one implementation of WeakCache.Provider suppose to be in classpath"); + private static Provider loadWeakCacheProvider() { + ClassLoader classLoader = AgentInstaller.class.getClassLoader(); + Class providerClass; + + String version = System.getProperty("java.version"); + try { + if (version == null || version.startsWith("1.7")) { + providerClass = + (Class) + classLoader.loadClass("datadog.trace.agent.tooling.CLHMWeakCache$Provider"); + } else { + providerClass = + (Class) + classLoader.loadClass("datadog.trace.agent.tooling.CaffeineWeakCache$Provider"); } - return provider; + + return providerClass.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Can't load implementation of WeakCache.Provider", e); } - throw new IllegalStateException("Can't load implementation of WeakCache.Provider"); } private static final long DEFAULT_CACHE_CAPACITY = 32; diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CLHMWeakCache.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CLHMWeakCache.java new file mode 100644 index 00000000000..08940541ffc --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CLHMWeakCache.java @@ -0,0 +1,68 @@ +package datadog.trace.agent.tooling; + +import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap; +import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; +import datadog.trace.api.Function; +import datadog.trace.bootstrap.WeakCache; +import java.util.concurrent.ConcurrentMap; + +public class CLHMWeakCache implements WeakCache { + public static final class Provider implements WeakCache.Provider { + @Override + public WeakCache newWeakCache(long maxSize) { + return new CLHMWeakCache<>(maxSize); + } + } + + private static final int CACHE_CONCURRENCY = + Math.max(8, Runtime.getRuntime().availableProcessors()); + private final WeakConcurrentMap weakMap; + private final long maxSize; + + public CLHMWeakCache(long maxSize) { + // No parameterization because WeakKey isn't visible + ConcurrentMap linkedMap = + new ConcurrentLinkedHashMap.Builder() + .maximumWeightedCapacity(maxSize) + .concurrencyLevel(CACHE_CONCURRENCY) + .build(); + + weakMap = new WeakConcurrentMap<>(false, true, linkedMap); + + this.maxSize = maxSize; + } + + @Override + public V getIfPresent(K key) { + return weakMap.getIfPresent(key); + } + + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + V value = weakMap.getIfPresent(key); + if (value == null) { + value = mappingFunction.apply(key); + + expungeIfNecessary(); + V oldValue = weakMap.putIfProbablyAbsent(key, value); + if (oldValue != null) { + value = oldValue; + } + } + + return value; + } + + @Override + public void put(K key, V value) { + expungeIfNecessary(); + + weakMap.put(key, value); + } + + private void expungeIfNecessary() { + if (weakMap.approximateSize() >= maxSize) { + weakMap.expungeStaleEntries(); + } + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java new file mode 100644 index 00000000000..542eb0367fa --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java @@ -0,0 +1,51 @@ +package datadog.trace.agent.tooling; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import datadog.trace.api.Function; +import datadog.trace.bootstrap.WeakCache; +import java.util.concurrent.TimeUnit; + +public class CaffeineWeakCache implements WeakCache { + public static final class Provider implements WeakCache.Provider { + @Override + public WeakCache newWeakCache(long maxSize) { + return new CaffeineWeakCache<>(maxSize); + } + } + + private final Cache cache; + + public CaffeineWeakCache(long maxSize) { + cache = + Caffeine.newBuilder() + .weakKeys() + .maximumSize(maxSize) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build(); + } + + @Override + public V getIfPresent(K key) { + return cache.getIfPresent(key); + } + + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + // Unable to use cache.get() directly because it relies on java.util.function.Function which is + // only available in Java8+. This is less efficient. The raciness is unimportant because this + // is a cache + V value = cache.getIfPresent(key); + if (value == null) { + value = mappingFunction.apply(key); + + cache.put(key, value); + } + return value; + } + + @Override + public void put(K key, V value) { + cache.put(key, value); + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/GuavaWeakCache.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/GuavaWeakCache.java deleted file mode 100644 index b427c83c4c1..00000000000 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/GuavaWeakCache.java +++ /dev/null @@ -1,90 +0,0 @@ -package datadog.trace.agent.tooling; - -import com.google.auto.service.AutoService; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import datadog.trace.bootstrap.WeakCache; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; - -/** - * no null keys nor null values are permitted - * - * @param - * @param - */ -@Slf4j -public final class GuavaWeakCache implements WeakCache { - @AutoService(WeakCache.Provider.class) - public static final class Provider implements WeakCache.Provider { - private static final int CACHE_CONCURRENCY = - Math.max(8, Runtime.getRuntime().availableProcessors()); - - @Override - public GuavaWeakCache newWeakCache() { - return new GuavaWeakCache( - CacheBuilder.newBuilder() - .weakKeys() - .concurrencyLevel(CACHE_CONCURRENCY) - .expireAfterAccess(10, TimeUnit.MINUTES) - .build()); - } - - @Override - public GuavaWeakCache newWeakCache(final long maxSize) { - return new GuavaWeakCache( - CacheBuilder.newBuilder() - .weakKeys() - .maximumSize(maxSize) - .concurrencyLevel(CACHE_CONCURRENCY) - .expireAfterAccess(10, TimeUnit.MINUTES) - .build()); - } - } - - private final Cache cache; - - private GuavaWeakCache(final Cache cache) { - this.cache = cache; - } - - /** - * @return null if key is not present - * @param key - */ - @Override - public V getIfPresent(final K key) { - return cache.getIfPresent(key); - } - - @Override - public V getIfPresentOrCompute(final K key, final Callable loader) { - final V v = cache.getIfPresent(key); - if (v != null) { - return v; - } - try { - return cache.get(key, loader); - } catch (ExecutionException e) { - log.error("Can't get value from cache", e); - } - return null; - } - - @Override - public V get(final K key, final Callable loader) { - try { - return cache.get(key, loader); - } catch (ExecutionException e) { - log.error("Can't get value from cache", e); - } - return null; - } - - @Override - public void put(final K key, final V value) { - cache.put(key, value); - } -} From aa06610445147b08eb33f93ab064cea7a6400ab6 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Thu, 29 Oct 2020 19:01:29 -0400 Subject: [PATCH 04/12] Replace Guava caches in DDCachingPoolStrategy --- .../agent-tooling/agent-tooling.gradle | 1 - .../bytebuddy/DDCachingPoolStrategy.java | 49 +++++++++---------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/dd-java-agent/agent-tooling/agent-tooling.gradle b/dd-java-agent/agent-tooling/agent-tooling.gradle index 5bffe813c16..997690c7227 100644 --- a/dd-java-agent/agent-tooling/agent-tooling.gradle +++ b/dd-java-agent/agent-tooling/agent-tooling.gradle @@ -17,7 +17,6 @@ dependencies { compile group: 'com.github.ben-manes.caffeine', name: 'caffeine', version: '2.8.6' compile deps.bytebuddy compile deps.bytebuddyagent - compile deps.guava compile project(':dd-trace-core') compile project(':dd-trace-core:jfr-openjdk') diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java index af41d338134..3bb21a79642 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java @@ -2,9 +2,12 @@ import static net.bytebuddy.agent.builder.AgentBuilder.PoolStrategy; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; +import datadog.trace.agent.tooling.AgentTooling; +import datadog.trace.api.Function; +import datadog.trace.bootstrap.WeakCache; import java.lang.ref.WeakReference; +import java.util.concurrent.ConcurrentMap; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.method.MethodDescription; @@ -56,23 +59,16 @@ public class DDCachingPoolStrategy implements PoolStrategy { *
  • Allow for quick fast path equivalence check of composite keys * */ - final Cache> loaderRefCache = - CacheBuilder.newBuilder() - .weakKeys() - .concurrencyLevel(CONCURRENCY_LEVEL) - .initialCapacity(LOADER_CAPACITY / 2) - .maximumSize(LOADER_CAPACITY) - .build(); + final WeakCache> loaderRefCache = + AgentTooling.newWeakCache(LOADER_CAPACITY); /** * Single shared Type.Resolution cache -- uses a composite key -- conceptually of loader & name */ - final Cache sharedResolutionCache = - CacheBuilder.newBuilder() - .softValues() + final ConcurrentMap sharedResolutionCache = + new ConcurrentLinkedHashMap.Builder() + .maximumWeightedCapacity(TYPE_CAPACITY) .concurrencyLevel(CONCURRENCY_LEVEL) - .initialCapacity(TYPE_CAPACITY) - .maximumSize(TYPE_CAPACITY) .build(); /** Fast path for bootstrap */ @@ -86,12 +82,15 @@ public final TypePool typePool( return createCachingTypePool(bootstrapCacheProvider, classFileLocator); } - WeakReference loaderRef = loaderRefCache.getIfPresent(classLoader); - - if (loaderRef == null) { - loaderRef = new WeakReference<>(classLoader); - loaderRefCache.put(classLoader, loaderRef); - } + WeakReference loaderRef = + loaderRefCache.computeIfAbsent( + classLoader, + new Function>() { + @Override + public WeakReference apply(ClassLoader input) { + return new WeakReference<>(input); + } + }); final int loaderHash = classLoader.hashCode(); return createCachingTypePool(loaderHash, loaderRef, classFileLocator); @@ -118,10 +117,6 @@ private TypePool createCachingTypePool( cacheProvider, classFileLocator, TypePool.Default.ReaderMode.FAST); } - final long approximateSize() { - return sharedResolutionCache.size(); - } - /** * TypeCacheKey is key for the sharedResolutionCache. Conceptually, it is a mix of ClassLoader & * class name. @@ -205,12 +200,12 @@ static final class SharedResolutionCacheAdapter implements TypePool.CacheProvide private final int loaderHash; private final WeakReference loaderRef; - private final Cache sharedResolutionCache; + private final ConcurrentMap sharedResolutionCache; SharedResolutionCacheAdapter( final int loaderHash, final WeakReference loaderRef, - final Cache sharedResolutionCache) { + final ConcurrentMap sharedResolutionCache) { this.loaderHash = loaderHash; this.loaderRef = loaderRef; this.sharedResolutionCache = sharedResolutionCache; @@ -219,7 +214,7 @@ static final class SharedResolutionCacheAdapter implements TypePool.CacheProvide @Override public TypePool.Resolution find(final String className) { final TypePool.Resolution existingResolution = - sharedResolutionCache.getIfPresent(new TypeCacheKey(loaderHash, loaderRef, className)); + sharedResolutionCache.get(new TypeCacheKey(loaderHash, loaderRef, className)); if (existingResolution != null) { return existingResolution; } From 2e8c864b6eadf0211a112249fe7ef959a548cddc Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Thu, 29 Oct 2020 19:01:55 -0400 Subject: [PATCH 05/12] Datastax cassandra instrumentation had a guava dep --- .../datastax-cassandra-3/datastax-cassandra-3.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/dd-java-agent/instrumentation/datastax-cassandra-3/datastax-cassandra-3.gradle b/dd-java-agent/instrumentation/datastax-cassandra-3/datastax-cassandra-3.gradle index d7376741b03..da135695599 100644 --- a/dd-java-agent/instrumentation/datastax-cassandra-3/datastax-cassandra-3.gradle +++ b/dd-java-agent/instrumentation/datastax-cassandra-3/datastax-cassandra-3.gradle @@ -47,6 +47,7 @@ testSets { dependencies { compileOnly group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.0.0' + compileOnly deps.guava testCompile group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.2.0' testCompile group: 'org.cassandraunit', name: 'cassandra-unit', version: '3.1.3.2' From e583356b8372f331557e01d5a5f33197e9a5c4b0 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Thu, 29 Oct 2020 19:36:00 -0400 Subject: [PATCH 06/12] Update test --- .../trace/agent/tooling/WeakCacheTest.groovy | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy index df7ee9e7640..5dc54e13ed1 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/WeakCacheTest.groovy @@ -7,64 +7,68 @@ class WeakCacheTest extends Specification { def supplier = new CounterSupplier() def weakCache = AgentTooling.newWeakCache() - def weakCacheFor1elem = AgentTooling.newWeakCache(1) - def "getOrCreate a value"() { + def "computeIfAbsent a value"() { when: - def count = weakCache.get('key', supplier) + def count = weakCache.computeIfAbsent('key', supplier) then: count == 1 supplier.counter == 1 - weakCache.cache.size() == 1 + weakCache.getIfPresent('key') == 1 } - def "getOrCreate a value multiple times same class loader same key"() { + def "computeIfAbsent a value multiple times same class loader same key"() { when: - def count1 = weakCache.get('key', supplier) - def count2 = weakCache.get('key', supplier) + def count1 = weakCache.computeIfAbsent('key', supplier) + def count2 = weakCache.computeIfAbsent('key', supplier) then: count1 == 1 count2 == 1 supplier.counter == 1 - weakCache.cache.size() == 1 + weakCache.getIfPresent('key') == 1 } - def "getOrCreate a value multiple times same class loader different keys"() { + def "computeIfAbsent a value multiple times same class loader different keys"() { when: - def count1 = weakCache.get('key1', supplier) - def count2 = weakCache.get('key2', supplier) + def count1 = weakCache.computeIfAbsent('key1', supplier) + def count2 = weakCache.computeIfAbsent('key2', supplier) then: count1 == 1 count2 == 2 supplier.counter == 2 - weakCache.cache.size() == 2 + weakCache.getIfPresent('key1') == 1 + weakCache.getIfPresent('key2') == 2 } def "max size check"() { + setup: + def weakCacheFor1elem = AgentTooling.newWeakCache(1) + when: - def sizeBefore = weakCacheFor1elem.cache.size() def valBefore = weakCacheFor1elem.getIfPresent("key1") - def sizeAfter = weakCacheFor1elem.cache.size() - def valAfterGet = weakCacheFor1elem.getIfPresentOrCompute("key1", supplier) - def sizeAfterCompute = weakCacheFor1elem.cache.size() - weakCacheFor1elem.put("key1", 42) - def valAfterPut = weakCacheFor1elem.getIfPresentOrCompute("key1", supplier) - def valByKey2 = weakCacheFor1elem.getIfPresentOrCompute("key2", supplier) - def valAfterReplace = weakCacheFor1elem.getIfPresent("key1") + def valAfterGet = weakCacheFor1elem.computeIfAbsent("key1", supplier) then: valBefore == null valAfterGet == 1 - sizeBefore == 0 - sizeAfter == 0 - sizeAfterCompute == 1 - valAfterPut == 42 + + when: + weakCacheFor1elem.put("key1", 42) + + then: + weakCacheFor1elem.computeIfAbsent("key1", supplier) == 42 + + when: + def valByKey2 = weakCacheFor1elem.computeIfAbsent("key2", supplier) + + then: valByKey2 == 2 - valAfterReplace == null - weakCacheFor1elem.cache.size() == 1 + + // The following check doesn't work because caches are allowed to temporarily exceed the max size + // weakCacheFor1elem.getIfPresent("key1") == null } class CounterSupplier implements Function { From 54629fc18377c8572e2d3378241be550fca9e0d0 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Fri, 30 Oct 2020 12:41:24 -0400 Subject: [PATCH 07/12] Add some debug logging --- .../main/java/datadog/trace/agent/tooling/AgentTooling.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java index ac6fdee3541..b0022f3e0b9 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java @@ -5,12 +5,14 @@ import datadog.trace.bootstrap.WeakCache; import datadog.trace.bootstrap.WeakCache.Provider; import datadog.trace.bootstrap.WeakMap; +import lombok.extern.slf4j.Slf4j; /** * This class contains class references for objects shared by the agent installer as well as muzzle * (both compile and runtime). Extracted out from AgentInstaller to begin separating some of the * logic out. */ +@Slf4j public class AgentTooling { static { @@ -35,10 +37,12 @@ private static Provider loadWeakCacheProvider() { providerClass = (Class) classLoader.loadClass("datadog.trace.agent.tooling.CLHMWeakCache$Provider"); + log.debug("Using CLHMWeakCache Provider"); } else { providerClass = (Class) classLoader.loadClass("datadog.trace.agent.tooling.CaffeineWeakCache$Provider"); + log.debug("Using CaffeineWeakCache Provider"); } return providerClass.getDeclaredConstructor().newInstance(); From 21c547254aaeb4c9e96fef83342c7d16b4d8f4e9 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Fri, 30 Oct 2020 14:27:41 -0400 Subject: [PATCH 08/12] approximateSize() was being used by tests --- .../trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java index 3bb21a79642..b4113b0185d 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java @@ -117,6 +117,10 @@ private TypePool createCachingTypePool( cacheProvider, classFileLocator, TypePool.Default.ReaderMode.FAST); } + final long approximateSize() { + return sharedResolutionCache.size(); + } + /** * TypeCacheKey is key for the sharedResolutionCache. Conceptually, it is a mix of ClassLoader & * class name. From c3f33f0f7a817a638edea77e1bbb7801685c4a08 Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Fri, 30 Oct 2020 17:18:14 -0400 Subject: [PATCH 09/12] ShadowPackageRenamingTest relied on guava being used --- .../ShadowPackageRenamingTest.groovy | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy index 1e8a5f93384..5b286961c8b 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy @@ -1,8 +1,9 @@ package datadog.trace.agent.integration.classloading -import com.google.common.collect.MapMaker import com.google.common.reflect.ClassPath import datadog.trace.agent.test.IntegrationTestUtils +import okio.BufferedSink +import spock.lang.Ignore import spock.lang.Specification class ShadowPackageRenamingTest extends Specification { @@ -11,12 +12,12 @@ class ShadowPackageRenamingTest extends Specification { final Class ddClass = IntegrationTestUtils.getAgentClassLoader() .loadClass("datadog.trace.agent.tooling.AgentInstaller") - final URL userGuava = - MapMaker.getProtectionDomain().getCodeSource().getLocation() - final URL agentGuavaDep = + final URL userOkio = + BufferedSink.getProtectionDomain().getCodeSource().getLocation() + final URL agentOkioDep = ddClass .getClassLoader() - .loadClass("com.google.common.collect.MapMaker") + .loadClass("okio.BufferedSink") .getProtectionDomain() .getCodeSource() .getLocation() @@ -26,8 +27,8 @@ class ShadowPackageRenamingTest extends Specification { expect: agentSource.getFile() == "/" agentSource.getProtocol() == "x-internal-jar" - agentSource == agentGuavaDep - agentSource.getFile() != userGuava.getFile() + agentSource == agentOkioDep + agentSource.getFile() != userOkio.getFile() } // @Ignore("OT 0.32 removed this field. Need to find another option.") @@ -51,6 +52,7 @@ class ShadowPackageRenamingTest extends Specification { thrown ClassNotFoundException } + @Ignore("Agent jar check inaccurate") def "agent jar contains no bootstrap classes"() { setup: final ClassPath agentClasspath = ClassPath.from(IntegrationTestUtils.getAgentClassLoader()) @@ -61,6 +63,7 @@ class ShadowPackageRenamingTest extends Specification { final String[] bootstrapPrefixes = IntegrationTestUtils.getBootstrapPackagePrefixes() final String[] agentPrefixes = IntegrationTestUtils.getAgentPackagePrefixes() final List badBootstrapPrefixes = [] + for (ClassPath.ClassInfo info : bootstrapClasspath.getAllClasses()) { bootstrapClasses.add(info.getName()) // make sure all bootstrap classes can be loaded from system @@ -79,6 +82,7 @@ class ShadowPackageRenamingTest extends Specification { final List agentDuplicateClassFile = new ArrayList<>() final List badAgentPrefixes = [] + assert agentClasspath.getAllClasses().size() > 50 for (ClassPath.ClassInfo classInfo : agentClasspath.getAllClasses()) { if (bootstrapClasses.contains(classInfo.getName())) { agentDuplicateClassFile.add(classInfo) From a979b8fe7ed931678b66585edbfd9ae76cea1c09 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Mon, 23 Nov 2020 11:12:31 +0000 Subject: [PATCH 10/12] Use AgentTaskScheduler.INSTANCE for background cleanup --- .../java/datadog/trace/agent/tooling/CaffeineWeakCache.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java index 542eb0367fa..6b092971e24 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/CaffeineWeakCache.java @@ -4,6 +4,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import datadog.trace.api.Function; import datadog.trace.bootstrap.WeakCache; +import datadog.trace.util.AgentTaskScheduler; import java.util.concurrent.TimeUnit; public class CaffeineWeakCache implements WeakCache { @@ -22,6 +23,7 @@ public CaffeineWeakCache(long maxSize) { .weakKeys() .maximumSize(maxSize) .expireAfterAccess(10, TimeUnit.MINUTES) + .executor(AgentTaskScheduler.INSTANCE) .build(); } From 4798688ffe95d80eb692c2c8fba6a473cbbb8b66 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Mon, 23 Nov 2020 14:02:32 +0000 Subject: [PATCH 11/12] Patch Caffeine's BoundedLocalCache.PerformCleanupTask to avoid loading ForkJoinTask before instrumentation is ready --- .../agent-tooling/agent-tooling.gradle | 12 ++++++ .../caffeine/cache/BoundedLocalCache.java | 42 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 dd-java-agent/agent-tooling/src/patch/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java diff --git a/dd-java-agent/agent-tooling/agent-tooling.gradle b/dd-java-agent/agent-tooling/agent-tooling.gradle index 997690c7227..544a5a5c257 100644 --- a/dd-java-agent/agent-tooling/agent-tooling.gradle +++ b/dd-java-agent/agent-tooling/agent-tooling.gradle @@ -3,6 +3,18 @@ apply from: "$rootDir/gradle/java.gradle" minimumBranchCoverage = 0.6 excludedClassesCoverage += ['datadog.trace.agent.tooling.*'] +// patch inner class from Caffeine to avoid ForkJoinTask from being loaded too early +sourceSets { + patch { + java {} + } +} +jar { + from(sourceSets.patch.output) { + include 'com/github/benmanes/caffeine/cache/BoundedLocalCache$PerformCleanupTask.class' + } +} + configurations { // classpath used by the instrumentation muzzle plugin instrumentationMuzzle diff --git a/dd-java-agent/agent-tooling/src/patch/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java b/dd-java-agent/agent-tooling/src/patch/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java new file mode 100644 index 00000000000..25d7b16b900 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/patch/java/com/github/benmanes/caffeine/cache/BoundedLocalCache.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 Ben Manes. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.github.benmanes.caffeine.cache; + +import java.lang.ref.WeakReference; + +/** skeleton outer class just for compilation purposes, not included in the final patch. */ +abstract class BoundedLocalCache { + abstract void performCleanUp(Runnable task); + + /** patched to not extend ForkJoinTask as we don't want that class loaded too early. */ + static final class PerformCleanupTask implements Runnable { + private static final long serialVersionUID = 1L; + + final WeakReference> reference; + + PerformCleanupTask(BoundedLocalCache cache) { + reference = new WeakReference>(cache); + } + + @Override + public void run() { + BoundedLocalCache cache = reference.get(); + if (cache != null) { + cache.performCleanUp(/* ignored */ null); + } + } + } +} From eaf51897cf34d6e83d6bbeec1ceb3d3d91f95e0c Mon Sep 17 00:00:00 2001 From: Laplie Anderson Date: Mon, 23 Nov 2020 12:47:44 -0500 Subject: [PATCH 12/12] Use Platform class to check Java version --- .../datadog/trace/agent/tooling/AgentTooling.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java index b0022f3e0b9..5e889afde43 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java @@ -2,6 +2,7 @@ import datadog.trace.agent.tooling.bytebuddy.DDCachingPoolStrategy; import datadog.trace.agent.tooling.bytebuddy.DDLocationStrategy; +import datadog.trace.api.Platform; import datadog.trace.bootstrap.WeakCache; import datadog.trace.bootstrap.WeakCache.Provider; import datadog.trace.bootstrap.WeakMap; @@ -31,18 +32,17 @@ private static Provider loadWeakCacheProvider() { ClassLoader classLoader = AgentInstaller.class.getClassLoader(); Class providerClass; - String version = System.getProperty("java.version"); try { - if (version == null || version.startsWith("1.7")) { + if (Platform.isJavaVersionAtLeast(8)) { providerClass = (Class) - classLoader.loadClass("datadog.trace.agent.tooling.CLHMWeakCache$Provider"); - log.debug("Using CLHMWeakCache Provider"); + classLoader.loadClass("datadog.trace.agent.tooling.CaffeineWeakCache$Provider"); + log.debug("Using CaffeineWeakCache Provider"); } else { providerClass = (Class) - classLoader.loadClass("datadog.trace.agent.tooling.CaffeineWeakCache$Provider"); - log.debug("Using CaffeineWeakCache Provider"); + classLoader.loadClass("datadog.trace.agent.tooling.CLHMWeakCache$Provider"); + log.debug("Using CLHMWeakCache Provider"); } return providerClass.getDeclaredConstructor().newInstance();