338 lines
14 KiB
Java
338 lines
14 KiB
Java
|
package io.grpc.internal;
|
||
|
|
||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||
|
import com.google.common.util.concurrent.SettableFuture;
|
||
|
import io.grpc.CallOptions;
|
||
|
import io.grpc.ClientStreamTracer;
|
||
|
import io.grpc.Context;
|
||
|
import io.grpc.InternalChannelz;
|
||
|
import io.grpc.InternalLogId;
|
||
|
import io.grpc.LoadBalancer;
|
||
|
import io.grpc.Metadata;
|
||
|
import io.grpc.MethodDescriptor;
|
||
|
import io.grpc.Status;
|
||
|
import io.grpc.SynchronizationContext;
|
||
|
import io.grpc.internal.ClientStreamListener;
|
||
|
import io.grpc.internal.ClientTransport;
|
||
|
import io.grpc.internal.ManagedClientTransport;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.Collection;
|
||
|
import java.util.Collections;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.LinkedHashSet;
|
||
|
import java.util.concurrent.Executor;
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
/* loaded from: classes6.dex */
|
||
|
public final class DelayedClientTransport implements ManagedClientTransport {
|
||
|
private final Executor defaultAppExecutor;
|
||
|
private LoadBalancer.SubchannelPicker lastPicker;
|
||
|
private long lastPickerVersion;
|
||
|
private ManagedClientTransport.Listener listener;
|
||
|
private Runnable reportTransportInUse;
|
||
|
private Runnable reportTransportNotInUse;
|
||
|
private Runnable reportTransportTerminated;
|
||
|
private Status shutdownStatus;
|
||
|
private final SynchronizationContext syncContext;
|
||
|
private final InternalLogId logId = InternalLogId.allocate((Class<?>) DelayedClientTransport.class, (String) null);
|
||
|
private final Object lock = new Object();
|
||
|
private Collection<PendingStream> pendingStreams = new LinkedHashSet();
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public DelayedClientTransport(Executor executor, SynchronizationContext synchronizationContext) {
|
||
|
this.defaultAppExecutor = executor;
|
||
|
this.syncContext = synchronizationContext;
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.ManagedClientTransport
|
||
|
public final Runnable start(ManagedClientTransport.Listener listener) {
|
||
|
this.listener = listener;
|
||
|
this.reportTransportInUse = new Runnable(this, listener) { // from class: io.grpc.internal.DelayedClientTransport.1
|
||
|
final DelayedClientTransport this$0;
|
||
|
final ManagedClientTransport.Listener val$listener;
|
||
|
|
||
|
{
|
||
|
this.this$0 = this;
|
||
|
this.val$listener = listener;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Runnable
|
||
|
public void run() {
|
||
|
this.val$listener.transportInUse(true);
|
||
|
}
|
||
|
};
|
||
|
this.reportTransportNotInUse = new Runnable(this, listener) { // from class: io.grpc.internal.DelayedClientTransport.2
|
||
|
final DelayedClientTransport this$0;
|
||
|
final ManagedClientTransport.Listener val$listener;
|
||
|
|
||
|
{
|
||
|
this.this$0 = this;
|
||
|
this.val$listener = listener;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Runnable
|
||
|
public void run() {
|
||
|
this.val$listener.transportInUse(false);
|
||
|
}
|
||
|
};
|
||
|
this.reportTransportTerminated = new Runnable(this, listener) { // from class: io.grpc.internal.DelayedClientTransport.3
|
||
|
final DelayedClientTransport this$0;
|
||
|
final ManagedClientTransport.Listener val$listener;
|
||
|
|
||
|
{
|
||
|
this.this$0 = this;
|
||
|
this.val$listener = listener;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Runnable
|
||
|
public void run() {
|
||
|
this.val$listener.transportTerminated();
|
||
|
}
|
||
|
};
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.ClientTransport
|
||
|
public final ClientStream newStream(MethodDescriptor<?, ?> methodDescriptor, Metadata metadata, CallOptions callOptions, ClientStreamTracer[] clientStreamTracerArr) {
|
||
|
ClientStream failingClientStream;
|
||
|
try {
|
||
|
PickSubchannelArgsImpl pickSubchannelArgsImpl = new PickSubchannelArgsImpl(methodDescriptor, metadata, callOptions);
|
||
|
LoadBalancer.SubchannelPicker subchannelPicker = null;
|
||
|
long j = -1;
|
||
|
while (true) {
|
||
|
synchronized (this.lock) {
|
||
|
if (this.shutdownStatus != null) {
|
||
|
failingClientStream = new FailingClientStream(this.shutdownStatus, clientStreamTracerArr);
|
||
|
break;
|
||
|
}
|
||
|
LoadBalancer.SubchannelPicker subchannelPicker2 = this.lastPicker;
|
||
|
if (subchannelPicker2 != null) {
|
||
|
if (subchannelPicker != null && j == this.lastPickerVersion) {
|
||
|
failingClientStream = createPendingStream(pickSubchannelArgsImpl, clientStreamTracerArr);
|
||
|
break;
|
||
|
}
|
||
|
j = this.lastPickerVersion;
|
||
|
ClientTransport transportFromPickResult = GrpcUtil.getTransportFromPickResult(subchannelPicker2.pickSubchannel(pickSubchannelArgsImpl), callOptions.isWaitForReady());
|
||
|
if (transportFromPickResult != null) {
|
||
|
failingClientStream = transportFromPickResult.newStream(pickSubchannelArgsImpl.getMethodDescriptor(), pickSubchannelArgsImpl.getHeaders(), pickSubchannelArgsImpl.getCallOptions(), clientStreamTracerArr);
|
||
|
break;
|
||
|
}
|
||
|
subchannelPicker = subchannelPicker2;
|
||
|
} else {
|
||
|
failingClientStream = createPendingStream(pickSubchannelArgsImpl, clientStreamTracerArr);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return failingClientStream;
|
||
|
} finally {
|
||
|
this.syncContext.drain();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private PendingStream createPendingStream(LoadBalancer.PickSubchannelArgs pickSubchannelArgs, ClientStreamTracer[] clientStreamTracerArr) {
|
||
|
PendingStream pendingStream = new PendingStream(pickSubchannelArgs, clientStreamTracerArr);
|
||
|
this.pendingStreams.add(pendingStream);
|
||
|
if (getPendingStreamsCount() == 1) {
|
||
|
this.syncContext.executeLater(this.reportTransportInUse);
|
||
|
}
|
||
|
return pendingStream;
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.ClientTransport
|
||
|
public final void ping(ClientTransport.PingCallback pingCallback, Executor executor) {
|
||
|
throw new UnsupportedOperationException("This method is not expected to be called");
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.InternalInstrumented
|
||
|
public final ListenableFuture<InternalChannelz.SocketStats> getStats() {
|
||
|
SettableFuture create = SettableFuture.create();
|
||
|
create.set(null);
|
||
|
return create;
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.ManagedClientTransport
|
||
|
public final void shutdown(Status status) {
|
||
|
Runnable runnable;
|
||
|
synchronized (this.lock) {
|
||
|
if (this.shutdownStatus != null) {
|
||
|
return;
|
||
|
}
|
||
|
this.shutdownStatus = status;
|
||
|
this.syncContext.executeLater(new Runnable(this, status) { // from class: io.grpc.internal.DelayedClientTransport.4
|
||
|
final DelayedClientTransport this$0;
|
||
|
final Status val$status;
|
||
|
|
||
|
{
|
||
|
this.this$0 = this;
|
||
|
this.val$status = status;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Runnable
|
||
|
public void run() {
|
||
|
this.this$0.listener.transportShutdown(this.val$status);
|
||
|
}
|
||
|
});
|
||
|
if (!hasPendingStreams() && (runnable = this.reportTransportTerminated) != null) {
|
||
|
this.syncContext.executeLater(runnable);
|
||
|
this.reportTransportTerminated = null;
|
||
|
}
|
||
|
this.syncContext.drain();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.ManagedClientTransport
|
||
|
public final void shutdownNow(Status status) {
|
||
|
Collection<PendingStream> collection;
|
||
|
Runnable runnable;
|
||
|
shutdown(status);
|
||
|
synchronized (this.lock) {
|
||
|
collection = this.pendingStreams;
|
||
|
runnable = this.reportTransportTerminated;
|
||
|
this.reportTransportTerminated = null;
|
||
|
if (!collection.isEmpty()) {
|
||
|
this.pendingStreams = Collections.emptyList();
|
||
|
}
|
||
|
}
|
||
|
if (runnable != null) {
|
||
|
for (PendingStream pendingStream : collection) {
|
||
|
Runnable stream = pendingStream.setStream(new FailingClientStream(status, ClientStreamListener.RpcProgress.REFUSED, pendingStream.tracers));
|
||
|
if (stream != null) {
|
||
|
stream.run();
|
||
|
}
|
||
|
}
|
||
|
this.syncContext.execute(runnable);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public final boolean hasPendingStreams() {
|
||
|
boolean isEmpty;
|
||
|
synchronized (this.lock) {
|
||
|
isEmpty = this.pendingStreams.isEmpty();
|
||
|
}
|
||
|
return !isEmpty;
|
||
|
}
|
||
|
|
||
|
final int getPendingStreamsCount() {
|
||
|
int size;
|
||
|
synchronized (this.lock) {
|
||
|
size = this.pendingStreams.size();
|
||
|
}
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
public final void reprocess(LoadBalancer.SubchannelPicker subchannelPicker) {
|
||
|
Runnable runnable;
|
||
|
synchronized (this.lock) {
|
||
|
this.lastPicker = subchannelPicker;
|
||
|
this.lastPickerVersion++;
|
||
|
if (subchannelPicker != null && hasPendingStreams()) {
|
||
|
ArrayList arrayList = new ArrayList(this.pendingStreams);
|
||
|
ArrayList arrayList2 = new ArrayList();
|
||
|
Iterator it = arrayList.iterator();
|
||
|
while (it.hasNext()) {
|
||
|
PendingStream pendingStream = (PendingStream) it.next();
|
||
|
LoadBalancer.PickResult pickSubchannel = subchannelPicker.pickSubchannel(pendingStream.args);
|
||
|
CallOptions callOptions = pendingStream.args.getCallOptions();
|
||
|
ClientTransport transportFromPickResult = GrpcUtil.getTransportFromPickResult(pickSubchannel, callOptions.isWaitForReady());
|
||
|
if (transportFromPickResult != null) {
|
||
|
Executor executor = this.defaultAppExecutor;
|
||
|
if (callOptions.getExecutor() != null) {
|
||
|
executor = callOptions.getExecutor();
|
||
|
}
|
||
|
Runnable createRealStream = pendingStream.createRealStream(transportFromPickResult);
|
||
|
if (createRealStream != null) {
|
||
|
executor.execute(createRealStream);
|
||
|
}
|
||
|
arrayList2.add(pendingStream);
|
||
|
}
|
||
|
}
|
||
|
synchronized (this.lock) {
|
||
|
if (hasPendingStreams()) {
|
||
|
this.pendingStreams.removeAll(arrayList2);
|
||
|
if (this.pendingStreams.isEmpty()) {
|
||
|
this.pendingStreams = new LinkedHashSet();
|
||
|
}
|
||
|
if (!hasPendingStreams()) {
|
||
|
this.syncContext.executeLater(this.reportTransportNotInUse);
|
||
|
if (this.shutdownStatus != null && (runnable = this.reportTransportTerminated) != null) {
|
||
|
this.syncContext.executeLater(runnable);
|
||
|
this.reportTransportTerminated = null;
|
||
|
}
|
||
|
}
|
||
|
this.syncContext.drain();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: package-private */
|
||
|
/* loaded from: classes6.dex */
|
||
|
public class PendingStream extends DelayedStream {
|
||
|
private final LoadBalancer.PickSubchannelArgs args;
|
||
|
private final Context context;
|
||
|
final DelayedClientTransport this$0;
|
||
|
private final ClientStreamTracer[] tracers;
|
||
|
|
||
|
private PendingStream(DelayedClientTransport delayedClientTransport, LoadBalancer.PickSubchannelArgs pickSubchannelArgs, ClientStreamTracer[] clientStreamTracerArr) {
|
||
|
this.this$0 = delayedClientTransport;
|
||
|
this.context = Context.current();
|
||
|
this.args = pickSubchannelArgs;
|
||
|
this.tracers = clientStreamTracerArr;
|
||
|
}
|
||
|
|
||
|
/* JADX INFO: Access modifiers changed from: private */
|
||
|
public Runnable createRealStream(ClientTransport clientTransport) {
|
||
|
Context attach = this.context.attach();
|
||
|
try {
|
||
|
ClientStream newStream = clientTransport.newStream(this.args.getMethodDescriptor(), this.args.getHeaders(), this.args.getCallOptions(), this.tracers);
|
||
|
this.context.detach(attach);
|
||
|
return setStream(newStream);
|
||
|
} catch (Throwable th) {
|
||
|
this.context.detach(attach);
|
||
|
throw th;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.DelayedStream, io.grpc.internal.ClientStream
|
||
|
public void cancel(Status status) {
|
||
|
super.cancel(status);
|
||
|
synchronized (this.this$0.lock) {
|
||
|
if (this.this$0.reportTransportTerminated != null) {
|
||
|
boolean remove = this.this$0.pendingStreams.remove(this);
|
||
|
if (!this.this$0.hasPendingStreams() && remove) {
|
||
|
this.this$0.syncContext.executeLater(this.this$0.reportTransportNotInUse);
|
||
|
if (this.this$0.shutdownStatus != null) {
|
||
|
this.this$0.syncContext.executeLater(this.this$0.reportTransportTerminated);
|
||
|
this.this$0.reportTransportTerminated = null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this.this$0.syncContext.drain();
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.DelayedStream
|
||
|
protected void onEarlyCancellation(Status status) {
|
||
|
for (ClientStreamTracer clientStreamTracer : this.tracers) {
|
||
|
clientStreamTracer.streamClosed(status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.internal.DelayedStream, io.grpc.internal.ClientStream
|
||
|
public void appendTimeoutInsight(InsightBuilder insightBuilder) {
|
||
|
if (this.args.getCallOptions().isWaitForReady()) {
|
||
|
insightBuilder.append("wait_for_ready");
|
||
|
}
|
||
|
super.appendTimeoutInsight(insightBuilder);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override // io.grpc.InternalWithLogId
|
||
|
public final InternalLogId getLogId() {
|
||
|
return this.logId;
|
||
|
}
|
||
|
}
|