hmm # lbzip2-rs v0.4.0 "Skadi" ❄️
🧙♂ Med Allfaderns visdom och blick över varje bit.
Pure Rust parallel bzip2 decompressor. No C dependencies. Zero per-block allocations, physical-core aware, no polling. Usable as a library (in-process, zero-copy) or as a CLI tool:
# Decompress any bzip2 file (including pbzip2 concatenated streams)
What makes this crate unique: 100% Rust, zero-copy in-process library with a lightweight parallel split method that finds block boundaries with tiny forward-scans (~500 bytes per split). The decoder uses a streaming worker-pool (reorder buffer) to avoid global barriers and is tuned for modern CPU caches (packed Huffman tables fit L1, thread-local buffers leverage L2), yielding high throughput on many-core machines.
Part of the znippy group of software, designed for fast zero-copy integration with osm-katana — the parallel OSM-to-GeoParquet pipeline.
Performance vs C lbzip2
Laptop — T14s (Ryzen AI 360, 8 cores + SMT, 64 GB DDR5)
Planet 1 GB slice (1023 MB compressed → 9861 MB decompressed), interleaved runs, 20s cooldown:
| Condition | Rust lbzip2-rs | C lbzip2 | Δ |
|---|---|---|---|
| Cold start (fair) | 23.6s (417 MB/s) | 25.4s (388 MB/s) | Rust +7.6% |
| Thermal throttled | 27.5s | 25.6s | C +7% (laptop throttling) |
| CPU time (total work) | 2m58s | 3m21s | Rust −12% CPU |
Rust uses 12% less total CPU — the single-thread decode is 1.5× faster than C libbz2. On sustained workloads, thermal throttling on thin laptops can mask the advantage.
Single-thread decode (library, no I/O)
| Implementation | Time | Throughput | vs C bzip2 |
|---|---|---|---|
| C bzip2 (libbz2 1.0.8) | 123.5s | 80 MB/s | 1.0× |
| C lbzip2 -n1 | 96.0s | 103 MB/s | 1.3× |
| Rust lbzip2-rs | 87.9s | 112 MB/s | 1.4× |
Odin — Threadripper PRO 3975WX, 32 cores, 512 GB DDR4
| Mode | Throughput | Notes |
|---|---|---|
| lbzip2-rs parallel (32 cores) | 1909 MB/s | Worker pool, 5.2s for 1 GB |
End-to-end: Planet bz2 → PBF (osm-katana)
| Input | 147 GB planet-241021.osm.bz2 |
| Output | 68 GB planet-241021.osm.pbf |
| Time | 81 minutes |
| Elements | 10.5 billion |
| Throughput | 309 MB/s decompressed XML |
Full pipeline: bz2 decompress → VTD XML parse → PBF encode, 15 workers.
Usage
use ChunkDecoder;
let data: & = /* compressed chunk including BZhN header */;
let decoder = from_header?;
// Returns segments separately — no giant memcpy
let = decoder.decode_chunk_segments?;
for seg in &segments
Single-stream sequential API:
let output = decompress?;
Förklaring för Farbror Dan 🏍️🇸🇪
Hur fungerar worker-pool-arkitekturen?
Tänk dig 6 rum (slottar) som återanvänds i en ring. Varje rum rymmer 200 MB komprimerad data uppdelad i N väggar (en per CPU-kärna). N målare (workers) målar väggar utan att stanna — när en vägg i rum 1 är klar går målaren direkt till rum 2.
Rum 1: [████████████░░] Lisa nästan klar
Rum 2: [██████░░░░░░░░] Kalle + andra redan igång!
Rum 3: [██░░░░░░░░░░░░] snabbaste redan här
Ingen barriär, ingen väntan. Materialaren fyller rum, målarna målar, skrivaren skriver — som ett löpande band. 🐴
License
MIT OR Apache-2.0, plus the original bzip2 license (BSD-style, Julian Seward) for the block-decode routines inspired by the C reference implementation. See LICENSE-BZIP2 for the full text.