httpdl: unify completed counter and dedupe mirror loop; engine: harden untrack

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).
This commit is contained in:
2026-06-20 21:12:07 +09:00
parent 11734af7fb
commit d9de63f451
3 changed files with 46 additions and 49 deletions

View File

@@ -91,6 +91,10 @@ func (e *Engine) track(d Download) {
e.mu.Unlock()
}
// untrack removes d from the active set. Every Download implementation is a
// pointer type, so the == compares identities — never the fields of a value,
// which could panic on a non-comparable one. (Keying on Stat().ID is not an
// option: a torrent's ID changes from source to infohash once metadata loads.)
func (e *Engine) untrack(d Download) {
e.mu.Lock()
defer e.mu.Unlock()