Esempio n. 1
0
File: paxos.go Progetto: bvk/ascent
func (this *Paxos) doUpdateConfig(change *thispb.Configuration) error {
	if !this.wal.IsRecovering() {
		record := thispb.WALRecord{}
		record.ConfigChange = change
		_, errQueue := wal.QueueChangeProto(this.wal, this.uid, &record)
		if errQueue != nil {
			this.Errorf("could not append config change wal record: %v", errQueue)
			return errQueue
		}
	}

	this.doRestoreConfig(change)
	return nil
}
Esempio n. 2
0
File: paxos.go Progetto: bvk/ascent
func (this *Paxos) doUpdateLearner(change *thispb.LearnerChange) error {
	if this.chosenValue != nil {
		return nil
	}

	if !this.wal.IsRecovering() {
		walRecord := thispb.WALRecord{}
		walRecord.LearnerChange = change
		_, errQueue := wal.QueueChangeProto(this.wal, this.uid, &walRecord)
		if errQueue != nil {
			this.Errorf("could not write learner change record: %v", errQueue)
			return errQueue
		}
	}

	if change.ChosenValue != nil {
		this.chosenValue = change.GetChosenValue()
		this.Infof("consensus result learned from proposer is %s",
			this.chosenValue)

		if this.watch != nil {
			this.watch.ConsensusUpdate(this.uid, -1, this.chosenValue)
		}
		return nil
	}

	acceptor := change.GetVotedAcceptor()
	for index := range change.VotedBallotList {
		ballot := change.VotedBallotList[index]
		value := change.VotedValueList[index]
		this.ballotValueMap[ballot] = value
		acceptorSet, found := this.ballotAcceptorsMap[ballot]
		if !found {
			acceptorSet = make(map[string]struct{})
			this.ballotAcceptorsMap[ballot] = acceptorSet
		}
		acceptorSet[acceptor] = struct{}{}

		if len(acceptorSet) >= this.MajoritySize() {
			this.chosenValue = value
			this.Infof("consensus result learned through votes is %s", value)

			if this.watch != nil {
				this.watch.ConsensusUpdate(this.uid, -1, this.chosenValue)
			}
		}
	}
	return nil
}
Esempio n. 3
0
File: paxos.go Progetto: bvk/ascent
// RecoverCheckpoint recovers state from a checkpoint record.
func (this *Paxos) RecoverCheckpoint(uid string, data []byte) error {
	if uid != this.uid {
		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.ErrInvalid
	}
	checkpoint := walRecord.GetCheckpoint()

	config := checkpoint.GetConfiguration()
	this.doRestoreConfig(config)

	if this.IsProposer() {
		if checkpoint.ProposerState == nil {
			this.Errorf("checkpoint record has no proposer state")
			return errs.ErrInvalid
		}
		this.doRestoreProposer(checkpoint.GetProposerState())
	}

	if this.IsAcceptor() {
		if checkpoint.AcceptorState == nil {
			this.Errorf("checkpoint record has no acceptor state")
			return errs.ErrInvalid
		}
		this.doRestoreAcceptor(checkpoint.GetAcceptorState())
	}

	if this.IsLearner() {
		if checkpoint.LearnerState == nil {
			this.Errorf("checkpoint record has no learner state")
		}
		this.doRestoreLearner(checkpoint.GetLearnerState())
	}
	return nil
}
Esempio n. 4
0
File: paxos.go Progetto: bvk/ascent
func (this *Paxos) doUpdateProposer(change *thispb.ProposerChange) error {
	if !this.wal.IsRecovering() {
		walRecord := thispb.WALRecord{}
		walRecord.ProposerChange = change
		_, errSync := wal.SyncChangeProto(this.wal, this.uid, &walRecord)
		if errSync != nil {
			this.Errorf("could not write proposer change record: %v", errSync)
			return errSync
		}
	}

	if change.ProposalBallot != nil {
		ballot := change.GetProposalBallot()
		if this.proposalBallot < ballot {
			this.proposalBallot = ballot
		}
	}
	return nil
}
Esempio n. 5
0
File: paxos.go Progetto: bvk/ascent
// TakeCheckpoint saves current state into the wal as a checkpoint record.
func (this *Paxos) TakeCheckpoint() error {
	lock := this.ctlr.ReadLockAll()
	defer lock.Unlock()

	if !this.IsConfigured() {
		this.Errorf("classic paxos instance is not yet configured")
		return errs.ErrInvalid
	}

	checkpoint := thispb.Checkpoint{}

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

	if this.IsProposer() {
		state := thispb.ProposerState{}
		this.doSaveProposer(&state)
		checkpoint.ProposerState = &state
	}

	if this.IsAcceptor() {
		state := thispb.AcceptorState{}
		this.doSaveAcceptor(&state)
		checkpoint.AcceptorState = &state
	}

	if this.IsLearner() {
		state := thispb.LearnerState{}
		this.doSaveLearner(&state)
		checkpoint.LearnerState = &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
	}
	return nil
}
Esempio n. 6
0
File: paxos.go Progetto: bvk/ascent
func (this *Paxos) doUpdateAcceptor(change *thispb.AcceptorChange) error {
	if !this.wal.IsRecovering() {
		walRecord := thispb.WALRecord{}
		walRecord.AcceptorChange = change
		_, errSync := wal.SyncChangeProto(this.wal, this.uid, &walRecord)
		if errSync != nil {
			this.Errorf("could not write acceptor change record: %v", errSync)
			return errSync
		}
	}

	if change.PromisedBallot != nil {
		this.promisedBallot = change.GetPromisedBallot()
	}

	if change.VotedBallot != nil {
		ballot := change.GetVotedBallot()
		value := change.GetVotedValue()
		this.votedBallot = ballot
		this.votedValue = value
		this.votedValueMap[ballot] = value
	}

	if change.AckedLearner != nil {
		learner := change.GetAckedLearner()
		if change.GetAckedChosenValue() {
			this.doneLearnerSet[learner] = struct{}{}
		} else {
			for _, ballot := range change.GetAckedBallotList() {
				learnerSet, found := this.learnerAckMap[ballot]
				if !found {
					learnerSet = make(map[string]struct{})
					this.learnerAckMap[ballot] = learnerSet
				}
				learnerSet[learner] = struct{}{}
			}
		}
	}
	return nil
}
Esempio n. 7
0
File: paxos.go Progetto: bvk/ascent
// RecoverChange recovers an update from a change record.
func (this *Paxos) RecoverChange(lsn wal.LSN, uid string, data []byte) error {
	if lsn == nil {
		// We reached end of wal recovery, figure out the current state and resume
		// any inflight operations.
		_ = this.Refresh()
		return nil
	}

	if uid != this.uid {
		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:
		return this.doUpdateConfig(walRecord.GetConfigChange())

	case walRecord.ProposerChange != nil:
		return this.doUpdateProposer(walRecord.GetProposerChange())

	case walRecord.AcceptorChange != nil:
		return this.doUpdateAcceptor(walRecord.GetAcceptorChange())

	case walRecord.LearnerChange != nil:
		return this.doUpdateLearner(walRecord.GetLearnerChange())

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