This is the record of a review of the DAG transfer engine in September 2026. The review measured each fix against the build before it, with rclone running the same cell in the same window as a control. It is published as a dated record: the builds are review builds, not releases, and the current release is measured in the comparative battery of October 2026.
mod_dav behind nginx (WebDAV) and MinIO (S3).--limit-rate 2M for the rate cap cells.| Label | Commit | What it adds | sha256 (first 16) |
|---|---|---|---|
| before | 3417fcb46 | baseline | b1b3d6a619bde840 |
| after | 38d5c0b96 | session reuse and the review fixes (#735) | 12892e18beb9aa11 |
| third | 7336fa6b5 | no size probe per small file (#757) | 7b9c2a244bcce827 |
| fourth | 53ed27ce8 | parallel tree walk for check (#758) | bb8daf4e7e3b43a8 |
| ceiling | 4b25a288b | SFTP --parallel up to 16 (#761) | |
| FTP close | a0d19d381 | FTP data close on the server's signal (#769) | |
| stat overlap | 34c07bb6c | SFTP stat and open overlapped (#782), against its base 43a37db1c |
One run per cell, 8 September 2026. Seconds, lower is better.
| Cell | AeroFTP before | AeroFTP after | rclone before | rclone after | Ratio after |
|---|---|---|---|---|---|
SFTP small tree, --parallel 4, upload | 1391.20 | 330.52 | 687.47 | 643.64 | 1.95 |
SFTP small tree, --parallel 4, download | 1294.21 | 272.76 | 421.92 | 431.57 | 1.58 |
SFTP small tree, --parallel 16, upload | 1383.41 | 316.02 | 366.92 | 344.00 | 1.09 |
SFTP small tree, --parallel 16, download | 1293.45 | 264.41 | 115.86 | 109.89 | 0.42 |
| SFTP small tree, first sync | 1391.25 | 313.60 | 689.57 | 649.91 | 2.07 |
| SFTP 300 MiB, download | 155.00 | 41.91 | 17.41 | 18.97 | 0.45 |
| SFTP 300 MiB, upload | 39.79 | 20.92 | 11.88 | 11.52 | 0.55 |
| S3 small tree, sync with nothing to do | 69.90 | 3.50 | 28.11 | 30.27 | 8.65 |
| S3 small tree, sync with a delta | 73.82 | 3.77 | 30.96 | 30.74 | 8.15 |
rclone stayed within 9 percent on every control while AeroFTP moved by 47 to 95 percent, so the movement belongs to the build. The --parallel 16 rows did not improve over --parallel 4 because on these builds the SFTP pool stopped at four sessions; section 3 shows what happened when that ceiling was raised. The 300 MiB SFTP rows are single-stream on this build; the channel effect on them is on the fixed pipe page.
20 MiB under --limit-rate 2M should take 10.0 seconds. A faster time means the cap was ignored. One run per cell.
| Cell | before | after | Verdict |
|---|---|---|---|
| S3 download | 3.08 | 9.75 | cap honoured after |
| S3 upload | 2.16 | 10.13 | cap honoured after |
| WebDAV download | 2.90 | 9.55 | cap honoured after |
| WebDAV upload | 1.63 | 10.10 | cap honoured after |
| FTP download | 4.53 | 10.51 | cap honoured after |
| SFTP, both directions | 13 and 18 percent over target | 12 and 18 percent over target | cap honoured on both builds, unchanged |
A table of percentage changes without the 10-second target would show these rows as a large regression.
The FTP upload under the cap stayed about 3 seconds over target after #735. The overshoot was constant in seconds (2.93 s over a 10 s target, 3.03 s over a 20 s one), which pointed at a fixed cost rather than a mistuned limiter: the client waited a timed interval before closing each data connection. #769 waits for the server's signal instead. Two runs, prediction written into the script before measuring:
| Row | before #769 | predicted | measured, two runs |
|---|---|---|---|
| FTP upload at 2M | 12.93 | 11.00 | 10.96, 10.84 |
| FTP upload, 20 MiB, no cap | 4.76 | 2.70 | 2.96, 2.71 |
| FTP upload, 1 MiB, no cap | 2.40 | 2.14 | 2.43, 2.27 |
Before #761, the SFTP provider capped its pool at four sessions, so --parallel 16 did what --parallel 4 did. Two runs per build, interleaved, integrity verified.
| Cell | ceiling 4, two runs | ceiling 16, two runs | Change of the mean |
|---|---|---|---|
small tree, --parallel 16, download | 258.32, 254.60 | 123.33, 129.60 | -51% |
small tree, --parallel 16, upload | 285.74, 289.91 | 144.67, 147.31 | -49% |
small tree, --parallel 4, download (control) | 252.49, 248.85 | 248.05, 243.85 | -2% |
small tree, --parallel 4, upload (control) | 296.16, 293.33 | 286.95, 284.72 | -3% |
The --parallel 16 rows halve and the --parallel 4 rows do not move: the ceiling was raised without changing the default. A socket count taken during the runs read 10 connections at --parallel 16 and 6 at --parallel 4 on the new build (the count includes the main connection), so the pool follows the request instead of always opening its maximum.
Against rclone at --transfers 16, after this fix: upload 145.99 s against 344.00 s (ratio 2.36), download 126.47 s against 109.89 s (ratio 0.87).
The download at --parallel 16 was the last row of the review where rclone was ahead. #782 overlaps the stat and open round trips for small files whose size is already known from the listing. Two interleaved runs, 20 integrity checks, 0 failed.
| Run | AeroFTP base | rclone, same window | AeroFTP with #782 | rclone, same window |
|---|---|---|---|---|
| 1 | 133.63 | 105.63 | 99.60 | 106.01 |
| 2 | 136.48 | 109.05 | 103.49 | 109.65 |
The medians move from 135.06 s to 101.54 s (-24.8 percent) while rclone moves by +0.5 percent. rclone in the same runs sits at about 107.5 s, so AeroFTP finished this cell about 5.6 percent ahead (ratio 1.06). The same change also improved --parallel 4 from 252.17 s to 202.04 s, where rclone took 382.62 s in the same window (one run per build, ratio 1.89).
The saving was larger than a simple model predicts: one round trip per file over ten sessions accounts for about 25 seconds, and the measured saving was 33.5 seconds. The direction and the order of magnitude agree; the remaining third is not explained here.
The "after" build added one size probe before every small-file download (a signed HEAD on S3, a one-byte Range request on WebDAV). Three builds in one window, interleaved twice, integrity verified on all twelve runs:
| Cell | before | after | third (#757) |
|---|---|---|---|
| S3 small tree, download | 67.68, 69.02 | 124.94, 127.77 | 69.67, 67.41 |
| WebDAV small tree, download | 69.60, 71.85 | 130.53, 124.24 | 64.97, 67.39 |
The added time matches one extra round trip per file on each of the four download channels: 5,000 files over 4 channels is 1,250 files per channel, and the mean increases (58.0 s on S3, 56.7 s on WebDAV) divided by 1,250 give 46 ms and 45 ms, against a measured RTT of 47.36 ms. #757 removed the probe.
check on a populated remote #758 moved the remote tree walk of check, reconcile and cryptcheck onto parallel sessions. One run per build: check opened 5 sessions instead of 1 and went from 11.37 s to 5.78 s. sync reached the remote tree through other walkers on that build and did not change; #762 followed for it.
The only FTP cell of the review where both tools ran the same transport. 1 MiB upload, three runs per arm, base commit 43a37db1c.
| Arm | Seconds |
|---|---|
| AeroFTP, plain FTP | 1.98 |
| AeroFTP, explicit TLS (its default) | 2.22 |
| rclone, plain FTP | 2.00 |
rclone, explicit TLS limited to TLS 1.2 (needs --ftp-disable-tls13) | 3.22 |
| rclone, explicit TLS with its defaults | does not complete the transfer |
Plain against plain the two tools are level. With TLS, AeroFTP is faster. Against this server (vsftpd 3.0.5, which requires each data connection to reuse the control connection's TLS session), rclone v1.74.0 with its default settings did not complete an upload over explicit TLS, and with --ftp-disable-tls13 it did; the mechanism on rclone's side was not isolated, so this is a result for this server and these versions. AeroFTP caps FTP over TLS at TLS 1.2 because, with its TLS library, a TLS 1.3 session ticket is consumed when used and a second data connection would not resume the control connection's session; its rclone exporter writes disable_tls13 into exported FTP remotes since 4.2.0.
An earlier reading of this cell compared AeroFTP over TLS with rclone in plain FTP and reported a 0.48 s gap. That arm of the cell had failed on every run and was not counted; the figure above replaces it.
The first pass of the review flagged eight anomalies. Each was repeated with the rclone control before anything was concluded.
| Anomaly in the first pass | After repetition | Verdict |
|---|---|---|
| WebDAV 300 MiB upload, +44% | +15%, and rclone moved +29% in the same window | the link, not the build |
| FTP 300 MiB upload, +20% | -12% | sign reversed, environment |
| S3 first sync, +15% | -5% | environment |
| SFTP sync with nothing to do, -20% | +2% | environment |
| FTP slower above 4 channels | a six-point curve with two runs each: 8 channels is the best point, rclone has the same shape | noise |
| Interrupted upload resumed slowly, +39% | on this link 15 of 16 legs finished before the 60 s kill, so they measured no resume | instrument; rows dropped |
| FTP upload under the rate cap, +20% | reproduced, then explained as a fixed cost per data connection | fixed by #769, section 2 |
| S3 mixed 200-file upload, +17% | eight runs per build, rclone subtracted: -2.0 points against a noise floor of 13.4% | not a regression |
Six of the eight did not survive repetition, and the seventh was a real cost with a different cause. Publishing after the first pass would have reported six false leads.
The review also swept the number of channels on one 300 MiB download per protocol. Those tables live on the fixed pipe page, because they measure channel count, not the DAG engine against an older path.
The S3 points of that sweep were all single-stream. On these builds the S3 multi-stream download took the object size from a HEAD response through a call that always returns 0 for HEAD, so no download ever reached the range path, whatever the requested channel count. #881 fixed it on 19 September. The differences between the S3 points are noise, and the sweep says nothing about S3 ranged downloads. They are measured on 4.2.1 in the comparative battery.