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 }
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 }
// 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 }
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 }
// 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 }
// 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 }