Skip to content

Commit 00bd02b

Browse files
authored
Simplify InstanceStore implementation to use simple, synchronized HashMaps (#9739)
The keys used to lookup instances are always string literals, bounded in code by a fixed number of calls. These keys are never collected, so we don't need to use a weak map. The instance store is accessed when setting up helpers to guarantee the same instance is used by different instrumentations sharing a common type (via their parent class-loader.) Therefore each store just needs basic synchronization to guarantee it only creates one instance per-key.
1 parent 7950d54 commit 00bd02b

File tree

2 files changed

+46
-22
lines changed

2 files changed

+46
-22
lines changed
Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,61 @@
11
package datadog.trace.bootstrap;
22

33
import datadog.trace.api.GenericClassValue;
4-
import java.util.function.Function;
4+
import java.util.Collections;
5+
import java.util.HashMap;
6+
import java.util.Map;
57

68
/**
79
* An {@code InstanceStore} is a class global map for registering instances. This can be useful when
8-
* helper classes are injected into multiple class loaders but need to share unique keys of a type
10+
* helper classes are injected into multiple class loaders and need to share instances of a type
911
* from a common parent class loader.
1012
*
11-
* <p>The {@code InstanceStore} is backed by a {@code WeakMapContextStore} that has a max size of
12-
* 100 keys.
13+
* <p>Instance keys are expected to be string literals, defined as constants in the helper classes.
1314
*/
14-
public final class InstanceStore {
15-
private InstanceStore() {}
15+
public final class InstanceStore<T> implements ContextStore<String, T> {
1616

1717
private static final ClassValue<? super ContextStore<String, ?>> classInstanceStore =
18-
GenericClassValue.of(
19-
(Function<Class<?>, ContextStore<String, ?>>) input -> new WeakMapContextStore<>(100));
18+
GenericClassValue.of(input -> new InstanceStore<>());
2019

20+
/** @return global store of instances with the same common type */
2121
@SuppressWarnings("unchecked")
22-
public static <T> ContextStore<String, T> of(Class<T> type) {
23-
return (ContextStore<String, T>) classInstanceStore.get(type);
22+
public static <T> InstanceStore<T> of(Class<T> type) {
23+
return (InstanceStore<T>) classInstanceStore.get(type);
24+
}
25+
26+
// simple approach; instance stores don't need highly concurrent access or weak keys
27+
private final Map<String, T> store = Collections.synchronizedMap(new HashMap<>());
28+
29+
private InstanceStore() {}
30+
31+
@Override
32+
public T get(String key) {
33+
return store.get(key);
34+
}
35+
36+
@Override
37+
public void put(String key, T instance) {
38+
store.put(key, instance);
39+
}
40+
41+
@Override
42+
public T putIfAbsent(String key, T instance) {
43+
T existing = store.putIfAbsent(key, instance);
44+
return existing != null ? existing : instance;
45+
}
46+
47+
@Override
48+
public T putIfAbsent(String key, Factory<T> instanceFactory) {
49+
return store.computeIfAbsent(key, instanceFactory::create);
50+
}
51+
52+
@Override
53+
public T computeIfAbsent(String key, KeyAwareFactory<? super String, T> instanceFactory) {
54+
return store.computeIfAbsent(key, instanceFactory::create);
55+
}
56+
57+
@Override
58+
public T remove(String key) {
59+
return store.remove(key);
2460
}
2561
}

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/InstanceStoreTest.groovy

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
package datadog.trace.bootstrap
22

3-
import datadog.trace.agent.tooling.WeakMaps
43
import datadog.trace.test.util.DDSpecification
54
import spock.lang.Shared
65

76
import java.util.concurrent.atomic.AtomicInteger
87

98
class InstanceStoreTest extends DDSpecification {
10-
static {
11-
WeakMaps.registerAsSupplier()
12-
}
139

1410
@Shared
1511
private AtomicInteger counter = new AtomicInteger()
@@ -19,14 +15,6 @@ class InstanceStoreTest extends DDSpecification {
1915
"key-${counter.incrementAndGet()}"
2016
}
2117

22-
def "test empty InstanceStore"() {
23-
setup:
24-
WeakMapContextStore<String, Some> someStore = InstanceStore.of(Some) as WeakMapContextStore<String, Some>
25-
26-
expect:
27-
someStore.size() == 0
28-
}
29-
3018
def "test returns existing value"() {
3119
setup:
3220
def someStore = InstanceStore.of(Some)

0 commit comments

Comments
 (0)