// ElectLeader performs a leader election for the next round. func (this *Election) ElectLeader(timeout time.Duration) ( string, int64, error) { lock := this.ctlr.ReadLockAll() target := this.msn.UID() if !this.InCommittee() { target = this.committee[rand.Intn(len(this.committee))] } lock.Unlock() request := thispb.ElectRequest{} request.ElectionRound = proto.Int64(this.CurrentRound() + 1) message := thispb.ElectionMessage{} message.ElectRequest = &request reqHeader := this.msn.NewRequest(this.namespace, this.uid, "Election.Elect", timeout) defer this.msn.CloseMessage(reqHeader) if err := msg.SendProto(this.msn, target, reqHeader, &message); err != nil { this.Errorf("could not send elect request to %s: %v", target, err) return "", -1, err } message.Reset() _, errRecv := msg.ReceiveProto(this.msn, reqHeader, &message) if errRecv != nil { this.Errorf("could not receive elect response from %s: %v", target, errRecv) return "", -1, errRecv } if message.ElectResponse == nil { this.Errorf("elect response from %s is empty", target) return "", -1, errs.ErrCorrupt } response := message.GetElectResponse() change := thispb.ElectionChange{} change.ElectionRound = response.ElectionRound change.ElectionWinner = response.ElectionWinner if err := this.UpdateElection(&change); err != nil { this.Errorf("could not update to new election round: %v", err) return "", -1, err } newRound := response.GetElectionRound() newLeader := response.GetElectionWinner() return newLeader, newRound, nil }
// Propose proposes given value for a consensus. // // value: The value to propose for consensus. // // timeout: Maximum time duration for the propose operation. // // Returns the chosen value on success. func (this *Paxos) Propose(value []byte, timeout time.Duration) ( []byte, error) { // If local instance is not a proposer, find a random proposer. proposer := this.msn.UID() if !this.IsProposer() { proposer = this.proposerList[rand.Intn(len(this.proposerList))] this.Infof("using %s as the proposer", proposer) } // Send the propose request. request := thispb.ProposeRequest{} request.ProposedValue = value message := thispb.PaxosMessage{} message.ProposeRequest = &request reqHeader := this.msn.NewRequest(this.namespace, this.uid, "ClassicPaxos.Propose", timeout) errSend := msg.SendProto(this.msn, proposer, reqHeader, &message) if errSend != nil { this.Errorf("could not send propose request to %s: %v", proposer, errSend) return nil, errSend } // Wait for the response. _, errRecv := msg.ReceiveProto(this.msn, reqHeader, &message) if errRecv != nil { this.Errorf("could not receive propose response from %s: %v", proposer, errRecv) return nil, errRecv } if message.ProposeResponse == nil { this.Errorf("propose response from %s is empty", proposer) return nil, errs.ErrCorrupt } response := message.GetProposeResponse() return response.GetChosenValue(), nil }