Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/znippy-zoomies

.nornir/decompressors-design.md

Decompressors — design

Class: design · Function: decompressors (the parallel decode family). Strict: chosen shape only. The bake-off numbers are in benchmarks.md; how to run them in decompressors-guide.md; the "why not keep four hand-rolled pipelines" road-not-taken in reasoning.md and chunk_revolver-unsorted.md.

Per-decompressor deep-dives (exact dataflow + skade-style SVG each)

Each decoder is documented on its own, with a hand-authored flow diagram of its exact dataflow (input → boundary scan → self-dispatch workers → ordered/positional sink → output):

What it is

Five workspace member crates (Cargo.toml:17), each a pure-Rust parallel decompressor for a stock archive format — the format every existing tool already reads, decoded across every core where the legacy serial tools leave the box idle. These are the subjects of the bake-off.

Crate Version Format Core idea
lgz 0.3.6 multi-member gzip (.gz) split at member boundaries, DEFLATE-decode members in parallel
lbzip2 0.5.4 bzip2 (.bz2) scan block-start bit patterns, decode independent BWT blocks in parallel
linflate 0.1.4 raw DEFLATE SIMD match-copy, branchless refill, segment-aware — the shared decode core
ljar 0.2.3 JAR (.jar) Central-Directory scan → parallel per-entry DEFLATE
lzip-parallel 0.2.4 ZIP (.zip) near-verbatim twin of ljar (JAR ⊂ ZIP)

The shared decode shape

Each format is a set of independently decodable segments (gzip members, bzip2 blocks, ZIP/JAR entries). The decode is the same three-move gatling pipeline:

  1. Scan the compressed bytes for segment boundaries (deflate_scan.rs / block_scan.rs / central_dir.rs) — cheaply, up front.
  2. Fan the segments across N workers, each decoding one segment to completion (the linflate fast loop for DEFLATE formats; the BWT/MTF/Huffman path for bzip2).
  3. Collect the outputs in order and write them out.

linflate is the reused DEFLATE core underneath lgz, ljar, and lzip-parallel: inflate_segment / inflate_segment_with_prefix / inflate_to_vec (linflate/src/lib.rs) decode one segment given its (optional) back-reference prefix window.

Public library surfaces

Each crate ships a library twin of its CLI (so a decode is callable, not just a binary):

All five also expose the crate-local functional_status(component, check, ok, detail) introspection shim (mirrors lib.rs:35), so nornir test --features testmatrix sees each decode.

Parallelism substrate (the no-rayon law, workspace-wide)

All five crates are now rayon-free and fan out through the one shared engine:

The writer tail (landed). Each format's decode (the middle "Fan" move) is already parallel; what left the DEFLATE codecs writer-bound (lgz ~3.1, ljar ~3.5, lzip ~4.0 of 12 cores, vs lbz2 ~10.4) was the single ordered collector + writer at the tail — not slot starvation (widening ring_slots is refuted). The fix, now on master, is the gatling::parwrite layer (gatling/src/parwrite.rs): each worker preads and writes its own output — independent files (extract_entries_unordered, ZIP/JAR) or offset-pwrited regions of one pre-sized stream (write_segments_positional / write_slices_positional). Measured cores_busy: ljar/lzip → ~11.5/12, lgz → 7.8/12 (offset-pwrite on -o files; stdout can't be offset-written), lbz2 held ~10.4. See gatling-design.md and gatling-reasoning.md.