private boolean tryEmit(Buffer buffer) {

      IN next;

      Iterator<Buffer.View> views = codec.iterateDecode(buffer, decoderContext);

      if (!views.hasNext()) {
        combine(buffer);
        return false;
      }

      Buffer.View cursor;

      while (views.hasNext()) {
        cursor = views.next();
        if (cursor != null) {
          next = codec.decodeNext(cursor.get(), decoderContext);
          if (next != null && BackpressureUtils.getAndSub(PENDING_UPDATER, this, 1L) > 0) {
            subscriber.onNext(next);
          } else {
            combine(buffer.slice(cursor.getStart(), buffer.limit()));
            return next != null;
          }
        } else {
          combine(buffer);
          return false;
        }
      }
      if (buffer.remaining() > 0) {
        combine(buffer);
        return false;
      }
      return true;
    }
Beispiel #2
0
 @Override
 public Buffer get() {
   Buffer b = Buffer.this.duplicate();
   b.limit(end);
   b.position(start);
   return b;
 }
Beispiel #3
0
  /**
   * Create a new {@code Buffer} by copying the underlying {@link ByteBuffer} into a newly-allocated
   * {@code Buffer}.
   *
   * @return the new {@code Buffer}
   */
  public Buffer copy() {
    if (buffer == null) return new Buffer();
    snapshot();
    Buffer b = new Buffer(buffer.remaining(), false);
    b.append(buffer);
    reset();

    return b.flip();
  }
Beispiel #4
0
 @Override
 public boolean equals(Object o) {
   if (this == o) return true;
   if (!(o instanceof Buffer)) {
     return false;
   }
   Buffer that = (Buffer) o;
   return buffer.equals(that.byteBuffer());
 }
Beispiel #5
0
  /**
   * Very efficient method for parsing an {@link Integer} from the given {@literal Buffer} range.
   * Much faster than {@link Integer#parseInt(String)}.
   *
   * @param b The {@literal Buffer} to slice.
   * @param start start of the range.
   * @param end end of the range.
   * @return The int value or {@literal null} if the {@literal Buffer} could not be read.
   */
  public static Integer parseInt(Buffer b, int start, int end) {
    b.snapshot();

    b.buffer.limit(end);
    b.buffer.position(start);

    Integer i = parseInt(b);

    b.reset();

    return i;
  }
Beispiel #6
0
 /**
  * Append the given {@link Buffer} to this {@literal Buffer}.
  *
  * @param buffers The {@link Buffer Buffers} to append.
  * @return {@literal this}
  */
 public Buffer append(Buffer... buffers) {
   if (buffers == null) return this;
   for (Buffer b : buffers) {
     if (b == null) continue;
     int pos = position();
     int len = b.remaining();
     ensureCapacity(len);
     if (b.byteBuffer() != null) {
       buffer.put(b.byteBuffer());
       buffer.position(pos + len);
     }
   }
   return this;
 }
 @Override
 public IN apply(Buffer buffer) {
   if (consumer != null) {
     int pos;
     while ((pos = buffer.position()) < buffer.limit()) {
       super.apply(buffer);
       if (pos == buffer.position()) {
         break;
       }
     }
     return null;
   }
   return super.apply(buffer);
 }
 private String readTypeName(Buffer buffer) {
   int len = buffer.readInt();
   if (buffer.remaining() <= len) {
     throw new IllegalArgumentException(
         "Incomplete buffer. Must contain "
             + len
             + " bytes, "
             + "but only "
             + buffer.remaining()
             + " were found.");
   }
   byte[] bytes = new byte[len];
   buffer.read(bytes);
   return new String(bytes);
 }
  @Override
  protected IN decodeNext(Buffer buffer, Object context) {
    try {
      Class<IN> clazz = readType(buffer);
      byte[] bytes = buffer.asBytes();
      buffer.position(buffer.limit());

      return deserializer(engine, clazz).apply(bytes);
    } catch (RuntimeException e) {
      if (log.isErrorEnabled()) {
        log.error("Could not decode " + buffer, e);
      }
      throw e;
    }
  }
