diff options
Diffstat (limited to 'main/snappy/snappy_unittest.cc')
| -rw-r--r-- | main/snappy/snappy_unittest.cc | 1164 | 
1 files changed, 0 insertions, 1164 deletions
| diff --git a/main/snappy/snappy_unittest.cc b/main/snappy/snappy_unittest.cc deleted file mode 100644 index 59c108f4..00000000 --- a/main/snappy/snappy_unittest.cc +++ /dev/null @@ -1,1164 +0,0 @@ -// Copyright 2005 and onwards Google Inc. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -//     * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -//     * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -//     * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <math.h> -#include <stdlib.h> - - -#include <algorithm> -#include <string> -#include <vector> - -#include "snappy.h" -#include "snappy-internal.h" -#include "snappy-test.h" -#include "snappy-sinksource.h" - -DEFINE_int32(start_len, -1, -             "Starting prefix size for testing (-1: just full file contents)"); -DEFINE_int32(end_len, -1, -             "Starting prefix size for testing (-1: just full file contents)"); -DEFINE_int32(bytes, 10485760, -             "How many bytes to compress/uncompress per file for timing"); - -DEFINE_bool(zlib, false, -            "Run zlib compression (http://www.zlib.net)"); -DEFINE_bool(lzo, false, -            "Run LZO compression (http://www.oberhumer.com/opensource/lzo/)"); -DEFINE_bool(quicklz, false, -            "Run quickLZ compression (http://www.quicklz.com/)"); -DEFINE_bool(liblzf, false, -            "Run libLZF compression " -            "(http://www.goof.com/pcg/marc/liblzf.html)"); -DEFINE_bool(fastlz, false, -            "Run FastLZ compression (http://www.fastlz.org/"); -DEFINE_bool(snappy, true, "Run snappy compression"); - - -DEFINE_bool(write_compressed, false, -            "Write compressed versions of each file to <file>.comp"); -DEFINE_bool(write_uncompressed, false, -            "Write uncompressed versions of each file to <file>.uncomp"); - -namespace snappy { - - -#ifdef HAVE_FUNC_MMAP - -// To test against code that reads beyond its input, this class copies a -// string to a newly allocated group of pages, the last of which -// is made unreadable via mprotect. Note that we need to allocate the -// memory with mmap(), as POSIX allows mprotect() only on memory allocated -// with mmap(), and some malloc/posix_memalign implementations expect to -// be able to read previously allocated memory while doing heap allocations. -class DataEndingAtUnreadablePage { - public: -  explicit DataEndingAtUnreadablePage(const string& s) { -    const size_t page_size = getpagesize(); -    const size_t size = s.size(); -    // Round up space for string to a multiple of page_size. -    size_t space_for_string = (size + page_size - 1) & ~(page_size - 1); -    alloc_size_ = space_for_string + page_size; -    mem_ = mmap(NULL, alloc_size_, -                PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); -    CHECK_NE(MAP_FAILED, mem_); -    protected_page_ = reinterpret_cast<char*>(mem_) + space_for_string; -    char* dst = protected_page_ - size; -    memcpy(dst, s.data(), size); -    data_ = dst; -    size_ = size; -    // Make guard page unreadable. -    CHECK_EQ(0, mprotect(protected_page_, page_size, PROT_NONE)); -  } - -  ~DataEndingAtUnreadablePage() { -    // Undo the mprotect. -    CHECK_EQ(0, mprotect(protected_page_, getpagesize(), PROT_READ|PROT_WRITE)); -    CHECK_EQ(0, munmap(mem_, alloc_size_)); -  } - -  const char* data() const { return data_; } -  size_t size() const { return size_; } - - private: -  size_t alloc_size_; -  void* mem_; -  char* protected_page_; -  const char* data_; -  size_t size_; -}; - -#else  // HAVE_FUNC_MMAP - -// Fallback for systems without mmap. -typedef string DataEndingAtUnreadablePage; - -#endif - -enum CompressorType { -  ZLIB, LZO, LIBLZF, QUICKLZ, FASTLZ, SNAPPY -}; - -const char* names[] = { -  "ZLIB", "LZO", "LIBLZF", "QUICKLZ", "FASTLZ", "SNAPPY" -}; - -static size_t MinimumRequiredOutputSpace(size_t input_size, -                                         CompressorType comp) { -  switch (comp) { -#ifdef ZLIB_VERSION -    case ZLIB: -      return ZLib::MinCompressbufSize(input_size); -#endif  // ZLIB_VERSION - -#ifdef LZO_VERSION -    case LZO: -      return input_size + input_size/64 + 16 + 3; -#endif  // LZO_VERSION - -#ifdef LZF_VERSION -    case LIBLZF: -      return input_size; -#endif  // LZF_VERSION - -#ifdef QLZ_VERSION_MAJOR -    case QUICKLZ: -      return input_size + 36000;  // 36000 is used for scratch. -#endif  // QLZ_VERSION_MAJOR - -#ifdef FASTLZ_VERSION -    case FASTLZ: -      return max(static_cast<int>(ceil(input_size * 1.05)), 66); -#endif  // FASTLZ_VERSION - -    case SNAPPY: -      return snappy::MaxCompressedLength(input_size); - -    default: -      LOG(FATAL) << "Unknown compression type number " << comp; -  } -} - -// Returns true if we successfully compressed, false otherwise. -// -// If compressed_is_preallocated is set, do not resize the compressed buffer. -// This is typically what you want for a benchmark, in order to not spend -// time in the memory allocator. If you do set this flag, however, -// "compressed" must be preinitialized to at least MinCompressbufSize(comp) -// number of bytes, and may contain junk bytes at the end after return. -static bool Compress(const char* input, size_t input_size, CompressorType comp, -                     string* compressed, bool compressed_is_preallocated) { -  if (!compressed_is_preallocated) { -    compressed->resize(MinimumRequiredOutputSpace(input_size, comp)); -  } - -  switch (comp) { -#ifdef ZLIB_VERSION -    case ZLIB: { -      ZLib zlib; -      uLongf destlen = compressed->size(); -      int ret = zlib.Compress( -          reinterpret_cast<Bytef*>(string_as_array(compressed)), -          &destlen, -          reinterpret_cast<const Bytef*>(input), -          input_size); -      CHECK_EQ(Z_OK, ret); -      if (!compressed_is_preallocated) { -        compressed->resize(destlen); -      } -      return true; -    } -#endif  // ZLIB_VERSION - -#ifdef LZO_VERSION -    case LZO: { -      unsigned char* mem = new unsigned char[LZO1X_1_15_MEM_COMPRESS]; -      lzo_uint destlen; -      int ret = lzo1x_1_15_compress( -          reinterpret_cast<const uint8*>(input), -          input_size, -          reinterpret_cast<uint8*>(string_as_array(compressed)), -          &destlen, -          mem); -      CHECK_EQ(LZO_E_OK, ret); -      delete[] mem; -      if (!compressed_is_preallocated) { -        compressed->resize(destlen); -      } -      break; -    } -#endif  // LZO_VERSION - -#ifdef LZF_VERSION -    case LIBLZF: { -      int destlen = lzf_compress(input, -                                 input_size, -                                 string_as_array(compressed), -                                 input_size); -      if (destlen == 0) { -        // lzf *can* cause lots of blowup when compressing, so they -        // recommend to limit outsize to insize, and just not compress -        // if it's bigger.  Ideally, we'd just swap input and output. -        compressed->assign(input, input_size); -        destlen = input_size; -      } -      if (!compressed_is_preallocated) { -        compressed->resize(destlen); -      } -      break; -    } -#endif  // LZF_VERSION - -#ifdef QLZ_VERSION_MAJOR -    case QUICKLZ: { -      qlz_state_compress *state_compress = new qlz_state_compress; -      int destlen = qlz_compress(input, -                                 string_as_array(compressed), -                                 input_size, -                                 state_compress); -      delete state_compress; -      CHECK_NE(0, destlen); -      if (!compressed_is_preallocated) { -        compressed->resize(destlen); -      } -      break; -    } -#endif  // QLZ_VERSION_MAJOR - -#ifdef FASTLZ_VERSION -    case FASTLZ: { -      // Use level 1 compression since we mostly care about speed. -      int destlen = fastlz_compress_level( -          1, -          input, -          input_size, -          string_as_array(compressed)); -      if (!compressed_is_preallocated) { -        compressed->resize(destlen); -      } -      CHECK_NE(destlen, 0); -      break; -    } -#endif  // FASTLZ_VERSION - -    case SNAPPY: { -      size_t destlen; -      snappy::RawCompress(input, input_size, -                          string_as_array(compressed), -                          &destlen); -      CHECK_LE(destlen, snappy::MaxCompressedLength(input_size)); -      if (!compressed_is_preallocated) { -        compressed->resize(destlen); -      } -      break; -    } - - -    default: { -      return false;     // the asked-for library wasn't compiled in -    } -  } -  return true; -} - -static bool Uncompress(const string& compressed, CompressorType comp, -                       int size, string* output) { -  switch (comp) { -#ifdef ZLIB_VERSION -    case ZLIB: { -      output->resize(size); -      ZLib zlib; -      uLongf destlen = output->size(); -      int ret = zlib.Uncompress( -          reinterpret_cast<Bytef*>(string_as_array(output)), -          &destlen, -          reinterpret_cast<const Bytef*>(compressed.data()), -          compressed.size()); -      CHECK_EQ(Z_OK, ret); -      CHECK_EQ(static_cast<uLongf>(size), destlen); -      break; -    } -#endif  // ZLIB_VERSION - -#ifdef LZO_VERSION -    case LZO: { -      output->resize(size); -      lzo_uint destlen; -      int ret = lzo1x_decompress( -          reinterpret_cast<const uint8*>(compressed.data()), -          compressed.size(), -          reinterpret_cast<uint8*>(string_as_array(output)), -          &destlen, -          NULL); -      CHECK_EQ(LZO_E_OK, ret); -      CHECK_EQ(static_cast<lzo_uint>(size), destlen); -      break; -    } -#endif  // LZO_VERSION - -#ifdef LZF_VERSION -    case LIBLZF: { -      output->resize(size); -      int destlen = lzf_decompress(compressed.data(), -                                   compressed.size(), -                                   string_as_array(output), -                                   output->size()); -      if (destlen == 0) { -        // This error probably means we had decided not to compress, -        // and thus have stored input in output directly. -        output->assign(compressed.data(), compressed.size()); -        destlen = compressed.size(); -      } -      CHECK_EQ(destlen, size); -      break; -    } -#endif  // LZF_VERSION - -#ifdef QLZ_VERSION_MAJOR -    case QUICKLZ: { -      output->resize(size); -      qlz_state_decompress *state_decompress = new qlz_state_decompress; -      int destlen = qlz_decompress(compressed.data(), -                                   string_as_array(output), -                                   state_decompress); -      delete state_decompress; -      CHECK_EQ(destlen, size); -      break; -    } -#endif  // QLZ_VERSION_MAJOR - -#ifdef FASTLZ_VERSION -    case FASTLZ: { -      output->resize(size); -      int destlen = fastlz_decompress(compressed.data(), -                                      compressed.length(), -                                      string_as_array(output), -                                      size); -      CHECK_EQ(destlen, size); -      break; -    } -#endif  // FASTLZ_VERSION - -    case SNAPPY: { -      snappy::RawUncompress(compressed.data(), compressed.size(), -                            string_as_array(output)); -      break; -    } - - -    default: { -      return false;     // the asked-for library wasn't compiled in -    } -  } -  return true; -} - -static void Measure(const char* data, -                    size_t length, -                    CompressorType comp, -                    int repeats, -                    int block_size) { -  // Run tests a few time and pick median running times -  static const int kRuns = 5; -  double ctime[kRuns]; -  double utime[kRuns]; -  int compressed_size = 0; - -  { -    // Chop the input into blocks -    int num_blocks = (length + block_size - 1) / block_size; -    vector<const char*> input(num_blocks); -    vector<size_t> input_length(num_blocks); -    vector<string> compressed(num_blocks); -    vector<string> output(num_blocks); -    for (int b = 0; b < num_blocks; b++) { -      int input_start = b * block_size; -      int input_limit = min<int>((b+1)*block_size, length); -      input[b] = data+input_start; -      input_length[b] = input_limit-input_start; - -      // Pre-grow the output buffer so we don't measure string append time. -      compressed[b].resize(MinimumRequiredOutputSpace(block_size, comp)); -    } - -    // First, try one trial compression to make sure the code is compiled in -    if (!Compress(input[0], input_length[0], comp, &compressed[0], true)) { -      LOG(WARNING) << "Skipping " << names[comp] << ": " -                   << "library not compiled in"; -      return; -    } - -    for (int run = 0; run < kRuns; run++) { -      CycleTimer ctimer, utimer; - -      for (int b = 0; b < num_blocks; b++) { -        // Pre-grow the output buffer so we don't measure string append time. -        compressed[b].resize(MinimumRequiredOutputSpace(block_size, comp)); -      } - -      ctimer.Start(); -      for (int b = 0; b < num_blocks; b++) -        for (int i = 0; i < repeats; i++) -          Compress(input[b], input_length[b], comp, &compressed[b], true); -      ctimer.Stop(); - -      // Compress once more, with resizing, so we don't leave junk -      // at the end that will confuse the decompressor. -      for (int b = 0; b < num_blocks; b++) { -        Compress(input[b], input_length[b], comp, &compressed[b], false); -      } - -      for (int b = 0; b < num_blocks; b++) { -        output[b].resize(input_length[b]); -      } - -      utimer.Start(); -      for (int i = 0; i < repeats; i++) -        for (int b = 0; b < num_blocks; b++) -          Uncompress(compressed[b], comp, input_length[b], &output[b]); -      utimer.Stop(); - -      ctime[run] = ctimer.Get(); -      utime[run] = utimer.Get(); -    } - -    compressed_size = 0; -    for (int i = 0; i < compressed.size(); i++) { -      compressed_size += compressed[i].size(); -    } -  } - -  sort(ctime, ctime + kRuns); -  sort(utime, utime + kRuns); -  const int med = kRuns/2; - -  float comp_rate = (length / ctime[med]) * repeats / 1048576.0; -  float uncomp_rate = (length / utime[med]) * repeats / 1048576.0; -  string x = names[comp]; -  x += ":"; -  string urate = (uncomp_rate >= 0) -                 ? StringPrintf("%.1f", uncomp_rate) -                 : string("?"); -  printf("%-7s [b %dM] bytes %6d -> %6d %4.1f%%  " -         "comp %5.1f MB/s  uncomp %5s MB/s\n", -         x.c_str(), -         block_size/(1<<20), -         static_cast<int>(length), static_cast<uint32>(compressed_size), -         (compressed_size * 100.0) / max<int>(1, length), -         comp_rate, -         urate.c_str()); -} - - -static int VerifyString(const string& input) { -  string compressed; -  DataEndingAtUnreadablePage i(input); -  const size_t written = snappy::Compress(i.data(), i.size(), &compressed); -  CHECK_EQ(written, compressed.size()); -  CHECK_LE(compressed.size(), -           snappy::MaxCompressedLength(input.size())); -  CHECK(snappy::IsValidCompressedBuffer(compressed.data(), compressed.size())); - -  string uncompressed; -  DataEndingAtUnreadablePage c(compressed); -  CHECK(snappy::Uncompress(c.data(), c.size(), &uncompressed)); -  CHECK_EQ(uncompressed, input); -  return uncompressed.size(); -} - - -// Test that data compressed by a compressor that does not -// obey block sizes is uncompressed properly. -static void VerifyNonBlockedCompression(const string& input) { -  if (input.length() > snappy::kBlockSize) { -    // We cannot test larger blocks than the maximum block size, obviously. -    return; -  } - -  string prefix; -  Varint::Append32(&prefix, input.size()); - -  // Setup compression table -  snappy::internal::WorkingMemory wmem; -  int table_size; -  uint16* table = wmem.GetHashTable(input.size(), &table_size); - -  // Compress entire input in one shot -  string compressed; -  compressed += prefix; -  compressed.resize(prefix.size()+snappy::MaxCompressedLength(input.size())); -  char* dest = string_as_array(&compressed) + prefix.size(); -  char* end = snappy::internal::CompressFragment(input.data(), input.size(), -                                                dest, table, table_size); -  compressed.resize(end - compressed.data()); - -  // Uncompress into string -  string uncomp_str; -  CHECK(snappy::Uncompress(compressed.data(), compressed.size(), &uncomp_str)); -  CHECK_EQ(uncomp_str, input); - -} - -// Expand the input so that it is at least K times as big as block size -static string Expand(const string& input) { -  static const int K = 3; -  string data = input; -  while (data.size() < K * snappy::kBlockSize) { -    data += input; -  } -  return data; -} - -static int Verify(const string& input) { -  VLOG(1) << "Verifying input of size " << input.size(); - -  // Compress using string based routines -  const int result = VerifyString(input); - - -  VerifyNonBlockedCompression(input); -  if (!input.empty()) { -    VerifyNonBlockedCompression(Expand(input)); -  } - - -  return result; -} - -// This test checks to ensure that snappy doesn't coredump if it gets -// corrupted data. - -static bool IsValidCompressedBuffer(const string& c) { -  return snappy::IsValidCompressedBuffer(c.data(), c.size()); -} -static bool Uncompress(const string& c, string* u) { -  return snappy::Uncompress(c.data(), c.size(), u); -} - -TYPED_TEST(CorruptedTest, VerifyCorrupted) { -  string source = "making sure we don't crash with corrupted input"; -  VLOG(1) << source; -  string dest; -  TypeParam uncmp; -  snappy::Compress(source.data(), source.size(), &dest); - -  // Mess around with the data. It's hard to simulate all possible -  // corruptions; this is just one example ... -  CHECK_GT(dest.size(), 3); -  dest[1]--; -  dest[3]++; -  // this really ought to fail. -  CHECK(!IsValidCompressedBuffer(TypeParam(dest))); -  CHECK(!Uncompress(TypeParam(dest), &uncmp)); - -  // This is testing for a security bug - a buffer that decompresses to 100k -  // but we lie in the snappy header and only reserve 0 bytes of memory :) -  source.resize(100000); -  for (int i = 0; i < source.length(); ++i) { -    source[i] = 'A'; -  } -  snappy::Compress(source.data(), source.size(), &dest); -  dest[0] = dest[1] = dest[2] = dest[3] = 0; -  CHECK(!IsValidCompressedBuffer(TypeParam(dest))); -  CHECK(!Uncompress(TypeParam(dest), &uncmp)); - -  if (sizeof(void *) == 4) { -    // Another security check; check a crazy big length can't DoS us with an -    // over-allocation. -    // Currently this is done only for 32-bit builds.  On 64-bit builds, -    // where 3 GB might be an acceptable allocation size, Uncompress() -    // attempts to decompress, and sometimes causes the test to run out of -    // memory. -    dest[0] = dest[1] = dest[2] = dest[3] = 0xff; -    // This decodes to a really large size, i.e., about 3 GB. -    dest[4] = 'k'; -    CHECK(!IsValidCompressedBuffer(TypeParam(dest))); -    CHECK(!Uncompress(TypeParam(dest), &uncmp)); -  } else { -    LOG(WARNING) << "Crazy decompression lengths not checked on 64-bit build"; -  } - -  // This decodes to about 2 MB; much smaller, but should still fail. -  dest[0] = dest[1] = dest[2] = 0xff; -  dest[3] = 0x00; -  CHECK(!IsValidCompressedBuffer(TypeParam(dest))); -  CHECK(!Uncompress(TypeParam(dest), &uncmp)); - -  // try reading stuff in from a bad file. -  for (int i = 1; i <= 3; ++i) { -    string data = ReadTestDataFile(StringPrintf("baddata%d.snappy", i).c_str(), -                                   0); -    string uncmp; -    // check that we don't return a crazy length -    size_t ulen; -    CHECK(!snappy::GetUncompressedLength(data.data(), data.size(), &ulen) -          || (ulen < (1<<20))); -    uint32 ulen2; -    snappy::ByteArraySource source(data.data(), data.size()); -    CHECK(!snappy::GetUncompressedLength(&source, &ulen2) || -          (ulen2 < (1<<20))); -    CHECK(!IsValidCompressedBuffer(TypeParam(data))); -    CHECK(!Uncompress(TypeParam(data), &uncmp)); -  } -} - -// Helper routines to construct arbitrary compressed strings. -// These mirror the compression code in snappy.cc, but are copied -// here so that we can bypass some limitations in the how snappy.cc -// invokes these routines. -static void AppendLiteral(string* dst, const string& literal) { -  if (literal.empty()) return; -  int n = literal.size() - 1; -  if (n < 60) { -    // Fit length in tag byte -    dst->push_back(0 | (n << 2)); -  } else { -    // Encode in upcoming bytes -    char number[4]; -    int count = 0; -    while (n > 0) { -      number[count++] = n & 0xff; -      n >>= 8; -    } -    dst->push_back(0 | ((59+count) << 2)); -    *dst += string(number, count); -  } -  *dst += literal; -} - -static void AppendCopy(string* dst, int offset, int length) { -  while (length > 0) { -    // Figure out how much to copy in one shot -    int to_copy; -    if (length >= 68) { -      to_copy = 64; -    } else if (length > 64) { -      to_copy = 60; -    } else { -      to_copy = length; -    } -    length -= to_copy; - -    if ((to_copy < 12) && (offset < 2048)) { -      assert(to_copy-4 < 8);            // Must fit in 3 bits -      dst->push_back(1 | ((to_copy-4) << 2) | ((offset >> 8) << 5)); -      dst->push_back(offset & 0xff); -    } else if (offset < 65536) { -      dst->push_back(2 | ((to_copy-1) << 2)); -      dst->push_back(offset & 0xff); -      dst->push_back(offset >> 8); -    } else { -      dst->push_back(3 | ((to_copy-1) << 2)); -      dst->push_back(offset & 0xff); -      dst->push_back((offset >> 8) & 0xff); -      dst->push_back((offset >> 16) & 0xff); -      dst->push_back((offset >> 24) & 0xff); -    } -  } -} - -TEST(Snappy, SimpleTests) { -  Verify(""); -  Verify("a"); -  Verify("ab"); -  Verify("abc"); - -  Verify("aaaaaaa" + string(16, 'b') + string("aaaaa") + "abc"); -  Verify("aaaaaaa" + string(256, 'b') + string("aaaaa") + "abc"); -  Verify("aaaaaaa" + string(2047, 'b') + string("aaaaa") + "abc"); -  Verify("aaaaaaa" + string(65536, 'b') + string("aaaaa") + "abc"); -  Verify("abcaaaaaaa" + string(65536, 'b') + string("aaaaa") + "abc"); -} - -// Verify max blowup (lots of four-byte copies) -TEST(Snappy, MaxBlowup) { -  string input; -  for (int i = 0; i < 20000; i++) { -    ACMRandom rnd(i); -    uint32 bytes = static_cast<uint32>(rnd.Next()); -    input.append(reinterpret_cast<char*>(&bytes), sizeof(bytes)); -  } -  for (int i = 19999; i >= 0; i--) { -    ACMRandom rnd(i); -    uint32 bytes = static_cast<uint32>(rnd.Next()); -    input.append(reinterpret_cast<char*>(&bytes), sizeof(bytes)); -  } -  Verify(input); -} - -TEST(Snappy, RandomData) { -  ACMRandom rnd(FLAGS_test_random_seed); - -  const int num_ops = 20000; -  for (int i = 0; i < num_ops; i++) { -    if ((i % 1000) == 0) { -      VLOG(0) << "Random op " << i << " of " << num_ops; -    } - -    string x; -    int len = rnd.Uniform(4096); -    if (i < 100) { -      len = 65536 + rnd.Uniform(65536); -    } -    while (x.size() < len) { -      int run_len = 1; -      if (rnd.OneIn(10)) { -        run_len = rnd.Skewed(8); -      } -      char c = (i < 100) ? rnd.Uniform(256) : rnd.Skewed(3); -      while (run_len-- > 0 && x.size() < len) { -        x += c; -      } -    } - -    Verify(x); -  } -} - -TEST(Snappy, FourByteOffset) { -  // The new compressor cannot generate four-byte offsets since -  // it chops up the input into 32KB pieces.  So we hand-emit the -  // copy manually. - -  // The two fragments that make up the input string. -  string fragment1 = "012345689abcdefghijklmnopqrstuvwxyz"; -  string fragment2 = "some other string"; - -  // How many times each fragment is emitted. -  const int n1 = 2; -  const int n2 = 100000 / fragment2.size(); -  const int length = n1 * fragment1.size() + n2 * fragment2.size(); - -  string compressed; -  Varint::Append32(&compressed, length); - -  AppendLiteral(&compressed, fragment1); -  string src = fragment1; -  for (int i = 0; i < n2; i++) { -    AppendLiteral(&compressed, fragment2); -    src += fragment2; -  } -  AppendCopy(&compressed, src.size(), fragment1.size()); -  src += fragment1; -  CHECK_EQ(length, src.size()); - -  string uncompressed; -  CHECK(snappy::IsValidCompressedBuffer(compressed.data(), compressed.size())); -  CHECK(snappy::Uncompress(compressed.data(), compressed.size(), -                           &uncompressed)); -  CHECK_EQ(uncompressed, src); -} - - -static bool CheckUncompressedLength(const string& compressed, -                                    size_t* ulength) { -  const bool result1 = snappy::GetUncompressedLength(compressed.data(), -                                                     compressed.size(), -                                                     ulength); - -  snappy::ByteArraySource source(compressed.data(), compressed.size()); -  uint32 length; -  const bool result2 = snappy::GetUncompressedLength(&source, &length); -  CHECK_EQ(result1, result2); -  return result1; -} - -TEST(SnappyCorruption, TruncatedVarint) { -  string compressed, uncompressed; -  size_t ulength; -  compressed.push_back('\xf0'); -  CHECK(!CheckUncompressedLength(compressed, &ulength)); -  CHECK(!snappy::IsValidCompressedBuffer(compressed.data(), compressed.size())); -  CHECK(!snappy::Uncompress(compressed.data(), compressed.size(), -                            &uncompressed)); -} - -TEST(SnappyCorruption, UnterminatedVarint) { -  string compressed, uncompressed; -  size_t ulength; -  compressed.push_back(128); -  compressed.push_back(128); -  compressed.push_back(128); -  compressed.push_back(128); -  compressed.push_back(128); -  compressed.push_back(10); -  CHECK(!CheckUncompressedLength(compressed, &ulength)); -  CHECK(!snappy::IsValidCompressedBuffer(compressed.data(), compressed.size())); -  CHECK(!snappy::Uncompress(compressed.data(), compressed.size(), -                            &uncompressed)); -} - -TEST(Snappy, ReadPastEndOfBuffer) { -  // Check that we do not read past end of input - -  // Make a compressed string that ends with a single-byte literal -  string compressed; -  Varint::Append32(&compressed, 1); -  AppendLiteral(&compressed, "x"); - -  string uncompressed; -  DataEndingAtUnreadablePage c(compressed); -  CHECK(snappy::Uncompress(c.data(), c.size(), &uncompressed)); -  CHECK_EQ(uncompressed, string("x")); -} - -// Check for an infinite loop caused by a copy with offset==0 -TEST(Snappy, ZeroOffsetCopy) { -  const char* compressed = "\x40\x12\x00\x00"; -  //  \x40              Length (must be > kMaxIncrementCopyOverflow) -  //  \x12\x00\x00      Copy with offset==0, length==5 -  char uncompressed[100]; -  EXPECT_FALSE(snappy::RawUncompress(compressed, 4, uncompressed)); -} - -TEST(Snappy, ZeroOffsetCopyValidation) { -  const char* compressed = "\x05\x12\x00\x00"; -  //  \x05              Length -  //  \x12\x00\x00      Copy with offset==0, length==5 -  EXPECT_FALSE(snappy::IsValidCompressedBuffer(compressed, 4)); -} - - -namespace { - -int TestFindMatchLength(const char* s1, const char *s2, unsigned length) { -  return snappy::internal::FindMatchLength(s1, s2, s2 + length); -} - -}  // namespace - -TEST(Snappy, FindMatchLength) { -  // Exercise all different code paths through the function. -  // 64-bit version: - -  // Hit s1_limit in 64-bit loop, hit s1_limit in single-character loop. -  EXPECT_EQ(6, TestFindMatchLength("012345", "012345", 6)); -  EXPECT_EQ(11, TestFindMatchLength("01234567abc", "01234567abc", 11)); - -  // Hit s1_limit in 64-bit loop, find a non-match in single-character loop. -  EXPECT_EQ(9, TestFindMatchLength("01234567abc", "01234567axc", 9)); - -  // Same, but edge cases. -  EXPECT_EQ(11, TestFindMatchLength("01234567abc!", "01234567abc!", 11)); -  EXPECT_EQ(11, TestFindMatchLength("01234567abc!", "01234567abc?", 11)); - -  // Find non-match at once in first loop. -  EXPECT_EQ(0, TestFindMatchLength("01234567xxxxxxxx", "?1234567xxxxxxxx", 16)); -  EXPECT_EQ(1, TestFindMatchLength("01234567xxxxxxxx", "0?234567xxxxxxxx", 16)); -  EXPECT_EQ(4, TestFindMatchLength("01234567xxxxxxxx", "01237654xxxxxxxx", 16)); -  EXPECT_EQ(7, TestFindMatchLength("01234567xxxxxxxx", "0123456?xxxxxxxx", 16)); - -  // Find non-match in first loop after one block. -  EXPECT_EQ(8, TestFindMatchLength("abcdefgh01234567xxxxxxxx", -                                   "abcdefgh?1234567xxxxxxxx", 24)); -  EXPECT_EQ(9, TestFindMatchLength("abcdefgh01234567xxxxxxxx", -                                   "abcdefgh0?234567xxxxxxxx", 24)); -  EXPECT_EQ(12, TestFindMatchLength("abcdefgh01234567xxxxxxxx", -                                    "abcdefgh01237654xxxxxxxx", 24)); -  EXPECT_EQ(15, TestFindMatchLength("abcdefgh01234567xxxxxxxx", -                                    "abcdefgh0123456?xxxxxxxx", 24)); - -  // 32-bit version: - -  // Short matches. -  EXPECT_EQ(0, TestFindMatchLength("01234567", "?1234567", 8)); -  EXPECT_EQ(1, TestFindMatchLength("01234567", "0?234567", 8)); -  EXPECT_EQ(2, TestFindMatchLength("01234567", "01?34567", 8)); -  EXPECT_EQ(3, TestFindMatchLength("01234567", "012?4567", 8)); -  EXPECT_EQ(4, TestFindMatchLength("01234567", "0123?567", 8)); -  EXPECT_EQ(5, TestFindMatchLength("01234567", "01234?67", 8)); -  EXPECT_EQ(6, TestFindMatchLength("01234567", "012345?7", 8)); -  EXPECT_EQ(7, TestFindMatchLength("01234567", "0123456?", 8)); -  EXPECT_EQ(7, TestFindMatchLength("01234567", "0123456?", 7)); -  EXPECT_EQ(7, TestFindMatchLength("01234567!", "0123456??", 7)); - -  // Hit s1_limit in 32-bit loop, hit s1_limit in single-character loop. -  EXPECT_EQ(10, TestFindMatchLength("xxxxxxabcd", "xxxxxxabcd", 10)); -  EXPECT_EQ(10, TestFindMatchLength("xxxxxxabcd?", "xxxxxxabcd?", 10)); -  EXPECT_EQ(13, TestFindMatchLength("xxxxxxabcdef", "xxxxxxabcdef", 13)); - -  // Same, but edge cases. -  EXPECT_EQ(12, TestFindMatchLength("xxxxxx0123abc!", "xxxxxx0123abc!", 12)); -  EXPECT_EQ(12, TestFindMatchLength("xxxxxx0123abc!", "xxxxxx0123abc?", 12)); - -  // Hit s1_limit in 32-bit loop, find a non-match in single-character loop. -  EXPECT_EQ(11, TestFindMatchLength("xxxxxx0123abc", "xxxxxx0123axc", 13)); - -  // Find non-match at once in first loop. -  EXPECT_EQ(6, TestFindMatchLength("xxxxxx0123xxxxxxxx", -                                   "xxxxxx?123xxxxxxxx", 18)); -  EXPECT_EQ(7, TestFindMatchLength("xxxxxx0123xxxxxxxx", -                                   "xxxxxx0?23xxxxxxxx", 18)); -  EXPECT_EQ(8, TestFindMatchLength("xxxxxx0123xxxxxxxx", -                                   "xxxxxx0132xxxxxxxx", 18)); -  EXPECT_EQ(9, TestFindMatchLength("xxxxxx0123xxxxxxxx", -                                   "xxxxxx012?xxxxxxxx", 18)); - -  // Same, but edge cases. -  EXPECT_EQ(6, TestFindMatchLength("xxxxxx0123", "xxxxxx?123", 10)); -  EXPECT_EQ(7, TestFindMatchLength("xxxxxx0123", "xxxxxx0?23", 10)); -  EXPECT_EQ(8, TestFindMatchLength("xxxxxx0123", "xxxxxx0132", 10)); -  EXPECT_EQ(9, TestFindMatchLength("xxxxxx0123", "xxxxxx012?", 10)); - -  // Find non-match in first loop after one block. -  EXPECT_EQ(10, TestFindMatchLength("xxxxxxabcd0123xx", -                                    "xxxxxxabcd?123xx", 16)); -  EXPECT_EQ(11, TestFindMatchLength("xxxxxxabcd0123xx", -                                    "xxxxxxabcd0?23xx", 16)); -  EXPECT_EQ(12, TestFindMatchLength("xxxxxxabcd0123xx", -                                    "xxxxxxabcd0132xx", 16)); -  EXPECT_EQ(13, TestFindMatchLength("xxxxxxabcd0123xx", -                                    "xxxxxxabcd012?xx", 16)); - -  // Same, but edge cases. -  EXPECT_EQ(10, TestFindMatchLength("xxxxxxabcd0123", "xxxxxxabcd?123", 14)); -  EXPECT_EQ(11, TestFindMatchLength("xxxxxxabcd0123", "xxxxxxabcd0?23", 14)); -  EXPECT_EQ(12, TestFindMatchLength("xxxxxxabcd0123", "xxxxxxabcd0132", 14)); -  EXPECT_EQ(13, TestFindMatchLength("xxxxxxabcd0123", "xxxxxxabcd012?", 14)); -} - -TEST(Snappy, FindMatchLengthRandom) { -  const int kNumTrials = 10000; -  const int kTypicalLength = 10; -  ACMRandom rnd(FLAGS_test_random_seed); - -  for (int i = 0; i < kNumTrials; i++) { -    string s, t; -    char a = rnd.Rand8(); -    char b = rnd.Rand8(); -    while (!rnd.OneIn(kTypicalLength)) { -      s.push_back(rnd.OneIn(2) ? a : b); -      t.push_back(rnd.OneIn(2) ? a : b); -    } -    DataEndingAtUnreadablePage u(s); -    DataEndingAtUnreadablePage v(t); -    int matched = snappy::internal::FindMatchLength( -        u.data(), v.data(), v.data() + t.size()); -    if (matched == t.size()) { -      EXPECT_EQ(s, t); -    } else { -      EXPECT_NE(s[matched], t[matched]); -      for (int j = 0; j < matched; j++) { -        EXPECT_EQ(s[j], t[j]); -      } -    } -  } -} - - -static void CompressFile(const char* fname) { -  string fullinput; -  file::GetContents(fname, &fullinput, file::Defaults()).CheckSuccess(); - -  string compressed; -  Compress(fullinput.data(), fullinput.size(), SNAPPY, &compressed, false); - -  file::SetContents(string(fname).append(".comp"), compressed, file::Defaults()) -      .CheckSuccess(); -} - -static void UncompressFile(const char* fname) { -  string fullinput; -  file::GetContents(fname, &fullinput, file::Defaults()).CheckSuccess(); - -  size_t uncompLength; -  CHECK(CheckUncompressedLength(fullinput, &uncompLength)); - -  string uncompressed; -  uncompressed.resize(uncompLength); -  CHECK(snappy::Uncompress(fullinput.data(), fullinput.size(), &uncompressed)); - -  file::SetContents(string(fname).append(".uncomp"), uncompressed, -                    file::Defaults()).CheckSuccess(); -} - -static void MeasureFile(const char* fname) { -  string fullinput; -  file::GetContents(fname, &fullinput, file::Defaults()).CheckSuccess(); -  printf("%-40s :\n", fname); - -  int start_len = (FLAGS_start_len < 0) ? fullinput.size() : FLAGS_start_len; -  int end_len = fullinput.size(); -  if (FLAGS_end_len >= 0) { -    end_len = min<int>(fullinput.size(), FLAGS_end_len); -  } -  for (int len = start_len; len <= end_len; len++) { -    const char* const input = fullinput.data(); -    int repeats = (FLAGS_bytes + len) / (len + 1); -    if (FLAGS_zlib)     Measure(input, len, ZLIB, repeats, 1024<<10); -    if (FLAGS_lzo)      Measure(input, len, LZO, repeats, 1024<<10); -    if (FLAGS_liblzf)   Measure(input, len, LIBLZF, repeats, 1024<<10); -    if (FLAGS_quicklz)  Measure(input, len, QUICKLZ, repeats, 1024<<10); -    if (FLAGS_fastlz)   Measure(input, len, FASTLZ, repeats, 1024<<10); -    if (FLAGS_snappy)    Measure(input, len, SNAPPY, repeats, 4096<<10); - -    // For block-size based measurements -    if (0 && FLAGS_snappy) { -      Measure(input, len, SNAPPY, repeats, 8<<10); -      Measure(input, len, SNAPPY, repeats, 16<<10); -      Measure(input, len, SNAPPY, repeats, 32<<10); -      Measure(input, len, SNAPPY, repeats, 64<<10); -      Measure(input, len, SNAPPY, repeats, 256<<10); -      Measure(input, len, SNAPPY, repeats, 1024<<10); -    } -  } -} - -static struct { -  const char* label; -  const char* filename; -  size_t size_limit; -} files[] = { -  { "html", "html", 0 }, -  { "urls", "urls.10K", 0 }, -  { "jpg", "house.jpg", 0 }, -  { "jpg_200", "house.jpg", 200 }, -  { "pdf", "mapreduce-osdi-1.pdf", 0 }, -  { "html4", "html_x_4", 0 }, -  { "cp", "cp.html", 0 }, -  { "c", "fields.c", 0 }, -  { "lsp", "grammar.lsp", 0 }, -  { "xls", "kennedy.xls", 0 }, -  { "xls_200", "kennedy.xls", 200 }, -  { "txt1", "alice29.txt", 0 }, -  { "txt2", "asyoulik.txt", 0 }, -  { "txt3", "lcet10.txt", 0 }, -  { "txt4", "plrabn12.txt", 0 }, -  { "bin", "ptt5", 0 }, -  { "bin_200", "ptt5", 200 }, -  { "sum", "sum", 0 }, -  { "man", "xargs.1", 0 }, -  { "pb", "geo.protodata", 0 }, -  { "gaviota", "kppkn.gtb", 0 }, -}; - -static void BM_UFlat(int iters, int arg) { -  StopBenchmarkTiming(); - -  // Pick file to process based on "arg" -  CHECK_GE(arg, 0); -  CHECK_LT(arg, ARRAYSIZE(files)); -  string contents = ReadTestDataFile(files[arg].filename, -                                     files[arg].size_limit); - -  string zcontents; -  snappy::Compress(contents.data(), contents.size(), &zcontents); -  char* dst = new char[contents.size()]; - -  SetBenchmarkBytesProcessed(static_cast<int64>(iters) * -                             static_cast<int64>(contents.size())); -  SetBenchmarkLabel(files[arg].label); -  StartBenchmarkTiming(); -  while (iters-- > 0) { -    CHECK(snappy::RawUncompress(zcontents.data(), zcontents.size(), dst)); -  } -  StopBenchmarkTiming(); - -  delete[] dst; -} -BENCHMARK(BM_UFlat)->DenseRange(0, ARRAYSIZE(files) - 1); - -static void BM_UValidate(int iters, int arg) { -  StopBenchmarkTiming(); - -  // Pick file to process based on "arg" -  CHECK_GE(arg, 0); -  CHECK_LT(arg, ARRAYSIZE(files)); -  string contents = ReadTestDataFile(files[arg].filename, -                                     files[arg].size_limit); - -  string zcontents; -  snappy::Compress(contents.data(), contents.size(), &zcontents); - -  SetBenchmarkBytesProcessed(static_cast<int64>(iters) * -                             static_cast<int64>(contents.size())); -  SetBenchmarkLabel(files[arg].label); -  StartBenchmarkTiming(); -  while (iters-- > 0) { -    CHECK(snappy::IsValidCompressedBuffer(zcontents.data(), zcontents.size())); -  } -  StopBenchmarkTiming(); -} -BENCHMARK(BM_UValidate)->DenseRange(0, 4); - - -static void BM_ZFlat(int iters, int arg) { -  StopBenchmarkTiming(); - -  // Pick file to process based on "arg" -  CHECK_GE(arg, 0); -  CHECK_LT(arg, ARRAYSIZE(files)); -  string contents = ReadTestDataFile(files[arg].filename, -                                     files[arg].size_limit); - -  char* dst = new char[snappy::MaxCompressedLength(contents.size())]; - -  SetBenchmarkBytesProcessed(static_cast<int64>(iters) * -                             static_cast<int64>(contents.size())); -  StartBenchmarkTiming(); - -  size_t zsize = 0; -  while (iters-- > 0) { -    snappy::RawCompress(contents.data(), contents.size(), dst, &zsize); -  } -  StopBenchmarkTiming(); -  const double compression_ratio = -      static_cast<double>(zsize) / std::max<size_t>(1, contents.size()); -  SetBenchmarkLabel(StringPrintf("%s (%.2f %%)", -                                 files[arg].label, 100.0 * compression_ratio)); -  VLOG(0) << StringPrintf("compression for %s: %zd -> %zd bytes", -                          files[arg].label, contents.size(), zsize); -  delete[] dst; -} -BENCHMARK(BM_ZFlat)->DenseRange(0, ARRAYSIZE(files) - 1); - - -}  // namespace snappy - - -int main(int argc, char** argv) { -  InitGoogle(argv[0], &argc, &argv, true); -  File::Init(); -  RunSpecifiedBenchmarks(); - - -  if (argc >= 2) { -    for (int arg = 1; arg < argc; arg++) { -      if (FLAGS_write_compressed) { -        CompressFile(argv[arg]); -      } else if (FLAGS_write_uncompressed) { -        UncompressFile(argv[arg]); -      } else { -        MeasureFile(argv[arg]); -      } -    } -    return 0; -  } - -  return RUN_ALL_TESTS(); -} | 
