github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/plan_apply_pool.go (about)

     1  package nomad
     2  
     3  import (
     4  	"github.com/hashicorp/nomad/nomad/state"
     5  	"github.com/hashicorp/nomad/nomad/structs"
     6  )
     7  
     8  const (
     9  	// workerPoolBufferSize is the size of the buffers used to push
    10  	// request to the workers and to collect the responses. It should
    11  	// be large enough just to keep things busy
    12  	workerPoolBufferSize = 64
    13  )
    14  
    15  // EvaluatePool is used to have a pool of workers that are evaluating
    16  // if a plan is valid. It can be used to parallelize the evaluation
    17  // of a plan.
    18  type EvaluatePool struct {
    19  	workers    int
    20  	workerStop []chan struct{}
    21  	req        chan evaluateRequest
    22  	res        chan evaluateResult
    23  }
    24  
    25  type evaluateRequest struct {
    26  	snap   *state.StateSnapshot
    27  	plan   *structs.Plan
    28  	nodeID string
    29  }
    30  
    31  type evaluateResult struct {
    32  	nodeID string
    33  	fit    bool
    34  	reason string
    35  	err    error
    36  }
    37  
    38  // NewEvaluatePool returns a pool of the given size.
    39  func NewEvaluatePool(workers, bufSize int) *EvaluatePool {
    40  	p := &EvaluatePool{
    41  		workers:    workers,
    42  		workerStop: make([]chan struct{}, workers),
    43  		req:        make(chan evaluateRequest, bufSize),
    44  		res:        make(chan evaluateResult, bufSize),
    45  	}
    46  	for i := 0; i < workers; i++ {
    47  		stopCh := make(chan struct{})
    48  		p.workerStop[i] = stopCh
    49  		go p.run(stopCh)
    50  	}
    51  	return p
    52  }
    53  
    54  // Size returns the current size
    55  func (p *EvaluatePool) Size() int {
    56  	return p.workers
    57  }
    58  
    59  // SetSize is used to resize the worker pool
    60  func (p *EvaluatePool) SetSize(size int) {
    61  	// Protect against a negative size
    62  	if size < 0 {
    63  		size = 0
    64  	}
    65  
    66  	// Handle an upwards resize
    67  	if size >= p.workers {
    68  		for i := p.workers; i < size; i++ {
    69  			stopCh := make(chan struct{})
    70  			p.workerStop = append(p.workerStop, stopCh)
    71  			go p.run(stopCh)
    72  		}
    73  		p.workers = size
    74  		return
    75  	}
    76  
    77  	// Handle a downwards resize
    78  	for i := p.workers; i > size; i-- {
    79  		close(p.workerStop[i-1])
    80  		p.workerStop[i-1] = nil
    81  	}
    82  	p.workerStop = p.workerStop[:size]
    83  	p.workers = size
    84  }
    85  
    86  // RequestCh is used to push requests
    87  func (p *EvaluatePool) RequestCh() chan<- evaluateRequest {
    88  	return p.req
    89  }
    90  
    91  // ResultCh is used to read the results as they are ready
    92  func (p *EvaluatePool) ResultCh() <-chan evaluateResult {
    93  	return p.res
    94  }
    95  
    96  // Shutdown is used to shutdown the pool
    97  func (p *EvaluatePool) Shutdown() {
    98  	p.SetSize(0)
    99  }
   100  
   101  // run is a long running go routine per worker
   102  func (p *EvaluatePool) run(stopCh chan struct{}) {
   103  	for {
   104  		select {
   105  		case req := <-p.req:
   106  			fit, reason, err := evaluateNodePlan(req.snap, req.plan, req.nodeID)
   107  			p.res <- evaluateResult{req.nodeID, fit, reason, err}
   108  
   109  		case <-stopCh:
   110  			return
   111  		}
   112  	}
   113  }