rsync

Operator migration guide: vNEXT (DDP + async stack)

This guide is for operators upgrading from the previous oc-rsync release to vNEXT, the version that ships the parallel-deterministic-delete (DDP) pipeline, the opt-in async SSH transport, the opt-in tokio-based daemon listener, and a small set of Cargo feature flags that gate the new performance surfaces.

It calls out the behavioural changes vs prior versions, the flags that moved or disappeared, the opt-in switches that are new, the CI matrix changes that mean macOS and Windows are now first-class targets, and the rollback procedure for pinning to the previous release if a regression surfaces.

Architectural context for everything below is in docs/architecture/session-overview-ddp-async-iouring.md. The DDP specification is in docs/design/parallel-deterministic-delete.md. The async daemon and async SSH evaluations are in docs/design/daemon-async-runtime-choice.md and docs/design/ssh-transport-async-io-eval.md.

1. Wire-format compatibility

No protocol changes. vNEXT speaks protocol 32, byte-for-byte identically with the previous release and with upstream rsync 3.4.1.

If your monitoring relies on parsing oc-rsync output, the only observable change is the wall-clock ordering of *deleting itemize lines under --delete-during (section 2). Everything else - message text, error format, exit codes, role trailers, statistics summary - is unchanged.

2. Delete-mode semantics change

vNEXT replaces the previous batched pre-transfer delete sweep with a two-phase pipeline (parallel candidate compute on rayon, single emitter draining in upstream order). The final on-disk state is identical; what changes is the wall-clock event order and the interleave with the transfer loop.

What changed per mode

Mode Previous behaviour vNEXT behaviour
--delete-before Single batched sweep before the transfer loop. Single emitter drains the whole tree before the transfer loop. Same placement, deterministic per-directory order.
--delete-during Single batched sweep before the transfer loop; itemize order non-deterministic above 64 entries. Per-directory interleave with the transfer loop, matching upstream generator.c::generate_files() byte-for-byte.
--delete-delay Same batched sweep, just deferred placement. Per-segment plans buffered, replayed at finalisation in upstream order, mirroring do_delayed_deletions().
--delete-after Batched sweep after the transfer loop. Single emitter drains after the transfer loop, deterministic per-directory order.

Operator impact

What is unchanged

3. --delete-strict-order removal

The opt-in --delete-strict-order / --no-delete-strict-order flags introduced in the prior prerelease for #1940 are removed. Upstream per-directory ordering is now the unconditional default for every --delete-* mode.

Migration

Background: the historical design at docs/design/delete-during-strict-order-gate.md is marked SUPERSEDED. The replacement is the always-on DDP model in docs/design/parallel-deterministic-delete.md.

4. New opt-in feature flags

vNEXT introduces six Cargo feature flags that gate new performance surfaces. None are enabled by default. None change wire bytes. All can be combined.

async-ssh (core, rsync_io)

async-daemon (daemon)

parallel-receive-delta (transfer, experimental)

thread-slab-pool (engine)

ssh-socketpair-stderr (rsync_io, experimental)

vmsplice (fast_io, transfer, Linux only)

Receiver spill tunability (SpillPolicy)

The concurrent-delta receiver bounds its ReorderBuffer through a process-wide SpillPolicy introduced in STN-1 (design) and STN-2 (struct). The default policy keeps the historical behaviour - no spill, everything in memory, byte-equivalent to the previous release - so existing operators see no behavioural change.

Variable Maps to Accepted values
OC_RSYNC_SPILL_THRESHOLD_BYTES threshold_bytes Integer with optional K/M/G suffix (case-insensitive, base 1024). Empty string clears. 0 is rejected.
OC_RSYNC_SPILL_DIR dir Absolute or relative path. Created on first spill via create_dir_all.
OC_RSYNC_SPILL_RECLAIM reclaim_mode keep (default) or re-spill.
OC_RSYNC_SPILL_GRANULARITY granularity whole-batch (default) or per-item.
OC_RSYNC_SPILL_COMPRESSION compression none (default), zstd, or zstd:LEVEL where LEVEL is in [-22, 22].

Combining flags

The feature flags are independent. A common production combination for a high-concurrency Linux daemon endpoint is --features async-daemon,thread-slab-pool. A common client-side combination for high-RTT remote pulls is --features async-ssh. Default builds remain tokio-free and ship every previous-release behaviour unchanged.

5. CI matrix expansion

vNEXT expands CI to include cross-OS coverage for the new feature flags plus dedicated macOS and Windows interop smoke harnesses. This is infrastructure-only; operators do not need to do anything, but it means users on macOS and Windows now see the same green-CI signal that Linux users have always seen.

New rows

The feature-flags-cross-os matrix runs four feature rows (async, tracing, serde, concurrent-sessions) on ubuntu-latest, macos-latest, and windows-latest (12 jobs). Linux-only rows (io_uring, copy_file_range, crypto / deflate backends) stay in the feature-flags-linux matrix.