Beispiel #10
0
  /**
   * Split this buffer on the given delimiter. Save memory by reusing the provided {@code List}. The
   * delimiter is stripped from the end of the segment if {@code stripDelimiter} is {@code true}.
   *
   * @param views The already-allocated List to reuse.
   * @param delimiter The multi-byte delimiter.
   * @param stripDelimiter {@literal true} to ignore the delimiter, {@literal false} to leave it in
   *     the returned data.
   * @return An {@link Iterable} of {@link View Views} that point to the segments of this buffer.
   */
  public Iterable<View> split(List<View> views, Buffer delimiter, boolean stripDelimiter) {
    snapshot();

    byte[] delimBytes = delimiter.asBytes();
    if (delimBytes.length == 0) {
      return Collections.emptyList();
    }

    int start = this.position;
    for (byte b : this) {
      if (b != delimBytes[0]) {
        continue;
      }
      int end = -1;
      for (int i = 1; i < delimBytes.length; i++) {
        if (read() == delimBytes[i]) {
          end = stripDelimiter ? buffer.position() - delimBytes.length : buffer.position();
        } else {
          end = -1;
          break;
        }
      }
      if (end > 0) {
        views.add(createView(start, end));
        start = end + (stripDelimiter ? delimBytes.length : 0);
      }
    }
    if (start != buffer.position()) {
      buffer.position(start);
    }

    reset();

    return views;
  }
Beispiel #11
0
  @Test
  public void testAutoExpand() {

    int initial_small_size = Buffer.SMALL_BUFFER_SIZE;
    int initial_max_size = Buffer.MAX_BUFFER_SIZE;
    try {
      Buffer b = new Buffer();
      Buffer.SMALL_BUFFER_SIZE = 20; // to speed up the test
      Buffer.MAX_BUFFER_SIZE = 100;
      for (int i = 0; i < Buffer.MAX_BUFFER_SIZE - Buffer.SMALL_BUFFER_SIZE; i++) {
        b.append((byte) 0x1);
      }
    } finally {
      Buffer.SMALL_BUFFER_SIZE = initial_small_size;
      Buffer.MAX_BUFFER_SIZE = initial_max_size;
    }
  }
  @Test
  public void testCompleteSignalIsReceived() throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext());
    Flux.just(Buffer.wrap("One"), Buffer.wrap("Two"), Buffer.wrap("Three")).subscribe(processor);

    TestSubscriber<String> subscriber = TestSubscriber.create(0);
    Buffer.bufferToString(processor).subscribe(subscriber);

    subscriber.request(1);
    subscriber.awaitAndAssertNextValues("One");

    subscriber.request(1);
    subscriber.awaitAndAssertNextValues("Two");

    subscriber.request(1);
    subscriber.awaitAndAssertNextValues("Three").assertComplete();
  }
 @Override
 protected ChannelFuture doOnWrite(Object data, ChannelHandlerContext ctx) {
   if (data.getClass().equals(Buffer.class)) {
     body.append((Buffer) data);
     return null;
   } else {
     return ctx.write(data);
   }
 }
  @Test
  public void testClientReceivesException() throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext());

    // as error is delivered on a different channelId compared to signal
    // its delivery could shutdown the processor before the processor subscriber
    // receives signal
    Flux.concat(
            Flux.just(Buffer.wrap("Item")),
            Flux.error(new RuntimeException("Something went wrong")))
        .subscribe(processor);

    TestSubscriber<String> subscriber = TestSubscriber.create();
    Buffer.bufferToString(processor).subscribe(subscriber);

    subscriber
        .await(TIMEOUT)
        .assertErrorWith(t -> assertThat(t.getMessage(), is("Something went wrong")));
  }
  @Override
  protected void doOnTerminate(
      ChannelHandlerContext ctx, ChannelFuture last, final ChannelPromise promise) {
    if (request.method() == Method.WS) {
      return;
    }

    ByteBuffer byteBuffer = body.flip().byteBuffer();

    if (request.checkHeader()) {
      HttpRequest req =
          new DefaultFullHttpRequest(
              request.getNettyRequest().getProtocolVersion(),
              request.getNettyRequest().getMethod(),
              request.getNettyRequest().getUri(),
              byteBuffer != null ? Unpooled.wrappedBuffer(byteBuffer) : Unpooled.EMPTY_BUFFER);

      req.headers().add(request.headers().delegate());

      if (byteBuffer != null) {
        HttpHeaders.setContentLength(req, body.limit());
      }

      ctx.writeAndFlush(req)
          .addListener(
              new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                  if (future.isSuccess()) {
                    promise.trySuccess();
                  } else {
                    promise.tryFailure(future.cause());
                  }
                }
              });
    } else {
      ctx.write(
          new DefaultHttpContent(
              byteBuffer != null ? Unpooled.wrappedBuffer(byteBuffer) : Unpooled.EMPTY_BUFFER));
    }
    body.reset();
  }
  @Test
  public void testRemotePublisherReceivesErrorBeforeProcessorIsShutdown()
      throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext());

    Flux.<Buffer>error(new Exception("Oops!")).subscribe(processor);

    TestSubscriber<String> subscriber = TestSubscriber.create(0);
    Buffer.bufferToString(processor).subscribe(subscriber);

    AeronFlux remotePublisher = new AeronFlux(createContext());
    TestSubscriber<String> remoteSubscriber = TestSubscriber.create(0);
    Buffer.bufferToString(remotePublisher).subscribe(remoteSubscriber);

    subscriber.request(1);
    remoteSubscriber.request(1);

    subscriber.await(TIMEOUT).assertError();
    remoteSubscriber.await(TIMEOUT).assertError();
  }
