Skip to content

Commit 003b60e

Browse files
committed
kvstorage: assert ReplicaID on destruction
DestroyReplica already performs a read of RaftReplicaID, so we can assert on it at no additional cost. Epic: none Release note: none
1 parent 91b3eee commit 003b60e

File tree

6 files changed

+44
-29
lines changed

6 files changed

+44
-29
lines changed

pkg/kv/kvserver/kvstorage/destroy.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,28 +118,30 @@ const DestroyReplicaTODO = 0
118118
// not be cleared.
119119
func DestroyReplica(
120120
ctx context.Context,
121-
rangeID roachpb.RangeID,
121+
id roachpb.FullReplicaID,
122122
reader storage.Reader,
123123
writer storage.Writer,
124124
nextReplicaID roachpb.ReplicaID,
125125
opts ClearRangeDataOptions,
126126
) error {
127-
diskReplicaID, err := stateloader.Make(rangeID).LoadRaftReplicaID(ctx, reader)
127+
diskReplicaID, err := stateloader.Make(id.RangeID).LoadRaftReplicaID(ctx, reader)
128128
if err != nil {
129129
return err
130130
}
131-
if diskReplicaID.ReplicaID >= nextReplicaID {
132-
return errors.AssertionFailedf("replica r%d/%d must not survive its own tombstone", rangeID, diskReplicaID)
131+
if repID := diskReplicaID.ReplicaID; repID != id.ReplicaID {
132+
return errors.AssertionFailedf("replica %v has a mismatching ID %d", id, repID)
133+
} else if repID >= nextReplicaID {
134+
return errors.AssertionFailedf("replica %v must not survive its own tombstone", id)
133135
}
134136
_ = DestroyReplicaTODO // 2.1 + 2.2 + 3.1
135-
if err := ClearRangeData(ctx, rangeID, reader, writer, opts); err != nil {
137+
if err := ClearRangeData(ctx, id.RangeID, reader, writer, opts); err != nil {
136138
return err
137139
}
138140

139141
// Save a tombstone to ensure that replica IDs never get reused. Assert that
140142
// the provided tombstone moves the existing one strictly forward. Failure to
141143
// do so indicates that something is going wrong in the replica lifecycle.
142-
sl := stateloader.Make(rangeID)
144+
sl := stateloader.Make(id.RangeID)
143145
ts, err := sl.LoadRangeTombstone(ctx, reader)
144146
if err != nil {
145147
return err

pkg/kv/kvserver/replica_app_batch.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ func (b *replicaAppBatch) runPostAddTriggersReplicaOnly(
364364
// required for correctness, since the merge protocol should guarantee that
365365
// no new replicas of the RHS can ever be created, but it doesn't hurt to
366366
// be careful.
367-
if err := kvstorage.DestroyReplica(ctx, rhsRepl.RangeID, b.batch, b.batch, mergedTombstoneReplicaID, kvstorage.ClearRangeDataOptions{
367+
if err := kvstorage.DestroyReplica(ctx, rhsRepl.ID(), b.batch, b.batch, mergedTombstoneReplicaID, kvstorage.ClearRangeDataOptions{
368368
ClearReplicatedByRangeID: true,
369369
ClearUnreplicatedByRangeID: true,
370370
}); err != nil {
@@ -455,7 +455,7 @@ func (b *replicaAppBatch) runPostAddTriggersReplicaOnly(
455455
// We've set the replica's in-mem status to reflect the pending destruction
456456
// above, and DestroyReplica will also add a range tombstone to the
457457
// batch, so that when we commit it, the removal is finalized.
458-
if err := kvstorage.DestroyReplica(ctx, b.r.RangeID, b.batch, b.batch, change.NextReplicaID(), kvstorage.ClearRangeDataOptions{
458+
if err := kvstorage.DestroyReplica(ctx, b.r.ID(), b.batch, b.batch, change.NextReplicaID(), kvstorage.ClearRangeDataOptions{
459459
ClearReplicatedBySpan: span,
460460
ClearReplicatedByRangeID: true,
461461
ClearUnreplicatedByRangeID: true,

pkg/kv/kvserver/replica_destroy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (r *Replica) destroyRaftMuLocked(ctx context.Context, nextReplicaID roachpb
111111
ClearUnreplicatedByRangeID: true,
112112
}
113113
// TODO(sep-raft-log): need both engines separately here.
114-
if err := kvstorage.DestroyReplica(ctx, r.RangeID, r.store.TODOEngine(), batch, nextReplicaID, opts); err != nil {
114+
if err := kvstorage.DestroyReplica(ctx, r.ID(), r.store.TODOEngine(), batch, nextReplicaID, opts); err != nil {
115115
return err
116116
}
117117
preTime := timeutil.Now()

pkg/kv/kvserver/replica_raftstorage.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ func (r *Replica) applySnapshotRaftMuLocked(
566566
Term: kvpb.RaftTerm(nonemptySnap.Metadata.Term),
567567
}
568568

569-
subsumedDescs := make([]*roachpb.RangeDescriptor, 0, len(subsumedRepls))
569+
subsume := make([]destroyReplicaInfo, 0, len(subsumedRepls))
570570
for _, sr := range subsumedRepls {
571571
// We mark the replica as destroyed so that new commands are not
572572
// accepted. This destroy status will be detected after the batch
@@ -580,10 +580,11 @@ func (r *Replica) applySnapshotRaftMuLocked(
580580
sr.shMu.destroyStatus.Set(
581581
kvpb.NewRangeNotFoundError(sr.RangeID, sr.store.StoreID()),
582582
destroyReasonRemoved)
583+
srDesc := sr.descRLocked()
583584
sr.mu.Unlock()
584585
sr.readOnlyCmdMu.Unlock()
585586

586-
subsumedDescs = append(subsumedDescs, sr.Desc())
587+
subsume = append(subsume, destroyReplicaInfo{id: sr.ID(), desc: srDesc})
587588
}
588589

589590
sb := snapWriteBuilder{
@@ -593,10 +594,10 @@ func (r *Replica) applySnapshotRaftMuLocked(
593594
sl: r.raftMu.stateLoader,
594595
writeSST: inSnap.SSTStorageScratch.WriteSST,
595596

596-
truncState: truncState,
597-
hardState: hs,
598-
desc: desc,
599-
subsumedDescs: subsumedDescs,
597+
truncState: truncState,
598+
hardState: hs,
599+
desc: desc,
600+
subsume: subsume,
600601

601602
cleared: inSnap.clearedSpans,
602603
}

pkg/kv/kvserver/snapshot_apply_prepare.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ import (
2020
"github.com/cockroachdb/errors"
2121
)
2222

23+
// destroyReplicaInfo contains the replica's metadata needed for its removal
24+
// from storage.
25+
// TODO(pav-kv): for WAG, add the truncated state and applied index. See #152845.
26+
type destroyReplicaInfo struct {
27+
id roachpb.FullReplicaID
28+
desc *roachpb.RangeDescriptor
29+
}
30+
2331
// snapWriteBuilder contains the data needed to prepare the on-disk state for a
2432
// snapshot.
2533
type snapWriteBuilder struct {
@@ -29,10 +37,10 @@ type snapWriteBuilder struct {
2937
sl stateloader.StateLoader
3038
writeSST func(context.Context, func(context.Context, storage.Writer) error) error
3139

32-
truncState kvserverpb.RaftTruncatedState
33-
hardState raftpb.HardState
34-
desc *roachpb.RangeDescriptor
35-
subsumedDescs []*roachpb.RangeDescriptor
40+
truncState kvserverpb.RaftTruncatedState
41+
hardState raftpb.HardState
42+
desc *roachpb.RangeDescriptor
43+
subsume []destroyReplicaInfo
3644

3745
// cleared contains the spans that this snapshot application clears before
3846
// writing new state on top.
@@ -115,7 +123,7 @@ func (s *snapWriteBuilder) clearSubsumedReplicaDiskData(ctx context.Context) err
115123
}
116124
keySpans := getKeySpans(s.desc)
117125
totalKeySpans := append([]roachpb.Span(nil), keySpans...)
118-
for _, subDesc := range s.subsumedDescs {
126+
for _, sub := range s.subsume {
119127
// We have to create an SST for the subsumed replica's range-id local keys.
120128
if err := s.writeSST(ctx, func(ctx context.Context, w storage.Writer) error {
121129
// NOTE: We set mustClearRange to true because we are setting
@@ -126,16 +134,16 @@ func (s *snapWriteBuilder) clearSubsumedReplicaDiskData(ctx context.Context) err
126134
ClearUnreplicatedByRangeID: true,
127135
MustUseClearRange: true,
128136
}
129-
s.cleared = append(s.cleared, rditer.Select(subDesc.RangeID, rditer.SelectOpts{
137+
s.cleared = append(s.cleared, rditer.Select(sub.id.RangeID, rditer.SelectOpts{
130138
ReplicatedByRangeID: opts.ClearReplicatedByRangeID,
131139
UnreplicatedByRangeID: opts.ClearUnreplicatedByRangeID,
132140
})...)
133-
return kvstorage.DestroyReplica(ctx, subDesc.RangeID, reader, w, mergedTombstoneReplicaID, opts)
141+
return kvstorage.DestroyReplica(ctx, sub.id, reader, w, mergedTombstoneReplicaID, opts)
134142
}); err != nil {
135143
return err
136144
}
137145

138-
srKeySpans := getKeySpans(subDesc)
146+
srKeySpans := getKeySpans(sub.desc)
139147
// Compute the total key space covered by the current replica and all
140148
// subsumed replicas.
141149
for i := range srKeySpans {

pkg/kv/kvserver/snapshot_apply_prepare_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ func TestPrepareSnapApply(t *testing.T) {
6969
}
7070
}
7171

72-
id := roachpb.FullReplicaID{RangeID: 123, ReplicaID: 4}
72+
const replicaID = 4
73+
id := roachpb.FullReplicaID{RangeID: 123, ReplicaID: replicaID}
7374
descA := desc(101, "a", "b")
7475
descB := desc(102, "b", "z")
7576
createRangeData(t, eng, *descA)
@@ -79,7 +80,7 @@ func TestPrepareSnapApply(t *testing.T) {
7980
ctx := context.Background()
8081
require.NoError(t, sl.SetRaftReplicaID(ctx, eng, id.ReplicaID))
8182
for _, rID := range []roachpb.RangeID{101, 102} {
82-
require.NoError(t, stateloader.Make(rID).SetRaftReplicaID(ctx, eng, id.ReplicaID))
83+
require.NoError(t, stateloader.Make(rID).SetRaftReplicaID(ctx, eng, replicaID))
8384
}
8485

8586
swb := snapWriteBuilder{
@@ -88,10 +89,13 @@ func TestPrepareSnapApply(t *testing.T) {
8889
sl: sl,
8990
writeSST: writeSST,
9091

91-
truncState: kvserverpb.RaftTruncatedState{Index: 100, Term: 20},
92-
hardState: raftpb.HardState{Term: 20, Commit: 100},
93-
desc: desc(id.RangeID, "a", "k"),
94-
subsumedDescs: []*roachpb.RangeDescriptor{descA, descB},
92+
truncState: kvserverpb.RaftTruncatedState{Index: 100, Term: 20},
93+
hardState: raftpb.HardState{Term: 20, Commit: 100},
94+
desc: desc(id.RangeID, "a", "k"),
95+
subsume: []destroyReplicaInfo{
96+
{id: roachpb.FullReplicaID{RangeID: descA.RangeID, ReplicaID: replicaID}, desc: descA},
97+
{id: roachpb.FullReplicaID{RangeID: descB.RangeID, ReplicaID: replicaID}, desc: descB},
98+
},
9599
}
96100

97101
err := swb.prepareSnapApply(ctx)

0 commit comments

Comments
 (0)