Exemplo n.º 1
0
// RefreshLeader queries committee members for the latest election information.
func (this *Election) RefreshLeader(timeout time.Duration) (
	string, int64, error) {

	lock := this.ctlr.ReadLock("config")
	committee := append([]string{}, this.committee...)
	lock.Unlock()

	request := thispb.StatusRequest{}
	message := thispb.ElectionMessage{}
	message.StatusRequest = &request

	reqHeader := this.msn.NewRequest(this.namespace, this.uid, "Election.Status",
		timeout)
	defer this.msn.CloseMessage(reqHeader)

	count, errSend := msg.SendAllProto(this.msn, committee, reqHeader, &message)
	if errSend != nil && count < this.MajoritySize() {
		this.Errorf("could not send status request to committee: %v", errSend)
		return "", -1, errSend
	}

	// Wait for majority number of status responses and pick the winner for the
	// largest election round. It may also happen that no election round exists
	// because this instance is just created.

	maxElectionRound := int64(-1)
	maxElectionWinner := ""
	remoteSet := make(map[string]struct{})

	for ii := 0; ii < count && len(remoteSet) < this.MajoritySize(); ii++ {
		message := thispb.ElectionMessage{}
		resHeader, errRecv := msg.ReceiveProto(this.msn, reqHeader, &message)
		if errRecv != nil {
			this.Warningf("could not receive any more status responses for %s: %v",
				reqHeader, errRecv)
			break
		}

		memberID := resHeader.GetMessengerId()
		if _, ok := remoteSet[memberID]; ok {
			this.Warningf("duplicate status response from %s (ignored)", memberID)
			continue
		}

		// TODO Check the response header for errors.

		if message.StatusResponse == nil {
			this.Warningf("status response data is empty from %s (ignored)",
				memberID)
			continue
		}

		response := message.GetStatusResponse()
		if response.ElectionRound != nil {
			round := response.GetElectionRound()
			if round > maxElectionRound {
				maxElectionRound = round
				maxElectionWinner = response.GetElectionWinner()
			}
		}
		remoteSet[memberID] = struct{}{}
	}

	if len(remoteSet) < this.MajoritySize() {
		this.Errorf("could not get majority responses %v in finding leader",
			remoteSet)
		return "", -1, errs.ErrRetry
	}

	if maxElectionRound > this.CurrentRound() {
		change := thispb.ElectionChange{}
		change.ElectionRound = proto.Int64(maxElectionRound)
		change.ElectionWinner = proto.String(maxElectionWinner)
		if err := this.UpdateElection(&change); err != nil {
			this.Errorf("could not update election status: %v", err)
			return maxElectionWinner, maxElectionRound, err
		}
	}

	this.Infof("found %s as the last known leader in round %d",
		maxElectionWinner, maxElectionRound)
	return maxElectionWinner, maxElectionRound, nil
}