private void removeStream(IStream stream) { if (stream.isUnidirectional()) stream.getAssociatedStream().disassociate(stream); IStream removed = streams.remove(stream.getId()); if (removed != null) { assert removed == stream; if (streamIds.get() % 2 == stream.getId() % 2) localStreamCount.decrementAndGet(); if (LOG.isDebugEnabled()) LOG.debug("Removed {}", stream); notifyStreamClosed(stream); } }
@Override public int compareTo(FrameBytes that) { // FrameBytes may have or not have a related stream (for example, PING do not have a related stream) // FrameBytes without related streams have higher priority IStream thisStream = getStream(); IStream thatStream = that.getStream(); if (thisStream == null) return thatStream == null ? 0 : -1; if (thatStream == null) return 1; // If this.stream.priority > that.stream.priority => this.stream has less priority than that.stream return thatStream.getPriority() - thisStream.getPriority(); }
IStream stream = new StandardStream(frame.getStreamId(), frame.getPriority(), this, associatedStream, scheduler, promise); stream.setIdleTimeout(endPoint.getIdleTimeout()); flowControlStrategy.onNewStream(this, stream); stream.updateCloseState(frame.isClose(), local); stream.setStreamFrameListener(listener); if (stream.isUnidirectional()) stream.updateCloseState(true, !local); if (!stream.isClosed()) stream.getAssociatedStream().associate(stream); int streamId = stream.getId();
private void processSyn(SessionFrameListener listener, IStream stream, SynStreamFrame frame) { stream.process(frame); // Update the last stream id before calling the application (which may send a GO_AWAY) updateLastStreamId(stream); StreamFrameListener streamListener; if (stream.isUnidirectional()) { PushInfo pushInfo = new PushInfo(frame.getHeaders(), frame.isClose()); streamListener = notifyOnPush(stream.getAssociatedStream().getStreamFrameListener(), stream, pushInfo); } else { SynInfo synInfo = new SynInfo(frame.getHeaders(), frame.isClose(), frame.getPriority()); streamListener = notifyOnSyn(listener, stream, synInfo); } stream.setStreamFrameListener(streamListener); // The onSyn() listener may have sent a frame that closed the stream if (stream.isClosed()) removeStream(stream); }
if (stream.getWindowSize() <= 0) if (stream != null && stream.isReset() && frameBytes instanceof StandardSession.DataFrameBytes) frameBytes.failed(new StreamException(frameBytes.getStream().getId(), StreamStatus.INVALID_STREAM, "Stream: " + frameBytes.getStream() + " is reset!")); continue;
@Override public void onDataConsumed(ISession session, IStream stream, DataInfo dataInfo, int delta) { // This is the algorithm for flow control. // This method may be called multiple times with delta=1, but we only send a window // update when the whole dataInfo has been consumed. // Other policies may be to send window updates when consumed() is greater than // a certain threshold, etc. but for now the policy is not pluggable for simplicity. // Note that the frequency of window updates depends on the read buffer, that // should not be too smaller than the window size to avoid frequent window updates. // Therefore, a pluggable policy should be able to modify the read buffer capacity. int length = dataInfo.length(); if (dataInfo.consumed() == length && !stream.isClosed() && length > 0) { WindowUpdateFrame windowUpdateFrame = new WindowUpdateFrame(session.getVersion(), stream.getId(), length); session.control(stream, windowUpdateFrame, 0, TimeUnit.MILLISECONDS, Callback.Adapter.INSTANCE); } } }
int windowSize = stream.getWindowSize(); size = windowSize; buffer = generator.data(stream.getId(), size, dataInfo); return buffer;
@Override public void succeeded() { bufferPool.release(buffer); IStream stream = getStream(); dataInfo.consume(size); flowControlStrategy.updateWindow(StandardSession.this, stream, -size); if (dataInfo.available() > 0) { // We have written a frame out of this DataInfo, but there is more to write. // We need to keep the correct ordering of frames, to avoid that another // DataInfo for the same stream is written before this one is finished. flush(this, flusher.prepend(this)); } else { super.succeeded(); stream.updateCloseState(dataInfo.isClose(), true); if (stream.isClosed()) removeStream(stream); } }
private void updateLastStreamId(IStream stream) { int streamId = stream.getId(); if (streamId % 2 != streamIds.get() % 2) Atomics.updateMax(lastStreamId, streamId); }
@Override public void succeeded() { bufferPool.release(buffer); super.succeeded(); if (frame.getType() == ControlFrameType.GO_AWAY) { // After sending a GO_AWAY we need to hard close the connection. // Recipients will know the last good stream id and act accordingly. close(); } IStream stream = getStream(); if (stream != null && stream.isClosed()) removeStream(stream); }
private void processData(final IStream stream, DataFrame frame, ByteBuffer data) { ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(data, frame.isClose()) { @Override public void consume(int delta) { super.consume(delta); flowControlStrategy.onDataConsumed(StandardSession.this, stream, this, delta); } }; flowControlStrategy.onDataReceived(this, stream, dataInfo); stream.process(dataInfo); if (stream.isClosed()) removeStream(stream); }