Skip to content

Commit 23e6dab

Browse files
committed
kvstorage: support multi-key IterateIDPrefixKeys
Epic: none Release note: none
1 parent d190c24 commit 23e6dab

File tree

5 files changed

+80
-71
lines changed

5 files changed

+80
-71
lines changed

pkg/kv/kvserver/kvstorage/init.go

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ func checkCanInitializeEngine(ctx context.Context, eng storage.Engine) error {
144144
return err
145145
}
146146

147+
type readKeyFn func(roachpb.Key, protoutil.Message) (bool, error)
148+
type scanRangeIDFn func(roachpb.RangeID, readKeyFn) error
149+
147150
// IterateIDPrefixKeys helps visit system keys that use RangeID prefixing (such
148151
// as RaftHardStateKey, RangeTombstoneKey, and many others). Such keys could in
149152
// principle exist at any RangeID, and this helper efficiently discovers all the
@@ -152,11 +155,7 @@ func checkCanInitializeEngine(ctx context.Context, eng storage.Engine) error {
152155
//
153156
// Iteration stops on the first error (and will pass through that error).
154157
func IterateIDPrefixKeys(
155-
ctx context.Context,
156-
reader storage.Reader,
157-
keyFn func(roachpb.RangeID) roachpb.Key,
158-
msg protoutil.Message,
159-
f func(_ roachpb.RangeID) error,
158+
ctx context.Context, reader storage.Reader, scanRangeID scanRangeIDFn,
160159
) error {
161160
// NB: Range-ID local keys have no versions and no intents.
162161
iter, err := reader.NewMVCCIterator(ctx, storage.MVCCKeyIterKind, storage.IterOptions{
@@ -167,40 +166,62 @@ func IterateIDPrefixKeys(
167166
}
168167
defer iter.Close()
169168

170-
for rangeID := roachpb.RangeID(1); ; {
171-
rangeIDKey := keyFn(rangeID)
172-
iter.SeekGE(storage.MakeMVCCMetadataKey(rangeIDKey))
169+
iter.SeekGE(storage.MakeMVCCMetadataKey(keys.LocalRangeIDPrefix.AsRawKey()))
170+
iterOK, iterErr := iter.Valid()
171+
if !iterOK || iterErr != nil {
172+
return iterErr
173+
}
173174

174-
if ok, err := iter.Valid(); !ok || err != nil {
175-
return err
175+
getKeyFn := func(key roachpb.Key, msg protoutil.Message) (bool, error) {
176+
if !iterOK || iterErr != nil {
177+
return iterOK, iterErr
176178
}
177-
178179
unsafeKey := iter.UnsafeKey().Key
179-
if comp := unsafeKey.Compare(rangeIDKey); comp > 0 { // overshot
180-
curRangeID, _, _, _, err := keys.DecodeRangeIDKey(unsafeKey)
181-
if err != nil {
182-
return err
180+
comp := unsafeKey.Compare(key)
181+
if comp < 0 {
182+
iter.SeekGE(storage.MakeMVCCMetadataKey(key))
183+
if iterOK, iterErr = iter.Valid(); !iterOK || iterErr != nil {
184+
return iterOK, iterErr
185+
}
186+
unsafeKey = iter.UnsafeKey().Key
187+
comp = unsafeKey.Compare(key)
188+
if comp < 0 {
189+
return false, errors.AssertionFailedf("SeekGE undershot key %s", key)
183190
}
184-
rangeID = max(curRangeID, rangeID+1)
185-
continue
186-
} else if comp < 0 { // undershot
187-
return errors.AssertionFailedf("SeekGE undershot key %s", rangeIDKey)
188191
}
189-
190-
// Found the key. Parse and report the value.
192+
if comp > 0 {
193+
return false, nil
194+
}
195+
// Found the key (comp == 0). Parse and report the value.
191196
var meta enginepb.MVCCMetadata
192197
if err := iter.ValueProto(&meta); err != nil {
193-
return errors.Errorf("unable to unmarshal %s into MVCCMetadata", unsafeKey)
198+
return false, errors.Errorf("unable to unmarshal %s into MVCCMetadata", unsafeKey)
194199
}
195200
val := roachpb.Value{RawBytes: meta.RawBytes}
196201
if err := val.GetProto(msg); err != nil {
197-
return errors.Errorf("unable to unmarshal %s into %T", unsafeKey, msg)
202+
return false, errors.Errorf("unable to unmarshal %s into %T", unsafeKey, msg)
198203
}
199-
if err := f(rangeID); err != nil {
204+
return true, nil
205+
}
206+
207+
for iterOK && iterErr == nil {
208+
rangeID, _, _, _, err := keys.DecodeRangeIDKey(iter.UnsafeKey().Key)
209+
if err != nil {
210+
return err
211+
} else if err := scanRangeID(rangeID, getKeyFn); err != nil {
200212
return iterutil.Map(err)
213+
} else if !iterOK || iterErr != nil {
214+
return iterErr
215+
}
216+
newRangeID, _, _, _, err := keys.DecodeRangeIDKey(iter.UnsafeKey().Key)
217+
if err != nil {
218+
return err
219+
} else if newRangeID <= rangeID {
220+
iter.SeekGE(storage.MakeMVCCMetadataKey(keys.MakeRangeIDPrefix(rangeID + 1)))
221+
iterOK, iterErr = iter.Valid()
201222
}
202-
rangeID++
203223
}
224+
return iterErr
204225
}
205226

206227
// ReadStoreIdent reads the StoreIdent from the store.
@@ -485,41 +506,31 @@ func loadReplicas(ctx context.Context, eng storage.Engine) ([]Replica, error) {
485506
// TODO(tbg): tighten up the case where we see a RaftReplicaID but no HardState.
486507
// This leads to the general desire to validate the internal consistency of the
487508
// entire raft state (i.e. HardState, TruncatedState, Log).
488-
{
489-
logEvery := log.Every(10 * time.Second)
490-
var i int
491-
var msg kvserverpb.RaftReplicaID
492-
if err := IterateIDPrefixKeys(ctx, eng, func(rangeID roachpb.RangeID) roachpb.Key {
493-
return keys.RaftReplicaIDKey(rangeID)
494-
}, &msg, func(rangeID roachpb.RangeID) error {
495-
if logEvery.ShouldLog() && i > 0 { // only log if slow
496-
log.KvExec.Infof(ctx, "loaded replica ID for %d/%d replicas", i, len(s))
497-
}
498-
i++
499-
s.setReplicaID(rangeID, msg.ReplicaID)
500-
return nil
501-
}); err != nil {
502-
return nil, err
509+
logEvery := log.Every(10 * time.Second)
510+
var i int
511+
if err := IterateIDPrefixKeys(ctx, eng, func(id roachpb.RangeID, get readKeyFn) error {
512+
if logEvery.ShouldLog() && i > 0 { // only log if slow
513+
log.KvExec.Infof(ctx, "loaded state for %d/%d replicas", i, len(s))
503514
}
504-
log.KvExec.Infof(ctx, "loaded replica ID for %d/%d replicas", len(s), len(s))
505-
506-
logEvery = log.Every(10 * time.Second)
507-
i = 0
515+
i++
508516
var hs raftpb.HardState
509-
if err := IterateIDPrefixKeys(ctx, eng, func(rangeID roachpb.RangeID) roachpb.Key {
510-
return keys.RaftHardStateKey(rangeID)
511-
}, &hs, func(rangeID roachpb.RangeID) error {
512-
if logEvery.ShouldLog() && i > 0 { // only log if slow
513-
log.KvExec.Infof(ctx, "loaded Raft state for %d/%d replicas", i, len(s))
514-
}
515-
i++
516-
s.setHardState(rangeID, hs)
517-
return nil
518-
}); err != nil {
519-
return nil, err
517+
if ok, err := get(keys.RaftHardStateKey(id), &hs); err != nil {
518+
return err
519+
} else if ok {
520+
s.setHardState(id, hs)
520521
}
521-
log.KvExec.Infof(ctx, "loaded Raft state for %d/%d replicas", len(s), len(s))
522+
var rID kvserverpb.RaftReplicaID
523+
if ok, err := get(keys.RaftReplicaIDKey(id), &rID); err != nil {
524+
return err
525+
} else if ok {
526+
s.setReplicaID(id, rID.ReplicaID)
527+
}
528+
return nil
529+
}); err != nil {
530+
return nil, err
522531
}
532+
log.KvExec.Infof(ctx, "loaded state for %d/%d replicas", len(s), len(s))
533+
523534
sl := make([]Replica, 0, len(s))
524535
for _, repl := range s {
525536
sl = append(sl, repl)

pkg/kv/kvserver/kvstorage/init_test.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,15 @@ func TestIterateIDPrefixKeys(t *testing.T) {
100100
})
101101

102102
var seen []seenT
103-
var tombstone kvserverpb.RangeTombstone
104-
require.NoError(t, IterateIDPrefixKeys(
105-
ctx, eng, keys.RangeTombstoneKey, &tombstone,
106-
func(rangeID roachpb.RangeID) error {
107-
seen = append(seen, seenT{rangeID: rangeID, tombstone: tombstone})
108-
return nil
109-
}))
103+
require.NoError(t, IterateIDPrefixKeys(ctx, eng, func(id roachpb.RangeID, get readKeyFn) error {
104+
var tombstone kvserverpb.RangeTombstone
105+
if ok, err := get(keys.RangeTombstoneKey(id), &tombstone); err != nil {
106+
return err
107+
} else if ok {
108+
seen = append(seen, seenT{rangeID: id, tombstone: tombstone})
109+
}
110+
return nil
111+
}))
110112

111113
require.Equal(t, wanted, seen)
112114
}

pkg/kv/kvserver/kvstorage/testdata/TestDataDriven/assert_replicaid

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@ load-and-reconcile trace=true
88
no RaftReplicaID for r5:{a-c} [(n1,s1):50, next=51, gen=0]
99
beginning range descriptor iteration
1010
range descriptor iteration done: 1 range descriptors, 0 intents, 0 tombstones; stats: <redacted>
11-
loaded replica ID for 1/1 replicas
12-
loaded Raft state for 1/1 replicas
11+
loaded state for 1/1 replicas
1312
loaded 1 replicas

pkg/kv/kvserver/kvstorage/testdata/TestDataDriven/assert_replicaid_uninitialized

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,5 @@ load-and-reconcile trace=true
88
no RaftReplicaID for <nil>
99
beginning range descriptor iteration
1010
range descriptor iteration done: 0 range descriptors, 0 intents, 0 tombstones; stats: <redacted>
11-
loaded replica ID for 0/0 replicas
12-
loaded Raft state for 1/1 replicas
11+
loaded state for 1/1 replicas
1312
loaded 1 replicas

pkg/kv/kvserver/kvstorage/testdata/TestDataDriven/init

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ r6/60: uninitialized
1515
r8/80: r8:{c-f} [(n1,s1):80, next=81, gen=0]
1616
beginning range descriptor iteration
1717
range descriptor iteration done: 1 range descriptors, 0 intents, 0 tombstones; stats: <redacted>
18-
loaded replica ID for 2/2 replicas
19-
loaded Raft state for 2/2 replicas
18+
loaded state for 2/2 replicas
2019
loaded 2 replicas
2120
verified 2/2 replicas
2221

@@ -27,7 +26,6 @@ r6/60: uninitialized
2726
r8/80: r8:{c-f} [(n1,s1):80, next=81, gen=0]
2827
beginning range descriptor iteration
2928
range descriptor iteration done: 1 range descriptors, 0 intents, 0 tombstones; stats: <redacted>
30-
loaded replica ID for 2/2 replicas
31-
loaded Raft state for 2/2 replicas
29+
loaded state for 2/2 replicas
3230
loaded 2 replicas
3331
verified 2/2 replicas

0 commit comments

Comments
 (0)