Two Pike cleanups.
--auto-split was a got-only third connection-count policy (beside -x and -s)
that invented rather than matched aria2. Removing it also retires the now-dead
autoConns/maxAutoConns and the per-host transport cap that existed only to scale
for it; min(split, M*-x) is the sole policy again.
main's exit-code mapping fell back to substring-matching third-party error text
(strings.Contains "connection refused"/"timeout"/...), which rots when a
dependency rewords a message. The typed checks (errors.Is on the syscall errno,
*net.DNSError, net.Error.Timeout, context.DeadlineExceeded) already cover the
real stdlib errors -- verified end to end: refused -> 6, bad host -> 19. The two
cases that genuinely needed the text match are our own errors, now typed
sentinels: httpdl.ErrTimeout (idle timeout) and the bt metadata timeout wrapping
context.DeadlineExceeded.
The pool let an idle worker steal the back half of a slower in-flight
segment, behind a mutex that also serialized every advance. At the default
-x 1 it never fired, and it carried the trickiest invariant in the tree
(minSplit >= readBuf keeps an owner's in-flight write out of the stolen tail).
makeSegments already caps the segment count at the connection count, so the
segments map one-to-one onto workers: give each its own goroutine, advance
written with a plain atomic add, and snapshot the fixed slice with no lock.
pool/newPool/acquire/steal/advance and the seg.owned field all go away.
Net -156 lines. Behaviour at the user's flags is unchanged, except a slow
mirror's tail segment is no longer rebalanced onto idle connections.
Findings from a Rob-Pike-lens review (bugs/races/network), each verified
against the code before fixing:
- httpdl: name/out are now atomic.Pointer[string] -- the engine publishes a
download to the reporter before Run resolves the name, so Stat raced the
write (bt already did this)
- httpdl: a malformed --proxy fails loudly instead of silently bypassing it
- httpdl: a 206 must carry a matching Content-Range; a 200 in segmented mode is
fatal so it fails over instead of burning the retry budget
- httpdl: single-stream mirror failover validates the range before appending;
ErrTooSlow only when the error is a real ctx cancellation
- httpdl: idle guard tracks progress by timestamp (no Reset/Stop race, no
sticky fired flag)
- httpdl/control: reject a resume file whose segments don't tile [0,total)
- bt: clamp the listen-port range; verify on-disk data before choosing pieces
under --check-integrity
- cli: reject size overflow; show --seed-time=MIN; clamp --select-file range
- progress/engine/main: clamp ETA against int64 overflow; show queued
downloads as waiting; join the reporter on exit instead of a 20ms sleep
From a Rob Pike pass over the tree:
- singleOnce adds deltas to d.completed like pump does, instead of
storing absolute offsets, so the counter has one write discipline.
- one overMirrors helper replaces the three copy-pasted mirror-fallover
loops in probeRetry, fetchSeg and single.
- failedDownload becomes a pointer, the only value-type Download impl, so
Engine.untrack's == is always pointer identity and can't compare the
fields of a value (keying on Stat().ID is out — a torrent's ID changes
from source to infohash once metadata loads).
an idle worker now steals the back half of the busiest in-flight segment
instead of exiting, so one slow segment no longer drains alone over a single
connection. control file persists stolen tails; resume re-tiles.
add --auto-split (got-only, opt-in): derive the connection count from file
size (one per min-split-size, up to 16), overriding -x/-s. default stays
aria2-faithful at 1 connection for a single server.