@Override public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener) { // Synchronization is necessary to atomically create // the stream id and enqueue the frame to be sent. boolean queued; synchronized (this) { int streamId = frame.getStreamId(); if (streamId <= 0) { streamId = streamIds.getAndAdd(2); PriorityFrame priority = frame.getPriority(); priority = priority == null ? null : new PriorityFrame( streamId, priority.getParentStreamId(), priority.getWeight(), priority.isExclusive()); frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream()); } final IStream stream = createLocalStream(streamId, promise); if (stream == null) return; stream.setListener(listener); ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream)); queued = flusher.append(entry); } // Iterate outside the synchronized block. if (queued) flusher.iterate(); }
private void frame(HTTP2Flusher.Entry entry, boolean flush) { if (LOG.isDebugEnabled()) LOG.debug("{} {}", flush ? "Sending" : "Queueing", entry.frame); // Ping frames are prepended to process them as soon as possible. boolean queued = entry.frame.getType() == FrameType.PING ? flusher.prepend(entry) : flusher.append(entry); if (queued && flush) { if (entry.stream != null) entry.stream.notIdle(); flusher.iterate(); } }
@Override public void push( IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener) { // Synchronization is necessary to atomically create // the stream id and enqueue the frame to be sent. boolean queued; synchronized (this) { int streamId = streamIds.getAndAdd(2); frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData()); final IStream pushStream = createLocalStream(streamId, promise); if (pushStream == null) return; pushStream.setListener(listener); ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream)); queued = flusher.append(entry); } // Iterate outside the synchronized block. if (queued) flusher.iterate(); }
@Override public void onWindowUpdate(IStream stream, WindowUpdateFrame frame) { // WindowUpdateFrames arrive concurrently with writes. // Increasing (or reducing) the window size concurrently // with writes requires coordination with the flusher, that // decides how many frames to write depending on the available // window sizes. If the window sizes vary concurrently, the // flusher may take non-optimal or wrong decisions. // Here, we "queue" window updates to the flusher, so it will // be the only component responsible for window updates, for // both increments and reductions. flusher.window(stream, frame); }
@Override public String toString() { return String.format( "%s@%x{l:%s <-> r:%s,queueSize=%d,sendWindow=%s,recvWindow=%s,streams=%d,%s}", getClass().getSimpleName(), hashCode(), getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress(), flusher.getQueueSize(), sendWindow, recvWindow, streams.size(), closed); }
private void terminate(Throwable cause) { while (true) { CloseState current = closed.get(); switch (current) { case NOT_CLOSED: case LOCALLY_CLOSED: case REMOTELY_CLOSED: { if (closed.compareAndSet(current, CloseState.CLOSED)) { flusher.terminate(cause); for (IStream stream : streams.values()) stream.close(); streams.clear(); disconnect(); return; } break; } default: { return; } } } }