stash/pkg/job/progress.go
WithoutPants 5495d72849 File storage rewrite (#2676)
* Restructure data layer part 2 (#2599)
* Refactor and separate image model
* Refactor image query builder
* Handle relationships in image query builder
* Remove relationship management methods
* Refactor gallery model/query builder
* Add scenes to gallery model
* Convert scene model
* Refactor scene models
* Remove unused methods
* Add unit tests for gallery
* Add image tests
* Add scene tests
* Convert unnecessary scene value pointers to values
* Convert unnecessary pointer values to values
* Refactor scene partial
* Add scene partial tests
* Refactor ImagePartial
* Add image partial tests
* Refactor gallery partial update
* Add partial gallery update tests
* Use zero/null package for null values
* Add files and scan system
* Add sqlite implementation for files/folders
* Add unit tests for files/folders
* Image refactors
* Update image data layer
* Refactor gallery model and creation
* Refactor scene model
* Refactor scenes
* Don't set title from filename
* Allow galleries to freely add/remove images
* Add multiple scene file support to graphql and UI
* Add multiple file support for images in graphql/UI
* Add multiple file for galleries in graphql/UI
* Remove use of some deprecated fields
* Remove scene path usage
* Remove gallery path usage
* Remove path from image
* Move funscript to video file
* Refactor caption detection
* Migrate existing data
* Add post commit/rollback hook system
* Lint. Comment out import/export tests
* Add WithDatabase read only wrapper
* Prepend tasks to list
* Add 32 pre-migration
* Add warnings in release and migration notes
2022-09-06 07:03:42 +00:00

176 lines
3.8 KiB
Go

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 {
defined bool
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.defined = false
p.total = 0
p.calculatePercent()
}
// Definite notifies that the total is known.
func (p *Progress) Definite() {
p.mutex.Lock()
defer p.mutex.Unlock()
p.defined = true
p.calculatePercent()
}
// SetTotal sets the total number of work units and sets definite to true.
// 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.defined = true
p.calculatePercent()
}
// AddTotal adds to the total number of work units. This is used to calculate the
// progress percentage.
func (p *Progress) AddTotal(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() {
switch {
case !p.defined || p.total <= 0:
p.percent = ProgressIndefinite
case p.processed < 0:
p.percent = 0
default:
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. This is used to calculate the percentage.
// If total is set already, then the number of processed work units will not exceed the total.
func (p *Progress) Increment() {
p.mutex.Lock()
defer p.mutex.Unlock()
if !p.defined || p.total <= 0 || p.processed < p.total {
p.processed++
p.calculatePercent()
}
}
// AddProcessed increments the number of processed work units by the provided
// amount. This is used to calculate the percentage.
func (p *Progress) AddProcessed(v int) {
p.mutex.Lock()
defer p.mutex.Unlock()
newVal := v
if p.defined && p.total > 0 && newVal > p.total {
newVal = p.total
}
p.processed = newVal
p.calculatePercent()
}
func (p *Progress) addTask(t *task) {
p.mutex.Lock()
defer p.mutex.Unlock()
p.currentTasks = append([]*task{t}, p.currentTasks...)
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()
}