Beispiel #17
0
  /**
   * Very efficient method for parsing an {@link Integer} from the given {@literal Buffer}. Much
   * faster than {@link Integer#parseInt(String)}.
   *
   * @param b The {@literal Buffer} to slice.
   * @return The int value or {@literal null} if the {@literal Buffer} could not be read.
   */
  public static Integer parseInt(Buffer b) {
    if (b.remaining() == 0) {
      return null;
    }

    b.snapshot();
    int len = b.remaining();

    int num = 0;
    int dec = 1;
    for (int i = (b.position + len); i > b.position; ) {
      char c = (char) b.buffer.get(--i);
      num += Character.getNumericValue(c) * dec;
      dec *= 10;
    }

    b.reset();

    return num;
  }
 @Test
 public void decode() throws InterruptedException {
   Stream<ByteBuffer> source =
       Streams.just(Buffer.wrap("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}").byteBuffer());
   List<Object> results =
       Streams.wrap(decoder.decode(source, ResolvableType.forClass(Pojo.class), null))
           .toList()
           .await();
   assertEquals(1, results.size());
   assertEquals("foofoo", ((Pojo) results.get(0)).getFoo());
 }
  @Test
  public void testRemotePublisherReceivesCompleteBeforeProcessorIsShutdown()
      throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext());

    Flux.just(Buffer.wrap("Live")).subscribe(processor);

    TestSubscriber<String> subscriber = TestSubscriber.create(0);
    Buffer.bufferToString(processor).subscribe(subscriber);

    AeronFlux remotePublisher = new AeronFlux(createContext());
    TestSubscriber<String> remoteSubscriber = TestSubscriber.create(0);
    Buffer.bufferToString(remotePublisher).subscribe(remoteSubscriber);

    subscriber.request(1);
    remoteSubscriber.request(1);

    subscriber.awaitAndAssertNextValues("Live").assertComplete();
    remoteSubscriber.awaitAndAssertNextValues("Live").assertComplete();
  }
Beispiel #20
0
    private Buffer combine(Buffer buffer) {
      Buffer aggregate = this.aggregate;
      Buffer combined;
      for (; ; ) {
        combined = buffer.newBuffer().append(aggregate).append(buffer).flip();

        if (AGGREGATE.compareAndSet(this, aggregate, combined)) {
          return combined;
        }
        aggregate = this.aggregate;
      }
    }
  @Test
  public void testExceptionWithNullMessageIsHandled() throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext());

    TestSubscriber<String> subscriber = TestSubscriber.create();
    Buffer.bufferToString(processor).subscribe(subscriber);

    Flux<Buffer> sourceStream = Flux.error(new RuntimeException());
    sourceStream.subscribe(processor);

    subscriber.await(TIMEOUT).assertErrorWith(t -> assertThat(t.getMessage(), is("")));
  }
Beispiel #22
0
  @Test
  public void testEquals() {
    Buffer buffer = Buffer.wrap("Hello");

    assertTrue(buffer.equals(Buffer.wrap("Hello")));
    assertFalse(buffer.equals(Buffer.wrap("Other")));
  }
 @Test
 public void decodeMultipleChunksToArray() throws InterruptedException {
   JsonObjectDecoder decoder = new JsonObjectDecoder(true);
   Stream<ByteBuffer> source =
       Streams.just(
           Buffer.wrap("[{\"foo\": \"foofoo\", \"bar\"").byteBuffer(),
           Buffer.wrap(": \"barbar\"},{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}]")
               .byteBuffer());
   List<String> results =
       Streams.wrap(decoder.decode(source, null, null))
           .map(
               chunk -> {
                 byte[] b = new byte[chunk.remaining()];
                 chunk.get(b);
                 return new String(b, StandardCharsets.UTF_8);
               })
           .toList()
           .await();
   assertEquals(2, results.size());
   assertEquals("{\"foo\": \"foofoo\", \"bar\": \"barbar\"}", results.get(0));
   assertEquals("{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}", results.get(1));
 }
  @Test
  public void testCancelsUpstreamSubscriptionWhenLastSubscriptionIsCancelledAndAutoCancel()
      throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext().autoCancel(true));

    final CountDownLatch subscriptionCancelledLatch = new CountDownLatch(1);
    Publisher<Buffer> dataPublisher =
        new Publisher<Buffer>() {
          @Override
          public void subscribe(Subscriber<? super Buffer> subscriber) {
            subscriber.onSubscribe(
                new Subscription() {
                  @Override
                  public void request(long n) {
                    System.out.println("Requested: " + n);
                  }

                  @Override
                  public void cancel() {
                    System.out.println("Upstream subscription cancelled");
                    subscriptionCancelledLatch.countDown();
                  }
                });
          }
        };
    dataPublisher.subscribe(processor);

    TestSubscriber<String> client = TestSubscriber.create();

    Buffer.bufferToString(processor).subscribe(client);

    processor.onNext(Buffer.wrap("Hello"));

    client.awaitAndAssertNextValues("Hello").cancel();

    assertTrue(
        "Subscription wasn't cancelled",
        subscriptionCancelledLatch.await(TIMEOUT.getSeconds(), TimeUnit.SECONDS));
  }
