Skip to content

Commit 4391801

Browse files
authored
Simplify InstanceStore API and decouple it from ContextStore (#9861)
1 parent a632fe7 commit 4391801

File tree

3 files changed

+58
-37
lines changed

3 files changed

+58
-37
lines changed

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

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Collections;
55
import java.util.HashMap;
66
import java.util.Map;
7+
import java.util.function.Supplier;
78

89
/**
910
* An {@code InstanceStore} is a class global map for registering instances. This can be useful when
@@ -12,49 +13,62 @@
1213
*
1314
* <p>Instance keys are expected to be string literals, defined as constants in the helper classes.
1415
*/
15-
public final class InstanceStore<T> implements ContextStore<String, T> {
16+
public final class InstanceStore<T> {
1617

17-
private static final ClassValue<? super ContextStore<String, ?>> classInstanceStore =
18-
GenericClassValue.of(input -> new InstanceStore<>());
18+
@SuppressWarnings("rawtypes")
19+
private static final ClassValue<InstanceStore> classInstanceStore =
20+
GenericClassValue.of(type -> new InstanceStore<>());
1921

2022
/** @return global store of instances with the same common type */
2123
@SuppressWarnings("unchecked")
2224
public static <T> InstanceStore<T> of(Class<T> type) {
23-
return (InstanceStore<T>) classInstanceStore.get(type);
25+
return classInstanceStore.get(type);
2426
}
2527

2628
// simple approach; instance stores don't need highly concurrent access or weak keys
2729
private final Map<String, T> store = Collections.synchronizedMap(new HashMap<>());
2830

2931
private InstanceStore() {}
3032

31-
@Override
33+
/**
34+
* Gets the instance of {@code T} currently associated with the given key.
35+
*
36+
* @param key the instance key
37+
* @return the associated instance
38+
*/
3239
public T get(String key) {
3340
return store.get(key);
3441
}
3542

36-
@Override
43+
/**
44+
* Unconditionally associates an instance of {@code T} with the given key.
45+
*
46+
* @param key the instance key
47+
* @param instance the instance
48+
*/
3749
public void put(String key, T instance) {
3850
store.put(key, instance);
3951
}
4052

41-
@Override
42-
public T putIfAbsent(String key, T instance) {
43-
T existing = store.putIfAbsent(key, instance);
44-
return existing != null ? existing : instance;
53+
/**
54+
* If the given key is not already associated with an instance, create one using the factory and
55+
* associate it. Unlike {@link java.util.Map#putIfAbsent} this always returns the final associated
56+
* instance.
57+
*
58+
* @param key the instance key
59+
* @param instanceFactory the factory to create instances
60+
* @return final associated instance
61+
*/
62+
public T putIfAbsent(String key, Supplier<T> instanceFactory) {
63+
return store.computeIfAbsent(key, k -> instanceFactory.get());
4564
}
4665

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
66+
/**
67+
* Removes the instance of {@code T} currently associated with the given key.
68+
*
69+
* @param key the instance key
70+
* @return the previously associated instance; {@code null} if there was none
71+
*/
5872
public T remove(String key) {
5973
return store.remove(key);
6074
}

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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.trace.bootstrap
22

33
import datadog.trace.test.util.DDSpecification
4+
import java.util.function.Supplier
45
import spock.lang.Shared
56

67
import java.util.concurrent.atomic.AtomicInteger
@@ -15,27 +16,34 @@ class InstanceStoreTest extends DDSpecification {
1516
"key-${counter.incrementAndGet()}"
1617
}
1718

18-
def "test returns existing value"() {
19+
def "test basic operation"() {
1920
setup:
2021
def someStore = InstanceStore.of(Some)
2122
def some1 = new Some()
2223
def some2 = new Some()
2324
def key = nextKey()
24-
someStore.put(key, some1)
25+
def current
2526

2627
when:
27-
def current = someStore.putIfAbsent(key, some2)
28+
someStore.put(key, some1)
29+
current = someStore.get(key)
2830

2931
then:
3032
current == some1
31-
current != some2
3233

3334
when:
34-
current = someStore.putIfAbsent(key, some2)
35+
someStore.put(key, some2)
36+
current = someStore.get(key)
3537

3638
then:
37-
current == some1
38-
current != some2
39+
current == some2
40+
41+
when:
42+
someStore.remove(key)
43+
current = someStore.get(key)
44+
45+
then:
46+
current == null
3947
}
4048

4149
def "test returns existing store"() {
@@ -45,13 +53,13 @@ class InstanceStoreTest extends DDSpecification {
4553
InstanceStore.of(Some).put(key, some1)
4654

4755
when:
48-
def current = InstanceStore.of(Some).putIfAbsent(key, new Some())
56+
def current = InstanceStore.of(Some).putIfAbsent(key, Some::new)
4957

5058
then:
5159
current == some1
5260

5361
when:
54-
current = InstanceStore.of(Some).putIfAbsent(key, new Some())
62+
current = InstanceStore.of(Some).putIfAbsent(key, Some::new)
5563

5664
then:
5765
current == some1
@@ -63,13 +71,13 @@ class InstanceStoreTest extends DDSpecification {
6371
def key = nextKey()
6472

6573
when:
66-
def current = someStore.putIfAbsent(key, some1)
74+
def current = someStore.putIfAbsent(key, () -> some1)
6775

6876
then:
6977
current == some1
7078

7179
when:
72-
current = someStore.putIfAbsent(key, new Some())
80+
current = someStore.putIfAbsent(key, Some::new)
7381

7482
then:
7583
current == some1
@@ -113,7 +121,7 @@ class InstanceStoreTest extends DDSpecification {
113121

114122
static class Some {}
115123

116-
static class Creator implements ContextStore.Factory<Some> {
124+
static class Creator implements Supplier<Some> {
117125
private AtomicInteger invocations
118126
private Some some
119127

@@ -127,7 +135,7 @@ class InstanceStoreTest extends DDSpecification {
127135
}
128136

129137
@Override
130-
Some create() {
138+
Some get() {
131139
invocations.incrementAndGet()
132140
return some
133141
}

dd-java-agent/instrumentation/undertow/src/main/java/datadog/trace/instrumentation/undertow/UndertowDecorator.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import datadog.trace.api.Config;
44
import datadog.trace.api.gateway.BlockResponseFunction;
55
import datadog.trace.api.naming.SpanNaming;
6-
import datadog.trace.bootstrap.ContextStore;
76
import datadog.trace.bootstrap.InstanceStore;
87
import datadog.trace.bootstrap.instrumentation.api.AgentPropagation;
98
import datadog.trace.bootstrap.instrumentation.api.AgentScope;
@@ -23,13 +22,13 @@ public class UndertowDecorator
2322
UTF8BytesString.create("undertow-http-server");
2423

2524
@SuppressWarnings("rawtypes")
26-
private static final ContextStore<String, AttachmentKey> attachmentStore =
25+
private static final InstanceStore<AttachmentKey> attachmentStore =
2726
InstanceStore.of(AttachmentKey.class);
2827

2928
@SuppressWarnings("unchecked")
3029
public static final AttachmentKey<AgentScope.Continuation> DD_UNDERTOW_CONTINUATION =
3130
attachmentStore.putIfAbsent(
32-
"DD_UNDERTOW_CONTINUATION", AttachmentKey.create(AgentScope.Continuation.class));
31+
"DD_UNDERTOW_CONTINUATION", () -> AttachmentKey.create(AgentScope.Continuation.class));
3332

3433
public static final UndertowDecorator DECORATE = new UndertowDecorator();
3534
public static final CharSequence UNDERTOW_REQUEST =

0 commit comments

Comments
 (0)