76
bw->entries = 0;
77
bw->restart_len = 0;
78
bw->last_key.len = 0;
79
+ if (!bw->zstream) {
80
+ REFTABLE_CALLOC_ARRAY(bw->zstream, 1);
81
+ deflateInit(bw->zstream, 9);
82
+ }
83
}
84
85
uint8_t block_writer_type(struct block_writer *bw)
143
w->next += 2;
144
put_be24(w->buf + 1 + w->header_off, w->next);
145
146
+ /*
147
+ * Log records are stored zlib-compressed. Note that the compression
148
+ * also spans over the restart points we have just written.
149
+ */
150
if (block_writer_type(w) == BLOCK_TYPE_LOG) {
151
int block_header_skip = 4 + w->header_off;
144
- uLongf src_len = w->next - block_header_skip;
145
- uLongf dest_cap = src_len * 1.001 + 12;
146
- uint8_t *compressed;
147
-
148
- REFTABLE_ALLOC_ARRAY(compressed, dest_cap);
149
-
150
- while (1) {
151
- uLongf out_dest_len = dest_cap;
152
- int zresult = compress2(compressed, &out_dest_len,
153
- w->buf + block_header_skip,
154
- src_len, 9);
155
- if (zresult == Z_BUF_ERROR && dest_cap < LONG_MAX) {
156
- dest_cap *= 2;
157
- compressed =
158
- reftable_realloc(compressed, dest_cap);
159
- if (compressed)
160
- continue;
161
- }
162
-
163
- if (Z_OK != zresult) {
164
- reftable_free(compressed);
165
- return REFTABLE_ZLIB_ERROR;
166
- }
167
-
168
- memcpy(w->buf + block_header_skip, compressed,
169
- out_dest_len);
170
- w->next = out_dest_len + block_header_skip;
152
+ uLongf src_len = w->next - block_header_skip, compressed_len;
153
+ unsigned char *compressed;
154
+ int ret;
155
+
156
+ ret = deflateReset(w->zstream);
157
+ if (ret != Z_OK)
158
+ return REFTABLE_ZLIB_ERROR;
159
+
160
+ /*
161
+ * Precompute the upper bound of how many bytes the compressed
162
+ * data may end up with. Combined with `Z_FINISH`, `deflate()`
163
+ * is guaranteed to return `Z_STREAM_END`.
164
+ */
165
+ compressed_len = deflateBound(w->zstream, src_len);
166
+ REFTABLE_ALLOC_ARRAY(compressed, compressed_len);
167
+
168
+ w->zstream->next_out = compressed;
169
+ w->zstream->avail_out = compressed_len;
170
+ w->zstream->next_in = w->buf + block_header_skip;
171
+ w->zstream->avail_in = src_len;
172
+
173
+ /*
174
+ * We want to perform all decompression in a single step, which
175
+ * is why we can pass Z_FINISH here. As we have precomputed the
176
+ * deflated buffer's size via `deflateBound()` this function is
177
+ * guaranteed to succeed according to the zlib documentation.
178
+ */
179
+ ret = deflate(w->zstream, Z_FINISH);
180
+ if (ret != Z_STREAM_END) {
181
reftable_free(compressed);
172
- break;
182
+ return REFTABLE_ZLIB_ERROR;
183
}
184
+
185
+ /*
186
+ * Overwrite the uncompressed data we have already written and
187
+ * adjust the `next` pointer to point right after the
188
+ * compressed data.
189
+ */
190
+ memcpy(w->buf + block_header_skip, compressed,
191
+ w->zstream->total_out);
192
+ w->next = w->zstream->total_out + block_header_skip;
193
+
194
+ reftable_free(compressed);
195
}
196
+
197
return w->next;
198
}
199
447
448
void block_writer_release(struct block_writer *bw)
449
{
450
+ deflateEnd(bw->zstream);
451
+ FREE_AND_NULL(bw->zstream);
452
FREE_AND_NULL(bw->restarts);
453
strbuf_release(&bw->last_key);
454
/* the block is not owned. */