package com.datastax.oss.driver.internal.core.protocol;
import com.datastax.oss.driver.api.core.context.DriverContext;
import io.netty.buffer.ByteBuf;
import java.io.IOException;
import java.nio.ByteBuffer;
import net.jcip.annotations.ThreadSafe;
import org.xerial.snappy.Snappy;
@ThreadSafe
public class SnappyCompressor extends ByteBufCompressor {
public SnappyCompressor(@SuppressWarnings("unused") DriverContext context) {
try {
Snappy.getNativeLibraryVersion();
} catch (NoClassDefFoundError e) {
throw new IllegalStateException(
"Error initializing compressor, make sure that the Snappy library is in the classpath "
+ "(the driver declares it as an optional dependency, "
+ "so you need to declare it explicitly)",
e);
}
}
@Override
public String algorithm() {
return "snappy";
}
@Override
protected ByteBuf compressDirect(ByteBuf input) {
int maxCompressedLength = Snappy.maxCompressedLength(input.readableBytes());
ByteBuf output = input.alloc().directBuffer(maxCompressedLength);
try {
ByteBuffer in = inputNioBuffer(input);
input.readerIndex(input.writerIndex());
ByteBuffer out = outputNioBuffer(output);
int written = Snappy.compress(in, out);
output.writerIndex(output.writerIndex() + written);
return output;
} catch (IOException e) {
output.release();
throw new RuntimeException(e);
}
}
@Override
protected ByteBuf compressHeap(ByteBuf input) {
int maxCompressedLength = Snappy.maxCompressedLength(input.readableBytes());
int inOffset = input.arrayOffset() + input.readerIndex();
byte[] in = input.array();
int len = input.readableBytes();
input.readerIndex(input.writerIndex());
ByteBuf output = input.alloc().heapBuffer(maxCompressedLength);
try {
int offset = output.arrayOffset() + output.writerIndex();
byte[] out = output.array();
int written = Snappy.compress(in, inOffset, len, out, offset);
output.writerIndex(output.writerIndex() + written);
return output;
} catch (IOException e) {
output.release();
throw new RuntimeException(e);
}
}
@Override
protected ByteBuf decompressDirect(ByteBuf input) {
ByteBuffer in = inputNioBuffer(input);
input.readerIndex(input.writerIndex());
ByteBuf output = null;
try {
if (!Snappy.isValidCompressedBuffer(in)) {
throw new IllegalArgumentException(
"Provided frame does not appear to be Snappy compressed");
}
output = input.alloc().directBuffer(Snappy.uncompressedLength(in));
ByteBuffer out = outputNioBuffer(output);
int size = Snappy.uncompress(in, out);
output.writerIndex(output.writerIndex() + size);
return output;
} catch (IOException e) {
if (output != null) {
output.release();
}
throw new RuntimeException(e);
}
}
@Override
protected ByteBuf decompressHeap(ByteBuf input) throws RuntimeException {
int inOffset = input.arrayOffset() + input.readerIndex();
byte[] in = input.array();
int len = input.readableBytes();
input.readerIndex(input.writerIndex());
ByteBuf output = null;
try {
if (!Snappy.isValidCompressedBuffer(in, inOffset, len)) {
throw new IllegalArgumentException(
"Provided frame does not appear to be Snappy compressed");
}
output = input.alloc().heapBuffer(Snappy.uncompressedLength(in, inOffset, len));
int offset = output.arrayOffset() + output.writerIndex();
byte[] out = output.array();
int written = Snappy.uncompress(in, inOffset, len, out, offset);
output.writerIndex(output.writerIndex() + written);
return output;
} catch (IOException e) {
if (output != null) {
output.release();
}
throw new RuntimeException(e);
}
}
}