diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/SpanConcurrentHashMap.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/ReferencedCountedConcurrentHashMap.java similarity index 83% rename from apm-agent-core/src/main/java/co/elastic/apm/agent/collections/SpanConcurrentHashMap.java rename to apm-agent-core/src/main/java/co/elastic/apm/agent/collections/ReferencedCountedConcurrentHashMap.java index bf44500987..272ef741f7 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/SpanConcurrentHashMap.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/ReferencedCountedConcurrentHashMap.java @@ -18,14 +18,14 @@ */ package co.elastic.apm.agent.collections; -import co.elastic.apm.agent.tracer.AbstractSpan; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; import javax.annotation.Nullable; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; /** - * Hash map dedicated to storage of in-flight spans and transactions, reference count is being incremented/decremented + * Hash map dedicated to storage of reference counted objects where counts are being incremented/decremented * when entry is added/removed. Usage of this map is intended for providing GC-based storage of context associated * to a framework-level object key, when the latter is collected by GC it allows to decrement and then recycle the * span/transaction. @@ -33,9 +33,9 @@ * @param key type * @param context type */ -public class SpanConcurrentHashMap> extends ConcurrentHashMap { +public class ReferencedCountedConcurrentHashMap extends ConcurrentHashMap { - SpanConcurrentHashMap() { + ReferencedCountedConcurrentHashMap() { } @Nullable @@ -71,7 +71,7 @@ public void clear() { super.clear(); } - private void onPut(@Nullable AbstractSpan previous, AbstractSpan value) { + private void onPut(@Nullable ReferenceCounted previous, ReferenceCounted value) { if (previous == null) { // new entry value.incrementReferences(); @@ -82,7 +82,7 @@ private void onPut(@Nullable AbstractSpan previous, AbstractSpan value) { } } - private void onRemove(@Nullable AbstractSpan removed) { + private void onRemove(@Nullable ReferenceCounted removed) { if (removed == null) { return; } diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/WeakConcurrentProviderImpl.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/WeakConcurrentProviderImpl.java index bbeb057509..593d3c280a 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/WeakConcurrentProviderImpl.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/WeakConcurrentProviderImpl.java @@ -22,7 +22,7 @@ import co.elastic.apm.agent.sdk.weakconcurrent.WeakConcurrent; import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; import co.elastic.apm.agent.sdk.weakconcurrent.WeakSet; -import co.elastic.apm.agent.tracer.AbstractSpan; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; import com.blogspot.mydailyjava.weaklockfree.AbstractWeakConcurrentMap; import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentSet; @@ -37,8 +37,8 @@ public class WeakConcurrentProviderImpl implements WeakConcurrent.WeakConcurrent private static final WeakConcurrentSet> registeredMaps = new WeakConcurrentSet<>(WeakConcurrentSet.Cleaner.INLINE); - public static > WeakMap createWeakSpanMap() { - SpanConcurrentHashMap, V> map = new SpanConcurrentHashMap<>(); + public static WeakMap createWeakReferenceCountedMap() { + ReferencedCountedConcurrentHashMap, V> map = new ReferencedCountedConcurrentHashMap<>(); NullSafeWeakConcurrentMap result = new NullSafeWeakConcurrentMap<>(map); registeredMaps.add(result); return result; diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/WeakReferenceCountedMap.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/WeakReferenceCountedMap.java new file mode 100644 index 0000000000..3b23b7f826 --- /dev/null +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/collections/WeakReferenceCountedMap.java @@ -0,0 +1,52 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 co.elastic.apm.agent.collections; + +import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; + +import javax.annotation.Nullable; + +public class WeakReferenceCountedMap implements ReferenceCountedMap { + + private final WeakMap map = WeakConcurrentProviderImpl.createWeakReferenceCountedMap(); + + @Override + @Nullable + public V get(K key) { + return map.get(key); + } + + @Override + public boolean contains(K key) { + return map.containsKey(key); + } + + @Override + public void put(K key, V value) { + map.put(key, value); + } + + @Override + @Nullable + public V remove(K key) { + return map.remove(key); + } +} diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java index 578d25b1a5..d669efa840 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java @@ -18,6 +18,7 @@ */ package co.elastic.apm.agent.impl; +import co.elastic.apm.agent.collections.WeakReferenceCountedMap; import co.elastic.apm.agent.common.JvmRuntimeInfo; import co.elastic.apm.agent.common.util.WildcardMatcher; import co.elastic.apm.agent.configuration.CoreConfiguration; @@ -49,11 +50,13 @@ import co.elastic.apm.agent.sdk.weakconcurrent.WeakConcurrent; import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; import co.elastic.apm.agent.tracer.GlobalTracer; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; +import co.elastic.apm.agent.util.DependencyInjectingServiceLoader; +import co.elastic.apm.agent.util.ExecutorUtils; import co.elastic.apm.agent.tracer.Scope; import co.elastic.apm.agent.tracer.dispatch.BinaryHeaderGetter; import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter; -import co.elastic.apm.agent.util.DependencyInjectingServiceLoader; -import co.elastic.apm.agent.util.ExecutorUtils; import co.elastic.apm.agent.util.PrivilegedActionUtils; import co.elastic.apm.agent.util.VersionUtils; import org.stagemonitor.configuration.ConfigurationOption; @@ -597,6 +600,11 @@ public ObjectPoolFactory getObjectPoolFactory() { return objectPoolFactory; } + @Override + public ReferenceCountedMap newReferenceCountedMap() { + return new WeakReferenceCountedMap<>(); + } + @Override @Nullable public AbstractSpan getActive() { @@ -938,5 +946,4 @@ public T require(Class type) { public Set getTraceHeaderNames() { return TraceContext.TRACE_TEXTUAL_HEADERS; } - } diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/SpanConcurrentHashMapTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/ReferencedCountedConcurrentHashMapTest.java similarity index 95% rename from apm-agent-core/src/test/java/co/elastic/apm/agent/collections/SpanConcurrentHashMapTest.java rename to apm-agent-core/src/test/java/co/elastic/apm/agent/collections/ReferencedCountedConcurrentHashMapTest.java index 4d2fa6c719..5e1a337e52 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/SpanConcurrentHashMapTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/collections/ReferencedCountedConcurrentHashMapTest.java @@ -34,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -class SpanConcurrentHashMapTest { +class ReferencedCountedConcurrentHashMapTest { @Nullable private Object key; @@ -45,7 +45,7 @@ void putRemove() { checkRefCount(testSpan, 0); key = new Object(); - WeakMap map = WeakConcurrentProviderImpl.createWeakSpanMap(); + WeakMap map = WeakConcurrentProviderImpl.createWeakReferenceCountedMap(); map.put(key, testSpan); checkRefCount(testSpan, 1); @@ -63,7 +63,7 @@ void putRemove() { void putTwice(PutOperation operation) { TestSpan testSpan = new TestSpan(); key = new Object(); - WeakMap map = WeakConcurrentProviderImpl.createWeakSpanMap(); + WeakMap map = WeakConcurrentProviderImpl.createWeakReferenceCountedMap(); checkRefCount(testSpan, 0); @@ -82,7 +82,7 @@ void swapValues() { TestSpan ts2 = new TestSpan(); key = new Object(); - WeakMap map = WeakConcurrentProviderImpl.createWeakSpanMap(); + WeakMap map = WeakConcurrentProviderImpl.createWeakReferenceCountedMap(); map.put(key, ts1); map.put(key, ts2); @@ -99,7 +99,7 @@ void testPutIfAbsent() { TestSpan ts2 = new TestSpan(); key = new Object(); - WeakMap map = WeakConcurrentProviderImpl.createWeakSpanMap(); + WeakMap map = WeakConcurrentProviderImpl.createWeakReferenceCountedMap(); map.putIfAbsent(key, ts1); map.putIfAbsent(key, ts2); @@ -130,7 +130,7 @@ void execute(WeakMap map, Object key, TestSpan value) { @Test void clear() { - WeakMap map = WeakConcurrentProviderImpl.createWeakSpanMap(); + WeakMap map = WeakConcurrentProviderImpl.createWeakReferenceCountedMap(); List> list = new ArrayList<>(); for (int i = 0; i < 5; i++) { @@ -153,7 +153,7 @@ void weakMapDecrementOnStaleKeyGC() { key = new Object(); TestSpan span = new TestSpan(); - WeakMap> map = WeakConcurrentProviderImpl.createWeakSpanMap(); + WeakMap> map = WeakConcurrentProviderImpl.createWeakReferenceCountedMap(); map.put(key, span); diff --git a/apm-agent-plugins/apm-asynchttpclient-plugin/src/main/java/co/elastic/apm/agent/asynchttpclient/AbstractAsyncHttpClientInstrumentation.java b/apm-agent-plugins/apm-asynchttpclient-plugin/src/main/java/co/elastic/apm/agent/asynchttpclient/AbstractAsyncHttpClientInstrumentation.java index db5416f51e..125713ba69 100644 --- a/apm-agent-plugins/apm-asynchttpclient-plugin/src/main/java/co/elastic/apm/agent/asynchttpclient/AbstractAsyncHttpClientInstrumentation.java +++ b/apm-agent-plugins/apm-asynchttpclient-plugin/src/main/java/co/elastic/apm/agent/asynchttpclient/AbstractAsyncHttpClientInstrumentation.java @@ -19,14 +19,13 @@ package co.elastic.apm.agent.asynchttpclient; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.httpclient.HttpClientHelper; import co.elastic.apm.agent.tracer.AbstractSpan; import co.elastic.apm.agent.tracer.Outcome; import co.elastic.apm.agent.tracer.Span; import co.elastic.apm.agent.sdk.DynamicTransformer; import co.elastic.apm.agent.sdk.ElasticApmInstrumentation; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; @@ -54,7 +53,7 @@ public abstract class AbstractAsyncHttpClientInstrumentation extends TracerAware public static class Helper { - static final WeakMap, Span> handlerSpanMap = WeakConcurrentProviderImpl.createWeakSpanMap(); + static final ReferenceCountedMap, Span> handlerSpanMap = tracer.newReferenceCountedMap(); public static final List> ASYNC_HANDLER_INSTRUMENTATIONS = Arrays.>asList( AsyncHandlerOnCompletedInstrumentation.class, diff --git a/apm-agent-plugins/apm-dubbo-plugin/src/main/java/co/elastic/apm/agent/dubbo/AlibabaCallbackHolder.java b/apm-agent-plugins/apm-dubbo-plugin/src/main/java/co/elastic/apm/agent/dubbo/AlibabaCallbackHolder.java index 482fc1221e..faac9a8617 100644 --- a/apm-agent-plugins/apm-dubbo-plugin/src/main/java/co/elastic/apm/agent/dubbo/AlibabaCallbackHolder.java +++ b/apm-agent-plugins/apm-dubbo-plugin/src/main/java/co/elastic/apm/agent/dubbo/AlibabaCallbackHolder.java @@ -18,11 +18,11 @@ */ package co.elastic.apm.agent.dubbo; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.AbstractSpan; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.GlobalTracer; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import com.alibaba.dubbo.remoting.exchange.ResponseCallback; public class AlibabaCallbackHolder { - public static final WeakMap> callbackSpanMap = WeakConcurrentProviderImpl.createWeakSpanMap(); + public static final ReferenceCountedMap> callbackSpanMap = GlobalTracer.get().newReferenceCountedMap(); } diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/main/java/co/elastic/apm/agent/grpc/GrpcHelper.java b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/main/java/co/elastic/apm/agent/grpc/GrpcHelper.java index 22700e9e85..9178a983f7 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/main/java/co/elastic/apm/agent/grpc/GrpcHelper.java +++ b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/main/java/co/elastic/apm/agent/grpc/GrpcHelper.java @@ -18,7 +18,6 @@ */ package co.elastic.apm.agent.grpc; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.GlobalTracer; import co.elastic.apm.agent.tracer.AbstractSpan; import co.elastic.apm.agent.tracer.Outcome; @@ -31,6 +30,7 @@ import co.elastic.apm.agent.tracer.dispatch.HeaderUtils; import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter; import co.elastic.apm.agent.tracer.dispatch.TextHeaderSetter; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import io.grpc.CallOptions; import io.grpc.ClientCall; import io.grpc.Metadata; @@ -58,27 +58,27 @@ public static GrpcHelper getInstance() { /** * Map of all in-flight {@link Span} with {@link ClientCall} instance as key. */ - private final WeakMap, Span> clientCallSpans; + private final ReferenceCountedMap, Span> clientCallSpans; /** * Map of all in-flight {@link Span} with {@link ClientCall} instance as key. */ - private final WeakMap, Span> delayedClientCallSpans; + private final ReferenceCountedMap, Span> delayedClientCallSpans; /** * Map of all in-flight {@link Span} with {@link ClientCall.Listener} instance as key. */ - private final WeakMap, Span> clientCallListenerSpans; + private final ReferenceCountedMap, Span> clientCallListenerSpans; /** * Map of all in-flight {@link Transaction} with {@link ServerCall.Listener} instance as key. */ - private final WeakMap, Transaction> serverListenerTransactions; + private final ReferenceCountedMap, Transaction> serverListenerTransactions; /** * Map of all in-flight {@link Transaction} with {@link ServerCall} instance as key. */ - private final WeakMap, Transaction> serverCallTransactions; + private final ReferenceCountedMap, Transaction> serverCallTransactions; /** * gRPC header cache used to minimize allocations @@ -91,19 +91,18 @@ public static GrpcHelper getInstance() { private final Tracer tracer; public GrpcHelper() { - clientCallSpans = WeakConcurrentProviderImpl.createWeakSpanMap(); - delayedClientCallSpans = WeakConcurrentProviderImpl.createWeakSpanMap(); - clientCallListenerSpans = WeakConcurrentProviderImpl.createWeakSpanMap(); + tracer = GlobalTracer.get(); + clientCallSpans = tracer.newReferenceCountedMap(); + delayedClientCallSpans = tracer.newReferenceCountedMap(); + clientCallListenerSpans = tracer.newReferenceCountedMap(); - serverListenerTransactions = WeakConcurrentProviderImpl.createWeakSpanMap(); - serverCallTransactions = WeakConcurrentProviderImpl.createWeakSpanMap(); + serverListenerTransactions = tracer.newReferenceCountedMap(); + serverCallTransactions = tracer.newReferenceCountedMap(); headerCache = WeakConcurrent.buildMap(); headerSetter = new GrpcHeaderSetter(); headerGetter = new GrpcHeaderGetter(); - - tracer = GlobalTracer.get(); } // transaction management (server part) @@ -480,7 +479,7 @@ public void clientCallStartExit(@Nullable Span spanFromEntry, ClientCall.List } public void cancelCall(ClientCall clientCall, @Nullable Throwable cause) { - WeakMap, Span> clientCallMap = (isDelayedClientCall(clientCall)) ? delayedClientCallSpans : clientCallSpans; + ReferenceCountedMap, Span> clientCallMap = (isDelayedClientCall(clientCall)) ? delayedClientCallSpans : clientCallSpans; // we can't remove yet, in order to avoid reference decrement prematurely Span span = clientCallMap.get(clientCall); if (span != null) { diff --git a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/co/elastic/apm/agent/grpc/GrpcHelperTest.java b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/co/elastic/apm/agent/grpc/GrpcHelperTest.java index d0f59ddc86..755d62530b 100644 --- a/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/co/elastic/apm/agent/grpc/GrpcHelperTest.java +++ b/apm-agent-plugins/apm-grpc/apm-grpc-plugin/src/test/java/co/elastic/apm/agent/grpc/GrpcHelperTest.java @@ -18,6 +18,7 @@ */ package co.elastic.apm.agent.grpc; +import co.elastic.apm.agent.AbstractInstrumentationTest; import co.elastic.apm.agent.tracer.Outcome; import io.grpc.Status; import org.junit.jupiter.api.Test; @@ -26,7 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat; -class GrpcHelperTest { +class GrpcHelperTest extends AbstractInstrumentationTest { @ParameterizedTest @EnumSource(Status.Code.class) diff --git a/apm-agent-plugins/apm-java-concurrent-plugin/src/main/java/co/elastic/apm/agent/concurrent/JavaConcurrent.java b/apm-agent-plugins/apm-java-concurrent-plugin/src/main/java/co/elastic/apm/agent/concurrent/JavaConcurrent.java index 63a7bfa1a7..9507eec38d 100644 --- a/apm-agent-plugins/apm-java-concurrent-plugin/src/main/java/co/elastic/apm/agent/concurrent/JavaConcurrent.java +++ b/apm-agent-plugins/apm-java-concurrent-plugin/src/main/java/co/elastic/apm/agent/concurrent/JavaConcurrent.java @@ -18,14 +18,14 @@ */ package co.elastic.apm.agent.concurrent; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.common.ThreadUtils; import co.elastic.apm.agent.tracer.AbstractSpan; import co.elastic.apm.agent.sdk.DynamicTransformer; import co.elastic.apm.agent.sdk.ElasticApmInstrumentation; import co.elastic.apm.agent.sdk.state.GlobalState; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.GlobalTracer; import co.elastic.apm.agent.tracer.Tracer; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import javax.annotation.Nullable; import java.util.ArrayList; @@ -42,7 +42,7 @@ @GlobalState public class JavaConcurrent { - private static final WeakMap> contextMap = WeakConcurrentProviderImpl.createWeakSpanMap(); + private static final ReferenceCountedMap> contextMap = GlobalTracer.get().newReferenceCountedMap(); private static final List> RUNNABLE_CALLABLE_FJTASK_INSTRUMENTATION = Collections. >singletonList(RunnableCallableForkJoinTaskInstrumentation.class); diff --git a/apm-agent-plugins/apm-process-plugin/src/main/java/co/elastic/apm/agent/process/ProcessHelper.java b/apm-agent-plugins/apm-process-plugin/src/main/java/co/elastic/apm/agent/process/ProcessHelper.java index cae224ae09..8d94043238 100644 --- a/apm-agent-plugins/apm-process-plugin/src/main/java/co/elastic/apm/agent/process/ProcessHelper.java +++ b/apm-agent-plugins/apm-process-plugin/src/main/java/co/elastic/apm/agent/process/ProcessHelper.java @@ -18,12 +18,12 @@ */ package co.elastic.apm.agent.process; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.AbstractSpan; +import co.elastic.apm.agent.tracer.GlobalTracer; import co.elastic.apm.agent.tracer.Outcome; import co.elastic.apm.agent.tracer.Span; import co.elastic.apm.agent.sdk.state.GlobalVariables; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import javax.annotation.Nonnull; import java.util.List; @@ -34,7 +34,7 @@ */ class ProcessHelper { - private static final ProcessHelper INSTANCE = new ProcessHelper(WeakConcurrentProviderImpl.>createWeakSpanMap()); + private static final ProcessHelper INSTANCE = new ProcessHelper(GlobalTracer.get().>newReferenceCountedMap()); /** * A thread local used to indicate whether the currently invoked instrumented method is invoked by the plugin itself. @@ -44,9 +44,9 @@ class ProcessHelper { */ private static final ThreadLocal inTracingContext = GlobalVariables.get(ProcessHelper.class, "inTracingContext", new ThreadLocal()); - private final WeakMap> inFlightSpans; + private final ReferenceCountedMap> inFlightSpans; - ProcessHelper(WeakMap> inFlightSpans) { + ProcessHelper(ReferenceCountedMap> inFlightSpans) { this.inFlightSpans = inFlightSpans; } @@ -74,7 +74,7 @@ static void endProcessSpan(@Nonnull Process process, int exitValue) { * @param processName process name */ void doStartProcess(@Nonnull AbstractSpan parentContext, @Nonnull Process process, @Nonnull String processName) { - if (inFlightSpans.containsKey(process)) { + if (inFlightSpans.contains(process)) { return; } diff --git a/apm-agent-plugins/apm-process-plugin/src/test/java/co/elastic/apm/agent/process/ProcessHelperTest.java b/apm-agent-plugins/apm-process-plugin/src/test/java/co/elastic/apm/agent/process/ProcessHelperTest.java index ad6c06f4c0..84f95db191 100644 --- a/apm-agent-plugins/apm-process-plugin/src/test/java/co/elastic/apm/agent/process/ProcessHelperTest.java +++ b/apm-agent-plugins/apm-process-plugin/src/test/java/co/elastic/apm/agent/process/ProcessHelperTest.java @@ -25,9 +25,11 @@ import co.elastic.apm.agent.impl.transaction.Span; import co.elastic.apm.agent.impl.transaction.Transaction; import co.elastic.apm.agent.sdk.weakconcurrent.WeakConcurrent; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import javax.annotation.Nullable; import java.nio.file.Paths; import static org.assertj.core.api.Assertions.assertThat; @@ -57,7 +59,29 @@ void before() { TransactionUtils.fillTransaction(transaction); storageMap = WeakConcurrent.buildMap(); - helper = new ProcessHelper(storageMap); + helper = new ProcessHelper(new ReferenceCountedMap<>() { + @Nullable + @Override + public co.elastic.apm.agent.tracer.Span get(Process key) { + return storageMap.get(key); + } + + @Override + public boolean contains(Process key) { + return storageMap.containsKey(key); + } + + @Override + public void put(Process key, co.elastic.apm.agent.tracer.Span value) { + storageMap.put(key, value); + } + + @Nullable + @Override + public co.elastic.apm.agent.tracer.Span remove(Process key) { + return storageMap.remove(key); + } + }); } @Test diff --git a/apm-agent-plugins/apm-reactor-plugin/src/main/java/co/elastic/apm/agent/reactor/TracedSubscriber.java b/apm-agent-plugins/apm-reactor-plugin/src/main/java/co/elastic/apm/agent/reactor/TracedSubscriber.java index 3b6b64b505..7c6b6f3206 100644 --- a/apm-agent-plugins/apm-reactor-plugin/src/main/java/co/elastic/apm/agent/reactor/TracedSubscriber.java +++ b/apm-agent-plugins/apm-reactor-plugin/src/main/java/co/elastic/apm/agent/reactor/TracedSubscriber.java @@ -18,14 +18,15 @@ */ package co.elastic.apm.agent.reactor; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.AbstractSpan; import co.elastic.apm.agent.sdk.logging.Logger; import co.elastic.apm.agent.sdk.logging.LoggerFactory; import co.elastic.apm.agent.sdk.state.GlobalVariables; import co.elastic.apm.agent.sdk.weakconcurrent.WeakConcurrent; import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.GlobalTracer; import co.elastic.apm.agent.tracer.Tracer; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; @@ -46,7 +47,7 @@ public class TracedSubscriber implements CoreSubscriber { private static final AtomicBoolean isRegistered = GlobalVariables.get(ReactorInstrumentation.class, "reactor-hook-enabled", new AtomicBoolean(false)); - private static final WeakMap, AbstractSpan> contextMap = WeakConcurrentProviderImpl.createWeakSpanMap(); + private static final ReferenceCountedMap, AbstractSpan> contextMap = GlobalTracer.get().newReferenceCountedMap(); private static final String HOOK_KEY = "elastic-apm"; diff --git a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce34Instrumentation.java b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce34Instrumentation.java index 8dbe9a99e0..a96832a580 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce34Instrumentation.java +++ b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce34Instrumentation.java @@ -19,9 +19,8 @@ package co.elastic.apm.agent.lettuce; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.Span; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import com.lambdaworks.redis.protocol.RedisCommand; import net.bytebuddy.matcher.ElementMatcher; @@ -32,7 +31,7 @@ public abstract class Lettuce34Instrumentation extends TracerAwareInstrumentation { - static final WeakMap, Span> commandToSpan = WeakConcurrentProviderImpl.createWeakSpanMap(); + static final ReferenceCountedMap, Span> commandToSpan = tracer.newReferenceCountedMap(); /** * We don't support Lettuce up to version 3.3, as the {@link RedisCommand#getType()} method is missing diff --git a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce5StartSpanInstrumentation.java b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce5StartSpanInstrumentation.java index 6a32641b89..7cbcf9c314 100644 --- a/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce5StartSpanInstrumentation.java +++ b/apm-agent-plugins/apm-redis-plugin/apm-lettuce-plugin/src/main/java/co/elastic/apm/agent/lettuce/Lettuce5StartSpanInstrumentation.java @@ -19,10 +19,9 @@ package co.elastic.apm.agent.lettuce; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.Span; import co.elastic.apm.agent.redis.RedisSpanUtils; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import io.lettuce.core.protocol.RedisCommand; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -46,7 +45,7 @@ */ public class Lettuce5StartSpanInstrumentation extends TracerAwareInstrumentation { - static final WeakMap, Span> commandToSpan = WeakConcurrentProviderImpl.createWeakSpanMap(); + static final ReferenceCountedMap, Span> commandToSpan = tracer.newReferenceCountedMap(); @Override public ElementMatcher getTypeMatcher() { diff --git a/apm-agent-plugins/apm-scala-concurrent-plugin/src/main/java/co/elastic/apm/agent/scalaconcurrent/FutureInstrumentation.java b/apm-agent-plugins/apm-scala-concurrent-plugin/src/main/java/co/elastic/apm/agent/scalaconcurrent/FutureInstrumentation.java index 5fa4cd7bc5..8302093ddf 100644 --- a/apm-agent-plugins/apm-scala-concurrent-plugin/src/main/java/co/elastic/apm/agent/scalaconcurrent/FutureInstrumentation.java +++ b/apm-agent-plugins/apm-scala-concurrent-plugin/src/main/java/co/elastic/apm/agent/scalaconcurrent/FutureInstrumentation.java @@ -19,9 +19,8 @@ package co.elastic.apm.agent.scalaconcurrent; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.AbstractSpan; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; @@ -39,7 +38,7 @@ public abstract class FutureInstrumentation extends TracerAwareInstrumentation { @SuppressWarnings("WeakerAccess") - public static final WeakMap> promisesToContext = WeakConcurrentProviderImpl.createWeakSpanMap(); + public static final ReferenceCountedMap> promisesToContext = tracer.newReferenceCountedMap(); @Nonnull @Override diff --git a/apm-agent-plugins/apm-spring-webflux/apm-spring-webclient-plugin/src/main/java/co/elastic/apm/agent/springwebclient/WebClientSubscriber.java b/apm-agent-plugins/apm-spring-webflux/apm-spring-webclient-plugin/src/main/java/co/elastic/apm/agent/springwebclient/WebClientSubscriber.java index 53d9a90529..fbbd4467ce 100755 --- a/apm-agent-plugins/apm-spring-webflux/apm-spring-webclient-plugin/src/main/java/co/elastic/apm/agent/springwebclient/WebClientSubscriber.java +++ b/apm-agent-plugins/apm-spring-webflux/apm-spring-webclient-plugin/src/main/java/co/elastic/apm/agent/springwebclient/WebClientSubscriber.java @@ -18,11 +18,11 @@ */ package co.elastic.apm.agent.springwebclient; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.impl.context.web.ResultUtil; +import co.elastic.apm.agent.tracer.GlobalTracer; import co.elastic.apm.agent.tracer.Span; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; import co.elastic.apm.agent.tracer.Tracer; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import org.reactivestreams.Subscription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,7 +35,7 @@ public class WebClientSubscriber implements CoreSubscriber, Subscription { private static final Logger logger = LoggerFactory.getLogger(WebClientSubscriber.class); - private static final WeakMap, Span> spanMap = WeakConcurrentProviderImpl.createWeakSpanMap(); + private static final ReferenceCountedMap, Span> spanMap = GlobalTracer.get().newReferenceCountedMap(); private final Tracer tracer; private final CoreSubscriber subscriber; diff --git a/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-spring5/src/main/java/co/elastic/apm/agent/springwebflux/TransactionAwareSubscriber.java b/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-spring5/src/main/java/co/elastic/apm/agent/springwebflux/TransactionAwareSubscriber.java index 12b9cac98d..56a5983ed6 100644 --- a/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-spring5/src/main/java/co/elastic/apm/agent/springwebflux/TransactionAwareSubscriber.java +++ b/apm-agent-plugins/apm-spring-webflux/apm-spring-webflux-spring5/src/main/java/co/elastic/apm/agent/springwebflux/TransactionAwareSubscriber.java @@ -18,10 +18,10 @@ */ package co.elastic.apm.agent.springwebflux; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.AbstractSpan; +import co.elastic.apm.agent.tracer.GlobalTracer; import co.elastic.apm.agent.tracer.Transaction; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import co.elastic.apm.agent.sdk.logging.Logger; @@ -41,7 +41,7 @@ class TransactionAwareSubscriber implements CoreSubscriber, Subscription { private static final Logger log = LoggerFactory.getLogger(TransactionAwareSubscriber.class); - private static final WeakMap, Transaction> transactionMap = WeakConcurrentProviderImpl.createWeakSpanMap(); + private static final ReferenceCountedMap, Transaction> transactionMap = GlobalTracer.get().newReferenceCountedMap(); private final CoreSubscriber subscriber; diff --git a/apm-agent-plugins/apm-urlconnection-plugin/src/main/java/co/elastic/apm/agent/urlconnection/HttpUrlConnectionInstrumentation.java b/apm-agent-plugins/apm-urlconnection-plugin/src/main/java/co/elastic/apm/agent/urlconnection/HttpUrlConnectionInstrumentation.java index 4978e7485c..6ccb56b3a9 100644 --- a/apm-agent-plugins/apm-urlconnection-plugin/src/main/java/co/elastic/apm/agent/urlconnection/HttpUrlConnectionInstrumentation.java +++ b/apm-agent-plugins/apm-urlconnection-plugin/src/main/java/co/elastic/apm/agent/urlconnection/HttpUrlConnectionInstrumentation.java @@ -19,15 +19,14 @@ package co.elastic.apm.agent.urlconnection; import co.elastic.apm.agent.bci.TracerAwareInstrumentation; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.httpclient.HttpClientHelper; import co.elastic.apm.agent.tracer.AbstractSpan; import co.elastic.apm.agent.tracer.Outcome; import co.elastic.apm.agent.tracer.Span; import co.elastic.apm.agent.sdk.state.CallDepth; import co.elastic.apm.agent.sdk.state.GlobalState; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; import co.elastic.apm.agent.tracer.dispatch.HeaderUtils; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.NamedElement; import net.bytebuddy.description.method.MethodDescription; @@ -50,7 +49,7 @@ @GlobalState public abstract class HttpUrlConnectionInstrumentation extends TracerAwareInstrumentation { - public static final WeakMap inFlightSpans = WeakConcurrentProviderImpl.createWeakSpanMap(); + public static final ReferenceCountedMap> inFlightSpans = tracer.newReferenceCountedMap(); public static final CallDepth callDepth = CallDepth.get(HttpUrlConnectionInstrumentation.class); @Override diff --git a/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/src/main/java/co/elastic/apm/agent/vertx/v3/web/WebHelper.java b/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/src/main/java/co/elastic/apm/agent/vertx/v3/web/WebHelper.java index a7f787a44c..4f25c02a1a 100644 --- a/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/src/main/java/co/elastic/apm/agent/vertx/v3/web/WebHelper.java +++ b/apm-agent-plugins/apm-vertx/apm-vertx3-plugin/src/main/java/co/elastic/apm/agent/vertx/v3/web/WebHelper.java @@ -18,13 +18,12 @@ */ package co.elastic.apm.agent.vertx.v3.web; -import co.elastic.apm.agent.collections.WeakConcurrentProviderImpl; import co.elastic.apm.agent.tracer.GlobalTracer; import co.elastic.apm.agent.tracer.Tracer; import co.elastic.apm.agent.tracer.Transaction; import co.elastic.apm.agent.sdk.logging.Logger; import co.elastic.apm.agent.sdk.logging.LoggerFactory; -import co.elastic.apm.agent.sdk.weakconcurrent.WeakMap; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import co.elastic.apm.agent.vertx.AbstractVertxWebHelper; import io.vertx.core.Handler; import io.vertx.core.http.HttpServerRequest; @@ -38,7 +37,7 @@ public class WebHelper extends AbstractVertxWebHelper { private static final WebHelper INSTANCE = new WebHelper(GlobalTracer.get()); - static final WeakMap> transactionMap = WeakConcurrentProviderImpl.createWeakSpanMap(); + static final ReferenceCountedMap> transactionMap = GlobalTracer.get().newReferenceCountedMap(); public static WebHelper getInstance() { return INSTANCE; diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/AbstractSpan.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/AbstractSpan.java index d7d827e807..9cdd2eb076 100644 --- a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/AbstractSpan.java +++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/AbstractSpan.java @@ -22,10 +22,11 @@ import co.elastic.apm.agent.tracer.dispatch.BinaryHeaderSetter; import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter; import co.elastic.apm.agent.tracer.dispatch.TextHeaderSetter; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; import javax.annotation.Nullable; -public interface AbstractSpan> extends ElasticContext { +public interface AbstractSpan> extends ElasticContext, ReferenceCounted { int PRIORITY_DEFAULT = 0; int PRIORITY_LOW_LEVEL_FRAMEWORK = 10; diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java index 6916b2e23a..e012e0f04b 100644 --- a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java +++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/GlobalTracer.java @@ -21,6 +21,8 @@ import co.elastic.apm.agent.tracer.dispatch.BinaryHeaderGetter; import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter; import co.elastic.apm.agent.tracer.pooling.ObjectPoolFactory; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import javax.annotation.Nullable; import java.util.Set; @@ -82,6 +84,11 @@ public ObjectPoolFactory getObjectPoolFactory() { return tracer.getObjectPoolFactory(); } + @Override + public ReferenceCountedMap newReferenceCountedMap() { + return tracer.newReferenceCountedMap(); + } + @Override public Set getTraceHeaderNames() { return tracer.getTraceHeaderNames(); diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java index edca7331a7..4a0897397a 100644 --- a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java +++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/NoopTracer.java @@ -21,6 +21,8 @@ import co.elastic.apm.agent.tracer.dispatch.BinaryHeaderGetter; import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter; import co.elastic.apm.agent.tracer.pooling.ObjectPoolFactory; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import javax.annotation.Nullable; import java.util.Collections; @@ -59,6 +61,11 @@ public ObjectPoolFactory getObjectPoolFactory() { throw new IllegalStateException(); } + @Override + public ReferenceCountedMap newReferenceCountedMap() { + throw new IllegalStateException(); + } + @Override public Set getTraceHeaderNames() { return Collections.emptySet(); diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java index bef46b15b4..f3650830fc 100644 --- a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java +++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/Tracer.java @@ -22,6 +22,8 @@ import co.elastic.apm.agent.tracer.dispatch.HeaderGetter; import co.elastic.apm.agent.tracer.dispatch.TextHeaderGetter; import co.elastic.apm.agent.tracer.pooling.ObjectPoolFactory; +import co.elastic.apm.agent.tracer.reference.ReferenceCounted; +import co.elastic.apm.agent.tracer.reference.ReferenceCountedMap; import javax.annotation.Nullable; import java.util.Set; @@ -39,6 +41,8 @@ public interface Tracer { ObjectPoolFactory getObjectPoolFactory(); + ReferenceCountedMap newReferenceCountedMap(); + Set getTraceHeaderNames(); @Nullable diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/reference/ReferenceCounted.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/reference/ReferenceCounted.java new file mode 100644 index 0000000000..23ca749632 --- /dev/null +++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/reference/ReferenceCounted.java @@ -0,0 +1,26 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 co.elastic.apm.agent.tracer.reference; + +public interface ReferenceCounted { + + void incrementReferences(); + + void decrementReferences(); +} diff --git a/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/reference/ReferenceCountedMap.java b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/reference/ReferenceCountedMap.java new file mode 100644 index 0000000000..42ff17cc58 --- /dev/null +++ b/apm-agent-tracer/src/main/java/co/elastic/apm/agent/tracer/reference/ReferenceCountedMap.java @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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 co.elastic.apm.agent.tracer.reference; + +import javax.annotation.Nullable; + +public interface ReferenceCountedMap { + + @Nullable + V get(K key); + + boolean contains(K key); + + void put(K key, V value); + + @Nullable + V remove(K key); +}