13
0
geforkt von Mirrors/Velocity

Introduce zero memory-copy compression for regular Java native

The compression itself is zero-copy in most cases. However, the overhead
needed to copy a direct buffer into a heap buffer (and back) is still
present. If possible, use Linux for best performance.
Dieser Commit ist enthalten in:
Andrew Steinborn 2019-11-09 17:39:47 -05:00
Ursprung 8c98f5a4a6
Commit d73496e8df

Datei anzeigen

@ -16,19 +16,37 @@ public class JavaVelocityCompressor implements VelocityCompressor {
private final Deflater deflater; private final Deflater deflater;
private final Inflater inflater; private final Inflater inflater;
private final byte[] buf; private byte[] buf = new byte[0];
private boolean disposed = false; private boolean disposed = false;
private JavaVelocityCompressor(int level) { private JavaVelocityCompressor(int level) {
this.deflater = new Deflater(level); this.deflater = new Deflater(level);
this.inflater = new Inflater(); this.inflater = new Inflater();
this.buf = new byte[ZLIB_BUFFER_SIZE];
} }
@Override @Override
public void inflate(ByteBuf source, ByteBuf destination, int max) throws DataFormatException { public void inflate(ByteBuf source, ByteBuf destination, int max) throws DataFormatException {
ensureNotDisposed(); ensureNotDisposed();
final int available = source.readableBytes();
this.setInflaterInput(source);
if (destination.hasArray()) {
this.inflateDestinationIsHeap(destination, available, max);
} else {
if (buf.length == 0) {
buf = new byte[ZLIB_BUFFER_SIZE];
}
while (!inflater.finished() && inflater.getBytesRead() < available) {
ensureMaxSize(destination, max);
int read = inflater.inflate(buf);
destination.writeBytes(buf, 0, read);
}
}
inflater.reset();
}
private void setInflaterInput(ByteBuf source) {
final int available = source.readableBytes(); final int available = source.readableBytes();
if (source.hasArray()) { if (source.hasArray()) {
inflater.setInput(source.array(), source.arrayOffset() + source.readerIndex(), available); inflater.setInput(source.array(), source.arrayOffset() + source.readerIndex(), available);
@ -37,19 +55,45 @@ public class JavaVelocityCompressor implements VelocityCompressor {
source.readBytes(inData); source.readBytes(inData);
inflater.setInput(inData); inflater.setInput(inData);
} }
}
private void inflateDestinationIsHeap(ByteBuf destination, int available, int max)
throws DataFormatException {
while (!inflater.finished() && inflater.getBytesRead() < available) { while (!inflater.finished() && inflater.getBytesRead() < available) {
if (!destination.isWritable()) {
ensureMaxSize(destination, max);
destination.ensureWritable(ZLIB_BUFFER_SIZE);
}
ensureMaxSize(destination, max); ensureMaxSize(destination, max);
int read = inflater.inflate(buf); int produced = inflater.inflate(destination.array(), destination.arrayOffset()
destination.writeBytes(buf, 0, read); + destination.writerIndex(), destination.writableBytes());
destination.writerIndex(destination.writerIndex() + produced);
} }
inflater.reset();
} }
@Override @Override
public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException { public void deflate(ByteBuf source, ByteBuf destination) throws DataFormatException {
ensureNotDisposed(); ensureNotDisposed();
this.setDeflaterInput(source);
deflater.finish();
if (destination.hasArray()) {
this.deflateDestinationIsHeap(destination);
} else {
if (buf.length == 0) {
buf = new byte[ZLIB_BUFFER_SIZE];
}
while (!deflater.finished()) {
int bytes = deflater.deflate(buf);
destination.writeBytes(buf, 0, bytes);
}
}
deflater.reset();
}
private void setDeflaterInput(ByteBuf source) {
if (source.hasArray()) { if (source.hasArray()) {
deflater.setInput(source.array(), source.arrayOffset() + source.readerIndex(), deflater.setInput(source.array(), source.arrayOffset() + source.readerIndex(),
source.readableBytes()); source.readableBytes());
@ -58,12 +102,18 @@ public class JavaVelocityCompressor implements VelocityCompressor {
source.readBytes(inData); source.readBytes(inData);
deflater.setInput(inData); deflater.setInput(inData);
} }
deflater.finish(); }
private void deflateDestinationIsHeap(ByteBuf destination) {
while (!deflater.finished()) { while (!deflater.finished()) {
int bytes = deflater.deflate(buf); if (!destination.isWritable()) {
destination.writeBytes(buf, 0, bytes); destination.ensureWritable(ZLIB_BUFFER_SIZE);
}
int produced = deflater.deflate(destination.array(), destination.arrayOffset()
+ destination.writerIndex(), destination.writableBytes());
destination.writerIndex(destination.writerIndex() + produced);
} }
deflater.reset();
} }
@Override @Override