mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
raft: simplify auto-leave joint config on entry application logic
This commit simplifies the logic added in 37c7e4d to auto-leave joint
configurations. It does so by making the following adjustments to the
code:
- remove the `oldApplied <= r.pendingConfIndex` condition. This does
not seem necessary. When a node first attempts to auto-leave a joint
config, it will bump `r.pendingConfIndex` when proposing. In cases
where `oldApplied >= r.pendingConfIndex`, the proposal must have
already been applied. Reviewers should double check this.
- use raft.Step instead of custom proposal code. This code was already
present in stepLeader, so there was no reason to duplicate it. This
would have avoided bugs like the one we fixed in #14538.
- use `confChangeToMsg` to generate message, to centralize the creation
of all `MsgProp{EntryConfChange}` messages.
Signed-off-by: Nathan VanBenschoten <nvanbenschoten@gmail.com>
This commit is contained in:
25
raft/raft.go
25
raft/raft.go
@@ -548,26 +548,29 @@ func (r *raft) advance(rd Ready) {
|
||||
// new Commit index, this does not mean that we're also applying
|
||||
// all of the new entries due to commit pagination by size.
|
||||
if newApplied := rd.appliedCursor(); newApplied > 0 {
|
||||
oldApplied := r.raftLog.applied
|
||||
r.raftLog.appliedTo(newApplied)
|
||||
|
||||
if r.prs.Config.AutoLeave && oldApplied <= r.pendingConfIndex && newApplied >= r.pendingConfIndex && r.state == StateLeader {
|
||||
if r.prs.Config.AutoLeave && newApplied >= r.pendingConfIndex && r.state == StateLeader {
|
||||
// If the current (and most recent, at least for this leader's term)
|
||||
// configuration should be auto-left, initiate that now. We use a
|
||||
// nil Data which unmarshals into an empty ConfChangeV2 and has the
|
||||
// benefit that appendEntry can never refuse it based on its size
|
||||
// (which registers as zero).
|
||||
ent := pb.Entry{
|
||||
Type: pb.EntryConfChangeV2,
|
||||
Data: nil,
|
||||
m, err := confChangeToMsg(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// There's no way in which this proposal should be able to be rejected.
|
||||
if !r.appendEntry(ent) {
|
||||
panic("refused un-refusable auto-leaving ConfChangeV2")
|
||||
// NB: this proposal can't be dropped due to size, but can be
|
||||
// dropped if a leadership transfer is in progress. We'll keep
|
||||
// checking this condition on each applied entry, so either the
|
||||
// leadership transfer will succeed and the new leader will leave
|
||||
// the joint configuration, or the leadership transfer will fail,
|
||||
// and we will propose the config change on the next advance.
|
||||
if err := r.Step(m); err != nil {
|
||||
r.logger.Debugf("not initiating automatic transition out of joint configuration %s: %v", r.prs.Config, err)
|
||||
} else {
|
||||
r.logger.Infof("initiating automatic transition out of joint configuration %s", r.prs.Config)
|
||||
}
|
||||
r.bcastAppend()
|
||||
r.pendingConfIndex = r.raftLog.lastIndex()
|
||||
r.logger.Infof("initiating automatic transition out of joint configuration %s", r.prs.Config)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,13 @@ func MarshalConfChange(c ConfChangeI) (EntryType, []byte, error) {
|
||||
var typ EntryType
|
||||
var ccdata []byte
|
||||
var err error
|
||||
if ccv1, ok := c.AsV1(); ok {
|
||||
if c == nil {
|
||||
// A nil data unmarshals into an empty ConfChangeV2 and has the benefit
|
||||
// that appendEntry can never refuse it based on its size (which
|
||||
// registers as zero).
|
||||
typ = EntryConfChangeV2
|
||||
ccdata = nil
|
||||
} else if ccv1, ok := c.AsV1(); ok {
|
||||
typ = EntryConfChange
|
||||
ccdata, err = ccv1.Marshal()
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user