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 }