Skip to content

Commit c77083f

Browse files
authored
core: fix old ClientStreamTracer.Factory creating tracers twice (grpc#8381)
Fix a bug introduced in grpc#8355 : old ClientStreamTracer.Factory implementation creates tracers twice.
1 parent 0d80c33 commit c77083f

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

core/src/main/java/io/grpc/internal/GrpcUtil.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
import java.util.concurrent.ScheduledExecutorService;
6666
import java.util.concurrent.ThreadFactory;
6767
import java.util.concurrent.TimeUnit;
68-
import java.util.concurrent.atomic.AtomicReference;
6968
import java.util.logging.Level;
7069
import java.util.logging.Logger;
7170
import javax.annotation.Nullable;
@@ -785,15 +784,22 @@ static ClientStreamTracer newClientStreamTracer(
785784
} else {
786785
streamTracer = new ForwardingClientStreamTracer() {
787786
final ClientStreamTracer noop = new ClientStreamTracer() {};
788-
AtomicReference<ClientStreamTracer> delegate = new AtomicReference<>(noop);
787+
volatile ClientStreamTracer delegate = noop;
789788

790789
void maybeInit(StreamInfo info, Metadata headers) {
791-
delegate.compareAndSet(noop, streamTracerFactory.newClientStreamTracer(info, headers));
790+
if (delegate != noop) {
791+
return;
792+
}
793+
synchronized (this) {
794+
if (delegate == noop) {
795+
delegate = streamTracerFactory.newClientStreamTracer(info, headers);
796+
}
797+
}
792798
}
793799

794800
@Override
795801
protected ClientStreamTracer delegate() {
796-
return delegate.get();
802+
return delegate;
797803
}
798804

799805
@SuppressWarnings("deprecation")

core/src/test/java/io/grpc/internal/GrpcUtilTest.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import io.grpc.internal.ClientStreamListener.RpcProgress;
3939
import io.grpc.internal.GrpcUtil.Http2Error;
4040
import io.grpc.testing.TestMethodDescriptors;
41+
import java.util.ArrayDeque;
4142
import java.util.concurrent.atomic.AtomicReference;
4243
import org.junit.Rule;
4344
import org.junit.Test;
@@ -301,12 +302,14 @@ public void clientStreamTracerFactoryBackwardCompatibility() {
301302
final AtomicReference<Attributes> transportAttrsRef = new AtomicReference<>();
302303
final ClientStreamTracer mockTracer = mock(ClientStreamTracer.class);
303304
final Metadata.Key<String> key = Metadata.Key.of("fake-key", Metadata.ASCII_STRING_MARSHALLER);
305+
final ArrayDeque<ClientStreamTracer> tracers = new ArrayDeque<>();
304306
ClientStreamTracer.Factory oldFactoryImpl = new ClientStreamTracer.Factory() {
305307
@SuppressWarnings("deprecation")
306308
@Override
307309
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
308310
transportAttrsRef.set(info.getTransportAttrs());
309311
headers.put(key, "fake-value");
312+
tracers.offer(mockTracer);
310313
return mockTracer;
311314
}
312315
};
@@ -318,8 +321,12 @@ public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata header
318321
Attributes.newBuilder().set(Attributes.Key.<String>create("foo"), "bar").build();
319322
ClientStreamTracer tracer = GrpcUtil.newClientStreamTracer(oldFactoryImpl, info, metadata);
320323
tracer.streamCreated(transAttrs, metadata);
321-
324+
assertThat(tracers.poll()).isSameInstanceAs(mockTracer);
322325
assertThat(transportAttrsRef.get()).isEqualTo(transAttrs);
323326
assertThat(metadata.get(key)).isEqualTo("fake-value");
327+
328+
tracer.streamClosed(Status.UNAVAILABLE);
329+
// verify that newClientStreamTracer() is called no more than once
330+
assertThat(tracers).isEmpty();
324331
}
325332
}

0 commit comments

Comments
 (0)