summaryrefslogtreecommitdiffstats
path: root/src/compressor/brotli/BrotliCompressor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/compressor/brotli/BrotliCompressor.cc')
-rw-r--r--src/compressor/brotli/BrotliCompressor.cc95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/compressor/brotli/BrotliCompressor.cc b/src/compressor/brotli/BrotliCompressor.cc
new file mode 100644
index 00000000..27685da3
--- /dev/null
+++ b/src/compressor/brotli/BrotliCompressor.cc
@@ -0,0 +1,95 @@
+#include "brotli/encode.h"
+#include "brotli/decode.h"
+#include "BrotliCompressor.h"
+#include "include/scope_guard.h"
+
+#define MAX_LEN (CEPH_PAGE_SIZE)
+
+int BrotliCompressor::compress(const bufferlist &in, bufferlist &out)
+{
+ BrotliEncoderState* s = BrotliEncoderCreateInstance(nullptr,
+ nullptr,
+ nullptr);
+ if (!s) {
+ return -1;
+ }
+ auto sg = make_scope_guard([&s] { BrotliEncoderDestroyInstance(s); });
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)9);
+ BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, 22);
+ for (auto i = in.buffers().begin(); i != in.buffers().end();) {
+ size_t available_in = i->length();
+ size_t max_comp_size = BrotliEncoderMaxCompressedSize(available_in);
+ size_t available_out = max_comp_size;
+ bufferptr ptr = buffer::create_small_page_aligned(max_comp_size);
+ uint8_t* next_out = (uint8_t*)ptr.c_str();
+ const uint8_t* next_in = (uint8_t*)i->c_str();
+ ++i;
+ BrotliEncoderOperation finish = i != in.buffers().end() ?
+ BROTLI_OPERATION_PROCESS :
+ BROTLI_OPERATION_FINISH;
+ do {
+ if (!BrotliEncoderCompressStream(s,
+ finish,
+ &available_in,
+ &next_in,
+ &available_out,
+ &next_out,
+ nullptr)) {
+ return -1;
+ }
+ unsigned have = max_comp_size - available_out;
+ out.append(ptr, 0, have);
+ } while (available_out == 0);
+ if (BrotliEncoderIsFinished(s)) {
+ break;
+ }
+ }
+ return 0;
+}
+
+int BrotliCompressor::decompress(bufferlist::const_iterator &p,
+ size_t compressed_size,
+ bufferlist &out)
+{
+ BrotliDecoderState* s = BrotliDecoderCreateInstance(nullptr,
+ nullptr,
+ nullptr);
+ if (!s) {
+ return -1;
+ }
+ auto sg = make_scope_guard([&s] { BrotliDecoderDestroyInstance(s); });
+ size_t remaining = std::min<size_t>(p.get_remaining(), compressed_size);
+ while (remaining) {
+ const uint8_t* next_in;
+ size_t len = p.get_ptr_and_advance(remaining, (const char**)&next_in);
+ remaining -= len;
+ size_t available_in = len;
+ BrotliDecoderResult result = BROTLI_DECODER_RESULT_ERROR;
+ do {
+ size_t available_out = MAX_LEN;
+ bufferptr ptr = buffer::create_page_aligned(MAX_LEN);
+ uint8_t* next_out = (uint8_t*)ptr.c_str();
+ result = BrotliDecoderDecompressStream(s,
+ &available_in,
+ &next_in,
+ &available_out,
+ &next_out,
+ 0);
+ if (!result) {
+ return -1;
+ }
+ unsigned have = MAX_LEN - available_out;
+ out.append(ptr, 0, have);
+ } while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
+ if (BrotliDecoderIsFinished(s)) {
+ break;
+ }
+ }
+ return 0;
+}
+
+int BrotliCompressor::decompress(const bufferlist &in, bufferlist &out)
+{
+ auto i = std::cbegin(in);
+ return decompress(i, in.length(), out);
+}