@@ -3353,12 +3353,17 @@ func (r *Replica) stepRaftGroup(req *RaftMessageRequest) error {
3353
3353
3354
3354
// Check if the message is a proposal that should be dropped.
3355
3355
if r .shouldDropForwardedProposalLocked (req ) {
3356
- // If we could signal to the sender that it's proposal was
3357
- // accepted or dropped then we wouldn't need to track anything.
3356
+ // If we could signal to the sender that its proposal was accepted
3357
+ // or dropped then we wouldn't need to track anything.
3358
3358
return false /* unquiesceAndWakeLeader */ , nil
3359
3359
}
3360
3360
3361
3361
err := raftGroup .Step (req .Message )
3362
+ if err == nil {
3363
+ // If we stepped successfully and the request is a proposal, consider
3364
+ // tracking it so that we can ignore identical proposals in the future.
3365
+ r .maybeTrackForwardedProposalLocked (raftGroup , req )
3366
+ }
3362
3367
if err == raft .ErrProposalDropped {
3363
3368
// A proposal was forwarded to this replica but we couldn't propose it.
3364
3369
// Swallow the error since we don't have an effective way of signaling
@@ -3377,15 +3382,40 @@ func (r *Replica) shouldDropForwardedProposalLocked(req *RaftMessageRequest) boo
3377
3382
return false
3378
3383
}
3379
3384
3380
- if r .mu .replicaID != r .mu .leaderID {
3381
- // Always continue to forward proposals if we're not the leader.
3382
- return false
3385
+ for _ , e := range req .Message .Entries {
3386
+ switch e .Type {
3387
+ case raftpb .EntryNormal :
3388
+ cmdID , _ := DecodeRaftCommand (e .Data )
3389
+ if _ , ok := r .mu .remoteProposals [cmdID ]; ! ok {
3390
+ // Untracked remote proposal. Don't drop.
3391
+ return false
3392
+ }
3393
+ case raftpb .EntryConfChange :
3394
+ // Never drop EntryConfChange proposals.
3395
+ return false
3396
+ default :
3397
+ log .Fatalf (context .TODO (), "unexpected Raft entry: %v" , e )
3398
+ }
3383
3399
}
3400
+ // All entries tracked.
3401
+ return true
3402
+ }
3384
3403
3385
- // Record that the proposal was seen and drop the proposal if it was
3386
- // already seen. This prevents duplicate forwarded proposals from each
3387
- // being appended to a leader's raft log.
3388
- drop := true
3404
+ func (r * Replica ) maybeTrackForwardedProposalLocked (rg * raft.RawNode , req * RaftMessageRequest ) {
3405
+ if req .Message .Type != raftpb .MsgProp {
3406
+ // Not a proposal.
3407
+ return
3408
+ }
3409
+
3410
+ if rg .Status ().RaftState != raft .StateLeader {
3411
+ // We're not the leader. We can't be sure that the proposal made it into
3412
+ // the Raft log, so don't track it.
3413
+ return
3414
+ }
3415
+
3416
+ // Record that each of the proposal's entries was seen and appended. This
3417
+ // allows us to catch duplicate forwarded proposals in the future and
3418
+ // prevent them from being repeatedly appended to a leader's raft log.
3389
3419
for _ , e := range req .Message .Entries {
3390
3420
switch e .Type {
3391
3421
case raftpb .EntryNormal :
@@ -3394,28 +3424,18 @@ func (r *Replica) shouldDropForwardedProposalLocked(req *RaftMessageRequest) boo
3394
3424
// An empty command is proposed to unquiesce a range and
3395
3425
// wake the leader. Don't keep track of these forwarded
3396
3426
// proposals because they will never be cleaned up.
3397
- drop = false
3398
3427
} else {
3399
- // Record that the proposal was seen so that we can catch
3400
- // duplicate proposals in the future.
3401
3428
if r .mu .remoteProposals == nil {
3402
3429
r .mu .remoteProposals = map [storagebase.CmdIDKey ]struct {}{}
3403
3430
}
3404
- if _ , ok := r .mu .remoteProposals [cmdID ]; ! ok {
3405
- r .mu .remoteProposals [cmdID ] = struct {}{}
3406
- drop = false
3407
- }
3431
+ r .mu .remoteProposals [cmdID ] = struct {}{}
3408
3432
}
3409
3433
case raftpb .EntryConfChange :
3410
- // We could peek into the EntryConfChange to find the
3411
- // command ID, but we don't expect follower-initiated
3412
- // conf changes.
3413
- drop = false
3434
+ // Don't track EntryConfChanges.
3414
3435
default :
3415
3436
log .Fatalf (context .TODO (), "unexpected Raft entry: %v" , e )
3416
3437
}
3417
3438
}
3418
- return drop
3419
3439
}
3420
3440
3421
3441
type handleRaftReadyStats struct {
0 commit comments