Esempio n. 1
0
// 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
}
Esempio n. 2
0
// ElectRPC implements the Election.Elect rpc.
func (this *Election) ElectRPC(reqHeader *msgpb.Header,
	request *thispb.ElectRequest) (status error) {

	if !this.InCommittee() {
		return errs.ErrInvalid
	}

	round := request.GetElectionRound()
	current := this.CurrentRound()
	if round != current+1 {
		this.Errorf("could not begin election round %d because current round "+
			"is only at %d", round, current)
		return errs.ErrStale
	}

	uid := this.PaxosUIDFromElectionRound(round)
	paxos, errGet := this.GetPaxosInstance(uid)
	if errGet != nil {
		this.Errorf("could not find paxos instance for uid %s: %v", uid, errGet)
		return errGet
	}

	this.Infof("starting new election for round %d using paxos instance %s",
		round, uid)

	clientID := reqHeader.GetMessengerId()
	proposedValue := []byte(clientID)
	chosenValue, errPropose := paxos.Propose(proposedValue,
		msg.RequestTimeout(reqHeader))
	if errPropose != nil {
		this.Errorf("could not propose %s as the leader for election round %d: %v",
			proposedValue, round, errPropose)
		return errPropose
	}
	winner := string(chosenValue)

	// Send the election result.
	response := thispb.ElectResponse{}
	response.ElectionRound = proto.Int64(round)
	response.ElectionWinner = proto.String(winner)
	message := thispb.ElectionMessage{}
	message.ElectResponse = &response
	if err := msg.SendResponseProto(this.msn, reqHeader, &message); err != nil {
		this.Errorf("could not send election response to %s: %v", clientID, err)
		return err
	}
	return nil
}