github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/state/leadership/block.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package leadership
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names"
     9  )
    10  
    11  // block is used to deliver leaderlessness-notification requests to a manager's
    12  // loop goroutine on behalf of BlockUntilLeadershipReleased.
    13  type block struct {
    14  	serviceName string
    15  	unblock     chan struct{}
    16  	abort       <-chan struct{}
    17  }
    18  
    19  // validate returns an error if any fields are invalid or missing.
    20  func (b block) validate() error {
    21  	if !names.IsValidService(b.serviceName) {
    22  		return errors.Errorf("invalid service name %q", b.serviceName)
    23  	}
    24  	if b.unblock == nil {
    25  		return errors.New("missing unblock channel")
    26  	}
    27  	if b.abort == nil {
    28  		return errors.New("missing abort channel")
    29  	}
    30  	return nil
    31  }
    32  
    33  // invoke sends the block request on the supplied channel, and waits for the
    34  // unblock channel to be closed.
    35  func (b block) invoke(ch chan<- block) error {
    36  	if err := b.validate(); err != nil {
    37  		return errors.Annotatef(err, "cannot wait for leaderlessness")
    38  	}
    39  	for {
    40  		select {
    41  		case <-b.abort:
    42  			return errStopped
    43  		case ch <- b:
    44  			ch = nil
    45  		case <-b.unblock:
    46  			return nil
    47  		}
    48  	}
    49  }
    50  
    51  // blocks is used to keep track of leaderlessness-notification channels for
    52  // each service name.
    53  type blocks map[string][]chan struct{}
    54  
    55  // add records the block's unblock channel under the block's service name.
    56  func (b blocks) add(block block) {
    57  	b[block.serviceName] = append(b[block.serviceName], block.unblock)
    58  }
    59  
    60  // unblock closes all channels added under the supplied name and removes
    61  // them from blocks.
    62  func (b blocks) unblock(serviceName string) {
    63  	unblocks := b[serviceName]
    64  	delete(b, serviceName)
    65  	for _, unblock := range unblocks {
    66  		close(unblock)
    67  	}
    68  }