rust 77 lines · 3 tabs

Content-Defined Chunking With Parallel BLAKE3 Hashing Using Rayon

Shared by codesnips Aug 2026
3 tabs
mod chunker;mod parallel_hash;

use parallel_hash::{hash_buffer, root_hash};

const CHUNK_SIZE: usize = 64 * 1024;

fn main() {
    let buffer: Vec<u8> = (0..(5 * 1024 * 1024))
        .map(|i| (i % 251) as u8)
        .collect();

    let chunks = hash_buffer(&buffer, CHUNK_SIZE);

    println!("buffer = {} bytes in {} chunks", buffer.len(), chunks.len());
    for chunk in chunks.iter().take(3) {
        println!(
            "  offset={:>8} len={:>6} {}",
            chunk.offset,
            chunk.len,
            chunk.hash.to_hex()
        );
    }

    let root = root_hash(&chunks);
    println!("root  = {}", root.to_hex());
}
3 files · rust Explain with highlit

This snippet shows how a large in-memory byte buffer is split into fixed-size chunks and hashed independently, then combined into a stable content manifest suitable for deduplication or integrity checks. The design separates how the buffer is partitioned from how each partition is hashed, which is what makes the parallelism safe: each chunk is a disjoint, read-only slice of the original buffer, so there is no shared mutable state and Rayon can fan the work across a thread pool without locks.

In chunker.rs, the Chunk struct records an offset, the chunk len, and its hash, so the position of every chunk is preserved even though hashing happens out of order. The chunk_ranges function is a plain iterator over (offset, len) pairs computed from the buffer length and a target chunk_size; keeping range computation pure and cheap means the expensive hashing step can be expressed cleanly on top of it. The final chunk is handled by min, which clamps the last range to the true buffer end so trailing bytes are never dropped or over-read.

In parallel_hash.rs, the core work happens in hash_buffer. It borrows the buffer as &[u8], materializes the ranges, and switches into Rayon with into_par_iter. Each parallel task slices buf[offset..offset + len] and feeds it to blake3::hash, producing an independent Chunk. Because slices borrow immutably, Rust's borrow checker statically guarantees the absence of data races — the parallel closure never needs a Mutex. The results are collected with collect, and Rayon preserves input order, so the returned Vec<Chunk> is already sorted by offset without an explicit sort.

The root_hash helper folds each chunk hash into a second BLAKE3 hasher to derive a single manifest digest, giving a Merkle-style summary of the whole buffer. A key trade-off is chunk granularity: small chunks improve deduplication and parallel balance but add per-chunk hashing overhead, while large chunks reduce overhead but hurt load balancing. main.rs wires it together, printing per-chunk digests and the root, and demonstrates that identical content yields identical root_hash regardless of thread scheduling. This pattern is a good fit for backup systems, content-addressed storage, and any workload where a big buffer must be verified or deduplicated quickly.


Related snips

Share this code

Here's the card — post it anywhere.

Content-Defined Chunking With Parallel BLAKE3 Hashing Using Rayon — share card
Link copied