Direct ByteBuffers in Thrift with Finagle

485 Views Asked by At

We currently use thrift server for our RPC. One of the calls we wish to support wants to return the result of reading a file into a direct ByteBuffer. THRIFT-883 says this isn't supported (cause the ByteBuffer.array() isn't supported), so was wondering if we could support direct ByteBuffers if we switched to finagle?

Does finagle overcome this limitation or is it also faced with it?

Example code:

Thrift

struct BlockRequest {
  1: i64 blockId,
  2: i64 offset,
  3: i64 len
}

struct BlockResponse {
  1: i64 blockId
  2: i64 offset
  3: i64 len
  4: binary data
}

service DataService {
  BlockResponse requestBlock(1: BlockRequest request)
    throws (1: BlockInfoException bie, 2: FileDoesNotExistException fdne)
}

Java

  @Override
  public BlockResponse requestBlock(BlockRequest request) throws BlockInfoException,
      FileDoesNotExistException, TException {

    final long blockId = request.blockId;
    final long offset = request.offset;
    final long len = request.len;
...

    final RandomAccessFile file = new RandomAccessFile(filePath, "r");
    long fileLength = file.length();
    final long readLen;
    if (len == -1) {
      readLen = fileLength - offset;
    } else {
      readLen = len;
    }

    FileChannel channel = file.getChannel();
    final MappedByteBuffer data = channel.map(FileChannel.MapMode.READ_ONLY, offset, readLen);

    final BlockResponse response = new BlockResponse();
    response.setBlockId(blockId);
    response.setOffset(offset);
    response.setLen(readLen);
    response.setData(data);

    return response
...
1

There are 1 best solutions below

0
On

Won't be able to use thrift this, since the file could be large.

The real question is: Is it a good idea to put a potentially large file completely in one chunk over the wire? Your service already defines the ability to deliver a file in chunks, and exactly that would have been my proposal. Sure, you will have to copy the files into memory at some point, but this will be the case even if you just use raw sockets: At some point the data need to be in memory.

To protect against large blocks, limit the allowed maximum length. Whether you throw an exception for oversized requests or just indicate the server-side limitation in BlockResponse somehow (to allow the client to clearly distinguish between EOF and limit) is a matter of taste. I'd probably use the latter approach to prevent from unnecessary extra roundtrips.