Commit Graph
166 Commits
Author SHA1 Message Date
Thomas Waldmann a0cd1b3441 borg2 performance harness for rest:// repositories 2026-07-02 21:26:37 +02:00
Thomas WaldmannandClaude Opus 4.8 f2b96e3d15 fastcdc: add FastCDC chunker with a keyed Gear hash
Add a new "fastcdc" content-defined chunker selectable via --chunker-params.
It uses the FastCDC Gear rolling hash (fp = (fp << 1) + Gear[byte]), which is
window-less and cheaper per byte than buzhash's cyclic-polynomial update, so it
chunks noticeably faster (see "borg benchmark cpu" output), while producing
the same chunk-size distribution and deduplication.

The Gear table is keyed: it is derived from the repo id key via CSPRNG (own
"fastcdc" domain), exactly like the buzhash64 table, so chunk cut points stay
unpredictable without the key (anti-fingerprinting). It implements the same
FastCDC techniques as buzhash64 (sub-minimum skipping, normalized chunking with
a required nc_level, min/max clamping); the mask uses the high bits of the hash
(Gear accumulates entropy there).

chunker-params: "fastcdc,chunk_min,chunk_max,chunk_mask,nc_level" - there is no
window field, because Gear is window-less. e.g. fastcdc,19,23,21,2

Also: borg benchmark cpu now measures the fastcdc chunker; tests in
borg.testsuite.chunkers (golden vector, size distribution, keyed gear table,
param parsing, slow fuzz); docs and changelog.

Benchmarks (scripts/chunker_bench.py, buzhash64 vs fastcdc, both nc_level=2,
incompressible data unless noted):

  5 GiB, 2 MiB target (default params):
    buzhash64: CV 0.294, 1011 MB/s
    fastcdc:   CV 0.295, 1313 MB/s   (+30%)

  64 MiB, 64 KiB target:
    buzhash64: CV 0.374, shift-resilience 0.9928,  963 MB/s
    fastcdc:   CV 0.359, shift-resilience 0.9929, 1331 MB/s   (+38%)

  Re-backup of a 2.5 GiB file after scattered single-byte edits (dedup ratio,
  0.5 = v2 fully deduplicated, lower is better):
     64 edits:  buzhash64 0.5237, fastcdc 0.5236
    320 edits:  buzhash64 0.6133, fastcdc 0.6161

  borg benchmark cpu, 1 GB: fastcdc 3.80s, buzhash 4.36s, buzhash64 8.13s,
  fixed 0.56s.

