Example #1
0
  @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();
  }
Example #2
0
 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();
   }
 }
Example #3
0
  @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();
  }
Example #4
0
 @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);
 }
Example #5
0
 @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);
 }
Example #6
0
 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;
         }
     }
   }
 }