Skip to content

Commit f41e8ef

Browse files
committed
kvstorage: add echotest for DestroyReplica
Epic: none Release note: none
1 parent a8d4ee7 commit f41e8ef

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed

pkg/kv/kvserver/kvstorage/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,34 @@ go_test(
3838
srcs = [
3939
"cluster_version_test.go",
4040
"datadriven_test.go",
41+
"destroy_test.go",
4142
],
4243
data = glob(["testdata/**"]),
4344
embed = [":kvstorage"],
4445
deps = [
4546
"//pkg/clusterversion",
4647
"//pkg/keys",
48+
"//pkg/kv/kvpb",
49+
"//pkg/kv/kvserver/concurrency/lock",
50+
"//pkg/kv/kvserver/kvserverpb",
51+
"//pkg/kv/kvserver/logstore",
52+
"//pkg/kv/kvserver/print",
4753
"//pkg/kv/kvserver/stateloader",
4854
"//pkg/raft/raftpb",
4955
"//pkg/roachpb",
5056
"//pkg/settings/cluster",
5157
"//pkg/storage",
5258
"//pkg/testutils",
5359
"//pkg/testutils/datapathutils",
60+
"//pkg/testutils/echotest",
5461
"//pkg/util/hlc",
5562
"//pkg/util/leaktest",
5663
"//pkg/util/log",
5764
"//pkg/util/stop",
5865
"//pkg/util/tracing",
5966
"//pkg/util/uuid",
6067
"@com_github_cockroachdb_datadriven//:datadriven",
68+
"@com_github_cockroachdb_redact//:redact",
6169
"@com_github_stretchr_testify//require",
6270
],
6371
)
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package kvstorage
7+
8+
import (
9+
"context"
10+
"fmt"
11+
"path/filepath"
12+
"strings"
13+
"testing"
14+
15+
"github.com/cockroachdb/cockroach/pkg/keys"
16+
"github.com/cockroachdb/cockroach/pkg/kv/kvpb"
17+
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/lock"
18+
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverpb"
19+
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/logstore"
20+
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/print"
21+
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/stateloader"
22+
"github.com/cockroachdb/cockroach/pkg/raft/raftpb"
23+
"github.com/cockroachdb/cockroach/pkg/roachpb"
24+
"github.com/cockroachdb/cockroach/pkg/storage"
25+
"github.com/cockroachdb/cockroach/pkg/testutils/datapathutils"
26+
"github.com/cockroachdb/cockroach/pkg/testutils/echotest"
27+
"github.com/cockroachdb/cockroach/pkg/util/hlc"
28+
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
29+
"github.com/cockroachdb/cockroach/pkg/util/log"
30+
"github.com/cockroachdb/cockroach/pkg/util/uuid"
31+
"github.com/cockroachdb/redact"
32+
"github.com/stretchr/testify/require"
33+
)
34+
35+
func TestDestroyReplica(t *testing.T) {
36+
defer leaktest.AfterTest(t)()
37+
defer log.Scope(t).Close(t)
38+
39+
storage.DisableMetamorphicSimpleValueEncoding(t) // for deterministic output
40+
eng := storage.NewDefaultInMemForTesting()
41+
defer eng.Close()
42+
43+
var sb redact.StringBuilder
44+
ctx := context.Background()
45+
mutate := func(name string, write func(storage.ReadWriter)) {
46+
b := eng.NewBatch()
47+
defer b.Close()
48+
write(b)
49+
str, err := print.DecodeWriteBatch(b.Repr())
50+
require.NoError(t, err)
51+
_, err = sb.WriteString(fmt.Sprintf(">> %s:\n%s", name, str))
52+
require.NoError(t, err)
53+
require.NoError(t, b.Commit(false))
54+
}
55+
56+
r := replicaInfo{
57+
id: roachpb.FullReplicaID{RangeID: 123, ReplicaID: 3},
58+
hs: raftpb.HardState{Term: 5, Commit: 14},
59+
ts: kvserverpb.RaftTruncatedState{Index: 10, Term: 5},
60+
keys: roachpb.RSpan{Key: []byte("a"), EndKey: []byte("z")},
61+
last: 15,
62+
applied: 12,
63+
}
64+
mutate("raft", func(rw storage.ReadWriter) {
65+
r.createRaftState(ctx, t, rw)
66+
})
67+
mutate("state", func(rw storage.ReadWriter) {
68+
r.createStateMachine(ctx, t, rw)
69+
})
70+
mutate("destroy", func(rw storage.ReadWriter) {
71+
require.NoError(t, DestroyReplica(ctx, r.id, rw, rw, r.id.ReplicaID+1, ClearRangeDataOptions{
72+
ClearUnreplicatedByRangeID: true,
73+
ClearReplicatedByRangeID: true,
74+
ClearReplicatedBySpan: r.keys,
75+
}))
76+
})
77+
78+
str := strings.ReplaceAll(sb.String(), "\n\n", "\n")
79+
echotest.Require(t, str, filepath.Join(datapathutils.TestDataPath(t), t.Name()+".txt"))
80+
}
81+
82+
// replicaInfo contains the basic info about the replica, used for generating
83+
// its storage counterpart.
84+
//
85+
// TODO(pav-kv): make it reusable for other tests.
86+
type replicaInfo struct {
87+
id roachpb.FullReplicaID
88+
hs raftpb.HardState
89+
ts kvserverpb.RaftTruncatedState
90+
keys roachpb.RSpan
91+
last kvpb.RaftIndex
92+
applied kvpb.RaftIndex
93+
}
94+
95+
func (r *replicaInfo) createRaftState(ctx context.Context, t *testing.T, w storage.Writer) {
96+
sl := logstore.NewStateLoader(r.id.RangeID)
97+
require.NoError(t, sl.SetHardState(ctx, w, r.hs))
98+
require.NoError(t, sl.SetRaftTruncatedState(ctx, w, &r.ts))
99+
for i := r.ts.Index + 1; i <= r.last; i++ {
100+
require.NoError(t, storage.MVCCBlindPutProto(
101+
ctx, w,
102+
sl.RaftLogKey(i), hlc.Timestamp{}, /* timestamp */
103+
&raftpb.Entry{Index: uint64(i), Term: 5},
104+
storage.MVCCWriteOptions{},
105+
))
106+
}
107+
}
108+
109+
func (r *replicaInfo) createStateMachine(ctx context.Context, t *testing.T, rw storage.ReadWriter) {
110+
sl := stateloader.Make(r.id.RangeID)
111+
require.NoError(t, sl.SetRangeTombstone(ctx, rw, kvserverpb.RangeTombstone{
112+
NextReplicaID: r.id.ReplicaID,
113+
}))
114+
require.NoError(t, sl.SetRaftReplicaID(ctx, rw, r.id.ReplicaID))
115+
// TODO(pav-kv): figure out whether LastReplicaGCTimestamp should be in the
116+
// log or state engine.
117+
require.NoError(t, storage.MVCCBlindPutProto(
118+
ctx, rw,
119+
keys.RangeLastReplicaGCTimestampKey(r.id.RangeID),
120+
hlc.Timestamp{}, /* timestamp */
121+
&hlc.Timestamp{WallTime: 12345678},
122+
storage.MVCCWriteOptions{},
123+
))
124+
createRangeData(t, rw, r.keys)
125+
}
126+
127+
func createRangeData(t *testing.T, rw storage.ReadWriter, span roachpb.RSpan) {
128+
ts := hlc.Timestamp{WallTime: 1}
129+
for _, k := range []roachpb.Key{
130+
keys.RangeDescriptorKey(span.Key), // system
131+
span.Key.AsRawKey(), // user
132+
roachpb.Key(span.EndKey).Prevish(2), // user
133+
} {
134+
// Put something under the system or user key.
135+
require.NoError(t, rw.PutMVCC(
136+
storage.MVCCKey{Key: k, Timestamp: ts}, storage.MVCCValue{},
137+
))
138+
// Put something under the corresponding lock key.
139+
ek, _ := storage.LockTableKey{
140+
Key: k, Strength: lock.Intent, TxnUUID: uuid.UUID{},
141+
}.ToEngineKey(nil)
142+
require.NoError(t, rw.PutEngineKey(ek, nil))
143+
}
144+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
echo
2+
----
3+
>> raft:
4+
Put: 0,0 /Local/RangeID/123/u/RaftHardState (0x0169f67b757266746800): term:5 vote:0 commit:14 lead:0 lead_epoch:0
5+
Put: 0,0 /Local/RangeID/123/u/RaftTruncatedState (0x0169f67b757266747400): index:10 term:5
6+
Put: 0,0 /Local/RangeID/123/u/RaftLog/logIndex:11 (0x0169f67b757266746c000000000000000b00): Term:5 Index:11 Type:EntryNormal : EMPTY
7+
Put: 0,0 /Local/RangeID/123/u/RaftLog/logIndex:12 (0x0169f67b757266746c000000000000000c00): Term:5 Index:12 Type:EntryNormal : EMPTY
8+
Put: 0,0 /Local/RangeID/123/u/RaftLog/logIndex:13 (0x0169f67b757266746c000000000000000d00): Term:5 Index:13 Type:EntryNormal : EMPTY
9+
Put: 0,0 /Local/RangeID/123/u/RaftLog/logIndex:14 (0x0169f67b757266746c000000000000000e00): Term:5 Index:14 Type:EntryNormal : EMPTY
10+
Put: 0,0 /Local/RangeID/123/u/RaftLog/logIndex:15 (0x0169f67b757266746c000000000000000f00): Term:5 Index:15 Type:EntryNormal : EMPTY
11+
>> state:
12+
Put: 0,0 /Local/RangeID/123/u/RangeTombstone (0x0169f67b757266746200): next_replica_id:3
13+
Put: 0,0 /Local/RangeID/123/u/RaftReplicaID (0x0169f67b757266747200): replica_id:3
14+
Put: 0,0 /Local/RangeID/123/u/RangeLastReplicaGCTimestamp (0x0169f67b75726c727400): 0.012345678,0
15+
Put: 0.000000001,0 /Local/Range"a"/RangeDescriptor (0x016b126100017264736300000000000000000109): ""
16+
Put: /Local/Range"a"/RangeDescriptor/Intent/00000000-0000-0000-0000-000000000000:
17+
Put: 0.000000001,0 "a" (0x6100000000000000000109): ""
18+
Put: "a"/Intent/00000000-0000-0000-0000-000000000000:
19+
Put: 0.000000001,0 "y\xff" (0x79ff00000000000000000109): ""
20+
Put: "y\xff"/Intent/00000000-0000-0000-0000-000000000000:
21+
>> destroy:
22+
Delete (Sized at 31): 0,0 /Local/RangeID/123/u/RangeTombstone (0x0169f67b757266746200):
23+
Delete (Sized at 39): 0,0 /Local/RangeID/123/u/RaftHardState (0x0169f67b757266746800):
24+
Delete (Sized at 43): 0,0 /Local/RangeID/123/u/RaftLog/logIndex:11 (0x0169f67b757266746c000000000000000b00):
25+
Delete (Sized at 43): 0,0 /Local/RangeID/123/u/RaftLog/logIndex:12 (0x0169f67b757266746c000000000000000c00):
26+
Delete (Sized at 43): 0,0 /Local/RangeID/123/u/RaftLog/logIndex:13 (0x0169f67b757266746c000000000000000d00):
27+
Delete (Sized at 43): 0,0 /Local/RangeID/123/u/RaftLog/logIndex:14 (0x0169f67b757266746c000000000000000e00):
28+
Delete (Sized at 43): 0,0 /Local/RangeID/123/u/RaftLog/logIndex:15 (0x0169f67b757266746c000000000000000f00):
29+
Delete (Sized at 31): 0,0 /Local/RangeID/123/u/RaftReplicaID (0x0169f67b757266747200):
30+
Delete (Sized at 33): 0,0 /Local/RangeID/123/u/RaftTruncatedState (0x0169f67b757266747400):
31+
Delete (Sized at 34): 0,0 /Local/RangeID/123/u/RangeLastReplicaGCTimestamp (0x0169f67b75726c727400):
32+
Delete (Sized at 20): 0.000000001,0 /Local/Range"a"/RangeDescriptor (0x016b126100017264736300000000000000000109):
33+
Delete (Sized at 36): /Local/Lock/Local/Range"a"/RangeDescriptor 0300000000000000000000000000000000 (0x017a6b12016b126100ff0172647363000100030000000000000000000000000000000012):
34+
Delete (Sized at 26): /Local/Lock"a" 0300000000000000000000000000000000 (0x017a6b1261000100030000000000000000000000000000000012):
35+
Delete (Sized at 27): /Local/Lock"y\xff" 0300000000000000000000000000000000 (0x017a6b1279ff000100030000000000000000000000000000000012):
36+
Delete (Sized at 11): 0.000000001,0 "a" (0x6100000000000000000109):
37+
Delete (Sized at 12): 0.000000001,0 "y\xff" (0x79ff00000000000000000109):
38+
Put: 0,0 /Local/RangeID/123/u/RangeTombstone (0x0169f67b757266746200): next_replica_id:4

0 commit comments

Comments
 (0)