All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.agent.shaded.grpc.internal.DelayedStream Maven / Gradle / Ivy

There is a newer version: 0.9.24
Show newest version
/*
 * Copyright 2015, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 *    * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.glowroot.agent.shaded.grpc.internal;

import static org.glowroot.agent.shaded.google.common.base.Preconditions.checkNotNull;
import static org.glowroot.agent.shaded.google.common.base.Preconditions.checkState;

import org.glowroot.agent.shaded.grpc.Compressor;
import org.glowroot.agent.shaded.grpc.Decompressor;
import org.glowroot.agent.shaded.grpc.Metadata;
import org.glowroot.agent.shaded.grpc.Status;

import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;

import javax.annotation.concurrent.GuardedBy;

/**
 * A stream that queues requests before the transport is available, and delegates to a real stream
 * implementation when the transport is available.
 *
 * 

{@code ClientStream} itself doesn't require thread-safety. However, the state of {@code * DelayedStream} may be internally altered by different threads, thus internal synchronization is * necessary. */ // TODO(zhangkun83): merge it with DelayedClientTransport.PendingStream as it will be no longer // needed by ClientCallImpl as we move away from ListenableFuture class DelayedStream implements ClientStream { // set to non null once both listener and realStream are valid. After this point it is safe // to call methods on startedRealStream. Note: this may be true even after the delayed stream is // cancelled. This should be okay. private volatile ClientStream startedRealStream; @GuardedBy("this") private String authority; @GuardedBy("this") private ClientStreamListener listener; @GuardedBy("this") private ClientStream realStream; @GuardedBy("this") private Status error; @GuardedBy("this") private final List pendingMessages = new LinkedList(); private boolean messageCompressionEnabled; @GuardedBy("this") private boolean pendingHalfClose; @GuardedBy("this") private int pendingFlowControlRequests; @GuardedBy("this") private boolean pendingFlush; @GuardedBy("this") private Compressor compressor; @GuardedBy("this") private Decompressor decompressor; static final class PendingMessage { final InputStream message; final boolean shouldBeCompressed; public PendingMessage(InputStream message, boolean shouldBeCompressed) { this.message = message; this.shouldBeCompressed = shouldBeCompressed; } } @Override public synchronized void setAuthority(String authority) { checkState(listener == null, "must be called before start"); checkNotNull(authority, "authority"); if (realStream == null) { this.authority = authority; } else { realStream.setAuthority(authority); } } @Override public void start(ClientStreamListener listener) { synchronized (this) { // start may be called at most once. checkState(this.listener == null, "already started"); this.listener = checkNotNull(listener, "listener"); // Check error first rather than success. if (error != null) { listener.closed(error, new Metadata()); } // In the event that an error happened, realStream will be a noop stream. We still call // start stream in order to drain references to pending messages. if (realStream != null) { startStream(); } } } @GuardedBy("this") private void startStream() { checkState(realStream != null, "realStream"); checkState(listener != null, "listener"); realStream.start(listener); if (decompressor != null) { realStream.setDecompressor(decompressor); } if (compressor != null) { realStream.setCompressor(compressor); } for (PendingMessage message : pendingMessages) { realStream.setMessageCompression(message.shouldBeCompressed); realStream.writeMessage(message.message); } // Set this again, incase no messages were sent. realStream.setMessageCompression(messageCompressionEnabled); pendingMessages.clear(); if (pendingHalfClose) { realStream.halfClose(); pendingHalfClose = false; } if (pendingFlowControlRequests > 0) { realStream.request(pendingFlowControlRequests); pendingFlowControlRequests = 0; } if (pendingFlush) { realStream.flush(); pendingFlush = false; } // Ensures visibility. startedRealStream = realStream; } void setStream(ClientStream stream) { synchronized (this) { if (error != null) { // If there is an error, unstartedStream will be a Noop. return; } checkState(realStream == null, "Stream already created: %s", realStream); realStream = checkNotNull(stream, "stream"); // listener can only be non-null if start has already been called. if (listener != null) { startStream(); } } } void setError(Status reason) { synchronized (this) { // If the client has already cancelled the stream don't bother keeping the next error. if (error == null) { error = checkNotNull(reason); realStream = NoopClientStream.INSTANCE; if (listener != null) { listener.closed(error, new Metadata()); // call startStream anyways to drain pending messages. startStream(); } } } } @Override public void writeMessage(InputStream message) { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { pendingMessages.add(new PendingMessage(message, messageCompressionEnabled)); return; } } } startedRealStream.writeMessage(message); } @Override public void flush() { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { pendingFlush = true; return; } } } startedRealStream.flush(); } @Override public void cancel(Status reason) { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { setError(reason); return; } } } startedRealStream.cancel(reason); } @Override public void halfClose() { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { pendingHalfClose = true; return; } } } startedRealStream.halfClose(); } @Override public void request(int numMessages) { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { pendingFlowControlRequests += numMessages; return; } } } startedRealStream.request(numMessages); } @Override public void setCompressor(Compressor compressor) { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { this.compressor = compressor; return; } } } startedRealStream.setCompressor(compressor); } @Override public void setDecompressor(Decompressor decompressor) { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { this.decompressor = decompressor; return; } } } startedRealStream.setDecompressor(decompressor); } @Override public boolean isReady() { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { return false; } } } return startedRealStream.isReady(); } @Override public void setMessageCompression(boolean enable) { if (startedRealStream == null) { synchronized (this) { if (startedRealStream == null) { messageCompressionEnabled = enable; return; } } } startedRealStream.setMessageCompression(enable); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy