| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407 | // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.//  This source code is licensed under both the GPLv2 (found in the//  COPYING file in the root directory) and Apache 2.0 License//  (found in the LICENSE.Apache file in the root directory).//// Copyright (c) 2011 The LevelDB Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file. See the AUTHORS file for names of contributors.//#pragma once#include <algorithm>#include <limits>#ifdef ROCKSDB_MALLOC_USABLE_SIZE#ifdef OS_FREEBSD#include <malloc_np.h>#else  // OS_FREEBSD#include <malloc.h>#endif  // OS_FREEBSD#endif  // ROCKSDB_MALLOC_USABLE_SIZE#include <string>#include "memory/memory_allocator.h"#include "rocksdb/options.h"#include "rocksdb/table.h"#include "util/coding.h"#include "util/compression_context_cache.h"#include "util/string_util.h"#ifdef SNAPPY#include <snappy.h>#endif#ifdef ZLIB#include <zlib.h>#endif#ifdef BZIP2#include <bzlib.h>#endif#if defined(LZ4)#include <lz4.h>#include <lz4hc.h>#endif#if defined(ZSTD)#include <zstd.h>#if ZSTD_VERSION_NUMBER >= 10103  // v1.1.3+#include <zdict.h>#endif  // ZSTD_VERSION_NUMBER >= 10103namespace ROCKSDB_NAMESPACE {// Need this for the context allocation override// On windows we need to do this explicitly#if (ZSTD_VERSION_NUMBER >= 500)#if defined(ROCKSDB_JEMALLOC) && defined(OS_WIN) && \    defined(ZSTD_STATIC_LINKING_ONLY)#define ROCKSDB_ZSTD_CUSTOM_MEMnamespace port {ZSTD_customMem GetJeZstdAllocationOverrides();}  // namespace port#endif  // defined(ROCKSDB_JEMALLOC) && defined(OS_WIN) &&        // defined(ZSTD_STATIC_LINKING_ONLY)// We require `ZSTD_sizeof_DDict` and `ZSTD_createDDict_byReference` to use// `ZSTD_DDict`. The former was introduced in v1.0.0 and the latter was// introduced in v1.1.3. But an important bug fix for `ZSTD_sizeof_DDict` came// in v1.1.4, so that is the version we require. As of today's latest version// (v1.3.8), they are both still in the experimental API, which means they are// only exported when the compiler flag `ZSTD_STATIC_LINKING_ONLY` is set.#if defined(ZSTD_STATIC_LINKING_ONLY) && ZSTD_VERSION_NUMBER >= 10104#define ROCKSDB_ZSTD_DDICT#endif  // defined(ZSTD_STATIC_LINKING_ONLY) && ZSTD_VERSION_NUMBER >= 10104// Cached data represents a portion that can be re-used// If, in the future we have more than one native context to// cache we can arrange this as a tupleclass ZSTDUncompressCachedData { public:  using ZSTDNativeContext = ZSTD_DCtx*;  ZSTDUncompressCachedData() {}  // Init from cache  ZSTDUncompressCachedData(const ZSTDUncompressCachedData& o) = delete;  ZSTDUncompressCachedData& operator=(const ZSTDUncompressCachedData&) = delete;  ZSTDUncompressCachedData(ZSTDUncompressCachedData&& o) ROCKSDB_NOEXCEPT      : ZSTDUncompressCachedData() {    *this = std::move(o);  }  ZSTDUncompressCachedData& operator=(ZSTDUncompressCachedData&& o)      ROCKSDB_NOEXCEPT {    assert(zstd_ctx_ == nullptr);    std::swap(zstd_ctx_, o.zstd_ctx_);    std::swap(cache_idx_, o.cache_idx_);    return *this;  }  ZSTDNativeContext Get() const { return zstd_ctx_; }  int64_t GetCacheIndex() const { return cache_idx_; }  void CreateIfNeeded() {    if (zstd_ctx_ == nullptr) {#ifdef ROCKSDB_ZSTD_CUSTOM_MEM      zstd_ctx_ =          ZSTD_createDCtx_advanced(port::GetJeZstdAllocationOverrides());#else   // ROCKSDB_ZSTD_CUSTOM_MEM      zstd_ctx_ = ZSTD_createDCtx();#endif  // ROCKSDB_ZSTD_CUSTOM_MEM      cache_idx_ = -1;    }  }  void InitFromCache(const ZSTDUncompressCachedData& o, int64_t idx) {    zstd_ctx_ = o.zstd_ctx_;    cache_idx_ = idx;  }  ~ZSTDUncompressCachedData() {    if (zstd_ctx_ != nullptr && cache_idx_ == -1) {      ZSTD_freeDCtx(zstd_ctx_);    }  } private:  ZSTDNativeContext zstd_ctx_ = nullptr;  int64_t cache_idx_ = -1;  // -1 means this instance owns the context};#endif  // (ZSTD_VERSION_NUMBER >= 500)}  // namespace ROCKSDB_NAMESPACE#endif  // ZSTD#if !(defined ZSTD) || !(ZSTD_VERSION_NUMBER >= 500)namespace ROCKSDB_NAMESPACE {class ZSTDUncompressCachedData {  void* padding;  // unused public:  using ZSTDNativeContext = void*;  ZSTDUncompressCachedData() {}  ZSTDUncompressCachedData(const ZSTDUncompressCachedData&) {}  ZSTDUncompressCachedData& operator=(const ZSTDUncompressCachedData&) = delete;  ZSTDUncompressCachedData(ZSTDUncompressCachedData&&)      ROCKSDB_NOEXCEPT = default;  ZSTDUncompressCachedData& operator=(ZSTDUncompressCachedData&&)      ROCKSDB_NOEXCEPT = default;  ZSTDNativeContext Get() const { return nullptr; }  int64_t GetCacheIndex() const { return -1; }  void CreateIfNeeded() {}  void InitFromCache(const ZSTDUncompressCachedData&, int64_t) {} private:  void ignore_padding__() { padding = nullptr; }};}  // namespace ROCKSDB_NAMESPACE#endif#if defined(XPRESS)#include "port/xpress.h"#endifnamespace ROCKSDB_NAMESPACE {// Holds dictionary and related data, like ZSTD's digested compression// dictionary.struct CompressionDict {#if ZSTD_VERSION_NUMBER >= 700  ZSTD_CDict* zstd_cdict_ = nullptr;#endif  // ZSTD_VERSION_NUMBER >= 700  std::string dict_; public:#if ZSTD_VERSION_NUMBER >= 700  CompressionDict(std::string dict, CompressionType type, int level) {#else   // ZSTD_VERSION_NUMBER >= 700  CompressionDict(std::string dict, CompressionType /*type*/, int /*level*/) {#endif  // ZSTD_VERSION_NUMBER >= 700    dict_ = std::move(dict);#if ZSTD_VERSION_NUMBER >= 700    zstd_cdict_ = nullptr;    if (!dict_.empty() && (type == kZSTD || type == kZSTDNotFinalCompression)) {      if (level == CompressionOptions::kDefaultCompressionLevel) {        // 3 is the value of ZSTD_CLEVEL_DEFAULT (not exposed publicly), see        // https://github.com/facebook/zstd/issues/1148        level = 3;      }      // Should be safe (but slower) if below call fails as we'll use the      // raw dictionary to compress.      zstd_cdict_ = ZSTD_createCDict(dict_.data(), dict_.size(), level);      assert(zstd_cdict_ != nullptr);    }#endif  // ZSTD_VERSION_NUMBER >= 700  }  ~CompressionDict() {#if ZSTD_VERSION_NUMBER >= 700    size_t res = 0;    if (zstd_cdict_ != nullptr) {      res = ZSTD_freeCDict(zstd_cdict_);    }    assert(res == 0);  // Last I checked they can't fail    (void)res;         // prevent unused var warning#endif                 // ZSTD_VERSION_NUMBER >= 700  }#if ZSTD_VERSION_NUMBER >= 700  const ZSTD_CDict* GetDigestedZstdCDict() const { return zstd_cdict_; }#endif  // ZSTD_VERSION_NUMBER >= 700  Slice GetRawDict() const { return dict_; }  static const CompressionDict& GetEmptyDict() {    static CompressionDict empty_dict{};    return empty_dict;  }  CompressionDict() = default;  // Disable copy/move  CompressionDict(const CompressionDict&) = delete;  CompressionDict& operator=(const CompressionDict&) = delete;  CompressionDict(CompressionDict&&) = delete;  CompressionDict& operator=(CompressionDict&&) = delete;};// Holds dictionary and related data, like ZSTD's digested uncompression// dictionary.struct UncompressionDict {  // Block containing the data for the compression dictionary in case the  // constructor that takes a string parameter is used.  std::string dict_;  // Block containing the data for the compression dictionary in case the  // constructor that takes a Slice parameter is used and the passed in  // CacheAllocationPtr is not nullptr.  CacheAllocationPtr allocation_;  // Slice pointing to the compression dictionary data. Can point to  // dict_, allocation_, or some other memory location, depending on how  // the object was constructed.  Slice slice_;#ifdef ROCKSDB_ZSTD_DDICT  // Processed version of the contents of slice_ for ZSTD compression.  ZSTD_DDict* zstd_ddict_ = nullptr;#endif  // ROCKSDB_ZSTD_DDICT#ifdef ROCKSDB_ZSTD_DDICT  UncompressionDict(std::string dict, bool using_zstd)#else   // ROCKSDB_ZSTD_DDICT  UncompressionDict(std::string dict, bool /* using_zstd */)#endif  // ROCKSDB_ZSTD_DDICT      : dict_(std::move(dict)), slice_(dict_) {#ifdef ROCKSDB_ZSTD_DDICT    if (!slice_.empty() && using_zstd) {      zstd_ddict_ = ZSTD_createDDict_byReference(slice_.data(), slice_.size());      assert(zstd_ddict_ != nullptr);    }#endif  // ROCKSDB_ZSTD_DDICT  }#ifdef ROCKSDB_ZSTD_DDICT  UncompressionDict(Slice slice, CacheAllocationPtr&& allocation,                    bool using_zstd)#else   // ROCKSDB_ZSTD_DDICT  UncompressionDict(Slice slice, CacheAllocationPtr&& allocation,                    bool /* using_zstd */)#endif  // ROCKSDB_ZSTD_DDICT      : allocation_(std::move(allocation)), slice_(std::move(slice)) {#ifdef ROCKSDB_ZSTD_DDICT    if (!slice_.empty() && using_zstd) {      zstd_ddict_ = ZSTD_createDDict_byReference(slice_.data(), slice_.size());      assert(zstd_ddict_ != nullptr);    }#endif  // ROCKSDB_ZSTD_DDICT  }  UncompressionDict(UncompressionDict&& rhs)      : dict_(std::move(rhs.dict_)),        allocation_(std::move(rhs.allocation_)),        slice_(std::move(rhs.slice_))#ifdef ROCKSDB_ZSTD_DDICT        ,        zstd_ddict_(rhs.zstd_ddict_)#endif  {#ifdef ROCKSDB_ZSTD_DDICT    rhs.zstd_ddict_ = nullptr;#endif  }  ~UncompressionDict() {#ifdef ROCKSDB_ZSTD_DDICT    size_t res = 0;    if (zstd_ddict_ != nullptr) {      res = ZSTD_freeDDict(zstd_ddict_);    }    assert(res == 0);  // Last I checked they can't fail    (void)res;         // prevent unused var warning#endif                 // ROCKSDB_ZSTD_DDICT  }  UncompressionDict& operator=(UncompressionDict&& rhs) {    if (this == &rhs) {      return *this;    }    dict_ = std::move(rhs.dict_);    allocation_ = std::move(rhs.allocation_);    slice_ = std::move(rhs.slice_);#ifdef ROCKSDB_ZSTD_DDICT    zstd_ddict_ = rhs.zstd_ddict_;    rhs.zstd_ddict_ = nullptr;#endif    return *this;  }  // The object is self-contained if the string constructor is used, or the  // Slice constructor is invoked with a non-null allocation. Otherwise, it  // is the caller's responsibility to ensure that the underlying storage  // outlives this object.  bool own_bytes() const { return !dict_.empty() || allocation_; }  const Slice& GetRawDict() const { return slice_; }#ifdef ROCKSDB_ZSTD_DDICT  const ZSTD_DDict* GetDigestedZstdDDict() const { return zstd_ddict_; }#endif  // ROCKSDB_ZSTD_DDICT  static const UncompressionDict& GetEmptyDict() {    static UncompressionDict empty_dict{};    return empty_dict;  }  size_t ApproximateMemoryUsage() const {    size_t usage = sizeof(struct UncompressionDict);    usage += dict_.size();    if (allocation_) {      auto allocator = allocation_.get_deleter().allocator;      if (allocator) {        usage += allocator->UsableSize(allocation_.get(), slice_.size());      } else {        usage += slice_.size();      }    }#ifdef ROCKSDB_ZSTD_DDICT    usage += ZSTD_sizeof_DDict(zstd_ddict_);#endif  // ROCKSDB_ZSTD_DDICT    return usage;  }  UncompressionDict() = default;  // Disable copy  UncompressionDict(const CompressionDict&) = delete;  UncompressionDict& operator=(const CompressionDict&) = delete;};class CompressionContext { private:#if defined(ZSTD) && (ZSTD_VERSION_NUMBER >= 500)  ZSTD_CCtx* zstd_ctx_ = nullptr;  void CreateNativeContext(CompressionType type) {    if (type == kZSTD || type == kZSTDNotFinalCompression) {#ifdef ROCKSDB_ZSTD_CUSTOM_MEM      zstd_ctx_ =          ZSTD_createCCtx_advanced(port::GetJeZstdAllocationOverrides());#else   // ROCKSDB_ZSTD_CUSTOM_MEM      zstd_ctx_ = ZSTD_createCCtx();#endif  // ROCKSDB_ZSTD_CUSTOM_MEM    }  }  void DestroyNativeContext() {    if (zstd_ctx_ != nullptr) {      ZSTD_freeCCtx(zstd_ctx_);    }  } public:  // callable inside ZSTD_Compress  ZSTD_CCtx* ZSTDPreallocCtx() const {    assert(zstd_ctx_ != nullptr);    return zstd_ctx_;  }#else   // ZSTD && (ZSTD_VERSION_NUMBER >= 500) private:  void CreateNativeContext(CompressionType /* type */) {}  void DestroyNativeContext() {}#endif  // ZSTD && (ZSTD_VERSION_NUMBER >= 500) public:  explicit CompressionContext(CompressionType type) {    CreateNativeContext(type);  }  ~CompressionContext() { DestroyNativeContext(); }  CompressionContext(const CompressionContext&) = delete;  CompressionContext& operator=(const CompressionContext&) = delete;};class CompressionInfo {  const CompressionOptions& opts_;  const CompressionContext& context_;  const CompressionDict& dict_;  const CompressionType type_;  const uint64_t sample_for_compression_; public:  CompressionInfo(const CompressionOptions& _opts,                  const CompressionContext& _context,                  const CompressionDict& _dict, CompressionType _type,                  uint64_t _sample_for_compression)      : opts_(_opts),        context_(_context),        dict_(_dict),        type_(_type),        sample_for_compression_(_sample_for_compression) {}  const CompressionOptions& options() const { return opts_; }  const CompressionContext& context() const { return context_; }  const CompressionDict& dict() const { return dict_; }  CompressionType type() const { return type_; }  uint64_t SampleForCompression() const { return sample_for_compression_; }};class UncompressionContext { private:  CompressionContextCache* ctx_cache_ = nullptr;  ZSTDUncompressCachedData uncomp_cached_data_; public:  struct NoCache {};  // Do not use context cache, used by TableBuilder  UncompressionContext(NoCache, CompressionType /* type */) {}  explicit UncompressionContext(CompressionType type) {    if (type == kZSTD || type == kZSTDNotFinalCompression) {      ctx_cache_ = CompressionContextCache::Instance();      uncomp_cached_data_ = ctx_cache_->GetCachedZSTDUncompressData();    }  }  ~UncompressionContext() {    if (uncomp_cached_data_.GetCacheIndex() != -1) {      assert(ctx_cache_ != nullptr);      ctx_cache_->ReturnCachedZSTDUncompressData(          uncomp_cached_data_.GetCacheIndex());    }  }  UncompressionContext(const UncompressionContext&) = delete;  UncompressionContext& operator=(const UncompressionContext&) = delete;  ZSTDUncompressCachedData::ZSTDNativeContext GetZSTDContext() const {    return uncomp_cached_data_.Get();  }};class UncompressionInfo {  const UncompressionContext& context_;  const UncompressionDict& dict_;  const CompressionType type_; public:  UncompressionInfo(const UncompressionContext& _context,                    const UncompressionDict& _dict, CompressionType _type)      : context_(_context), dict_(_dict), type_(_type) {}  const UncompressionContext& context() const { return context_; }  const UncompressionDict& dict() const { return dict_; }  CompressionType type() const { return type_; }};inline bool Snappy_Supported() {#ifdef SNAPPY  return true;#else  return false;#endif}inline bool Zlib_Supported() {#ifdef ZLIB  return true;#else  return false;#endif}inline bool BZip2_Supported() {#ifdef BZIP2  return true;#else  return false;#endif}inline bool LZ4_Supported() {#ifdef LZ4  return true;#else  return false;#endif}inline bool XPRESS_Supported() {#ifdef XPRESS  return true;#else  return false;#endif}inline bool ZSTD_Supported() {#ifdef ZSTD  // ZSTD format is finalized since version 0.8.0.  return (ZSTD_versionNumber() >= 800);#else  return false;#endif}inline bool ZSTDNotFinal_Supported() {#ifdef ZSTD  return true;#else  return false;#endif}inline bool CompressionTypeSupported(CompressionType compression_type) {  switch (compression_type) {    case kNoCompression:      return true;    case kSnappyCompression:      return Snappy_Supported();    case kZlibCompression:      return Zlib_Supported();    case kBZip2Compression:      return BZip2_Supported();    case kLZ4Compression:      return LZ4_Supported();    case kLZ4HCCompression:      return LZ4_Supported();    case kXpressCompression:      return XPRESS_Supported();    case kZSTDNotFinalCompression:      return ZSTDNotFinal_Supported();    case kZSTD:      return ZSTD_Supported();    default:      assert(false);      return false;  }}inline std::string CompressionTypeToString(CompressionType compression_type) {  switch (compression_type) {    case kNoCompression:      return "NoCompression";    case kSnappyCompression:      return "Snappy";    case kZlibCompression:      return "Zlib";    case kBZip2Compression:      return "BZip2";    case kLZ4Compression:      return "LZ4";    case kLZ4HCCompression:      return "LZ4HC";    case kXpressCompression:      return "Xpress";    case kZSTD:      return "ZSTD";    case kZSTDNotFinalCompression:      return "ZSTDNotFinal";    case kDisableCompressionOption:      return "DisableOption";    default:      assert(false);      return "";  }}inline std::string CompressionOptionsToString(    CompressionOptions& compression_options) {  std::string result;  result.reserve(512);  result.append("window_bits=")      .append(ToString(compression_options.window_bits))      .append("; ");  result.append("level=")      .append(ToString(compression_options.level))      .append("; ");  result.append("strategy=")      .append(ToString(compression_options.strategy))      .append("; ");  result.append("max_dict_bytes=")      .append(ToString(compression_options.max_dict_bytes))      .append("; ");  result.append("zstd_max_train_bytes=")      .append(ToString(compression_options.zstd_max_train_bytes))      .append("; ");  result.append("enabled=")      .append(ToString(compression_options.enabled))      .append("; ");  return result;}// compress_format_version can have two values:// 1 -- decompressed sizes for BZip2 and Zlib are not included in the compressed// block. Also, decompressed sizes for LZ4 are encoded in platform-dependent// way.// 2 -- Zlib, BZip2 and LZ4 encode decompressed size as Varint32 just before the// start of compressed block. Snappy format is the same as version 1.inline bool Snappy_Compress(const CompressionInfo& /*info*/, const char* input,                            size_t length, ::std::string* output) {#ifdef SNAPPY  output->resize(snappy::MaxCompressedLength(length));  size_t outlen;  snappy::RawCompress(input, length, &(*output)[0], &outlen);  output->resize(outlen);  return true;#else  (void)input;  (void)length;  (void)output;  return false;#endif}inline bool Snappy_GetUncompressedLength(const char* input, size_t length,                                         size_t* result) {#ifdef SNAPPY  return snappy::GetUncompressedLength(input, length, result);#else  (void)input;  (void)length;  (void)result;  return false;#endif}inline bool Snappy_Uncompress(const char* input, size_t length, char* output) {#ifdef SNAPPY  return snappy::RawUncompress(input, length, output);#else  (void)input;  (void)length;  (void)output;  return false;#endif}namespace compression {// returns sizeinline size_t PutDecompressedSizeInfo(std::string* output, uint32_t length) {  PutVarint32(output, length);  return output->size();}inline bool GetDecompressedSizeInfo(const char** input_data,                                    size_t* input_length,                                    uint32_t* output_len) {  auto new_input_data =      GetVarint32Ptr(*input_data, *input_data + *input_length, output_len);  if (new_input_data == nullptr) {    return false;  }  *input_length -= (new_input_data - *input_data);  *input_data = new_input_data;  return true;}}  // namespace compression// compress_format_version == 1 -- decompressed size is not included in the// block header// compress_format_version == 2 -- decompressed size is included in the block// header in varint32 format// @param compression_dict Data for presetting the compression library's//    dictionary.inline bool Zlib_Compress(const CompressionInfo& info,                          uint32_t compress_format_version, const char* input,                          size_t length, ::std::string* output) {#ifdef ZLIB  if (length > std::numeric_limits<uint32_t>::max()) {    // Can't compress more than 4GB    return false;  }  size_t output_header_len = 0;  if (compress_format_version == 2) {    output_header_len = compression::PutDecompressedSizeInfo(        output, static_cast<uint32_t>(length));  }  // Resize output to be the plain data length.  // This may not be big enough if the compression actually expands data.  output->resize(output_header_len + length);  // The memLevel parameter specifies how much memory should be allocated for  // the internal compression state.  // memLevel=1 uses minimum memory but is slow and reduces compression ratio.  // memLevel=9 uses maximum memory for optimal speed.  // The default value is 8. See zconf.h for more details.  static const int memLevel = 8;  int level;  if (info.options().level == CompressionOptions::kDefaultCompressionLevel) {    level = Z_DEFAULT_COMPRESSION;  } else {    level = info.options().level;  }  z_stream _stream;  memset(&_stream, 0, sizeof(z_stream));  int st = deflateInit2(&_stream, level, Z_DEFLATED, info.options().window_bits,                        memLevel, info.options().strategy);  if (st != Z_OK) {    return false;  }  Slice compression_dict = info.dict().GetRawDict();  if (compression_dict.size()) {    // Initialize the compression library's dictionary    st = deflateSetDictionary(        &_stream, reinterpret_cast<const Bytef*>(compression_dict.data()),        static_cast<unsigned int>(compression_dict.size()));    if (st != Z_OK) {      deflateEnd(&_stream);      return false;    }  }  // Compress the input, and put compressed data in output.  _stream.next_in = (Bytef*)input;  _stream.avail_in = static_cast<unsigned int>(length);  // Initialize the output size.  _stream.avail_out = static_cast<unsigned int>(length);  _stream.next_out = reinterpret_cast<Bytef*>(&(*output)[output_header_len]);  bool compressed = false;  st = deflate(&_stream, Z_FINISH);  if (st == Z_STREAM_END) {    compressed = true;    output->resize(output->size() - _stream.avail_out);  }  // The only return value we really care about is Z_STREAM_END.  // Z_OK means insufficient output space. This means the compression is  // bigger than decompressed size. Just fail the compression in that case.  deflateEnd(&_stream);  return compressed;#else  (void)info;  (void)compress_format_version;  (void)input;  (void)length;  (void)output;  return false;#endif}// compress_format_version == 1 -- decompressed size is not included in the// block header// compress_format_version == 2 -- decompressed size is included in the block// header in varint32 format// @param compression_dict Data for presetting the compression library's//    dictionary.inline CacheAllocationPtr Zlib_Uncompress(    const UncompressionInfo& info, const char* input_data, size_t input_length,    int* decompress_size, uint32_t compress_format_version,    MemoryAllocator* allocator = nullptr, int windowBits = -14) {#ifdef ZLIB  uint32_t output_len = 0;  if (compress_format_version == 2) {    if (!compression::GetDecompressedSizeInfo(&input_data, &input_length,                                              &output_len)) {      return nullptr;    }  } else {    // Assume the decompressed data size will 5x of compressed size, but round    // to the page size    size_t proposed_output_len = ((input_length * 5) & (~(4096 - 1))) + 4096;    output_len = static_cast<uint32_t>(        std::min(proposed_output_len,                 static_cast<size_t>(std::numeric_limits<uint32_t>::max())));  }  z_stream _stream;  memset(&_stream, 0, sizeof(z_stream));  // For raw inflate, the windowBits should be -8..-15.  // If windowBits is bigger than zero, it will use either zlib  // header or gzip header. Adding 32 to it will do automatic detection.  int st =      inflateInit2(&_stream, windowBits > 0 ? windowBits + 32 : windowBits);  if (st != Z_OK) {    return nullptr;  }  const Slice& compression_dict = info.dict().GetRawDict();  if (compression_dict.size()) {    // Initialize the compression library's dictionary    st = inflateSetDictionary(        &_stream, reinterpret_cast<const Bytef*>(compression_dict.data()),        static_cast<unsigned int>(compression_dict.size()));    if (st != Z_OK) {      return nullptr;    }  }  _stream.next_in = (Bytef*)input_data;  _stream.avail_in = static_cast<unsigned int>(input_length);  auto output = AllocateBlock(output_len, allocator);  _stream.next_out = (Bytef*)output.get();  _stream.avail_out = static_cast<unsigned int>(output_len);  bool done = false;  while (!done) {    st = inflate(&_stream, Z_SYNC_FLUSH);    switch (st) {      case Z_STREAM_END:        done = true;        break;      case Z_OK: {        // No output space. Increase the output space by 20%.        // We should never run out of output space if        // compress_format_version == 2        assert(compress_format_version != 2);        size_t old_sz = output_len;        uint32_t output_len_delta = output_len / 5;        output_len += output_len_delta < 10 ? 10 : output_len_delta;        auto tmp = AllocateBlock(output_len, allocator);        memcpy(tmp.get(), output.get(), old_sz);        output = std::move(tmp);        // Set more output.        _stream.next_out = (Bytef*)(output.get() + old_sz);        _stream.avail_out = static_cast<unsigned int>(output_len - old_sz);        break;      }      case Z_BUF_ERROR:      default:        inflateEnd(&_stream);        return nullptr;    }  }  // If we encoded decompressed block size, we should have no bytes left  assert(compress_format_version != 2 || _stream.avail_out == 0);  *decompress_size = static_cast<int>(output_len - _stream.avail_out);  inflateEnd(&_stream);  return output;#else  (void)info;  (void)input_data;  (void)input_length;  (void)decompress_size;  (void)compress_format_version;  (void)allocator;  (void)windowBits;  return nullptr;#endif}// compress_format_version == 1 -- decompressed size is not included in the// block header// compress_format_version == 2 -- decompressed size is included in the block// header in varint32 formatinline bool BZip2_Compress(const CompressionInfo& /*info*/,                           uint32_t compress_format_version, const char* input,                           size_t length, ::std::string* output) {#ifdef BZIP2  if (length > std::numeric_limits<uint32_t>::max()) {    // Can't compress more than 4GB    return false;  }  size_t output_header_len = 0;  if (compress_format_version == 2) {    output_header_len = compression::PutDecompressedSizeInfo(        output, static_cast<uint32_t>(length));  }  // Resize output to be the plain data length.  // This may not be big enough if the compression actually expands data.  output->resize(output_header_len + length);  bz_stream _stream;  memset(&_stream, 0, sizeof(bz_stream));  // Block size 1 is 100K.  // 0 is for silent.  // 30 is the default workFactor  int st = BZ2_bzCompressInit(&_stream, 1, 0, 30);  if (st != BZ_OK) {    return false;  }  // Compress the input, and put compressed data in output.  _stream.next_in = (char*)input;  _stream.avail_in = static_cast<unsigned int>(length);  // Initialize the output size.  _stream.avail_out = static_cast<unsigned int>(length);  _stream.next_out = reinterpret_cast<char*>(&(*output)[output_header_len]);  bool compressed = false;  st = BZ2_bzCompress(&_stream, BZ_FINISH);  if (st == BZ_STREAM_END) {    compressed = true;    output->resize(output->size() - _stream.avail_out);  }  // The only return value we really care about is BZ_STREAM_END.  // BZ_FINISH_OK means insufficient output space. This means the compression  // is bigger than decompressed size. Just fail the compression in that case.  BZ2_bzCompressEnd(&_stream);  return compressed;#else  (void)compress_format_version;  (void)input;  (void)length;  (void)output;  return false;#endif}// compress_format_version == 1 -- decompressed size is not included in the// block header// compress_format_version == 2 -- decompressed size is included in the block// header in varint32 formatinline CacheAllocationPtr BZip2_Uncompress(    const char* input_data, size_t input_length, int* decompress_size,    uint32_t compress_format_version, MemoryAllocator* allocator = nullptr) {#ifdef BZIP2  uint32_t output_len = 0;  if (compress_format_version == 2) {    if (!compression::GetDecompressedSizeInfo(&input_data, &input_length,                                              &output_len)) {      return nullptr;    }  } else {    // Assume the decompressed data size will 5x of compressed size, but round    // to the next page size    size_t proposed_output_len = ((input_length * 5) & (~(4096 - 1))) + 4096;    output_len = static_cast<uint32_t>(        std::min(proposed_output_len,                 static_cast<size_t>(std::numeric_limits<uint32_t>::max())));  }  bz_stream _stream;  memset(&_stream, 0, sizeof(bz_stream));  int st = BZ2_bzDecompressInit(&_stream, 0, 0);  if (st != BZ_OK) {    return nullptr;  }  _stream.next_in = (char*)input_data;  _stream.avail_in = static_cast<unsigned int>(input_length);  auto output = AllocateBlock(output_len, allocator);  _stream.next_out = (char*)output.get();  _stream.avail_out = static_cast<unsigned int>(output_len);  bool done = false;  while (!done) {    st = BZ2_bzDecompress(&_stream);    switch (st) {      case BZ_STREAM_END:        done = true;        break;      case BZ_OK: {        // No output space. Increase the output space by 20%.        // We should never run out of output space if        // compress_format_version == 2        assert(compress_format_version != 2);        uint32_t old_sz = output_len;        output_len = output_len * 1.2;        auto tmp = AllocateBlock(output_len, allocator);        memcpy(tmp.get(), output.get(), old_sz);        output = std::move(tmp);        // Set more output.        _stream.next_out = (char*)(output.get() + old_sz);        _stream.avail_out = static_cast<unsigned int>(output_len - old_sz);        break;      }      default:        BZ2_bzDecompressEnd(&_stream);        return nullptr;    }  }  // If we encoded decompressed block size, we should have no bytes left  assert(compress_format_version != 2 || _stream.avail_out == 0);  *decompress_size = static_cast<int>(output_len - _stream.avail_out);  BZ2_bzDecompressEnd(&_stream);  return output;#else  (void)input_data;  (void)input_length;  (void)decompress_size;  (void)compress_format_version;  (void)allocator;  return nullptr;#endif}// compress_format_version == 1 -- decompressed size is included in the// block header using memcpy, which makes database non-portable)// compress_format_version == 2 -- decompressed size is included in the block// header in varint32 format// @param compression_dict Data for presetting the compression library's//    dictionary.inline bool LZ4_Compress(const CompressionInfo& info,                         uint32_t compress_format_version, const char* input,                         size_t length, ::std::string* output) {#ifdef LZ4  if (length > std::numeric_limits<uint32_t>::max()) {    // Can't compress more than 4GB    return false;  }  size_t output_header_len = 0;  if (compress_format_version == 2) {    // new encoding, using varint32 to store size information    output_header_len = compression::PutDecompressedSizeInfo(        output, static_cast<uint32_t>(length));  } else {    // legacy encoding, which is not really portable (depends on big/little    // endianness)    output_header_len = 8;    output->resize(output_header_len);    char* p = const_cast<char*>(output->c_str());    memcpy(p, &length, sizeof(length));  }  int compress_bound = LZ4_compressBound(static_cast<int>(length));  output->resize(static_cast<size_t>(output_header_len + compress_bound));  int outlen;#if LZ4_VERSION_NUMBER >= 10400  // r124+  LZ4_stream_t* stream = LZ4_createStream();  Slice compression_dict = info.dict().GetRawDict();  if (compression_dict.size()) {    LZ4_loadDict(stream, compression_dict.data(),                 static_cast<int>(compression_dict.size()));  }#if LZ4_VERSION_NUMBER >= 10700  // r129+  outlen =      LZ4_compress_fast_continue(stream, input, &(*output)[output_header_len],                                 static_cast<int>(length), compress_bound, 1);#else  // up to r128  outlen = LZ4_compress_limitedOutput_continue(      stream, input, &(*output)[output_header_len], static_cast<int>(length),      compress_bound);#endif  LZ4_freeStream(stream);#else   // up to r123  outlen = LZ4_compress_limitedOutput(input, &(*output)[output_header_len],                                      static_cast<int>(length), compress_bound);#endif  // LZ4_VERSION_NUMBER >= 10400  if (outlen == 0) {    return false;  }  output->resize(static_cast<size_t>(output_header_len + outlen));  return true;#else  // LZ4  (void)info;  (void)compress_format_version;  (void)input;  (void)length;  (void)output;  return false;#endif}// compress_format_version == 1 -- decompressed size is included in the// block header using memcpy, which makes database non-portable)// compress_format_version == 2 -- decompressed size is included in the block// header in varint32 format// @param compression_dict Data for presetting the compression library's//    dictionary.inline CacheAllocationPtr LZ4_Uncompress(const UncompressionInfo& info,                                         const char* input_data,                                         size_t input_length,                                         int* decompress_size,                                         uint32_t compress_format_version,                                         MemoryAllocator* allocator = nullptr) {#ifdef LZ4  uint32_t output_len = 0;  if (compress_format_version == 2) {    // new encoding, using varint32 to store size information    if (!compression::GetDecompressedSizeInfo(&input_data, &input_length,                                              &output_len)) {      return nullptr;    }  } else {    // legacy encoding, which is not really portable (depends on big/little    // endianness)    if (input_length < 8) {      return nullptr;    }    memcpy(&output_len, input_data, sizeof(output_len));    input_length -= 8;    input_data += 8;  }  auto output = AllocateBlock(output_len, allocator);#if LZ4_VERSION_NUMBER >= 10400  // r124+  LZ4_streamDecode_t* stream = LZ4_createStreamDecode();  const Slice& compression_dict = info.dict().GetRawDict();  if (compression_dict.size()) {    LZ4_setStreamDecode(stream, compression_dict.data(),                        static_cast<int>(compression_dict.size()));  }  *decompress_size = LZ4_decompress_safe_continue(      stream, input_data, output.get(), static_cast<int>(input_length),      static_cast<int>(output_len));  LZ4_freeStreamDecode(stream);#else   // up to r123  *decompress_size = LZ4_decompress_safe(input_data, output.get(),                                         static_cast<int>(input_length),                                         static_cast<int>(output_len));#endif  // LZ4_VERSION_NUMBER >= 10400  if (*decompress_size < 0) {    return nullptr;  }  assert(*decompress_size == static_cast<int>(output_len));  return output;#else  // LZ4  (void)info;  (void)input_data;  (void)input_length;  (void)decompress_size;  (void)compress_format_version;  (void)allocator;  return nullptr;#endif}// compress_format_version == 1 -- decompressed size is included in the// block header using memcpy, which makes database non-portable)// compress_format_version == 2 -- decompressed size is included in the block// header in varint32 format// @param compression_dict Data for presetting the compression library's//    dictionary.inline bool LZ4HC_Compress(const CompressionInfo& info,                           uint32_t compress_format_version, const char* input,                           size_t length, ::std::string* output) {#ifdef LZ4  if (length > std::numeric_limits<uint32_t>::max()) {    // Can't compress more than 4GB    return false;  }  size_t output_header_len = 0;  if (compress_format_version == 2) {    // new encoding, using varint32 to store size information    output_header_len = compression::PutDecompressedSizeInfo(        output, static_cast<uint32_t>(length));  } else {    // legacy encoding, which is not really portable (depends on big/little    // endianness)    output_header_len = 8;    output->resize(output_header_len);    char* p = const_cast<char*>(output->c_str());    memcpy(p, &length, sizeof(length));  }  int compress_bound = LZ4_compressBound(static_cast<int>(length));  output->resize(static_cast<size_t>(output_header_len + compress_bound));  int outlen;  int level;  if (info.options().level == CompressionOptions::kDefaultCompressionLevel) {    level = 0;  // lz4hc.h says any value < 1 will be sanitized to default  } else {    level = info.options().level;  }#if LZ4_VERSION_NUMBER >= 10400  // r124+  LZ4_streamHC_t* stream = LZ4_createStreamHC();  LZ4_resetStreamHC(stream, level);  Slice compression_dict = info.dict().GetRawDict();  const char* compression_dict_data =      compression_dict.size() > 0 ? compression_dict.data() : nullptr;  size_t compression_dict_size = compression_dict.size();  LZ4_loadDictHC(stream, compression_dict_data,                 static_cast<int>(compression_dict_size));#if LZ4_VERSION_NUMBER >= 10700  // r129+  outlen =      LZ4_compress_HC_continue(stream, input, &(*output)[output_header_len],                               static_cast<int>(length), compress_bound);#else   // r124-r128  outlen = LZ4_compressHC_limitedOutput_continue(      stream, input, &(*output)[output_header_len], static_cast<int>(length),      compress_bound);#endif  // LZ4_VERSION_NUMBER >= 10700  LZ4_freeStreamHC(stream);#elif LZ4_VERSION_MAJOR  // r113-r123  outlen = LZ4_compressHC2_limitedOutput(input, &(*output)[output_header_len],                                         static_cast<int>(length),                                         compress_bound, level);#else                    // up to r112  outlen =      LZ4_compressHC_limitedOutput(input, &(*output)[output_header_len],                                   static_cast<int>(length), compress_bound);#endif                   // LZ4_VERSION_NUMBER >= 10400  if (outlen == 0) {    return false;  }  output->resize(static_cast<size_t>(output_header_len + outlen));  return true;#else  // LZ4  (void)info;  (void)compress_format_version;  (void)input;  (void)length;  (void)output;  return false;#endif}#ifdef XPRESSinline bool XPRESS_Compress(const char* input, size_t length,                            std::string* output) {  return port::xpress::Compress(input, length, output);}#elseinline bool XPRESS_Compress(const char* /*input*/, size_t /*length*/,                            std::string* /*output*/) {  return false;}#endif#ifdef XPRESSinline char* XPRESS_Uncompress(const char* input_data, size_t input_length,                               int* decompress_size) {  return port::xpress::Decompress(input_data, input_length, decompress_size);}#elseinline char* XPRESS_Uncompress(const char* /*input_data*/,                               size_t /*input_length*/,                               int* /*decompress_size*/) {  return nullptr;}#endifinline bool ZSTD_Compress(const CompressionInfo& info, const char* input,                          size_t length, ::std::string* output) {#ifdef ZSTD  if (length > std::numeric_limits<uint32_t>::max()) {    // Can't compress more than 4GB    return false;  }  size_t output_header_len = compression::PutDecompressedSizeInfo(      output, static_cast<uint32_t>(length));  size_t compressBound = ZSTD_compressBound(length);  output->resize(static_cast<size_t>(output_header_len + compressBound));  size_t outlen = 0;  int level;  if (info.options().level == CompressionOptions::kDefaultCompressionLevel) {    // 3 is the value of ZSTD_CLEVEL_DEFAULT (not exposed publicly), see    // https://github.com/facebook/zstd/issues/1148    level = 3;  } else {    level = info.options().level;  }#if ZSTD_VERSION_NUMBER >= 500  // v0.5.0+  ZSTD_CCtx* context = info.context().ZSTDPreallocCtx();  assert(context != nullptr);#if ZSTD_VERSION_NUMBER >= 700  // v0.7.0+  if (info.dict().GetDigestedZstdCDict() != nullptr) {    outlen = ZSTD_compress_usingCDict(context, &(*output)[output_header_len],                                      compressBound, input, length,                                      info.dict().GetDigestedZstdCDict());  }#endif  // ZSTD_VERSION_NUMBER >= 700  if (outlen == 0) {    outlen = ZSTD_compress_usingDict(context, &(*output)[output_header_len],                                     compressBound, input, length,                                     info.dict().GetRawDict().data(),                                     info.dict().GetRawDict().size(), level);  }#else   // up to v0.4.x  outlen = ZSTD_compress(&(*output)[output_header_len], compressBound, input,                         length, level);#endif  // ZSTD_VERSION_NUMBER >= 500  if (outlen == 0) {    return false;  }  output->resize(output_header_len + outlen);  return true;#else  // ZSTD  (void)info;  (void)input;  (void)length;  (void)output;  return false;#endif}// @param compression_dict Data for presetting the compression library's//    dictionary.inline CacheAllocationPtr ZSTD_Uncompress(    const UncompressionInfo& info, const char* input_data, size_t input_length,    int* decompress_size, MemoryAllocator* allocator = nullptr) {#ifdef ZSTD  uint32_t output_len = 0;  if (!compression::GetDecompressedSizeInfo(&input_data, &input_length,                                            &output_len)) {    return nullptr;  }  auto output = AllocateBlock(output_len, allocator);  size_t actual_output_length = 0;#if ZSTD_VERSION_NUMBER >= 500  // v0.5.0+  ZSTD_DCtx* context = info.context().GetZSTDContext();  assert(context != nullptr);#ifdef ROCKSDB_ZSTD_DDICT  if (info.dict().GetDigestedZstdDDict() != nullptr) {    actual_output_length = ZSTD_decompress_usingDDict(        context, output.get(), output_len, input_data, input_length,        info.dict().GetDigestedZstdDDict());  }#endif  // ROCKSDB_ZSTD_DDICT  if (actual_output_length == 0) {    actual_output_length = ZSTD_decompress_usingDict(        context, output.get(), output_len, input_data, input_length,        info.dict().GetRawDict().data(), info.dict().GetRawDict().size());  }#else   // up to v0.4.x  (void)info;  actual_output_length =      ZSTD_decompress(output.get(), output_len, input_data, input_length);#endif  // ZSTD_VERSION_NUMBER >= 500  assert(actual_output_length == output_len);  *decompress_size = static_cast<int>(actual_output_length);  return output;#else  // ZSTD  (void)info;  (void)input_data;  (void)input_length;  (void)decompress_size;  (void)allocator;  return nullptr;#endif}inline bool ZSTD_TrainDictionarySupported() {#ifdef ZSTD  // Dictionary trainer is available since v0.6.1 for static linking, but not  // available for dynamic linking until v1.1.3. For now we enable the feature  // in v1.1.3+ only.  return (ZSTD_versionNumber() >= 10103);#else  return false;#endif}inline std::string ZSTD_TrainDictionary(const std::string& samples,                                        const std::vector<size_t>& sample_lens,                                        size_t max_dict_bytes) {  // Dictionary trainer is available since v0.6.1 for static linking, but not  // available for dynamic linking until v1.1.3. For now we enable the feature  // in v1.1.3+ only.#if ZSTD_VERSION_NUMBER >= 10103  // v1.1.3+  assert(samples.empty() == sample_lens.empty());  if (samples.empty()) {    return "";  }  std::string dict_data(max_dict_bytes, '\0');  size_t dict_len = ZDICT_trainFromBuffer(      &dict_data[0], max_dict_bytes, &samples[0], &sample_lens[0],      static_cast<unsigned>(sample_lens.size()));  if (ZDICT_isError(dict_len)) {    return "";  }  assert(dict_len <= max_dict_bytes);  dict_data.resize(dict_len);  return dict_data;#else   // up to v1.1.2  assert(false);  (void)samples;  (void)sample_lens;  (void)max_dict_bytes;  return "";#endif  // ZSTD_VERSION_NUMBER >= 10103}inline std::string ZSTD_TrainDictionary(const std::string& samples,                                        size_t sample_len_shift,                                        size_t max_dict_bytes) {  // Dictionary trainer is available since v0.6.1, but ZSTD was marked stable  // only since v0.8.0. For now we enable the feature in stable versions only.#if ZSTD_VERSION_NUMBER >= 10103  // v1.1.3+  // skips potential partial sample at the end of "samples"  size_t num_samples = samples.size() >> sample_len_shift;  std::vector<size_t> sample_lens(num_samples, size_t(1) << sample_len_shift);  return ZSTD_TrainDictionary(samples, sample_lens, max_dict_bytes);#else   // up to v1.1.2  assert(false);  (void)samples;  (void)sample_len_shift;  (void)max_dict_bytes;  return "";#endif  // ZSTD_VERSION_NUMBER >= 10103}}  // namespace ROCKSDB_NAMESPACE
 |