borgbackup/scripts
Thomas Waldmann 0e3876d5e4
buzhash64: add FastCDC-style normalized chunking
Normalized chunking switches between a stricter and a looser cut mask
around the target chunk size. This greatly tightens the chunk-size
distribution (coefficient of variation ~0.9 -> ~0.3 in tests) and removes
the dedup-hostile max-size-clamped chunks, with unchanged deduplication.

chunker-params for buzhash64 gains a required 6th field, nc_level:

  buzhash64,chunk_min,chunk_max,chunk_mask,window_size,nc_level

Use nc_level=2 for the new default, nc_level=0 to disable (then behavior
is byte-identical to the previous single-mask chunker).

buzhash (32bit) is untouched and stays bit-compatible with borg 1.x.

The mask transition point (normal_size) defaults to a principled formula
(target minus the expected loose-phase tail) so the mean stays near the
target; it can be tuned via the normal_size constructor arg.

scripts/chunker_bench.py: evidence harness used to measure chunk-size
distribution, dedup ratio, throughput and shift-resilience.

Measurements (before = nc_level 0, after = nc_level 2; both at the default
params buzhash64,19,23,21,4095; measured with scripts/chunker_bench.py):

5 GiB of incompressible data (~2000-2700 chunks, statistically stable):

  before:  CV 0.739,  49 max-size-clamped (8 MiB) chunks,   953 MB/s
  after:   CV 0.311,   0 max-size-clamped chunks,          1024 MB/s

Re-backup of a 2.5 GiB file after a few scattered single-byte edits
(deduplication ratio; 0.5 = v2 fully deduplicated against v1, lower is
better):

   64 edits:  before 0.5424  ->  after 0.5235
  320 edits:  before 0.6791  ->  after 0.6142

Normalized chunking deduplicates better after edits: removing the
max-size-clamped chunks means a single-byte change invalidates much less
data (about 36% less dedup overhead at 320 edits). Throughput was also
consistently higher with nc_level=2 at this scale.

Also: fix bug when computing the mask, one needs to use 1ULL instead of
1, so the shifting computation is done in a uint64, not in a 32bit int.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 12:00:09 +02:00
..
make-testdata fixed typos and grammar (AI) 2025-09-23 14:56:23 +02:00
shell_completions/fish create: add --exclude-dataless to skip cloud files not materialized locally 2026-06-11 07:36:53 +02:00
borg.exe.spec pyinstaller binary: do not exclude ssl, needed for pyfuse3/trio, fixes #9196 2026-02-14 19:32:38 +01:00
build-borg-using-nuitka.sh binary build scripts: use /bin/sh 2026-06-07 15:32:19 +02:00
build-borg-using-pyinstaller.sh binary build scripts: use /bin/sh 2026-06-07 15:32:19 +02:00
chunker_bench.py buzhash64: add FastCDC-style normalized chunking 2026-06-28 12:00:09 +02:00
Dockerfile.linux-run use xxhash from PyPI, fixes #6535 2026-03-08 13:06:01 +01:00
errorlist.py fixed typos and grammar (AI) 2025-09-23 14:56:23 +02:00
fetch-binaries build binaries on github 2025-10-16 00:37:46 +02:00
glibc_check.py fixed typos and grammar (AI) 2025-09-23 14:56:23 +02:00
linux-run rename Dockerfile to match script name 2026-02-14 19:32:32 +01:00
make.py docs: add docs for "key add", "key list" and "key remove" 2026-06-13 21:37:21 +02:00
msys2-install-deps remove xxhash / xxh64 requirement, mentions 2026-06-10 00:38:18 +02:00
sdist-sign use less setup.py, use pip and build 2024-01-02 19:50:59 +01:00
sign-binaries fix shellcheck warnings in bash scripts 2022-07-22 15:52:04 +00:00
upload-pypi upload-pypi: use borg-specific repository names 2025-11-01 19:57:26 +01:00