github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/lease/check.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package lease
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  )
     9  
    10  // token implements lease.Token.
    11  type token struct {
    12  	leaseName  string
    13  	holderName string
    14  	secretary  Secretary
    15  	checks     chan<- check
    16  	abort      <-chan struct{}
    17  }
    18  
    19  // Check is part of the lease.Token interface.
    20  func (t token) Check(trapdoorKey interface{}) error {
    21  
    22  	// This validation, which could be done at Token creation time, is deferred
    23  	// until this point for historical reasons. In particular, this code was
    24  	// extracted from a *leadership* implementation which has a LeadershipCheck
    25  	// method returning a token; if it returned an error as well it would seem
    26  	// to imply that the method implemented a check itself, rather than a check
    27  	// factory.
    28  	//
    29  	// Fixing that would be great but seems out of scope.
    30  	if err := t.secretary.CheckLease(t.leaseName); err != nil {
    31  		return errors.Annotatef(err, "cannot check lease %q", t.leaseName)
    32  	}
    33  	if err := t.secretary.CheckHolder(t.holderName); err != nil {
    34  		return errors.Annotatef(err, "cannot check holder %q", t.holderName)
    35  	}
    36  	return check{
    37  		leaseName:   t.leaseName,
    38  		holderName:  t.holderName,
    39  		trapdoorKey: trapdoorKey,
    40  		response:    make(chan error),
    41  		abort:       t.abort,
    42  	}.invoke(t.checks)
    43  }
    44  
    45  // check is used to deliver lease-check requests to a manager's loop
    46  // goroutine on behalf of a token (as returned by LeadershipCheck).
    47  type check struct {
    48  	leaseName   string
    49  	holderName  string
    50  	trapdoorKey interface{}
    51  	response    chan error
    52  	abort       <-chan struct{}
    53  }
    54  
    55  // invoke sends the check on the supplied channel and waits for an error
    56  // response.
    57  func (c check) invoke(ch chan<- check) error {
    58  	for {
    59  		select {
    60  		case <-c.abort:
    61  			return errStopped
    62  		case ch <- c:
    63  			ch = nil
    64  		case err := <-c.response:
    65  			return errors.Trace(err)
    66  		}
    67  	}
    68  }
    69  
    70  // respond notifies the originating invoke of completion status.
    71  func (c check) respond(err error) {
    72  	select {
    73  	case <-c.abort:
    74  	case c.response <- err:
    75  	}
    76  }