// committed instance will // - reject all request messages (pre-accept, accept), // - handle prepare to help it find committed, // - ignore others func (i *Instance) committedProcess(m message.Message) (action uint8, msg message.Message) { defer i.checkStatus(committed) if !i.isAtStatus(committed) { panic("") } switch content := m.Content().(type) { case *message.PreAccept: return noAction, nil case *message.Accept: return noAction, nil case *message.Timeout: // here we ignore the timeout event instead of panic, // because sometimes timeout event // comes right after the instance becomes committed return noAction, nil case *message.Prepare: return i.handlePrepare(content) case *message.PreAcceptReply, *message.PreAcceptOk, *message.AcceptReply, *message.PrepareReply, *message.Commit: return noAction, nil // ignore stale replies default: panic("") } }
// preparing instance could only acts as a sender. // It handles most kinds of messages (in some conditions with larger ballot) and // ignores all replies except prepare reply. func (i *Instance) preparingProcess(m message.Message) (action uint8, msg message.Message) { defer i.checkStatus(preparing, preAccepted, accepted, committed, nilStatus) if !i.isAtStatus(preparing) || i.recoveryInfo == nil { panic("") } switch content := m.Content().(type) { case *message.PreAccept: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handlePreAccept(content) case *message.Accept: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handleAccept(content) case *message.Commit: return i.handleCommit(content) case *message.Timeout: return i.handleTimeout(content) case *message.Prepare: // the instance itself is the first one to have ballot of this // magnitude. It can't receive others having the same if content.Ballot.Compare(i.ballot) == 0 { panic("") } if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.revertAndHandlePrepare(content) case *message.PrepareReply: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handlePrepareReply(content) case *message.PreAcceptReply: if i.recoveryInfo.formerStatus < preAccepted { panic("") } return noAction, nil case *message.PreAcceptOk: if i.recoveryInfo.formerStatus < preAccepted { panic("") } return noAction, nil case *message.AcceptReply: if i.recoveryInfo.formerStatus < accepted { panic("") } // ignore delayed replies return noAction, nil default: panic("") } }
// preaccepted instance // - handles preaccept-ok/-reply, preaccept, accept, commit, and prepare. func (i *Instance) preAcceptedProcess(m message.Message) (action uint8, msg message.Message) { defer i.checkStatus(preAccepted, accepted, committed, preparing) if !i.isAtStatus(preAccepted) { panic("") } switch content := m.Content().(type) { case *message.PreAccept: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handlePreAccept(content) case *message.Accept: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handleAccept(content) case *message.Commit: return i.handleCommit(content) case *message.Timeout: return i.handleTimeout(content) case *message.Prepare: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handlePrepare(content) case *message.PreAcceptReply: if content.Ballot.Compare(i.ballot) < 0 { // ignore stale PreAcceptReply return noAction, nil } return i.handlePreAcceptReply(content) case *message.PreAcceptOk: if !i.ballot.IsInitialBallot() { return noAction, nil // ignore stale reply } return i.handlePreAcceptOk(content) case *message.AcceptReply: panic("") case *message.PrepareReply: if i.ballot.IsInitialBallot() { panic("") } return noAction, nil default: panic("") } }
// NilStatus exists for: // - the instance is newly created when // - - received a proposal first time and only once. (sender) // - - received pre-accept, accept, commit, prepare the first time. (receiver) // - - required by commit dependencies and transitioning to preparing. (sender) // - the instance is not newly created when // - - after reverted back from `preparing`(sender -> receiver) // - - received prepare and waiting for further message. (receiver) func (i *Instance) nilStatusProcess(m message.Message) (action uint8, msg message.Message) { defer i.checkStatus(nilStatus, preAccepted, accepted, committed, preparing) if !i.isAtStatus(nilStatus) { panic("") } switch content := m.Content().(type) { case *message.Propose: return i.handlePropose(content) case *message.PreAccept: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handlePreAccept(content) case *message.Accept: if content.Ballot.Compare(i.ballot) < 0 { // [*] this could happens when the instance revert from preparing return noAction, nil } return i.handleAccept(content) case *message.Commit: return i.handleCommit(content) case *message.Timeout: return i.handleTimeout(content) case *message.Prepare: if content.Ballot.Compare(i.ballot) < 0 { return noAction, nil } return i.handlePrepare(content) case *message.PrepareReply: if i.isNewBorn() || i.ballot.GetNumber() == 0 { panic("Never send prepare before but receive prepare reply") } return noAction, nil case *message.PreAcceptReply, *message.AcceptReply, *message.PreAcceptOk: panic("") default: panic("") } }