AutomaticCodec
[folly.git] / folly / io / Compression.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <cstdint>
20 #include <limits>
21 #include <memory>
22 #include <string>
23 #include <vector>
24
25 #include <folly/Range.h>
26 #include <folly/io/IOBuf.h>
27
28 /**
29  * Compression / decompression over IOBufs
30  */
31
32 namespace folly { namespace io {
33
34 enum class CodecType {
35   /**
36    * This codec type is not defined; getCodec() will throw an exception
37    * if used. Useful if deriving your own classes from Codec without
38    * going through the getCodec() interface.
39    */
40   USER_DEFINED = 0,
41
42   /**
43    * Use no compression.
44    * Levels supported: 0
45    */
46   NO_COMPRESSION = 1,
47
48   /**
49    * Use LZ4 compression.
50    * Levels supported: 1 = fast, 2 = best; default = 1
51    */
52   LZ4 = 2,
53
54   /**
55    * Use Snappy compression.
56    * Levels supported: 1
57    */
58   SNAPPY = 3,
59
60   /**
61    * Use zlib compression.
62    * Levels supported: 0 = no compression, 1 = fast, ..., 9 = best; default = 6
63    */
64   ZLIB = 4,
65
66   /**
67    * Use LZ4 compression, prefixed with size (as Varint).
68    */
69   LZ4_VARINT_SIZE = 5,
70
71   /**
72    * Use LZMA2 compression.
73    * Levels supported: 0 = no compression, 1 = fast, ..., 9 = best; default = 6
74    */
75   LZMA2 = 6,
76   LZMA2_VARINT_SIZE = 7,
77
78   /**
79    * Use ZSTD compression.
80    */
81   ZSTD = 8,
82
83   /**
84    * Use gzip compression.  This is the same compression algorithm as ZLIB but
85    * gzip-compressed files tend to be easier to work with from the command line.
86    * Levels supported: 0 = no compression, 1 = fast, ..., 9 = best; default = 6
87    */
88   GZIP = 9,
89
90   /**
91    * Use LZ4 frame compression.
92    * Levels supported: 0 = fast, 16 = best; default = 0
93    */
94   LZ4_FRAME = 10,
95
96   NUM_CODEC_TYPES = 11,
97 };
98
99 class Codec {
100  public:
101   virtual ~Codec() { }
102
103   /**
104    * Return the maximum length of data that may be compressed with this codec.
105    * NO_COMPRESSION and ZLIB support arbitrary lengths;
106    * LZ4 supports up to 1.9GiB; SNAPPY supports up to 4GiB.
107    * May return UNLIMITED_UNCOMPRESSED_LENGTH if unlimited.
108    */
109   uint64_t maxUncompressedLength() const;
110
111   /**
112    * Return the codec's type.
113    */
114   CodecType type() const { return type_; }
115
116   /**
117    * Does this codec need the exact uncompressed length on decompression?
118    */
119   bool needsUncompressedLength() const;
120
121   /**
122    * Compress data, returning an IOBuf (which may share storage with data).
123    * Throws std::invalid_argument if data is larger than
124    * maxUncompressedLength().
125    *
126    * Regardless of the behavior of the underlying compressor, compressing
127    * an empty IOBuf chain will return an empty IOBuf chain.
128    */
129   std::unique_ptr<IOBuf> compress(const folly::IOBuf* data);
130
131   /**
132    * Compresses data. May involve additional copies compared to the overload
133    * that takes and returns IOBufs. Has the same error semantics as the IOBuf
134    * version.
135    */
136   std::string compress(StringPiece data);
137
138   /**
139    * Uncompress data. Throws std::runtime_error on decompression error.
140    *
141    * Some codecs (LZ4) require the exact uncompressed length; this is indicated
142    * by needsUncompressedLength().
143    *
144    * For other codes (zlib), knowing the exact uncompressed length ahead of
145    * time might be faster.
146    *
147    * Regardless of the behavior of the underlying compressor, uncompressing
148    * an empty IOBuf chain will return an empty IOBuf chain.
149    */
150   static constexpr uint64_t UNKNOWN_UNCOMPRESSED_LENGTH = uint64_t(-1);
151   static constexpr uint64_t UNLIMITED_UNCOMPRESSED_LENGTH = uint64_t(-2);
152
153   std::unique_ptr<IOBuf> uncompress(
154       const IOBuf* data,
155       uint64_t uncompressedLength = UNKNOWN_UNCOMPRESSED_LENGTH);
156
157   /**
158    * Uncompresses data. May involve additional copies compared to the overload
159    * that takes and returns IOBufs. Has the same error semantics as the IOBuf
160    * version.
161    */
162   std::string uncompress(
163       StringPiece data,
164       uint64_t uncompressedLength = UNKNOWN_UNCOMPRESSED_LENGTH);
165
166  protected:
167   explicit Codec(CodecType type);
168
169  public:
170   /**
171    * Returns a superset of the set of prefixes for which canUncompress() will
172    * return true. A superset is allowed for optimizations in canUncompress()
173    * based on other knowledge such as length. None of the prefixes may be empty.
174    * default: No prefixes.
175    */
176   virtual std::vector<std::string> validPrefixes() const;
177
178   /**
179    * Returns true if the codec thinks it can uncompress the data.
180    * If a codec doesn't have magic bytes at the beginning, like LZ4 and Snappy,
181    * it can always return false.
182    * default: Returns false.
183    */
184   virtual bool canUncompress(
185       const folly::IOBuf* data,
186       uint64_t uncompressedLength = UNKNOWN_UNCOMPRESSED_LENGTH) const;
187
188  private:
189   // default: no limits (save for special value UNKNOWN_UNCOMPRESSED_LENGTH)
190   virtual uint64_t doMaxUncompressedLength() const;
191   // default: doesn't need uncompressed length
192   virtual bool doNeedsUncompressedLength() const;
193   virtual std::unique_ptr<IOBuf> doCompress(const folly::IOBuf* data) = 0;
194   virtual std::unique_ptr<IOBuf> doUncompress(const folly::IOBuf* data,
195                                               uint64_t uncompressedLength) = 0;
196   // default: an implementation is provided by default to wrap the strings into
197   // IOBufs and delegate to the IOBuf methods. This incurs a copy of the output
198   // from IOBuf to string. Implementers, at their discretion, can override
199   // these methods to avoid the copy.
200   virtual std::string doCompressString(StringPiece data);
201   virtual std::string doUncompressString(
202       StringPiece data,
203       uint64_t uncompressedLength);
204
205   CodecType type_;
206 };
207
208 constexpr int COMPRESSION_LEVEL_FASTEST = -1;
209 constexpr int COMPRESSION_LEVEL_DEFAULT = -2;
210 constexpr int COMPRESSION_LEVEL_BEST = -3;
211
212 /**
213  * Return a codec for the given type. Throws on error.  The level
214  * is a non-negative codec-dependent integer indicating the level of
215  * compression desired, or one of the following constants:
216  *
217  * COMPRESSION_LEVEL_FASTEST is fastest (uses least CPU / memory,
218  *   worst compression)
219  * COMPRESSION_LEVEL_DEFAULT is the default (likely a tradeoff between
220  *   FASTEST and BEST)
221  * COMPRESSION_LEVEL_BEST is the best compression (uses most CPU / memory,
222  *   best compression)
223  *
224  * When decompressing, the compression level is ignored. All codecs will
225  * decompress all data compressed with the a codec of the same type, regardless
226  * of compression level.
227  */
228 std::unique_ptr<Codec> getCodec(CodecType type,
229                                 int level = COMPRESSION_LEVEL_DEFAULT);
230
231 /**
232  * Returns a codec that can uncompress any of the given codec types as well as
233  * {LZ4_FRAME, ZSTD, ZLIB, GZIP, LZMA2}. Appends each default codec to
234  * customCodecs in order, so long as a codec with the same type() isn't already
235  * present. When uncompress() is called, each codec's canUncompress() is called
236  * in the order that they are given. Appended default codecs are checked last.
237  * uncompress() is called on the first codec whose canUncompress() returns true.
238  * An exception is thrown if no codec canUncompress() the data.
239  * An exception is thrown if the chosen codec's uncompress() throws on the data.
240  * An exception is thrown if compress() is called on the returned codec.
241  *
242  * Requirements are checked in debug mode and are as follows:
243  * Let headers be the concatenation of every codec's validPrefixes().
244  *  1. Each codec must override validPrefixes() and canUncompress().
245  *  2. No codec's validPrefixes() may be empty.
246  *  3. No header in headers may be empty.
247  *  4. headers must not contain any duplicate elements.
248  *  5. No strict non-empty prefix of any header in headers may be in headers.
249  */
250 std::unique_ptr<Codec> getAutoUncompressionCodec(
251     std::vector<std::unique_ptr<Codec>> customCodecs = {});
252
253 /**
254  * Check if a specified codec is supported.
255  */
256 bool hasCodec(CodecType type);
257
258 }}  // namespaces