New interop jobs

macOS additions

The macos-test matrix now also runs the metadata and apple-fs crates on every toolchain row, covering the Darwin acl_exacl branch, the macOS timestamp path, and the AppleDouble + resource-fork pipeline. Tests requiring root self-skip via geteuid(); xattr-dependent tests probe support and skip on filesystems that lack it.

What this means for operators

6. Performance characteristics changes

DDP and the new pool primitives change the shape of receiver-side performance vs the previous release. Wall-clock totals are unchanged to within noise on the common workloads (local copy, single-file push/pull); the differences appear at the tails.

Parallel delete planning vs serial emitter trade-off

Under the previous release, the entire deletion sweep ran in a single batched pre-transfer phase, with per-directory scans fanning out on rayon above 64 entries. The wall-clock cost of deletion was front-loaded.

Under vNEXT:

io_uring pool primitives

Two new pool primitives ship in crates/fast_io/src/io_uring/:

These are additive primitives. Existing single-owner SharedRing consumers (disk_batch, file_writer, file_reader) keep working unchanged. Operators see no behavioural change; the wins are paid out as consumers migrate to the new pools in subsequent releases.

Buffer pool sharding

thread-slab-pool (section 4) shifts buffer-pool memory from a single shared queue to a per-thread slab. Steady-state idle memory grows by N_threads * byte_cap (default 1 MiB). Operators running with more than 32 worker threads per pool will see lower contention and slightly higher RSS.

6a. Windows NTFS ACL behaviour

--acls/-A now works on Windows targets via GetNamedSecurityInfoW/SetNamedSecurityInfoW, but the implementation is a Tier 1C partial path. Operators migrating Windows workloads should budget for the documented lossy cases before flipping -A on:

The cross-platform payload remains byte-compatible with upstream rsync and POSIX peers. The planned –windows-acls opt-in adds a higher- fidelity SDDL payload over the existing xattr stream for Windows-to- Windows transfers, and –fail-on-windows-acl-loss turns the lossy cases into a hard failure (exit code 23) for environments that need to preserve every NTFS ACE verbatim or abort. None of these three flags ship in this release; track docs/design/windows-ntfs-acl-support.md section 4 for the rollout schedule.

The full mapping matrix, hardlink-safe DACL application rules, and the SDDL wire format details are in docs/design/windows-ntfs-acl-support.md. The user-facing –acls entry in docs/oc-rsync.1.md enumerates the lossy cases alongside the flag synopsis.

7. Rollback procedure

If a regression surfaces in vNEXT, pin to the previous release. The wire protocol is unchanged, so a partial rollback (some clients new, some old; or client on one version, daemon on another) is safe.

Pin a release via cargo

cargo install oc-rsync --version <PREVIOUS_VERSION> --locked

Replace <PREVIOUS_VERSION> with the last known-good tag (e.g. 0.6.2). The --locked flag pins transitive dependencies to the release’s Cargo.lock.

Pin a release via the GitHub release page

Download the platform binary from https://github.com/oferchen/rsync/releases for the previous tag. Replace /usr/local/bin/oc-rsync (or your install path) with the downloaded binary. The binary is statically linked on Linux musl targets; on macOS and Windows the platform-native build is used.

Pin a release via package manager

Behavioural rollback notes

Filing a regression report

If you trip a regression, capture:

Open an issue at https://github.com/oferchen/rsync/issues with those five pieces of information. Wire-level regressions are highest priority; performance regressions on the workloads in section 6 are next.

Appendix: design and architecture references

Topic Document
Session architectural overview docs/architecture/session-overview-ddp-async-iouring.md
DDP specification docs/design/parallel-deterministic-delete.md
Legacy strict-order gate (SUPERSEDED) docs/design/delete-during-strict-order-gate.md
Delete architecture docs/architecture/delete-during.md
SSH transport async I/O evaluation docs/design/ssh-transport-async-io-eval.md
Daemon async runtime choice docs/design/daemon-async-runtime-choice.md
Daemon async accept + sync workers docs/design/daemon-async-accept-sync-workers.md
Parallel receive-side delta application docs/design/parallel-receive-delta-application.md
SSH stderr socketpair channel docs/design/socketpair-stderr-channel.md
SSH stderr handling audit docs/audits/ssh-stderr-handling.md
Per-thread buffer slab docs/design/per-thread-buffer-slab.md
vmsplice / splice zero copy docs/design/splice-vmsplice-zero-copy.md
io_uring session ring pool docs/design/iouring-session-ring-pool.md
io_uring per-thread rings docs/design/iouring-per-thread-rings.md
Cross-platform CI coverage docs/audits/cross-platform-ci-coverage.md
Windows NTFS ACL support docs/design/windows-ntfs-acl-support.md