Chunk-size distribution, deduplication and shift-resilience match buzhash64
within noise; fastcdc is consistently faster.

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 <[email protected]>
2026-07-01 23:24:25 +02:00
Thomas WaldmannandClaude Opus 4.8 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 <[email protected]>
2026-06-28 12:00:09 +02:00
Thomas WaldmannandClaude Opus 4.8 d5cd72b179 docs: add docs for "key add", "key list" and "key remove"
The multi-key feature (#9743) added the "borg key add", "borg key list"
and "borg key remove" subcommands but never wired up their docs:

- scripts/make.py: map key_add/key_list/key_remove to the "key" usage
  group, so build_man can locate their examples (it previously aborted
  with FileNotFoundError: docs/usage/key_add.rst).
- docs/usage/key.rst: include the three new generated snippets so they
  show up on the HTML key page.
- regenerate the affected docs: new key_{add,list,remove}.rst.inc usage
  snippets, new borg-key-{add,list,remove}.1 man pages, and borg-key.1
  (SYNOPSIS + SEE ALSO now reference the new subcommands).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 21:37:21 +02:00
Thomas WaldmannandClaude Sonnet 4.6 f484741fdd create: add --exclude-dataless to skip cloud files not materialized locally
Ports #9755 (1.4-maint) to master.

macOS flags files whose content lives in cloud storage (e.g. iCloud Drive)
and is not present locally with SF_DATALESS. Reading such a file triggers
downloading its content.

This adds --exclude-dataless to borg create: the flags are checked right
after stat() and before any open(), so excluded files/dirs never get
materialized. Skipped paths are reported with the usual 'x' status,
analogous to --exclude-nodump.

Notes:
- stat.SF_DATALESS only exists from Python 3.13 on, so there is a fallback
  to the value from macOS' sys/stat.h (0x40000000).
- The check covers directories too (they can also be dataless), and we skip
  before opening/recursing into them.
- Test fakes get_flags via monkeypatch since SF_DATALESS cannot be set from
  userspace.
- Fish shell completion updated; bash/zsh completions don't exist in master.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-06-11 07:36:53 +02:00
Thomas Waldmann 31202ea4f1 remove xxhash / xxh64 requirement, mentions 2026-06-10 00:38:18 +02:00
Thomas Waldmann 44e6ebdcd0 binary build scripts: use /bin/sh
there is no bash on some BSDs
2026-06-07 15:32:19 +02:00
Thomas Waldmann e8c4a517e6 CI: install rust and python-maturin for windows/msys2 2026-06-06 19:34:50 +02:00
Thomas Waldmann fb53f44f0f nuitka build: also use dist/binary for output 2026-06-04 18:31:57 +02:00
Thomas Waldmann 2768548032 build: add build-borg-using-pyinstaller.sh and use it in ci.yml 2026-06-04 18:25:12 +02:00
Thomas Waldmann 4431759d79 better script name 2026-06-03 12:57:45 +02:00
Thomas Waldmann 38cefed974 nuitka build script: simplify, see #3227
Including cffi is already enough to make it work.

Using --mode=onefile as suggested by Kay.
2026-06-03 12:55:11 +02:00
Thomas Waldmann b64d1dbc4d scripts/build-nuitka.sh: generate single-file binary using nuitka, fixes #3227
Very experimental and little tested.
2026-06-02 18:56:43 +02:00
Thomas Waldmann 6cfb90dae9 repo-compress: remove this command for now
for packs, this needs to get implemented differently to perform well.
processing needs to be pack-after-pack and the index needs to be
updated correctly and carefully, e.g. considering interruptions
of repo-compress.
2026-05-22 13:00:13 +02:00
Thomas Waldmann 227484b679 remove the superfluous borg.checksums module 2026-05-12 18:41:34 +02:00
Thomas Waldmann e91f4efab1 make build_usage / build_man: do not show options with SUPPRESS 2026-03-10 18:36:22 +01:00
Thomas Waldmann 9a469e32cf fix make build_man / build_usage 2026-03-10 18:36:05 +01:00
Suryansh Pal ba6706395a use xxhash from PyPI, fixes #6535 2026-03-08 13:06:01 +01:00
defnvary 4344eb37d1 use zstd from python stdlib or backport.zstd, closes #9261 2026-02-23 00:33:21 +05:30
Mrityunjay Raj 1c0bf36275 remove handwritten bash/zsh shell completions, fixes #9178
Remove the handwritten bash and zsh shell completion scripts now that
auto-generated completions via borg completion bash/zsh (powered by
shtab, #9172) are tested and working. Fish completions are kept as
shtab does not yet support fish.

Replace string-matching tests with focused behavior tests: script size
sanity, shell syntax validation (bash -n / zsh -n), and tests that
invoke the custom preamble functions in bash (sortby key dedup,
filescachemode mutual exclusivity, archive name and aid: prefix
completion against a real repository).
2026-02-17 19:33:54 +01:00
TW 4e3352ed58 Merge pull request #9327 from ThomasWaldmann/fixes-master
Misc. fixes (master)
2026-02-17 15:16:02 +01:00
Mrityunjay Raj f1ed09965f docs: fix broken :ref: references in man pages, fixes #7239 2026-02-16 22:36:07 +05:30
Thomas Waldmann de51d24464 pyinstaller binary: do not exclude ssl, needed for pyfuse3/trio, fixes #9196 2026-02-14 19:32:38 +01:00
Thomas Waldmann d73a88ebbe rename Dockerfile to match script name 2026-02-14 19:32:32 +01:00
Thomas Waldmann 94d56e1c89 pyinstaller: cockpit: add tcss file, add unicode data 2026-02-14 19:05:37 +01:00
Thomas Waldmann 40a2bb7032 linux-run: run commands (e.g. tox) in a podman linux container
this is useful to run the linux tests on a mac, e.g. to test fuse stuff.
2026-02-14 12:19:32 +01:00
Thomas Waldmann 8f40baa34b refactor: use |= operator for dictionary updates (py39) 2025-11-03 22:18:26 +01:00
Thomas Waldmann 471e302024 upload-pypi: use borg-specific repository names
so it finds the right api token in .pypirc
2025-11-01 19:57:26 +01:00
Thomas Waldmann c4a9582fdf build binaries on github
also:

- speed up CI for PRs
- update README for binaries
2025-10-16 00:37:46 +02:00
Thomas Waldmann 3120f9cd1c fixed typos and grammar (AI)
this was done by Junie AI.
2025-09-23 14:56:23 +02:00
Thomas Waldmann 85e0e05f35 vagrant: add debian trixie box
currently still known as "testing",
but soon to be released.
2025-08-09 16:28:47 +02:00
Thomas Waldmann 0324395baf pyinstaller spec: avoid pkg_resources warning 2025-06-18 22:35:38 +02:00
Thomas Waldmann 63ff136dfe buzhash64: integrate into build 2025-06-10 22:44:48 +02:00
TW 31a1ac18c7 Merge pull request #8899 from ThomasWaldmann/fish-completions
fish: fix archive name completion
2025-06-09 19:21:11 +02:00
Thomas Waldmann f44b1742f5 Extract ChunkerFixed into a dedicated module under chunkers.
Moved the `ChunkerFixed` implementation from `chunker` to a new `fixed` module for better modularity. Updated imports and type hints.

Removed now empty chunkers.chunker module.
2025-06-04 23:48:50 +02:00
Thomas Waldmann 31494f200d Extract buzhash logic into a dedicated module under chunkers
Moved `buzhash` implementation from `chunker` to a new `buzhash` module for better separation of concerns. Updated imports, adjusted `setup.py` and build configuration accordingly. Removed deprecated `Chunker` definitions from `chunker.pyi`.
2025-06-04 22:57:03 +02:00
Thomas Waldmann a78c310b72 Split reader functionality into a separate module under chunkers package
Extracted the `reader` logic from `chunker` into a dedicated `reader` module to improve modularity and maintainability. Updated imports, references, and build configurations accordingly.
2025-06-04 22:40:39 +02:00
Thomas Waldmann bc86bd4bb0 Move chunker module to chunkers package
Refactor by relocating the `chunker` module under a new `chunkers` package, adjusting imports and file references accordingly.
2025-06-04 22:12:45 +02:00
Thomas Waldmann a1ba5c3c81 fish: fix archive name completion 2025-06-04 01:01:08 +02:00
TW 39b847a138 Merge pull request #8859 from ThomasWaldmann/pyupgrade-py310-plus
pyupgrade --py310-plus ./**/*.py
2025-05-20 23:29:58 +02:00
Thomas Waldmann c7765adf08 pyupgrade --py310-plus ./**/*.py 2025-05-20 22:05:13 +02:00
Thomas Waldmann a4761f9158 zsh: no barchive, add --repo 2025-05-20 21:28:46 +02:00
Thomas Waldmann 7e78aaf04d zsh fixes, remove repo-list caching 2025-05-20 21:08:09 +02:00
Thomas Waldmann ca87c60565 minor bash completion fixes 2025-05-20 21:05:38 +02:00
Thomas Waldmann 3196f490f3 zsh: add new commands and options to zsh completions 2025-05-19 21:03:11 +02:00
Thomas Waldmann 9116533ec3 fish: add new commands and options to fish completions 2025-05-19 20:30:52 +02:00
Thomas Waldmann 15d3408360 bash: add new commands and options to bash completions
Updated bash completions to include new commands such as `analyze`, `debug`, `repo-space`, `tag`, and `undelete`, along with their respective options. Fixed a typo in the `--upgrader` completions and improved completion handling for various commands.
2025-05-19 20:30:49 +02:00
Thomas Waldmann 3df7702519 tests: fix and enable windows CI, fixes #8728
thanks a lot to @sothix for helping with this!

removed pytest-forked, is not found anymore:
error: target not found: mingw-w64-ucrt-x86_64-python-pytest-forked

use a virtual env to avoid mixup of user with system packages.

remove old workaround for setuptools (SETUPTOOLS_USE_DISTUTILS: stdlib).

fix pip install

use --system-site-packages as a workaround for broken pip install python-cffi.

do not upgrade pip setuptools build wheel

use python -m pytest to use the one from the venv
2025-05-19 11:00:11 +02:00
Thomas Waldmann 9e6d90754e remove remainders of append-only support
Some features like append-only repositories rely on a server-side component
that enforces them (because that shall only be controllable server-side,
not client-side).

So, that can only work, if such a server-side component exists, which is the
case for borg 1.x ssh: repositories (but not for borg 1.x non-ssh: repositories).

For borg2, we currently have:
- fs repos
- sftp: repos
- rclone: repos (enabling many different cloud providers)
- s3/b3: repos
- ssh: repos using client/server rpc code similar as in borg 1.x

So, only for the last method we have a borg server-side process that could enforce some features, but not for any of the other repo types.

For append-only the current idea is that this should not be done within borg,
but solved by a missing repo object delete permission enforced by the storage.

borg create could then use credentials that miss permission to delete,
while borg compact would use credentials that include permission to delete.
2025-04-28 18:55:15 +02:00
Thomas Waldmann 48b39d878f remove remainders of quota support
Some features like repository quotas rely on a server-side component
that enforces them (because that shall only be controllable server-side,
not client-side).

So, that can only work, if such a server-side component exists, which is the
case for borg 1.x ssh: repositories (but not for borg 1.x non-ssh: repositories).

For borg2, we currently have:
- fs repos
- sftp: repos
- rclone: repos (enabling many different cloud providers)
- s3/b3: repos
- ssh: repos using client/server rpc code similar as in borg 1.x

So, only for the last method we have a borg server-side process that could enforce some features, but not for any of the other repo types.

For quotas the current idea is that this should not be done within borg,
but enforced by a storage specific quota implementation (like fs quota,
or quota of the cloud storage provider). borg could offer information
about overall repo space used, but would not enforce quotas within borg.
2025-04-28 16:57:30 +02:00