FastLzFrameDecoder should not need to do any extra memory copies even when direct buffers are used (#11511)

Modifications:

Change code to not depend on heap buffers

Result:

Less memory copies
This commit is contained in:
Norman Maurer 2021-07-26 11:59:02 +02:00 committed by GitHub
parent 3549c4048c
commit ae875c35ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 37 deletions

View File

@ -15,6 +15,8 @@
*/ */
package io.netty.handler.codec.compression; package io.netty.handler.codec.compression;
import io.netty.buffer.ByteBuf;
/** /**
* Core of FastLZ compression algorithm. * Core of FastLZ compression algorithm.
* *
@ -422,10 +424,10 @@ final class FastLz {
* Decompression is memory safe and guaranteed not to write the output buffer * Decompression is memory safe and guaranteed not to write the output buffer
* more than what is specified in outLength. * more than what is specified in outLength.
*/ */
static int decompress(final byte[] input, final int inOffset, final int inLength, static int decompress(final ByteBuf input, final int inOffset, final int inLength,
final byte[] output, final int outOffset, final int outLength) { final ByteBuf output, final int outOffset, final int outLength) {
//int level = ((*(const flzuint8*)input) >> 5) + 1; //int level = ((*(const flzuint8*)input) >> 5) + 1;
final int level = (input[inOffset] >> 5) + 1; final int level = (input.getByte(inOffset) >> 5) + 1;
if (level != LEVEL_1 && level != LEVEL_2) { if (level != LEVEL_1 && level != LEVEL_2) {
throw new DecompressionException(String.format( throw new DecompressionException(String.format(
"invalid level: %d (expected: %d or %d)", level, LEVEL_1, LEVEL_2 "invalid level: %d (expected: %d or %d)", level, LEVEL_1, LEVEL_2
@ -437,7 +439,7 @@ final class FastLz {
// flzuint8* op = (flzuint8*) output; // flzuint8* op = (flzuint8*) output;
int op = 0; int op = 0;
// flzuint32 ctrl = (*ip++) & 31; // flzuint32 ctrl = (*ip++) & 31;
long ctrl = input[inOffset + ip++] & 31; long ctrl = input.getByte(inOffset + ip++) & 31;
int loop = 1; int loop = 1;
do { do {
@ -457,27 +459,27 @@ final class FastLz {
if (len == 6) { if (len == 6) {
if (level == LEVEL_1) { if (level == LEVEL_1) {
// len += *ip++; // len += *ip++;
len += input[inOffset + ip++] & 0xFF; len += input.getUnsignedByte(inOffset + ip++);
} else { } else {
do { do {
code = input[inOffset + ip++] & 0xFF; code = input.getUnsignedByte(inOffset + ip++);
len += code; len += code;
} while (code == 255); } while (code == 255);
} }
} }
if (level == LEVEL_1) { if (level == LEVEL_1) {
// ref -= *ip++; // ref -= *ip++;
ref -= input[inOffset + ip++] & 0xFF; ref -= input.getUnsignedByte(inOffset + ip++);
} else { } else {
code = input[inOffset + ip++] & 0xFF; code = input.getUnsignedByte(inOffset + ip++);
ref -= code; ref -= code;
/* match from 16-bit distance */ /* match from 16-bit distance */
// if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) // if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
// if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) // if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
if (code == 255 && ofs == 31 << 8) { if (code == 255 && ofs == 31 << 8) {
ofs = (input[inOffset + ip++] & 0xFF) << 8; ofs = input.getUnsignedByte(inOffset + ip++) << 8;
ofs += input[inOffset + ip++] & 0xFF; ofs += input.getUnsignedByte(inOffset + ip++);
ref = (int) (op - ofs - MAX_DISTANCE); ref = (int) (op - ofs - MAX_DISTANCE);
} }
@ -496,7 +498,7 @@ final class FastLz {
} }
if (ip < inLength) { if (ip < inLength) {
ctrl = input[inOffset + ip++] & 0xFF; ctrl = input.getUnsignedByte(inOffset + ip++);
} else { } else {
loop = 0; loop = 0;
} }
@ -504,12 +506,12 @@ final class FastLz {
if (ref == op) { if (ref == op) {
/* optimize copy for a run */ /* optimize copy for a run */
// flzuint8 b = ref[-1]; // flzuint8 b = ref[-1];
byte b = output[outOffset + ref - 1]; byte b = output.getByte(outOffset + ref - 1);
output[outOffset + op++] = b; output.setByte(outOffset + op++, b);
output[outOffset + op++] = b; output.setByte(outOffset + op++, b);
output[outOffset + op++] = b; output.setByte(outOffset + op++, b);
while (len != 0) { while (len != 0) {
output[outOffset + op++] = b; output.setByte(outOffset + op++, b);
--len; --len;
} }
} else { } else {
@ -517,12 +519,12 @@ final class FastLz {
ref--; ref--;
// *op++ = *ref++; // *op++ = *ref++;
output[outOffset + op++] = output[outOffset + ref++]; output.setByte(outOffset + op++, output.getByte(outOffset + ref++));
output[outOffset + op++] = output[outOffset + ref++]; output.setByte(outOffset + op++, output.getByte(outOffset + ref++));
output[outOffset + op++] = output[outOffset + ref++]; output.setByte(outOffset + op++, output.getByte(outOffset + ref++));
while (len != 0) { while (len != 0) {
output[outOffset + op++] = output[outOffset + ref++]; output.setByte(outOffset + op++, output.getByte(outOffset + ref++));
--len; --len;
} }
} }
@ -537,17 +539,17 @@ final class FastLz {
} }
//*op++ = *ip++; //*op++ = *ip++;
output[outOffset + op++] = input[inOffset + ip++]; output.setByte(outOffset + op++, input.getByte(inOffset + ip++));
for (--ctrl; ctrl != 0; ctrl--) { for (--ctrl; ctrl != 0; ctrl--) {
// *op++ = *ip++; // *op++ = *ip++;
output[outOffset + op++] = input[inOffset + ip++]; output.setByte(outOffset + op++, input.getByte(inOffset + ip++));
} }
loop = ip < inLength ? 1 : 0; loop = ip < inLength ? 1 : 0;
if (loop != 0) { if (loop != 0) {
// ctrl = *ip++; // ctrl = *ip++;
ctrl = input[inOffset + ip++] & 0xFF; ctrl = input.getUnsignedByte(inOffset + ip++);
} }
} }

View File

@ -149,21 +149,11 @@ public class FastLzFrameDecoder extends ByteToMessageDecoder {
try { try {
if (isCompressed) { if (isCompressed) {
final byte[] input;
final int inputOffset;
if (in.hasArray()) {
input = in.array();
inputOffset = in.arrayOffset() + idx;
} else {
input = new byte[chunkLength];
in.getBytes(idx, input);
inputOffset = 0;
}
output = ctx.alloc().heapBuffer(originalLength); output = ctx.alloc().buffer(originalLength);
int outputOffset = output.arrayOffset() + output.writerIndex(); int outputOffset = output.writerIndex();
final int decompressedBytes = decompress(input, inputOffset, chunkLength, final int decompressedBytes = decompress(in, idx, chunkLength,
output.array(), outputOffset, originalLength); output, outputOffset, originalLength);
if (originalLength != decompressedBytes) { if (originalLength != decompressedBytes) {
throw new DecompressionException(String.format( throw new DecompressionException(String.format(
"stream corrupted: originalLength(%d) and actual length(%d) mismatch", "stream corrupted: originalLength(%d) and actual length(%d) mismatch",