Files
ddc/internal/fetch/state.go
T

98 lines
2.1 KiB
Go

package fetch
import "sync/atomic"
const (
MaxConnections = 16
minSegmentBytes = int64(32) << 20
)
type Segment struct {
Start int64 `json:"start"`
End int64 `json:"end"`
Done int64 `json:"done"`
}
type State struct {
FileName string `json:"fileName"`
Validator string `json:"validator"`
TotalBytes int64 `json:"totalBytes"`
Segments []Segment `json:"segments"`
}
func (state State) DoneBytes() int64 {
var done int64
for _, segment := range state.Segments {
done += segment.Done
}
return done
}
func (state State) valid() bool {
if state.FileName == "" || len(state.Segments) == 0 {
return false
}
for _, segment := range state.Segments {
if segment.Start < 0 || segment.Done < 0 {
return false
}
if segment.End == 0 && state.TotalBytes > 0 {
return false
}
if segment.End > 0 && segment.Start+segment.Done > segment.End {
return false
}
}
return true
}
func planSegments(totalBytes int64, connections int) []Segment {
if totalBytes <= 0 {
return []Segment{{}}
}
count := min(int64(max(connections, 1)), max(totalBytes/minSegmentBytes, 1))
size := totalBytes / count
segments := make([]Segment, count)
for index := range segments {
start := int64(index) * size
segments[index] = Segment{Start: start, End: start + size}
}
segments[count-1].End = totalBytes
return segments
}
type liveSegment struct {
start int64
end int64
done atomic.Int64
}
func newLiveSegment(segment Segment) *liveSegment {
live := &liveSegment{start: segment.Start, end: segment.End}
live.done.Store(segment.Done)
return live
}
func (segment *liveSegment) position() int64 {
return segment.start + segment.done.Load()
}
func (segment *liveSegment) bounded() bool {
return segment.end > 0
}
func (segment *liveSegment) remaining() int64 {
if !segment.bounded() {
return -1
}
return segment.end - segment.position()
}
func (segment *liveSegment) complete() bool {
return segment.bounded() && segment.position() >= segment.end
}
func (segment *liveSegment) snapshot() Segment {
return Segment{Start: segment.start, End: segment.end, Done: segment.done.Load()}
}