Esempio n. 1
0
// ConsensusUpdate implements paxos.Watcher interface.
func (this *Election) ConsensusUpdate(uid string, index int64, value []byte) {
	round := this.ElectionRoundFromPaxosUID(uid)
	if round <= this.CurrentRound() {
		return
	}
	winner := string(value)

	lock, errLock := this.ctlr.LockAll()
	if errLock != nil {
		return
	}
	defer lock.Unlock()

	change := thispb.ElectionChange{}
	change.ElectionRound = proto.Int64(round)
	change.ElectionWinner = proto.String(winner)
	if err := this.doUpdateElection(&change); err != nil {
		this.Fatalf("could not update new election round status: %v", err)
	}

	if this.InCommittee() {
		change := thispb.CommitteeChange{}
		change.NewElectionRound = proto.Int64(round)
		change.NewElectionWinner = proto.String(winner)
		if err := this.doUpdateCommittee(&change); err != nil {
			this.Fatalf("could not update committee with new election status: %v",
				err)
		}
	}
}
Esempio n. 2
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. 3
0
func (this *Election) doUpdateElection(change *thispb.ElectionChange) error {
	if !this.wal.IsRecovering() {
		walRecord := thispb.WALRecord{}
		walRecord.ElectionChange = change
		_, errQueue := wal.QueueChangeProto(this.wal, this.uid, &walRecord)
		if errQueue != nil {
			this.Errorf("could not write election change wal record: %v", errQueue)
			return errQueue
		}
	}

	atomic.StoreInt64(&this.currentRound, change.GetElectionRound())
	this.currentWinner = change.GetElectionWinner()
	return nil
}
Esempio n. 4
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
}