javaokhttpokio

Efficient okio Source backed by an already allocated ByteString?


When using the OkHttp Websocket the listener uses a ByteString to provide the binary payload to the application. I want to feed these bytes into some code which takes a okio.Source (in this particular case, a GzipSource), but I cannot find any good way to do this efficiently.

My current solution looks like this:

        @Override
        public void onMessage(WebSocket webSocket, ByteString bytes) {
            Buffer gzipBuffer = new Buffer();
            gzipBuffer.write(bytes);

            GzipSource gzipSource = new GzipSource(gzipBuffer);
            ....
        }

The downside with this Buffer.write is that it makes for extra byte copies (and in the Buffer case, segmented ones, even if pooled it's extra overhead). And in this Websocket case, a byte array was just allocated for the ByteString itself (when handed over from the WebSocketReader impl).

My question is: is there any other preferred way to read from a ByteString, via a Source? Since the ByteString is supposed to be immutable and a Source would just hold some read position info, I'm thinking it should be perfectly doable (but not from external code, since I cannot access the byte[]).. So it feels like I'm missing an obvious solution here.. :)

Thanks for any hints or pointers!


Solution

  • The way you've written it is nearly optimal.

    Okio is optimized for moving data between transformation layers: compression, framing, threading, etc. Though moving data between layers is super-fast (no copies) there's an up-front cost to getting data into the system initially. That's usually I/O you need to do anyway: loading a file or sending a packet. But in this case you have to copy to get the bytes into the first buffer. This feels inefficient but the upside is your next Source.read() call will be fast so the overall throughout will still be great.