2016-02-20 21:07:09 +00:00
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/hashicorp/nomad/nomad/state"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// workerPoolBufferSize is the size of the buffers used to push
|
|
|
|
// request to the workers and to collect the responses. It should
|
|
|
|
// be large enough just to keep things busy
|
|
|
|
workerPoolBufferSize = 64
|
|
|
|
)
|
|
|
|
|
|
|
|
// EvaluatePool is used to have a pool of workers that are evaluating
|
|
|
|
// if a plan is valid. It can be used to parallelize the evaluation
|
|
|
|
// of a plan.
|
|
|
|
type EvaluatePool struct {
|
2016-02-20 21:23:34 +00:00
|
|
|
workers int
|
|
|
|
workerStop []chan struct{}
|
|
|
|
req chan evaluateRequest
|
|
|
|
res chan evaluateResult
|
2016-02-20 21:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type evaluateRequest struct {
|
|
|
|
snap *state.StateSnapshot
|
|
|
|
plan *structs.Plan
|
|
|
|
nodeID string
|
|
|
|
}
|
|
|
|
|
|
|
|
type evaluateResult struct {
|
|
|
|
nodeID string
|
|
|
|
fit bool
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewEvaluatePool returns a pool of the given size.
|
|
|
|
func NewEvaluatePool(workers, bufSize int) *EvaluatePool {
|
|
|
|
p := &EvaluatePool{
|
2016-02-20 21:23:34 +00:00
|
|
|
workers: workers,
|
|
|
|
workerStop: make([]chan struct{}, workers),
|
|
|
|
req: make(chan evaluateRequest, bufSize),
|
|
|
|
res: make(chan evaluateResult, bufSize),
|
2016-02-20 21:07:09 +00:00
|
|
|
}
|
|
|
|
for i := 0; i < workers; i++ {
|
2016-02-20 21:23:34 +00:00
|
|
|
stopCh := make(chan struct{})
|
|
|
|
p.workerStop[i] = stopCh
|
|
|
|
go p.run(stopCh)
|
2016-02-20 21:07:09 +00:00
|
|
|
}
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
2016-02-20 21:25:49 +00:00
|
|
|
// Size returns the current size
|
|
|
|
func (p *EvaluatePool) Size() int {
|
|
|
|
return p.workers
|
|
|
|
}
|
|
|
|
|
2016-02-20 21:23:34 +00:00
|
|
|
// SetSize is used to resize the worker pool
|
|
|
|
func (p *EvaluatePool) SetSize(size int) {
|
2016-02-20 23:56:08 +00:00
|
|
|
// Protect against a negative size
|
|
|
|
if size < 0 {
|
|
|
|
size = 0
|
|
|
|
}
|
|
|
|
|
2016-02-20 21:23:34 +00:00
|
|
|
// Handle an upwards resize
|
|
|
|
if size >= p.workers {
|
|
|
|
for i := p.workers; i < size; i++ {
|
|
|
|
stopCh := make(chan struct{})
|
|
|
|
p.workerStop = append(p.workerStop, stopCh)
|
|
|
|
go p.run(stopCh)
|
|
|
|
}
|
|
|
|
p.workers = size
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle a downwards resize
|
|
|
|
for i := p.workers; i > size; i-- {
|
|
|
|
close(p.workerStop[i-1])
|
|
|
|
p.workerStop[i-1] = nil
|
|
|
|
}
|
|
|
|
p.workerStop = p.workerStop[:size]
|
|
|
|
p.workers = size
|
|
|
|
}
|
|
|
|
|
2016-02-20 21:07:09 +00:00
|
|
|
// RequestCh is used to push requests
|
|
|
|
func (p *EvaluatePool) RequestCh() chan<- evaluateRequest {
|
|
|
|
return p.req
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResultCh is used to read the results as they are ready
|
|
|
|
func (p *EvaluatePool) ResultCh() <-chan evaluateResult {
|
|
|
|
return p.res
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown is used to shutdown the pool
|
|
|
|
func (p *EvaluatePool) Shutdown() {
|
2016-02-20 21:23:34 +00:00
|
|
|
p.SetSize(0)
|
2016-02-20 21:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// run is a long running go routine per worker
|
2016-02-20 21:23:34 +00:00
|
|
|
func (p *EvaluatePool) run(stopCh chan struct{}) {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case req := <-p.req:
|
|
|
|
fit, err := evaluateNodePlan(req.snap, req.plan, req.nodeID)
|
|
|
|
p.res <- evaluateResult{req.nodeID, fit, err}
|
|
|
|
|
|
|
|
case <-stopCh:
|
|
|
|
return
|
|
|
|
}
|
2016-02-20 21:07:09 +00:00
|
|
|
}
|
|
|
|
}
|