Beispiel #25
0
 protected <T> void assertTcpClientServerExchangedData(
     Class<? extends reactor.io.net.tcp.TcpServer> serverType,
     Class<? extends reactor.io.net.tcp.TcpClient> clientType,
     Buffer data)
     throws InterruptedException {
   assertTcpClientServerExchangedData(
       serverType,
       clientType,
       StandardCodecs.PASS_THROUGH_CODEC,
       data,
       (Buffer b) -> {
         byte[] b1 = data.flip().asBytes();
         byte[] b2 = b.asBytes();
         return Arrays.equals(b1, b2);
       });
 }
Beispiel #26
0
  /**
   * Very efficient method for parsing a {@link Long} from the given {@literal Buffer}. Much faster
   * than {@link Long#parseLong(String)}.
   *
   * @param b The {@literal Buffer} to slice.
   * @return The long value or {@literal null} if the {@literal Buffer} could not be read.
   */
  public static Long parseLong(Buffer b) {
    if (b.remaining() == 0) {
      return null;
    }
    ByteBuffer bb = b.buffer;
    int origPos = bb.position();
    int len = bb.remaining();

    long num = 0;
    int dec = 1;
    for (int i = len; i > 0; ) {
      char c = (char) bb.get(--i);
      num += Character.getNumericValue(c) * dec;
      dec *= 10;
    }

    bb.position(origPos);

    return num;
  }
Beispiel #27
0
    @Override
    public Buffer.View next() {
      int limit = buffer.limit();
      int endchunk = canDecodeNext(buffer, context);

      if (endchunk == -1) {
        return null;
      }

      Buffer.View view = buffer.createView(buffer.position(), endchunk);

      if (buffer.remaining() > 0) {
        buffer.position(Math.min(limit, view.getEnd()));
        buffer.limit(limit);
      }
      return view;
    }
  @Test
  public void testWorksWithTwoSubscribersViaEmitter() throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext());
    Flux.just(Buffer.wrap("Live"), Buffer.wrap("Hard"), Buffer.wrap("Die"), Buffer.wrap("Harder"))
        .subscribe(processor);

    FluxProcessor<Buffer, Buffer> emitter = EmitterProcessor.create();
    processor.subscribe(emitter);

    TestSubscriber<String> subscriber1 = TestSubscriber.create();
    Buffer.bufferToString(emitter).subscribe(subscriber1);

    TestSubscriber<String> subscriber2 = TestSubscriber.create();
    Buffer.bufferToString(emitter).subscribe(subscriber2);

    subscriber1.awaitAndAssertNextValues("Live", "Hard", "Die", "Harder").assertComplete();
    subscriber2.awaitAndAssertNextValues("Live", "Hard", "Die", "Harder").assertComplete();
  }
  @Test
  public void testNextSignalIsReceived() throws InterruptedException {
    AeronProcessor processor = AeronProcessor.create(createContext());
    TestSubscriber<String> subscriber = TestSubscriber.create(0);
    Buffer.bufferToString(processor).subscribe(subscriber);
    subscriber.request(4);

    Flux.just(
            Buffer.wrap("Live"),
            Buffer.wrap("Hard"),
            Buffer.wrap("Die"),
            Buffer.wrap("Harder"),
            Buffer.wrap("Extra"))
        .subscribe(processor);

    subscriber.awaitAndAssertNextValues("Live", "Hard", "Die", "Harder");

    subscriber.request(1);

    subscriber.awaitAndAssertNextValues("Extra");
    subscriber.await();
  }
 @Override
 public Buffer createElement(int element) {
   return Buffer.wrap("" + element);
 }