aboutsummaryrefslogtreecommitdiffstats
path: root/vespajlib/src/main/java/com/yahoo/compress
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-01-19 16:08:59 +0100
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2021-01-19 16:08:59 +0100
commit86507230475ff6964bcb98adda345d00867ce024 (patch)
treea5ba65698f120b284dac73ccef4036020e3482ce /vespajlib/src/main/java/com/yahoo/compress
parent095ba218f5dd1b57ef606c02393d43ae2e6e3c3d (diff)
Implement an output stream compressing with zstd
Diffstat (limited to 'vespajlib/src/main/java/com/yahoo/compress')
-rw-r--r--vespajlib/src/main/java/com/yahoo/compress/ZstdOuputStream.java88
1 files changed, 88 insertions, 0 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/compress/ZstdOuputStream.java b/vespajlib/src/main/java/com/yahoo/compress/ZstdOuputStream.java
new file mode 100644
index 00000000000..e81bcf6a465
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/compress/ZstdOuputStream.java
@@ -0,0 +1,88 @@
+// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.compress;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @author bjorncs
+ */
+public class ZstdOuputStream extends OutputStream {
+
+ private final ZstdCompressor compressor = new ZstdCompressor();
+
+ public static final int DEFAULT_INPUT_BUFFER_SIZE = 8*1024;
+
+ private final OutputStream out;
+ private final byte[] inputBuffer;
+ private final byte[] outputBuffer;
+ private int inputPosition = 0;
+ private boolean isClosed = false;
+
+ public ZstdOuputStream(OutputStream out, int inputBufferSize) {
+ this.out = out;
+ this.inputBuffer = new byte[inputBufferSize];
+ this.outputBuffer = new byte[ZstdCompressor.getMaxCompressedLength(inputBufferSize)];
+ }
+
+ public ZstdOuputStream(OutputStream out) {
+ this(out, DEFAULT_INPUT_BUFFER_SIZE);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ throwIfClosed();
+ inputBuffer[inputPosition++] = (byte) b;
+ flushIfFull();
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ throwIfClosed();
+ write(b, 0, b.length);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ throwIfClosed();
+ int end = off + len;
+ while (off < end) {
+ int copyLength = Math.min(end - off, inputBuffer.length - inputPosition);
+ System.arraycopy(b, off, inputBuffer, inputPosition, copyLength);
+ off += copyLength;
+ inputPosition += copyLength;
+ flushIfFull();
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ flushInternal();
+ out.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ throwIfClosed();
+ flush();
+ out.close();
+ isClosed = true;
+ }
+
+ private void flushInternal() throws IOException {
+ throwIfClosed();
+ int compressedLength = compressor.compress(inputBuffer, 0, inputPosition, outputBuffer, 0, outputBuffer.length);
+ out.write(outputBuffer, 0, compressedLength);
+ inputPosition = 0;
+ }
+
+ private void flushIfFull() throws IOException {
+ if (inputPosition == inputBuffer.length) {
+ flushInternal();
+ }
+ }
+
+ private void throwIfClosed() {
+ if (isClosed) throw new IllegalArgumentException("Output stream is already closed");
+ }
+}