YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/zlib.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
#include "yb/util/zlib.h"
18
#include <zlib.h>
19
20
#include <memory>
21
#include <string>
22
23
#include "yb/gutil/casts.h"
24
#include "yb/gutil/macros.h"
25
26
#include "yb/util/slice.h"
27
#include "yb/util/status.h"
28
#include "yb/util/status_format.h"
29
30
using std::ostream;
31
using std::string;
32
using std::unique_ptr;
33
34
#define ZRETURN_NOT_OK(call) \
35
6
  RETURN_NOT_OK(ZlibResultToStatus(call))
36
37
namespace yb {
38
namespace zlib {
39
40
namespace  {
41
11
Status ZlibResultToStatus(int rc) {
42
11
  switch (rc) {
43
8
    case Z_OK:
44
8
      return Status::OK();
45
3
    case Z_STREAM_END:
46
3
      return STATUS(EndOfFile, "zlib EOF");
47
0
    case Z_NEED_DICT:
48
0
      return STATUS(Corruption, "zlib error: NEED_DICT");
49
0
    case Z_ERRNO:
50
0
      return STATUS(IOError, "zlib error: Z_ERRNO");
51
0
    case Z_STREAM_ERROR:
52
0
      return STATUS(Corruption, "zlib error: STREAM_ERROR");
53
0
    case Z_DATA_ERROR:
54
0
      return STATUS(Corruption, "zlib error: DATA_ERROR");
55
0
    case Z_MEM_ERROR:
56
0
      return STATUS(RuntimeError, "zlib error: MEM_ERROR");
57
0
    case Z_BUF_ERROR:
58
0
      return STATUS(RuntimeError, "zlib error: BUF_ERROR");
59
0
    case Z_VERSION_ERROR:
60
0
      return STATUS(RuntimeError, "zlib error: VERSION_ERROR");
61
0
    default:
62
0
      return STATUS_FORMAT(RuntimeError, "zlib error: unknown error $0", rc);
63
11
  }
64
11
}
65
} // anonymous namespace
66
67
0
Status Compress(Slice input, ostream* out) {
68
0
  return CompressLevel(input, Z_DEFAULT_COMPRESSION, out);
69
0
}
70
71
// See https://zlib.net/zlib_how.html for context on using zlib.
72
2
Status CompressLevel(Slice input, int level, ostream* out) {
73
2
  z_stream zs;
74
2
  memset(&zs, 0, sizeof(zs));
75
2
  ZRETURN_NOT_OK(deflateInit2(&zs, level, Z_DEFLATED,
76
2
                              MAX_WBITS + 16 /* enable gzip */,
77
2
                              8 /* memory level, max is 9 */,
78
2
                              Z_DEFAULT_STRATEGY));
79
80
2
  zs.avail_in = narrow_cast<uInt>(input.size());
81
2
  zs.next_in = const_cast<uint8_t*>(input.data());
82
2
  const int kChunkSize = 64 * 1024;
83
2
  unique_ptr<unsigned char[]> chunk(new unsigned char[kChunkSize]);
84
2
  int flush;
85
4
  do {
86
4
    zs.avail_out = kChunkSize;
87
4
    zs.next_out = chunk.get();
88
4
    flush = (zs.avail_in == 0) ? Z_FINISH : Z_NO_FLUSH;
89
4
    Status s = ZlibResultToStatus(deflate(&zs, flush));
90
4
    if (!s.ok() && !s.IsEndOfFile()) {
91
0
      deflateEnd(&zs);
92
0
      return s;
93
0
    }
94
4
    auto out_size = zs.next_out - chunk.get();
95
4
    if (out_size > 0) {
96
4
      out->write(reinterpret_cast<char *>(chunk.get()), out_size);
97
4
    }
98
4
  } while (flush != Z_FINISH);
99
2
  ZRETURN_NOT_OK(deflateEnd(&zs));
100
2
  return Status::OK();
101
2
}
102
103
// See https://zlib.net/zlib_how.html for context on using zlib.
104
1
Status Uncompress(const Slice& compressed, std::ostream* out) {
105
  // Initialize the z_stream at the start of the data with the
106
  // data size as the available input.
107
1
  z_stream zs;
108
1
  memset(&zs, 0, sizeof(zs));
109
1
  zs.next_in = const_cast<uint8_t*>(compressed.data());
110
1
  zs.avail_in = narrow_cast<uInt>(compressed.size());
111
  // Initialize inflation with the windowBits set to be GZIP compatible.
112
  // The documentation (https://www.zlib.net/manual.html#Advanced) describes that
113
  // Adding 16 configures inflate to decode the gzip format.
114
1
  ZRETURN_NOT_OK(inflateInit2(&zs, MAX_WBITS + 16 /* enable gzip */));
115
  // Continue calling inflate, decompressing data into the buffer in `zs.next_out` and writing
116
  // the buffer content to `out`, until an error is received or there is no more data
117
  // to decompress.
118
1
  Status s;
119
1
  do {
120
1
    unsigned char buf[4096];
121
1
    zs.next_out = buf;
122
1
    zs.avail_out = arraysize(buf);
123
1
    s = ZlibResultToStatus(inflate(&zs, Z_NO_FLUSH));
124
1
    if (!s.ok() && !s.IsEndOfFile()) {
125
0
      inflateEnd(&zs);
126
0
      return s;
127
0
    }
128
1
    out->write(reinterpret_cast<char *>(buf), zs.next_out - buf);
129
1
  } while (zs.avail_out == 0);
130
  // If we haven't returned early with a bad status, finalize inflation.
131
1
  ZRETURN_NOT_OK(inflateEnd(&zs));
132
1
  return Status::OK();
133
1
}
134
135
} // namespace zlib
136
} // namespace yb