question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Representing a Buffer as a NIO ByteBuffer

See original GitHub issue

I recently needed to turn a Okio Buffer into a NIO ByteBuffer so I could pass it to AsynchronousSocketChannel to perform reads from the channel using Kotlin coroutines.

private suspend fun AsynchronousSocketChannel.aRead(
  buffer: Buffer,
  cursor: Buffer.UnsafeCursor
): Long {
  buffer.readAndWriteUnsafe(cursor).use {
    val oldSize = buffer.size()
    cursor.seek(oldSize)

    cursor.expandBuffer(8192)
    val length = cursor.end - cursor.start
    val read = aRead(ByteBuffer.wrap(cursor.data, cursor.start, length), 5, TimeUnit.SECONDS)

    if (read == -1) {
      cursor.resizeBuffer(oldSize)
      return -1
    } else {
      cursor.resizeBuffer(oldSize + read)
      return read.toLong()
    }
  }
}

Is this pattern worth a sample? Another use case for Buffer cursors that show off some their power. Maybe demonstrate how to turn a ReadableByteChannel/WriteableByteChannel into a Source/Sink? Happy to put something together and open a pull-request just wanted to make sure it was something worthwhile.

final class ByteChannelSource implements Source {
  private final ReadableByteChannel channel;
  private final Buffer.UnsafeCursor cursor = new Buffer.UnsafeCursor();

  public ByteChannelSource(ReadableByteChannel channel) {
    this.channel = channel;
  }

  @Override
  public long read(Buffer sink, long byteCount) throws IOException {
    try (Buffer.UnsafeCursor ignored = sink.readAndWriteUnsafe(cursor)) {
      long oldSize = sink.size();
      cursor.seek(oldSize);

      cursor.expandBuffer(8192);
      long length = Math.min(cursor.end - cursor.start, byteCount);
      int read = channel.read(ByteBuffer.wrap(cursor.data, cursor.start, (int) length));

      if (read == -1) {
        cursor.resizeBuffer(oldSize);
        return -1;
      } else {
        cursor.resizeBuffer(oldSize + read);
        return read;
      }
    }
  }

  @Override
  public Timeout timeout() {
    return Timeout.NONE;
  }

  @Override
  public void close() throws IOException {
    channel.close();
  }
}

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
bnormcommented, Jul 10, 2018

Finally got back around to this a little. I put together a gist showing extension functions for reading and writing to async socket and file channels using a Buffer as the source/sink.

As for Dispatcher, coroutines already allow you to jump between context/thread pools. So your example could become something like this:

suspend fun Http2Reader.readAllFrames(
    ioContext: CoroutineContext, handler Http2Reader.Handler) {
  while (true) {
    while (!hasFullFrame(source.buffer)) {
      withContext(ioContext) {
        source.read()
      }
    }
    // Decode frame and call handler.
  }
}

Where ioContext would be a dedicated thread pool of some kind and where everything in the withContext block would be executed on. I think all of the coroutine behavior you want already exists. However, this would require a dependency on the kotlinx.coroutines library unless you want to re-implement a small part of that library for Okio.

0reactions
bnormcommented, Sep 11, 2018

I’m guessing this ticket can be closed and the coroutine discussion can continue in #501. The ByteChannel side of this ticket is resolved.

Read more comments on GitHub >

github_iconTop Results From Across the Web

ByteBuffer (Java Platform SE 7 ) - Oracle Help Center
A byte buffer. This class defines six categories of operations upon byte buffers: Absolute and relative get and put methods that read and...
Read more >
Java NIO Buffer - Jenkov.com
A buffer is essentially a block of memory into which you can write data, which you can then later read again. This memory...
Read more >
Java NIO Buffer Tutorial - HowToDoInJava
Conceptually, a buffer is an array of primitive data elements wrapped inside an object. The advantage of a Buffer class over a simple...
Read more >
ByteBuffer | Android Developers
Specific byte orders are represented by instances of the ByteOrder class. The initial order of a byte buffer is always BIG_ENDIAN .
Read more >
java.nio.ByteBuffer java code examples - Tabnine
Best Java code snippets using java.nio.ByteBuffer (Showing top 20 results out of 59,778) · ByteBufferConverter.convertToByteBuffer(...) · AbstractHasher.putBytes( ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found