IGZIP inflate correctness, statistics, and IAA→IGZIP fallback#54
IGZIP inflate correctness, statistics, and IAA→IGZIP fallback#54asonje wants to merge 12 commits intointel:igzipfrom
Conversation
ISAL's stateful inflate pre-loads input in 8-byte word chunks into a 64-bit shift register (read_in). After reaching ISAL_BLOCK_FINISH for raw deflate (window_bits < 0), read_in_length still holds the bit count of bytes fetched beyond the true stream end. Shifting right by 3 gives the exact over-consumed byte count for every avail_in scenario: avail_in in [1,7] : previous avail_in<8 heuristic approximated this avail_in == 0 : previous heuristic was blind; now handled avail_in == 8 : gap in both old heuristics; now handled avail_in > 8 : multi-frame continuation; now handled The corrected consumed count is reported back to the caller via *input_length so that avail_in / next_in on the zlib stream are advanced accurately, preventing downstream compressed-size and CRC mismatches (reproduces as ZipException in Java ZipInputStream). Boundary guard updated: skip the raw-boundary fallback when *tofixed==1 because the correction has already accounted for any remaining bytes, so non-zero remaining is legitimate trailing data rather than un-corrected over-consumption. BLOCK_INPUT_DONE path (output-buffer-limited mid-stream) retains the existing Z_DATA_ERROR->zlib-fallback behaviour unchanged. Previously attempted stateless-probe approach removed entirely; the read_in_length field is simpler, exact, and has no multi-frame failure mode. Validated: 8/8 IGZIPInflateRegressionTest pass; full make run passes with only the pre-existing ordering-sensitive case 37961; JAR repro (250 entries, scan + build-init) passes clean.
…emove stale post-reset pre-set
The old name 'trailer_overconsumption_fixed' was a holdover from the
avail_in < 8 heuristic era. Since EXP-6f the fix is driven entirely by
isal_inflate.read_in_length >> 3; the flag only signals that a correction
was applied *within the current inflate call*.
Rename the field, its parameter aliases, and all local variables to
read_in_correction_applied to match the actual semantics.
Also remove the stale block in inflateReset:
if (was_igzip_path) {
inflate_settings->trailer_overconsumption_fixed = 1;
}
This block predated the read_in_length fix. It pre-armed the flag so
that the old avail_in < 8 boundary guard would not fire on the first
call after a reset. That logic was correct under the old heuristic but
is actively wrong now: ResetUncompressIGZIP already zeros the flag;
re-arming it to 1 would suppress the boundary guard on exactly the call
where it is needed most (first call after reset on a raw stream).
Remove was_igzip_path (now unused after the block removal) and inline
the INPUT_DONE log expression to eliminate an unused-variable warning
when DEBUG_LOG=OFF.
No behaviour change for correct streams; test suite: 8/8 IGZIP inflate
regressions PASS, only pre-existing 37961 flaky failure remains.
…STICS build flag
Statistics previously tracked QAT and IAA paths but left IGZIP with
commented-out placeholders. Two problems with those placeholders: the
enum values DEFLATE_IGZIP_COUNT, DEFLATE_IGZIP_ERROR_COUNT,
INFLATE_IGZIP_COUNT, INFLATE_IGZIP_ERROR_COUNT did not exist, and the
stat_names array had no entries for them.
Add the four missing Statistic enum values (after the IAA entries,
before ZLIB, matching the QAT/IAA grouping pattern) and their
corresponding stat_names strings. Uncomment the INCREMENT_STAT calls
in the deflate and inflate IGZIP dispatch blocks. The error condition
mirrors IAA/QAT: unconditional IGZIP_COUNT on every dispatch, and
IGZIP_ERROR_COUNT when ret != 0 (fallback or hard error).
Enable ENABLE_STATISTICS=ON in cmake.txt so the counters compile in by
default.
Validation (OpenSearch opensearch-core-3.3.1.jar, 250-entry JAR repro,
use_igzip_uncompress=1, log_stats_samples=50):
Thread (main): inflate_count=750 igzip=749 igzip_errors=0 zlib=0
— 99.9% of inflate calls served by IGZIP with zero errors or
zlib fallbacks; one call is the initial probe before path selection.
When IAA inflate or deflate fails (ret != 0), and use_igzip_uncompress / use_igzip_compress is enabled, the new iaa_fallback_igzip config flag (default 0) routes the retry to IGZIP before allowing the call to fall through to software zlib. Motivation: IAA is stateless and leaves input unconsumed on failure, so IGZIP can retry from the same position at no extra cost. This keeps hardware-accelerated decompression in play for inputs that IAA rejects but IGZIP can handle (e.g. streams that fail IsIAADecompressible or exceed IAA's single-call constraint). Implementation: - New ConfigOption IAA_FALLBACK_IGZIP added between IGNORE_ZLIB_DICTIONARY and LOG_LEVEL; default 0 (opt-in), range [0,1]. - inflate(): after IAA dispatch block, if path_selected==IAA && ret!=0 && configs[IAA_FALLBACK_IGZIP] && igzip_available, reset input_len/output_len (IAA may have modified them on failure), clear read_in_correction_applied, and run IGZIPRunInflateAndSelectPathAction with the same path-action handling as the normal IGZIP dispatch. Falls through to zlib if IGZIP also fails. - deflate(): identical pattern; initialises isal_strm via InitCompressIGZIP if needed (matching normal IGZIP deflate path). - Both fallback blocks are wrapped in #ifdef USE_IGZIP and guarded by igzip_available so they compile away and are unreachable without IGZIP. - Existing INFLATE/DEFLATE_IGZIP_COUNT stats capture fallback calls. Test suite: 44756/44757 PASS (37961 pre-existing flaky only).
Signed-off-by: Olasoji <[email protected]>
- SupportedOptionsIGZIPCompress: always returns true (ISA-L natively supports NO_FLUSH/SYNC_FLUSH/FULL_FLUSH/FINISH) - SupportedOptionsIGZIPUncompress: always returns true (remove dead zero-input new-stream guard) - IGZIPShouldFallbackDeflate + IsIGZIPSyncFlush: removed entirely; both streaming_flush_with_input and empty_sync_flush_reentry cases were artificial constraints inherited from one-shot IAA/QAT model - CompressIGZIP: add ZSTATE_NEW_HDR guard for empty SYNC_FLUSH calls; ISA-L emits sync bytes unconditionally, guard returns 0 progress so caller sees Z_BUF_ERROR matching zlib semantics - deflateSetDictionary: reject mid-stream calls when an accelerator path is active; underlying zlib stream is unadvanced so orig_deflateSetDictionary would incorrectly return Z_OK - inflate active-stream no-input block: remove dead - tests: remove 6 stale path==ZLIB assertions from 3 regression tests that assumed IGZIP would fall back on streaming flushes
When IAA compress fails and IGZIP is used as a fallback, path_selected remained IAA. The return-code block below then used the IAA/QAT one-shot logic (avail_in==0 -> Z_STREAM_END) instead of IGZIP streaming logic (IsIGZIPDeflateFinished). ISA-L fills its internal level buffer and returns after consuming all input but producing only partial output; avail_in reaches 0 while the stream is not yet at ZSTATE_END. The result was Z_STREAM_END returned with ~48KB of compressed data still buffered internally, corrupting every document written during indexing. Fix: set path_selected = IGZIP immediately after the fallback completes so that the return-code logic correctly calls IsIGZIPDeflateFinished and returns Z_OK for partial output, allowing the caller to drain the stream.
When iaa_prepend_empty_block=0 (the default), the old code returned true for all raw deflate and gzip inputs unconditionally, causing QPL's overconsumption bug to surface for Java ZipInputStream callers. JAR loading feeds inflate() with 512-byte chunks where avail_in > actual compressed size; QPL reports total_in == available_in, causing the Java-level ZipException that kills OpenSearch at launch. Fix (ported from exp-8): replace the IAA_PREPEND_EMPTY_BLOCK=0 branch with a 512-byte threshold guard. ZipInputStream always feeds <=512-byte chunks; Lucene stored-field reads always provide the exact compressed size which is typically well above 512 bytes. The few Lucene entries below the threshold fall back to IGZIP, which is also correct. Also removes PrependedEmptyBlockPresent() which is no longer called from the decompression path. The compress-side marker write in CompressIAA is unaffected (still controlled by iaa_prepend_empty_block).
Add USE_IGZIP (ON/OFF) and ISAL_PATH to the cmake options list, and add a Requirements for IGZIP section with a link to ISA-L. Signed-off-by: Olasoji <[email protected]>
pre_avail_in is only referenced inside #ifdef USE_IGZIP blocks. Without this guard, builds with USE_IGZIP=OFF trigger an -Wunused-variable error under -Werror, breaking CI. Signed-off-by: Olasoji <[email protected]>
Signed-off-by: Olasoji <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR improves the IGZIP accelerator integration by fixing raw-deflate inflate input over-consumption handling, wiring up IGZIP statistics, and adding an optional IAA→IGZIP fallback path before falling back to software zlib.
Changes:
- Fix IGZIP raw-deflate over-consumption handling and rename the correction flag to
read_in_correction_applied. - Add and activate IGZIP deflate/inflate stats counters and error counters.
- Add
iaa_fallback_igzipconfig option and implement IAA→IGZIP retry logic for both deflate and inflate.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| zlib_accel.cpp | Implements IAA→IGZIP fallback, enables IGZIP stats, adjusts inflate no-input handling, and renames correction flag usage. |
| igzip.cpp | Updates IGZIP option gating behavior and implements new raw-deflate read-in correction logic. |
| igzip.h | Renames the correction flag parameter/field in public IGZIP wrapper APIs. |
| statistics.h | Adds new IGZIP statistics enum entries. |
| statistics.cpp | Adds IGZIP stat name strings to match new enum entries. |
| iaa.cpp | Updates IAA decompressibility gating to avoid known ZipInputStream-style over-consumption issues. |
| config/config.h | Adds IAA_FALLBACK_IGZIP config option. |
| config/config.cpp | Adds default and parsing support for iaa_fallback_igzip. |
| tests/zlib_accel_test.cpp | Relaxes deflate path assertions to allow IGZIP behavior changes. |
| README.md | Documents IGZIP build flags and ISA-L dependency. |
| cmake.txt | Adds a local build command line (likely unintended to commit). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| int UncompressIGZIP(struct inflate_state *isal_strm_inflate, uint8_t *input, | ||
| uint32_t *input_length, uint8_t *output, | ||
| uint32_t *output_length, int window_bits, int *tofixed, | ||
| unsigned long *total_in, unsigned long *total_out, | ||
| bool *end_of_stream) { | ||
| uint32_t *output_length, int window_bits, | ||
| int *read_in_correction_applied, unsigned long *total_in, | ||
| unsigned long *total_out, bool *end_of_stream) { |
There was a problem hiding this comment.
read_in_correction_applied is described as being scoped to the current inflate call, but UncompressIGZIP doesn't reset *read_in_correction_applied to 0 at the start of each invocation. This can leave stale state across calls and affect later guard logic; consider setting it to 0 on entry and only setting it to 1 when a non-zero rewind_adjust_bytes is applied.
| const IGZIPInflatePathAction path_action = | ||
| IGZIPRunInflateAndSelectPathAction( | ||
| strm, &inflate_settings->isal_strm, inflate_settings->window_bits, | ||
| &inflate_settings->trailer_overconsumption_fixed, &input_len, | ||
| &inflate_settings->read_in_correction_applied, &input_len, | ||
| &output_len, &ret, &end_of_stream, pre_avail_in); |
There was a problem hiding this comment.
inflate_settings->read_in_correction_applied is passed into IGZIPRunInflateAndSelectPathAction without being reset beforehand (unlike the IAA→IGZIP fallback path). If this flag is intended to be per-call, stale values can leak across inflate() calls and change raw-boundary / INPUT_DONE guard behavior; consider resetting it to 0 before each IGZIPRunInflateAndSelectPathAction invocation.
| @@ -0,0 +1 @@ | |||
| cmake -DUSE_QAT=ON -DUSE_IAA=ON -DUSE_IGZIP=ON -DQPL_PATH=/home/sdp/qpl -DISAL_PATH=/home/sdp/isa-l/ -DDEBUG_LOG=OFF -DENABLE_STATISTICS=OFF -DCMAKE_BUILD_TYPE=Release .. | |||
There was a problem hiding this comment.
This file appears to be a local build command with hard-coded absolute paths (e.g., /home/sdp/...). Committing this into the repo is brittle and not generally useful; please remove it or replace with documented, parameterized build instructions in README (or a script) using placeholders/environment variables.
| cmake -DUSE_QAT=ON -DUSE_IAA=ON -DUSE_IGZIP=ON -DQPL_PATH=/home/sdp/qpl -DISAL_PATH=/home/sdp/isa-l/ -DDEBUG_LOG=OFF -DENABLE_STATISTICS=OFF -DCMAKE_BUILD_TYPE=Release .. | |
| # Example CMake configure command. Set QPL_PATH and ISAL_PATH for your local environment before running. | |
| cmake -DUSE_QAT=ON -DUSE_IAA=ON -DUSE_IGZIP=ON -DQPL_PATH="${QPL_PATH}" -DISAL_PATH="${ISAL_PATH}" -DDEBUG_LOG=OFF -DENABLE_STATISTICS=OFF -DCMAKE_BUILD_TYPE=Release .. |
| #ifdef USE_IGZIP | ||
| // IAA→IGZIP fallback: if IAA failed and IGZIP is available, retry with | ||
| // IGZIP before falling through to software zlib. | ||
| if (path_selected == IAA && ret != 0 && configs[IAA_FALLBACK_IGZIP] && | ||
| igzip_available) { |
There was a problem hiding this comment.
The new IAA→IGZIP fallback behavior (controlled by IAA_FALLBACK_IGZIP) is introduced here but doesn't appear to have a regression test. Please add coverage that forces an IAA failure and asserts IGZIP is attempted before falling back to zlib when iaa_fallback_igzip=1 (and not attempted when it is 0).
| // compression begins. | ||
| if (deflate_settings->path != UNDEFINED && deflate_settings->path != ZLIB) { | ||
| return Z_STREAM_ERROR; |
There was a problem hiding this comment.
Potential null dereference: deflate_stream_settings.Get(strm) can return nullptr (e.g., deflateSetDictionary called without a prior deflateInit*/deflateInit2*). The new mid-stream rejection check dereferences deflate_settings->path unconditionally; please guard for deflate_settings == nullptr and return Z_STREAM_ERROR in that case (matching zlib behavior).
matt-welch
left a comment
There was a problem hiding this comment.
Some of these comments may be repetitive with the existing copilot comments, but here's my review:
Code Review: PR #54 - IGZIP inflate correctness, statistics, and IAA->IGZIP fallback
Summary
This PR delivers three improvements to the igzip backend:
- Raw deflate over-consumption fix - Replaces an 8-byte-trailer heuristic with a precise
read_in_length >> 3calculation using ISA-L's internal shift register state - Statistics enablement - Activates 4 IGZIP performance counters (deflate/inflate counts + error counts)
- IAA->IGZIP fallback - New
iaa_fallback_igzipconfig option allows failed IAA operations to retry through IGZIP before reverting to software zlib
The changes span 11 files with ~230 additions and ~180 deletions. The net effect simplifies several code paths (removing guard logic from SupportedOptionsIGZIPCompress, SupportedOptionsIGZIPUncompress, and IGZIPShouldFallbackDeflate) and introduces a new fallback chain for both compress and decompress paths.
Issues to Address
1. cmake.txt should not be committed (new file)
A new file cmake.txt contains a single hardcoded build command with machine-specific absolute paths (/home/sdp/qpl, /home/sdp/isa-l/). This appears to be a local developer note accidentally included in the PR. It should be removed from the commit and either added to .gitignore or converted into parameterized instructions in the README or a helper script.
2. read_in_correction_applied is never reset at the start of UncompressIGZIP() (igzip.cpp)
The struct comment says "set when read_in_length correction was applied in the current inflate call", implying per-call scope. However, UncompressIGZIP() does not reset *read_in_correction_applied = 0 at the top. This means a stale 1 from a previous call persists into subsequent calls on the same stream, which suppresses:
- The
ISAL_BLOCK_INPUT_DONEfallback guard at line ~393 (the*read_in_correction_applied == 0check) - The raw boundary guard in
IGZIPRunInflateAndSelectPathAction()at line ~314
If the flag is intentionally per-stream-lifetime (set once, stays set), the comment and name should reflect that. If it's truly per-call, add *read_in_correction_applied = 0; at the entry of UncompressIGZIP(). Looking at inflateReset which does reset it to 0, the intent appears to be per-stream-session, not per-call. Either way, the documentation is misleading.
Also: In zlib_accel.cpp inflate(), the primary IGZIP path at ~line 730 calls IGZIPRunInflateAndSelectPathAction without resetting read_in_correction_applied beforehand, while the IAA->IGZIP fallback path at ~line 712 does reset it. This asymmetry looks like a bug - the primary path should also reset the flag before each call, or the semantics should be clearly documented as intentionally different.
3. Null pointer dereference risk in deflateSetDictionary (zlib_accel.cpp ~line 296)
DeflateSettings* deflate_settings = deflate_stream_settings.Get(strm);
// New code immediately dereferences:
if (deflate_settings->path != UNDEFINED && deflate_settings->path != ZLIB) {
return Z_STREAM_ERROR;
}deflate_stream_settings.Get(strm) can return nullptr if deflateSetDictionary is called without a prior deflateInit. The new mid-stream rejection check dereferences unconditionally. Add a null guard:
if (deflate_settings != nullptr &&
deflate_settings->path != UNDEFINED && deflate_settings->path != ZLIB) {
return Z_STREAM_ERROR;
}4. No test coverage for the IAA->IGZIP fallback path
The iaa_fallback_igzip feature is a meaningful behavioral change but has zero test coverage. Since CI doesn't have IAA hardware, consider adding a unit test that:
- Mocks or forces an IAA failure condition (e.g., by configuring IAA compress but providing data that triggers IAA error)
- Asserts that IGZIP is attempted when
iaa_fallback_igzip=1 - Asserts that IGZIP is NOT attempted when
iaa_fallback_igzip=0
Even a structural test verifying the config plumbing would be valuable.
5. SupportedOptionsIGZIPCompress, SupportedOptionsIGZIPUncompress, and IGZIPShouldFallbackDeflate are now dead code
All three functions have had their logic entirely removed and now unconditionally return a fixed value:
SupportedOptionsIGZIPCompress-> alwaystrueSupportedOptionsIGZIPUncompress-> alwaystrueIGZIPShouldFallbackDeflate-> alwaysfalse
The function bodies are replaced with (void) casts on every parameter. Since these are called from the hot path in deflate() and inflate(), they should either be:
- Removed entirely (callers inlined/simplified), or
- Kept but with a comment explaining why the guards were removed and whether they're expected to regain logic in the future
Leaving dead function scaffolding with voided parameters adds confusion about whether the removal is intentional or WIP. The same applies to IsIGZIPSyncFlush and kIGZIPMinFinishOutputSize which are deleted outright - good, but the inconsistency with the other three is worth resolving.
Items to Discuss
6. Removal of 6 path assertions from regression tests
Six ASSERT_EQ(GetDeflateExecutionPath(&stream), ZLIB) checks are removed from:
ResetMustNotStallSyncFlushOnSameStreamSyncFlushThenFinishDoesNotStall(2 assertions)SyncFlushFirstBlockThenFinish(3 assertions)
This is a direct consequence of SupportedOptionsIGZIPCompress and IGZIPShouldFallbackDeflate now allowing all flushes through IGZIP (previously Z_SYNC_FLUSH etc. would pin the stream to ZLIB). The tests still verify correctness of the compress/decompress round-trip, but no longer verify execution path.
Question: Are these tests now expected to run on the IGZIP path? If so, consider adding ASSERT_EQ(GetDeflateExecutionPath(&stream), IGZIP) to validate the new expected behavior rather than simply removing the path assertions. Path assertions are valuable for catching regressions in routing logic.
7. IsIAADecompressible 512-byte magic number (iaa.cpp)
The new guard:
static constexpr uint32_t kZipInputStreamBufferSize = 512;
return input_length > kZipInputStreamBufferSize;This completely removes the PrependedEmptyBlockPresent() detection and the IAA_PREPEND_EMPTY_BLOCK config handling. The 512-byte threshold is a heuristic tied to Java's ZipInputStream internal buffer size. Concerns:
- If a non-Java caller legitimately passes exactly 512 bytes of valid IAA-compressed data, it will be unnecessarily rejected
- The
IAA_PREPEND_EMPTY_BLOCKconfig option is still inconfig.hand the config loading code, but is now dead code iniaa.cpp. It should either be cleaned up or documented as deprecated. - The 512-byte value is a Java implementation detail that could change across JDK versions. A
static constexprwith a clear name is good, but adding a brief comment about which JDK versions this was validated against would help future maintainers.
8. inflateReset behavioral change
The old code preserved trailer_overconsumption_fixed = 1 after reset if the stream was previously on the IGZIP path. The new code removes this preservation entirely. This means after inflateReset, the correction flag starts fresh at 0 regardless of prior path.
Is this intentional? The old behavior was presumably there to prevent re-triggering the over-consumption correction on a stream that had already been fixed once. With the new read_in_length-based approach, is this no longer needed?
9. SYNC_FLUSH no-progress detection placement (igzip.cpp ~line 200-210)
The new SYNC_FLUSH no-progress check:
if (isal_strm->avail_in == 0 && isal_strm->flush == SYNC_FLUSH &&
isal_strm->end_of_stream == 0 &&
isal_strm->internal_state.state == ZSTATE_NEW_HDR) {
*output_length = 0;
*input_length = 0;
return 0;
}This check runs before isal_deflate() is called (line ~246 in the new code). By short-circuiting before ISA-L processes the stream, it ensures no sync marker bytes are emitted when there's no pending data. This is correct for matching zlib semantics, but:
- Accessing
isal_strm->internal_state.statedirectly couples to ISA-L internals. If ISA-L changes the state machine in a future version, this check will silently break. Consider documenting the ISA-L version this was validated against. - The
ZSTATE_NEW_HDRcheck assumes that "at the beginning of a new header" implies "no pending output". Is that always true, or are there edge cases where ISA-L is inZSTATE_NEW_HDRbut has buffered output not yet flushed?
Looks Good
- Statistics plumbing is clean and follows the existing QAT/IAA pattern exactly. The enum ordering in
statistics.hcorrectly places IGZIP counts between IAA and ZLIB counts. - Config plumbing for
iaa_fallback_igzipfollows established patterns (enum, default value, config file parsing). read_in_length >> 3approach is a clear improvement over the old 8-byte-trailer heuristic. Using ISA-L's actual shift register state eliminates guesswork about how many bytes were pre-fetched.- Rename
tofixed/trailer_overconsumption_fixed->read_in_correction_appliedimproves readability significantly. - README updates are appropriate and consistent with the existing QAT/IAA documentation pattern.
- The IAA->IGZIP fallback architecture in
zlib_accel.cppis well-structured: it restores input/output lengths, resets state, and correctly handles all path actions fromIGZIPRunInflateAndSelectPathAction.
Summary of Requested Changes
| Priority | Item | Action |
|---|---|---|
| Must fix | cmake.txt committed with hardcoded paths |
Remove from PR |
| Must fix | Null deref risk in deflateSetDictionary |
Add null guard |
| Should fix | read_in_correction_applied stale state / reset asymmetry |
Reset before primary IGZIP path, or clarify semantics |
| Should fix | Dead function bodies (SupportedOptionsIGZIP*, IGZIPShouldFallbackDeflate) |
Remove or document intent |
| Should fix | Dead IAA_PREPEND_EMPTY_BLOCK config option |
Clean up or deprecate |
| Should add | Test coverage for IAA->IGZIP fallback | Add config-based test |
| Suggest | Replace removed path assertions with updated expectations | Validate IGZIP path in regression tests |
| Suggest | Document ISA-L version for internal state access | Future-proof SYNC_FLUSH and read_in_length usage |
Fix raw deflate over-consumption and clean up the correction flag (6a89390, 93f144e)
After reaching ISAL_BLOCK_FINISH for raw deflate, ISA-L's stateful inflate pre-loads input in 8-byte chunks, leaving read_in_length holding the exact bit count consumed beyond the true stream end. Shifting right by 3 gives the over-consumed byte count for all avail_in scenarios — including avail_in == 0, == 8, and multi-frame continuations that the previous avail_in < 8 heuristic missed entirely.
As part of the same fix, the internal flag tracking whether a correction was applied is renamed from trailer_overconsumption_fixed to read_in_correction_applied to reflect its actual semantics (a within-call flag, not a permanent fix marker).
Wire up IGZIP statistics (92eaf59)
Added DEFLATE_IGZIP_COUNT, DEFLATE_IGZIP_ERROR_COUNT, INFLATE_IGZIP_COUNT, and INFLATE_IGZIP_ERROR_COUNT stats; All four are now active.
iaa_fallback_igzip config flag (b48d118)
When IAA inflate or deflate fails, and iaa_fallback_igzip=1 is set (default off), the retry is routed to IGZIP before falling through to software zlib.