Beispiel #1
0
func (this *Election) doUpdateConfig(change *thispb.Configuration) error {
	walRecord := thispb.WALRecord{}
	walRecord.ConfigChange = change
	_, errSync := wal.SyncChangeProto(this.wal, this.uid, &walRecord)
	if errSync != nil {
		this.Errorf("could not append config change wal record: %v", errSync)
		return errSync
	}

	this.doRestoreConfig(change)
	return nil
}
Beispiel #2
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
}
Beispiel #3
0
// TakeCheckpoint logs a checkpoint record to the wal.
func (this *Election) TakeCheckpoint() error {
	lock := this.ctlr.ReadLockAll()
	defer lock.Unlock()

	if this.MajoritySize() <= 0 {
		this.Errorf("election instance is not yet configured")
		return errs.ErrInvalid
	}

	checkpoint := thispb.Checkpoint{}

	config := thispb.Configuration{}
	this.doSaveConfig(&config)
	checkpoint.Configuration = &config

	if this.InCommittee() {
		state := thispb.CommitteeState{}
		this.doSaveCommittee(&state)
		checkpoint.CommitteeState = &state
	}

	state := thispb.ElectionState{}
	this.doSaveElection(&state)
	checkpoint.ElectionState = &state

	walRecord := thispb.WALRecord{}
	walRecord.Checkpoint = &checkpoint
	errAppend := wal.AppendCheckpointProto(this.wal, this.uid, &walRecord)
	if errAppend != nil {
		this.Errorf("could not append checkpoint record: %v", errAppend)
		return errAppend
	}

	// Checkpoint recent paxos instances' state.
	if this.InCommittee() {
		state := checkpoint.CommitteeState
		for _, round := range state.ElectionRoundList {
			if paxos, ok := this.classicPaxosMap[round]; ok {
				if err := paxos.TakeCheckpoint(); err != nil {
					this.Errorf("could not take checkpoint of paxos instance for "+
						"round %d: %v", err)
					return err
				}
			}
		}
	}
	return nil
}
Beispiel #4
0
func (this *Election) doUpdateCommittee(change *thispb.CommitteeChange) error {
	if !this.wal.IsRecovering() {
		walRecord := thispb.WALRecord{}
		walRecord.CommitteeChange = change
		_, errSync := wal.SyncChangeProto(this.wal, this.uid, &walRecord)
		if errSync != nil {
			this.Errorf("could not write committee change wal record: %v", errSync)
			return errSync
		}
	}

	round := change.GetNewElectionRound()
	winner := change.GetNewElectionWinner()
	this.electionHistoryMap[round] = winner
	return nil
}
Beispiel #5
0
// RecoverCheckpoint restores last known election state from a checkpoint
// record.
func (this *Election) RecoverCheckpoint(uid string, data []byte) error {
	if uid != this.uid {
		// Check if uid belongs to one of our paxos instances.
		if this.IsPaxosUID(uid) {
			paxos, errGet := this.doGetPaxosInstance(uid)
			if errGet != nil {
				this.Errorf("could not find paxos instance for %s: %v", uid, errGet)
				return errGet
			}
			return paxos.RecoverCheckpoint(uid, data)
		}

		this.Errorf("checkpoint record doesn't belong to this instance")
		return errs.ErrInvalid
	}

	walRecord := thispb.WALRecord{}
	if err := proto.Unmarshal(data, &walRecord); err != nil {
		this.Errorf("could not parse checkpoint wal record: %v", err)
		return err
	}

	if walRecord.Checkpoint == nil {
		this.Errorf("checkpoint record has no data")
		return errs.ErrCorrupt
	}
	checkpoint := walRecord.GetCheckpoint()

	this.doRestoreConfig(checkpoint.GetConfiguration())

	if this.InCommittee() {
		if checkpoint.CommitteeState == nil {
			this.Errorf("committee member checkpoint has no election state")
			return errs.ErrCorrupt
		}
		this.doRestoreCommittee(checkpoint.GetCommitteeState())
	}

	this.doRestoreElection(checkpoint.GetElectionState())
	return nil
}
Beispiel #6
0
// RecoverChange updates election state from a change record.
func (this *Election) RecoverChange(lsn wal.LSN, uid string,
	data []byte) error {

	if uid != this.uid {
		// Check if uid belongs to one of our paxos instances.
		if this.IsPaxosUID(uid) {
			paxos, errGet := this.doGetPaxosInstance(uid)
			if errGet != nil {
				this.Errorf("could not find paxos instance for %s: %v", uid, errGet)
				return errGet
			}
			return paxos.RecoverChange(lsn, uid, data)
		}

		this.Errorf("change record doesn't belong to this instance")
		return errs.ErrInvalid
	}

	walRecord := thispb.WALRecord{}
	if err := proto.Unmarshal(data, &walRecord); err != nil {
		this.Errorf("could not parse change record: %v", err)
		return err
	}

	switch {
	case walRecord.ConfigChange != nil:
		this.doRestoreConfig(walRecord.GetConfigChange())
		return nil

	case walRecord.CommitteeChange != nil:
		if !this.InCommittee() {
			this.Errorf("found committee change when instance is not a member")
			return errs.ErrCorrupt
		}
		return this.doUpdateCommittee(walRecord.GetCommitteeChange())

	case walRecord.ElectionChange != nil:
		return this.doUpdateElection(walRecord.GetElectionChange())

	default:
		this.Errorf("invalid/unknown change record %s", walRecord)
		return errs.ErrInvalid
	}
	return nil
}