func NewManager(_myId string, _members []string) *Manager { self := &Manager{ myId: _myId, members: _members, votes: make(Votes), threshold: util.ComputeQuorumThreshold(len(_members)), C: make(chan bool, 100), } self.state = fsm.NewFSM( "idle", fsm.Events{ {Name: "quorum", Src: []string{"idle", "elected"}, Dst: "electing"}, {Name: "complete", Src: []string{"electing"}, Dst: "elected"}, {Name: "next", Src: []string{"elected"}, Dst: "idle"}, }, fsm.Callbacks{ "electing": func(e *fsm.Event) { self.onElecting() }, "enter_elected": func(e *fsm.Event) { self.onElected(e.Args[0].(string), e.Args[1].(int64)) }, "leave_elected": func(e *fsm.Event) { self.view++ }, }, ) fmt.Printf("EM: Initializing with %d members and a quorum threshold %d\n", len(self.members), self.threshold) return self }
func NewController(_id string, _peers IdentityMap, _connMgr *ConnectionManager) *Controller { var members []string for _, peer := range _peers { members = append(members, peer.Id) } self := &Controller{ peers: _peers, connMgr: _connMgr, myId: _id, activePeers: make(map[string]*Peer), quorumThreshold: util.ComputeQuorumThreshold(len(_peers)) - 1, // We don't include ourselves timer: time.NewTimer(0), pulse: time.NewTicker(1), electionManager: election.NewManager(_id, members), minTmo: 500, maxTmo: 1000, } <-self.timer.C // drain the initial event self.pulse.Stop() <-self.pulse.C // drain the initial event self.state = fsm.NewFSM( "convening", fsm.Events{ {Name: "quorum", Src: []string{"convening"}, Dst: "initializing"}, {Name: "quorum-lost", Src: []string{"initializing", "electing", "electing-restart", "following", "leading"}, Dst: "convening"}, {Name: "elected-self", Src: []string{"initializing", "electing"}, Dst: "leading"}, {Name: "elected-other", Src: []string{"initializing", "electing"}, Dst: "following"}, {Name: "timeout", Src: []string{"initializing", "following", "electing"}, Dst: "electing"}, {Name: "election", Src: []string{"following", "leading"}, Dst: "electing"}, {Name: "heartbeat", Src: []string{"following"}, Dst: "following"}, }, fsm.Callbacks{ "convening": func(e *fsm.Event) { self.onConvening() }, "enter_initializing": func(e *fsm.Event) { self.onInitializing() }, "leave_initializing": func(e *fsm.Event) { self.timer.Stop() }, "enter_following": func(e *fsm.Event) { self.onEnterFollowing() }, "leave_following": func(e *fsm.Event) { self.onLeaveFollowing() }, "enter_electing": func(e *fsm.Event) { self.onElecting() }, "leave_electing": func(e *fsm.Event) { self.timer.Stop() }, "enter_leading": func(e *fsm.Event) { self.onEnterLeading() }, "leave_leading": func(e *fsm.Event) { self.onLeaveLeading() }, "heartbeat": func(e *fsm.Event) { self.onHeartBeat(e.Args[0].(string), e.Args[1].(int64)) }, "before_timeout": func(e *fsm.Event) { self.onTimeout() }, }, ) return self }