Dead, vestigial, and over-built code with no behavior change (except the
bool-vocabulary trim, a deliberate behavior tightening):
- httpdl: drop the vestigial sort+copy in validSegs (work-stealing was
removed in 270812d, so segments always tile [0,total) ascending now);
validate order in place, which also rejects a scrambled sidecar. Inline
the endOff() accessor to s.end.
- cli: shrink the boolean vocabulary to true/false, which is all that's
accepted. The invented yes/no/1/0/on/off spellings are gone, so e.g.
--enable-dht=yes (or yes in got.conf) is now a usage error.
- download: remove the dead, never-called Stat.Done() method.
- progress: drop speed(), a pure alias of humanSize; call humanSize directly.
- main: replace the jobsHolder mutex box with atomic.Pointer[[]job] for the
forced-exit session save; the capability stays, the lock and type go.
- bt: collapse isAddrInUse's X||X (missinggo.IsAddrInUse is that exact
string match); drop the now-unused missinggo import (tidy -> indirect).
- option: note that prealloc and falloc are identical here.
57 lines
1.9 KiB
Go
57 lines
1.9 KiB
Go
package httpdl
|
|
|
|
import "sync/atomic"
|
|
|
|
// seg is one contiguous byte range of the output file, downloaded by a single
|
|
// ranged GET. A segment IS a byte range — a plain HTTP downloader does not need
|
|
// the Piece/Segment/block layering that exists only to share code with
|
|
// BitTorrent. start and end are fixed when the file is divided; written is
|
|
// advanced (atomically) by the segment's one worker, so Stat() and the resume
|
|
// snapshot can read its frontier while it downloads.
|
|
type seg struct {
|
|
index int
|
|
start int64 // first byte offset, inclusive
|
|
end int64 // last byte offset, inclusive
|
|
written int64 // bytes already written into this segment (the resume point)
|
|
}
|
|
|
|
func (s *seg) length() int64 { return s.end - s.start + 1 }
|
|
func (s *seg) done() bool { return atomic.LoadInt64(&s.written) >= s.length() }
|
|
func (s *seg) addWritten(n int64) { atomic.AddInt64(&s.written, n) }
|
|
func (s *seg) progress() int64 { return atomic.LoadInt64(&s.written) }
|
|
func (s *seg) offset() int64 { return s.start + atomic.LoadInt64(&s.written) }
|
|
func (s *seg) remaining() int64 { return s.length() - atomic.LoadInt64(&s.written) }
|
|
|
|
// makeSegments divides a file of total bytes into contiguous segments, using at
|
|
// most conns of them and never splitting below minSplit. The remainder lands in
|
|
// the last segment. With conns==1 (the default) this yields one segment. Each
|
|
// segment gets its own worker, so the division here fixes the parallelism: there
|
|
// is no later rebalancing.
|
|
func makeSegments(total, minSplit int64, conns int) []seg {
|
|
if conns < 1 {
|
|
conns = 1
|
|
}
|
|
if minSplit < 1 {
|
|
minSplit = 1
|
|
}
|
|
n := int64(conns)
|
|
if max := total / minSplit; max < n {
|
|
n = max
|
|
}
|
|
if n < 1 {
|
|
n = 1
|
|
}
|
|
chunk := total / n
|
|
segs := make([]seg, n)
|
|
var start int64
|
|
for i := int64(0); i < n; i++ {
|
|
end := start + chunk - 1
|
|
if i == n-1 {
|
|
end = total - 1
|
|
}
|
|
segs[i] = seg{index: int(i), start: start, end: end}
|
|
start = end + 1
|
|
}
|
|
return segs
|
|
}
|