diff options
author | Michael Cahill <michael.cahill@wiredtiger.com> | 2014-01-31 17:49:29 +1100 |
---|---|---|
committer | Michael Cahill <michael.cahill@wiredtiger.com> | 2014-01-31 17:49:29 +1100 |
commit | 0417c196279d091a21742eaad70f007ad44a0645 (patch) | |
tree | 8cdbe6367253d406fef45aebd19671499c8b46de /ext/compressors | |
parent | 3df4a2fe2e4bd6f19b6dcdc5b10df46d2ed382ea (diff) | |
download | mongo-0417c196279d091a21742eaad70f007ad44a0645.tar.gz |
Fix some zlib-specific issues:
* always try to compress at least one item (WiredTiger makes the first "row" artificially large);
* loop on all calls since the zlib API allows calls to work incrementally
* reserve more bytes to finish up the last block, and fall back to "normal" compression if the reserved space is insufficient.
Diffstat (limited to 'ext/compressors')
-rw-r--r-- | ext/compressors/zlib/zlib_compress.c | 67 |
1 files changed, 42 insertions, 25 deletions
diff --git a/ext/compressors/zlib/zlib_compress.c b/ext/compressors/zlib/zlib_compress.c index 64da4d24d6e..3a932da5dea 100644 --- a/ext/compressors/zlib/zlib_compress.c +++ b/ext/compressors/zlib/zlib_compress.c @@ -161,7 +161,9 @@ zlib_compress(WT_COMPRESSOR *compressor, WT_SESSION *session, zs.avail_in = (uint32_t)src_len; zs.next_out = dst; zs.avail_out = (uint32_t)dst_len - 1; - if ((ret = deflate(&zs, Z_FINISH)) == Z_STREAM_END) { + while ((ret = deflate(&zs, Z_FINISH)) == Z_OK) + ; + if (ret == Z_STREAM_END) { *compression_failed = 0; *result_lenp = zs.total_out; } else @@ -183,15 +185,14 @@ zlib_find_slot(uint32_t target, uint32_t *offsets, uint32_t slots) { uint32_t base, indx, limit; - indx = 0; + indx = 1; /* Figure out which slot we got to: binary search */ if (target >= offsets[slots]) indx = slots; - else if (target >= offsets[1]) - for (base = 1, limit = slots - 1; limit != 0; limit >>= 1) { + else if (target > offsets[1]) + for (base = 2, limit = slots - base; limit != 0; limit >>= 1) { indx = base + (limit >> 1); - if (target < offsets[indx]) continue; base = indx + 1; @@ -241,9 +242,10 @@ zlib_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session, zs.next_out = dst; /* * Experimentally derived, reserve this many bytes for zlib to finish - * up a buffer. + * up a buffer. If this isn't sufficient, we don't fail but we will be + * inefficient. */ -#define WT_ZLIB_RESERVED 6 +#define WT_ZLIB_RESERVED 12 zs.avail_out = (uint32_t)(page_max - extra - WT_ZLIB_RESERVED); last_zs = zs; @@ -252,49 +254,62 @@ zlib_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session, * input. Continue until there is no input small enough or the * compression fails to fit. */ - for (;;) { + while (zs.avail_out > 0) { /* Find the slot we will try to compress up to. */ if ((curr_slot = zlib_find_slot( - zs.total_in + zs.avail_out, offsets, slots)) == last_slot) + zs.total_in + zs.avail_out, offsets, slots)) <= last_slot) break; zs.avail_in = offsets[curr_slot] - offsets[last_slot]; /* Save the stream state in case the chosen data doesn't fit. */ last_zs = zs; - if ((ret = deflate(&zs, Z_SYNC_FLUSH)) != Z_OK) - return ( - zlib_error(compressor, session, "deflate", ret)); + while (zs.avail_in > 0 && zs.avail_out > 0) + if ((ret = deflate(&zs, Z_SYNC_FLUSH)) != Z_OK) + return (zlib_error( + compressor, session, "deflate", ret)); - if (zs.avail_out == 0 && zs.avail_in > 0) { - /* Roll back the last operation: it didn't complete */ + /* Roll back the if the last deflate didn't complete. */ + if (zs.avail_in > 0) { zs = last_zs; break; - } - - last_slot = curr_slot; + } else + last_slot = curr_slot; } zs.avail_out += WT_ZLIB_RESERVED; - if ((ret = deflate(&zs, Z_FINISH)) != Z_STREAM_END) + while ((ret = deflate(&zs, Z_FINISH)) == Z_OK) + ; + /* + * If the end marker didn't fit, report that we got no work done. WT + * will compress the (possibly large) page image using ordinary + * compression instead. + */ + if (ret == Z_BUF_ERROR) + last_slot = 0; + else if (ret != Z_STREAM_END) + return ( + zlib_error(compressor, session, "deflate end block", ret)); + + if ((ret = deflateEnd(&zs)) != Z_OK && ret != Z_DATA_ERROR) return ( - zlib_error(compressor, session, "deflate", ret)); + zlib_error(compressor, session, "deflateEnd", ret)); if (last_slot > 0) { *result_slotsp = last_slot; *result_lenp = zs.total_out; + } else { + /* We didn't manage to compress anything: don't retry. */ + *result_slotsp = 0; + *result_lenp = 1; } - if ((ret = deflateEnd(&zs)) != Z_OK) - return ( - zlib_error(compressor, session, "deflateEnd", ret)); - #if 0 fprintf(stderr, "zlib_compress_raw (%s): page_max %" PRIuMAX ", slots %" PRIu32 ", take %" PRIu32 ": %" PRIu32 " -> %" PRIuMAX "\n", final ? "final" : "not final", (uintmax_t)page_max, - slots, last_slot, offset[last_slot], (uintmax_t)*result_lenp); + slots, last_slot, offsets[last_slot], (uintmax_t)*result_lenp); #endif return (0); } @@ -324,7 +339,9 @@ zlib_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session, zs.avail_in = (uint32_t)src_len; zs.next_out = dst; zs.avail_out = (uint32_t)dst_len; - if ((ret = inflate(&zs, Z_FINISH)) == Z_STREAM_END) { + while ((ret = inflate(&zs, Z_FINISH)) == Z_OK) + ; + if (ret == Z_STREAM_END) { *result_lenp = zs.total_out; ret = Z_OK; } |