github.com/taylorchu/nomad@v0.5.3-rc1.0.20170407200202-db11e7dd7b55/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  	err    error
    35  }
    36  
    37  // NewEvaluatePool returns a pool of the given size.
    38  func NewEvaluatePool(workers, bufSize int) *EvaluatePool {
    39  	p := &EvaluatePool{
    40  		workers:    workers,
    41  		workerStop: make([]chan struct{}, workers),
    42  		req:        make(chan evaluateRequest, bufSize),
    43  		res:        make(chan evaluateResult, bufSize),
    44  	}
    45  	for i := 0; i < workers; i++ {
    46  		stopCh := make(chan struct{})
    47  		p.workerStop[i] = stopCh
    48  		go p.run(stopCh)
    49  	}
    50  	return p
    51  }
    52  
    53  // Size returns the current size
    54  func (p *EvaluatePool) Size() int {
    55  	return p.workers
    56  }
    57  
    58  // SetSize is used to resize the worker pool
    59  func (p *EvaluatePool) SetSize(size int) {
    60  	// Protect against a negative size
    61  	if size < 0 {
    62  		size = 0
    63  	}
    64  
    65  	// Handle an upwards resize
    66  	if size >= p.workers {
    67  		for i := p.workers; i < size; i++ {
    68  			stopCh := make(chan struct{})
    69  			p.workerStop = append(p.workerStop, stopCh)
    70  			go p.run(stopCh)
    71  		}
    72  		p.workers = size
    73  		return
    74  	}
    75  
    76  	// Handle a downwards resize
    77  	for i := p.workers; i > size; i-- {
    78  		close(p.workerStop[i-1])
    79  		p.workerStop[i-1] = nil
    80  	}
    81  	p.workerStop = p.workerStop[:size]
    82  	p.workers = size
    83  }
    84  
    85  // RequestCh is used to push requests
    86  func (p *EvaluatePool) RequestCh() chan<- evaluateRequest {
    87  	return p.req
    88  }
    89  
    90  // ResultCh is used to read the results as they are ready
    91  func (p *EvaluatePool) ResultCh() <-chan evaluateResult {
    92  	return p.res
    93  }
    94  
    95  // Shutdown is used to shutdown the pool
    96  func (p *EvaluatePool) Shutdown() {
    97  	p.SetSize(0)
    98  }
    99  
   100  // run is a long running go routine per worker
   101  func (p *EvaluatePool) run(stopCh chan struct{}) {
   102  	for {
   103  		select {
   104  		case req := <-p.req:
   105  			fit, err := evaluateNodePlan(req.snap, req.plan, req.nodeID)
   106  			p.res <- evaluateResult{req.nodeID, fit, err}
   107  
   108  		case <-stopCh:
   109  			return
   110  		}
   111  	}
   112  }