optimize number of buffer allocations (#11879) · grpc/grpc-java@5a7f350

@@ -75,6 +75,10 @@ void deliverFrame(

7575

// effectively final. Can only be set once.

7676

private int maxOutboundMessageSize = NO_MAX_OUTBOUND_MESSAGE_SIZE;

7777

private WritableBuffer buffer;

78+

/**

79+

* if > 0 - the number of bytes to allocate for the current known-length message.

80+

*/

81+

private int knownLengthPendingAllocation;

7882

private Compressor compressor = Codec.Identity.NONE;

7983

private boolean messageCompression = true;

8084

private final OutputStreamAdapter outputStreamAdapter = new OutputStreamAdapter();

@@ -222,9 +226,7 @@ private int writeKnownLengthUncompressed(InputStream message, int messageLength)

222226

headerScratch.put(UNCOMPRESSED).putInt(messageLength);

223227

// Allocate the initial buffer chunk based on frame header + payload length.

224228

// Note that the allocator may allocate a buffer larger or smaller than this length

225-

if (buffer == null) {

226-

buffer = bufferAllocator.allocate(headerScratch.position() + messageLength);

227-

}

229+

knownLengthPendingAllocation = HEADER_LENGTH + messageLength;

228230

writeRaw(headerScratch.array(), 0, headerScratch.position());

229231

return writeToOutputStream(message, outputStreamAdapter);

230232

}

@@ -288,8 +290,9 @@ private void writeRaw(byte[] b, int off, int len) {

288290

commitToSink(false, false);

289291

}

290292

if (buffer == null) {

291-

// Request a buffer allocation using the message length as a hint.

292-

buffer = bufferAllocator.allocate(len);

293+

checkState(knownLengthPendingAllocation > 0, "knownLengthPendingAllocation reached 0");

294+

buffer = bufferAllocator.allocate(knownLengthPendingAllocation);

295+

knownLengthPendingAllocation -= min(knownLengthPendingAllocation, buffer.writableBytes());

293296

}

294297

int toWrite = min(len, buffer.writableBytes());

295298

buffer.write(b, off, toWrite);

@@ -388,6 +391,8 @@ public void write(byte[] b, int off, int len) {

388391

* {@link OutputStream}.

389392

*/

390393

private final class BufferChainOutputStream extends OutputStream {

394+

private static final int FIRST_BUFFER_SIZE = 4096;

395+391396

private final List<WritableBuffer> bufferList = new ArrayList<>();

392397

private WritableBuffer current;

393398

@@ -397,7 +402,7 @@ private final class BufferChainOutputStream extends OutputStream {

397402

* {@link #write(byte[], int, int)}.

398403

*/

399404

@Override

400-

public void write(int b) throws IOException {

405+

public void write(int b) {

401406

if (current != null && current.writableBytes() > 0) {

402407

current.write((byte)b);

403408

return;

@@ -410,7 +415,7 @@ public void write(int b) throws IOException {

410415

public void write(byte[] b, int off, int len) {

411416

if (current == null) {

412417

// Request len bytes initially from the allocator, it may give us more.

413-

current = bufferAllocator.allocate(len);

418+

current = bufferAllocator.allocate(Math.max(FIRST_BUFFER_SIZE, len));

414419

bufferList.add(current);

415420

}

416421

while (len > 0) {