2021-05-24 04:24:18 +00:00
|
|
|
package job
|
|
|
|
|
|
|
|
import "sync"
|
|
|
|
|
|
|
|
// ProgressIndefinite is the special percent value to indicate that the
|
|
|
|
// percent progress is not known.
|
|
|
|
const ProgressIndefinite float64 = -1
|
|
|
|
|
|
|
|
// Progress is used by JobExec to communicate updates to the job's progress to
|
|
|
|
// the JobManager.
|
|
|
|
type Progress struct {
|
|
|
|
processed int
|
|
|
|
total int
|
|
|
|
percent float64
|
|
|
|
currentTasks []*task
|
|
|
|
|
|
|
|
mutex sync.Mutex
|
|
|
|
updater *updater
|
|
|
|
}
|
|
|
|
|
|
|
|
type task struct {
|
|
|
|
description string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Progress) updated() {
|
|
|
|
var details []string
|
|
|
|
for _, t := range p.currentTasks {
|
|
|
|
details = append(details, t.description)
|
|
|
|
}
|
|
|
|
|
|
|
|
p.updater.updateProgress(p.percent, details)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indefinite sets the progress to an indefinite amount.
|
|
|
|
func (p *Progress) Indefinite() {
|
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
|
|
|
p.total = 0
|
|
|
|
p.calculatePercent()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetTotal sets the total number of work units. This is used to calculate the
|
|
|
|
// progress percentage.
|
|
|
|
func (p *Progress) SetTotal(total int) {
|
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
|
|
|
p.total = total
|
|
|
|
p.calculatePercent()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetProcessed sets the number of work units completed. This is used to
|
|
|
|
// calculate the progress percentage.
|
|
|
|
func (p *Progress) SetProcessed(processed int) {
|
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
|
|
|
p.processed = processed
|
|
|
|
p.calculatePercent()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Progress) calculatePercent() {
|
|
|
|
if p.total <= 0 {
|
|
|
|
p.percent = ProgressIndefinite
|
|
|
|
} else if p.processed < 0 {
|
|
|
|
p.percent = 0
|
|
|
|
} else {
|
|
|
|
p.percent = float64(p.processed) / float64(p.total)
|
|
|
|
if p.percent > 1 {
|
|
|
|
p.percent = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p.updated()
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetPercent sets the progress percent directly. This value will be
|
|
|
|
// overwritten if Indefinite, SetTotal, Increment or SetProcessed is called.
|
|
|
|
// Constrains the percent value between 0 and 1, inclusive.
|
|
|
|
func (p *Progress) SetPercent(percent float64) {
|
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
|
|
|
if percent < 0 {
|
|
|
|
percent = 0
|
|
|
|
} else if percent > 1 {
|
|
|
|
percent = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
p.percent = percent
|
|
|
|
p.updated()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Increment increments the number of processed work units, if this does not
|
|
|
|
// exceed the total units. This is used to calculate the percentage.
|
|
|
|
func (p *Progress) Increment() {
|
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
|
|
|
if p.processed < p.total {
|
2021-06-03 23:21:17 +00:00
|
|
|
p.processed++
|
2021-05-24 04:24:18 +00:00
|
|
|
p.calculatePercent()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Progress) addTask(t *task) {
|
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
|
|
|
p.currentTasks = append(p.currentTasks, t)
|
|
|
|
p.updated()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Progress) removeTask(t *task) {
|
|
|
|
p.mutex.Lock()
|
|
|
|
defer p.mutex.Unlock()
|
|
|
|
|
|
|
|
for i, tt := range p.currentTasks {
|
|
|
|
if tt == t {
|
|
|
|
p.currentTasks = append(p.currentTasks[:i], p.currentTasks[i+1:]...)
|
|
|
|
p.updated()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExecuteTask executes a task as part of a job. The description is used to
|
|
|
|
// populate the Details slice in the parent Job.
|
|
|
|
func (p *Progress) ExecuteTask(description string, fn func()) {
|
|
|
|
t := &task{
|
|
|
|
description: description,
|
|
|
|
}
|
|
|
|
|
|
|
|
p.addTask(t)
|
|
|
|
defer p.removeTask(t)
|
|
|
|
fn()
|
|
|
|
}
|