core: fix old ClientStreamTracer.Factory creating tracers twice (#8381)

Fix a bug introduced in #8355 : old ClientStreamTracer.Factory implementation creates tracers twice.
This commit is contained in:
ZHANG Dapeng 2021-08-04 14:32:49 -07:00 committed by GitHub
parent 0d80c33bce
commit c77083f013
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 5 deletions

View File

@ -65,7 +65,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
@ -785,15 +784,22 @@ public final class GrpcUtil {
} else {
streamTracer = new ForwardingClientStreamTracer() {
final ClientStreamTracer noop = new ClientStreamTracer() {};
AtomicReference<ClientStreamTracer> delegate = new AtomicReference<>(noop);
volatile ClientStreamTracer delegate = noop;
void maybeInit(StreamInfo info, Metadata headers) {
delegate.compareAndSet(noop, streamTracerFactory.newClientStreamTracer(info, headers));
if (delegate != noop) {
return;
}
synchronized (this) {
if (delegate == noop) {
delegate = streamTracerFactory.newClientStreamTracer(info, headers);
}
}
}
@Override
protected ClientStreamTracer delegate() {
return delegate.get();
return delegate;
}
@SuppressWarnings("deprecation")

View File

@ -38,6 +38,7 @@ import io.grpc.Status;
import io.grpc.internal.ClientStreamListener.RpcProgress;
import io.grpc.internal.GrpcUtil.Http2Error;
import io.grpc.testing.TestMethodDescriptors;
import java.util.ArrayDeque;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Rule;
import org.junit.Test;
@ -301,12 +302,14 @@ public class GrpcUtilTest {
final AtomicReference<Attributes> transportAttrsRef = new AtomicReference<>();
final ClientStreamTracer mockTracer = mock(ClientStreamTracer.class);
final Metadata.Key<String> key = Metadata.Key.of("fake-key", Metadata.ASCII_STRING_MARSHALLER);
final ArrayDeque<ClientStreamTracer> tracers = new ArrayDeque<>();
ClientStreamTracer.Factory oldFactoryImpl = new ClientStreamTracer.Factory() {
@SuppressWarnings("deprecation")
@Override
public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
transportAttrsRef.set(info.getTransportAttrs());
headers.put(key, "fake-value");
tracers.offer(mockTracer);
return mockTracer;
}
};
@ -318,8 +321,12 @@ public class GrpcUtilTest {
Attributes.newBuilder().set(Attributes.Key.<String>create("foo"), "bar").build();
ClientStreamTracer tracer = GrpcUtil.newClientStreamTracer(oldFactoryImpl, info, metadata);
tracer.streamCreated(transAttrs, metadata);
assertThat(tracers.poll()).isSameInstanceAs(mockTracer);
assertThat(transportAttrsRef.get()).isEqualTo(transAttrs);
assertThat(metadata.get(key)).isEqualTo("fake-value");
tracer.streamClosed(Status.UNAVAILABLE);
// verify that newClientStreamTracer() is called no more than once
assertThat(tracers).isEmpty();
}
}