0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
BlockCompressionCodecZlib.cc
Go to the documentation of this file.
1 /* -*- c++ -*-
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; version 3 of the
9  * License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
22 #include <Common/Compat.h>
23 
25 
26 #include <Common/DynamicBuffer.h>
27 #include <Common/Logger.h>
28 #include <Common/Checksum.h>
29 
30 using namespace Hypertable;
31 
32 
34  : m_inflate_initialized(false), m_deflate_initialized(false),
35  m_level(Z_BEST_SPEED) {
36  set_args(args);
37 }
38 
39 
42  deflateEnd(&m_stream_deflate);
44  inflateEnd(&m_stream_inflate);
45 }
46 
48  Args::const_iterator it = args.begin(), arg_end = args.end();
49 
50  for (; it != arg_end; ++it) {
51  if (*it == "--best" || *it == "-9") {
52  m_level = Z_BEST_COMPRESSION;
54  deflateEnd(&m_stream_deflate);
55  m_deflate_initialized = false;
56  }
57  }
58  else if (*it == "--normal") {
59  m_level = Z_DEFAULT_COMPRESSION;
61  deflateEnd(&m_stream_deflate);
62  m_deflate_initialized = false;
63  }
64  }
65  else {
66  HT_THROWF(Error::BLOCK_COMPRESSOR_INVALID_ARG, "Unrecognized argument "
67  "to Zlib codec: '%s'", (*it).c_str());
68  }
69  }
70 }
71 
72 void
74  DynamicBuffer &output, BlockHeader &header, size_t reserve) {
75  // see http://www.zlib.net/zlib_tech.html
76  uint32_t avail_out = input.fill() + 6 + (((input.fill() / 16000) + 1) * 5);
77 
78  if (!m_deflate_initialized) {
79  memset(&m_stream_deflate, 0, sizeof(m_stream_deflate));
80  m_stream_deflate.zalloc = Z_NULL;
81  m_stream_deflate.zfree = Z_NULL;
82  m_stream_deflate.opaque = Z_NULL;
83  int ret = deflateInit(&m_stream_deflate, m_level);
84  assert(ret == Z_OK);
85  (void)ret;
86  m_deflate_initialized = true;
87  }
88 
89  output.clear();
90  output.reserve(header.encoded_length() + avail_out + reserve);
91 
92  m_stream_deflate.avail_in = input.fill();
93  m_stream_deflate.next_in = input.base;
94 
95  m_stream_deflate.avail_out = avail_out;
96  m_stream_deflate.next_out = output.base + header.encoded_length();
97 
98  int ret = ::deflate(&m_stream_deflate, Z_FINISH);
99  assert(ret == Z_STREAM_END);
100  (void)ret;
101 
102  uint32_t zlen = avail_out - m_stream_deflate.avail_out;
103 
104  /* check for an incompressible block */
105  if (zlen >= input.fill()) {
106  header.set_compression_type(NONE);
107  memcpy(output.base+header.encoded_length(), input.base, input.fill());
108  header.set_data_length(input.fill());
109  header.set_data_zlength(input.fill());
110  }
111  else {
112  header.set_compression_type(ZLIB);
113  header.set_data_length(input.fill());
114  header.set_data_zlength(zlen);
115  }
116 
117  header.set_data_checksum(fletcher32(output.base + header.encoded_length(),
118  header.get_data_zlength()));
119 
120  deflateReset(&m_stream_deflate);
121 
122  output.ptr = output.base;
123  header.encode(&output.ptr);
124  output.ptr += header.get_data_zlength();
125 }
126 
127 
131 void
133  DynamicBuffer &output, BlockHeader &header) {
134  int ret;
135  const uint8_t *msg_ptr = input.base;
136  size_t remaining = input.fill();
137 
138  if (!m_inflate_initialized) {
139  memset(&m_stream_inflate, 0, sizeof(m_stream_inflate));
140  m_stream_inflate.zalloc = Z_NULL;
141  m_stream_inflate.zfree = Z_NULL;
142  m_stream_inflate.opaque = Z_NULL;
143  m_stream_inflate.avail_in = 0;
144  m_stream_inflate.next_in = Z_NULL;
145  int ret = inflateInit(&m_stream_inflate);
146  assert(ret == Z_OK);
147  (void)ret;
148  m_inflate_initialized = true;
149  }
150 
151  header.decode(&msg_ptr, &remaining);
152 
153  if (header.get_data_zlength() > remaining)
154  HT_THROWF(Error::BLOCK_COMPRESSOR_BAD_HEADER, "Block decompression error, "
155  "header zlength = %lu, actual = %lu",
156  (Lu)header.get_data_zlength(), (Lu)remaining);
157 
158  uint32_t checksum = fletcher32(msg_ptr, header.get_data_zlength());
159 
160  if (checksum != header.get_data_checksum())
162  "checksum mismatch header=%lx, computed=%lx",
163  (Lu)header.get_data_checksum(), (Lu)checksum);
164 
165  try {
166  output.reserve(header.get_data_length());
167 
168  // check compress bit
169  if (header.get_compression_type() == NONE)
170  memcpy(output.base, msg_ptr, header.get_data_length());
171  else {
172 
173  m_stream_inflate.avail_in = header.get_data_zlength();
174  m_stream_inflate.next_in = (Bytef *)msg_ptr;
175 
176  m_stream_inflate.avail_out = header.get_data_length();
177  m_stream_inflate.next_out = output.base;
178 
179  ret = ::inflate(&m_stream_inflate, Z_NO_FLUSH);
180  if (ret != Z_STREAM_END)
182  "inflate error (return value = %d)", ret);
183 
184  if (m_stream_inflate.avail_out != 0)
186  "inflate error, expected %lu but only inflated to %lu bytes",
187  (Lu)header.get_data_length(),
188  (Lu)header.get_data_length() - m_stream_inflate.avail_out);
189 
190  ::inflateReset(&m_stream_inflate);
191  }
192 
193  output.ptr = output.base + header.get_data_length();
194  }
195  catch (Exception &e) {
196  ::inflateReset(&m_stream_inflate);
197  output.free();
198  throw;
199  }
200 }
void free()
Frees resources.
void set_data_length(uint32_t length)
Sets the uncompressed data length field.
Definition: BlockHeader.h:91
bool m_deflate_initialized
Flag indicating that deflate state has been initialized.
void set_data_checksum(uint32_t checksum)
Sets the checksum field.
Definition: BlockHeader.h:113
bool m_inflate_initialized
Flag indicating that inflate state has been initialized.
virtual void deflate(const DynamicBuffer &input, DynamicBuffer &output, BlockHeader &header, size_t reserve=0)
Compresses a buffer using the ZLIB algorithm.
uint16_t get_compression_type()
Gets the compression type field.
Definition: BlockHeader.h:128
void set_data_zlength(uint32_t zlength)
Sets the compressed data length field.
Definition: BlockHeader.h:101
virtual void inflate(const DynamicBuffer &input, DynamicBuffer &output, BlockHeader &header)
Decompresses a buffer compressed with the ZLIB algorithm.
uint8_t * ptr
Pointer to the end of the used part of the buffer.
A dynamic, resizable and reference counted memory buffer.
Definition: DynamicBuffer.h:42
uint32_t get_data_checksum()
Gets the checksum field.
Definition: BlockHeader.h:118
std::vector< String > Args
Compression codec argument vector.
uint32_t fletcher32(const void *data8, size_t len8)
Compute fletcher32 checksum for arbitary data.
Definition: Checksum.cc:42
uint32_t get_data_length()
Gets the uncompressed data length field.
Definition: BlockHeader.h:96
A dynamic, resizable memory buffer.
Logging routines and macros.
Declarations for BlockCompressionCodecZlib.
Compatibility Macros for C/C++.
virtual void decode(const uint8_t **bufp, size_t *remainp)
Decodes serialized block header.
Definition: BlockHeader.cc:104
virtual void set_args(const Args &args)
Sets arguments to control compression behavior.
Hypertable definitions
Implementation of checksum routines.
void clear()
Clears the buffer.
void set_compression_type(uint16_t type)
Sets the compression type field.
Definition: BlockHeader.h:123
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
uint8_t * base
Pointer to the allocated memory buffer.
size_t fill() const
Returns the size of the used portion.
Definition: DynamicBuffer.h:70
This is a generic exception class for Hypertable.
Definition: Error.h:314
virtual size_t encoded_length()
Returns length of serizlized block header.
Definition: BlockHeader.cc:76
long unsigned int Lu
Shortcut for printf formats.
Definition: String.h:47
uint32_t get_data_zlength()
Gets the compressed data length field.
Definition: BlockHeader.h:106
Base class for block headers.
Definition: BlockHeader.h:48
void reserve(size_t len, bool nocopy=false)
Reserve space for additional data Will grow the space to exactly what's needed.
Definition: DynamicBuffer.h:95
virtual void encode(uint8_t **bufp)
Encodes serialized representation of block header.
Definition: BlockHeader.cc:82