-
Notifications
You must be signed in to change notification settings - Fork 4k
spanset: assert that batches don't access store local and unreplicated RangeID local keys #157153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -118,7 +118,9 @@ func TruncateLog( | |
| // are not tracked in the raft log delta. The delta will be adjusted below | ||
| // raft. | ||
| // We can pass zero as nowNanos because we're only interested in SysBytes. | ||
| ms, err := storage.ComputeStats(ctx, readWriter, start, end, 0 /* nowNanos */) | ||
| // TODO(#157895): Use the log engine here instead of the state machine engine. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likely can unTODO this, since this PR is merged. |
||
| ms, err := storage.ComputeStats(ctx, | ||
pav-kv marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| spanset.DisableForbiddenSpanAssertionsOnBatch(readWriter), start, end, 0 /* nowNanos */) | ||
| if err != nil { | ||
| return result.Result{}, errors.Wrap(err, "while computing stats of Raft log freed by truncation") | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2732,7 +2732,7 @@ func TestReplicaLatchingSplitDeclaresWrites(t *testing.T) { | |
| {spanset.SpanReadWrite, roachpb.Key("b"), false}, | ||
| {spanset.SpanReadWrite, roachpb.Key("d"), true}, | ||
| } { | ||
| err := spans.CheckAllowed(tc.access, roachpb.Span{Key: tc.key}) | ||
| err := spans.CheckAllowed(tc.access, spanset.TrickySpan{Key: tc.key}) | ||
| if tc.expectAccess { | ||
| require.NoError(t, err) | ||
| } else { | ||
|
|
@@ -15197,3 +15197,123 @@ func TestLeaderlessWatcherInit(t *testing.T) { | |
| t.Fatalf("expected LeaderlessWatcher channel to be closed") | ||
| } | ||
| } | ||
|
|
||
| // TestOverlapsUnreplicatedRangeIDLocalKeys verifies that the function | ||
| // overlapsUnreplicatedRangeIDLocalKeys() successfully catches any overlap with | ||
| // unreplicated rangeID local keys. | ||
| func TestOverlapsUnreplicatedRangeIDLocalKeys(t *testing.T) { | ||
| defer leaktest.AfterTest(t)() | ||
| defer log.Scope(t).Close(t) | ||
|
|
||
| s := func(start, end roachpb.Key) roachpb.Span { | ||
| return roachpb.Span{Key: start, EndKey: end} | ||
| } | ||
|
|
||
| testCases := []struct { | ||
| span roachpb.Span | ||
| notOk bool | ||
| }{ | ||
| // Full spans not overlapping with unreplicated local RangeID spans. | ||
| {span: s(roachpb.KeyMin, keys.LocalRangeIDPrefix.AsRawKey())}, | ||
| {span: s(keys.RangeForceFlushKey(1), keys.RangeLeaseKey(1))}, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can add a "typical" one here: a full replicated span (which includes both ForceFlush and RangeLease keys). |
||
| {span: s(keys.LocalRangeIDPrefix.AsRawKey().PrefixEnd(), roachpb.KeyMax)}, | ||
|
|
||
| // Full spans overlapping with unreplicated local RangeID spans. | ||
| {span: s(roachpb.KeyMin, keys.RaftTruncatedStateKey(1)), notOk: true}, | ||
| {span: s(keys.LocalRangeIDPrefix.AsRawKey(), keys.LocalRangeIDPrefix.AsRawKey().PrefixEnd()), | ||
| notOk: true}, | ||
| {span: s(keys.RaftTruncatedStateKey(1), keys.RaftTruncatedStateKey(2)), notOk: true}, | ||
| {span: s(keys.RaftTruncatedStateKey(1), roachpb.KeyMax), notOk: true}, | ||
|
|
||
| // Point spans not overlapping with unreplicated local RangeID spans. | ||
| {span: s(roachpb.KeyMin, nil)}, | ||
| {span: s(keys.LocalRangeIDPrefix.AsRawKey().Prevish(1), nil)}, | ||
| {span: s(keys.RangeForceFlushKey(1), nil)}, | ||
| {span: s(keys.LocalRangeIDPrefix.AsRawKey().PrefixEnd(), nil)}, | ||
| {span: s(roachpb.KeyMax, nil)}, | ||
|
|
||
| // Point spans overlapping with unreplicated local RangeID spans. | ||
| {span: s(keys.RangeTombstoneKey(1), nil), notOk: true}, | ||
| {span: s(keys.RaftTruncatedStateKey(1), nil), notOk: true}, | ||
| {span: s(keys.RaftTruncatedStateKey(2), nil), notOk: true}, | ||
|
|
||
| // Tricky spans not overlapping with unreplicated local RangeID spans. | ||
| {span: s(nil, keys.LocalRangeIDPrefix.AsRawKey())}, | ||
| {span: s(nil, keys.RangeForceFlushKey(1))}, | ||
| {span: s(nil, keys.LocalRangeIDPrefix.AsRawKey().PrefixEnd().Next())}, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can add one without |
||
|
|
||
| // Tricky spans overlapping with unreplicated local RangeID spans. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A couple of corner cases would be good: for the beginning and ending of the unreplicated span. Applies to a few blocks here. Could be convenient to pre-compute a couple of r1Unrepl := roachpb.Span{...}
{span: s(r1Unrepl.Key.Prev(), nil)},
{span: s(r1Unrepl.EndKey, nil)},
{span: s(nil, r1Unrepl.EndKey), notOk: true},
// etc |
||
| {span: s(nil, keys.RangeTombstoneKey(1).Next()), notOk: true}, | ||
| {span: s(nil, keys.RaftTruncatedStateKey(1).Next()), notOk: true}, | ||
| {span: s(nil, keys.RaftTruncatedStateKey(2).Next()), notOk: true}, | ||
| } | ||
|
|
||
| for _, tc := range testCases { | ||
| t.Run("", func(t *testing.T) { | ||
| err := overlapsUnreplicatedRangeIDLocalKeys(spanset.TrickySpan(tc.span)) | ||
| if tc.notOk { | ||
| require.Errorf(t, err, "expected error for span %s", tc.span) | ||
| } else { | ||
| require.NoErrorf(t, err, "expected no error for span %s", tc.span) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // TestOverlapsStoreLocalKeys verifies that the function | ||
| // overlapsStoreLocalKeys() successfully catches any overlap with | ||
| // store local keys. | ||
| func TestOverlapsStoreLocalKeys(t *testing.T) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice, thanks a lot for the clean up! Was able to review this test in a minute and spot an edge case to add. |
||
| defer leaktest.AfterTest(t)() | ||
| defer log.Scope(t).Close(t) | ||
|
|
||
| s := func(start, end roachpb.Key) roachpb.Span { | ||
| return roachpb.Span{Key: start, EndKey: end} | ||
| } | ||
|
|
||
| testCases := []struct { | ||
| span roachpb.Span | ||
| notOK bool | ||
| }{ | ||
| // Full spans not overlapping with Store-local span. | ||
| {span: s(roachpb.KeyMin, keys.LocalStorePrefix)}, | ||
| {span: s(keys.LocalStoreMax, roachpb.KeyMax)}, | ||
|
|
||
| // Full spans overlapping with Store-local span. | ||
| {span: s(roachpb.KeyMin, roachpb.Key(keys.LocalStorePrefix).Next()), notOK: true}, | ||
| {span: s(keys.LocalStorePrefix, keys.LocalStoreMax), notOK: true}, | ||
| {span: s(keys.StoreGossipKey(), keys.StoreIdentKey()), notOK: true}, | ||
| {span: s(keys.LocalStoreMax.Prevish(1), roachpb.KeyMax), notOK: true}, | ||
|
|
||
| // Point spans not overlapping with Store-local span. | ||
| {span: s(roachpb.KeyMin, nil)}, | ||
| {span: s(roachpb.Key(keys.LocalStorePrefix).Prevish(1), nil)}, | ||
| {span: s(keys.LocalStoreMax.Next(), nil)}, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add |
||
| {span: s(roachpb.KeyMax, nil)}, | ||
|
|
||
| // Point spans overlapping with Store-local span. | ||
| {span: s(keys.LocalStorePrefix, nil), notOK: true}, | ||
| {span: s(keys.StoreGossipKey(), nil), notOK: true}, | ||
| {span: s(keys.LocalStoreMax.Prevish(1), nil), notOK: true}, | ||
|
|
||
| // Tricky spans with nil StartKey not overlapping with Store-local span. | ||
| {span: s(nil, keys.LocalStorePrefix)}, | ||
| {span: s(nil, keys.LocalStoreMax.Next())}, | ||
|
|
||
| // Tricky spans with nil StartKey overlapping with Store-local span. | ||
| {span: s(nil, roachpb.Key(keys.LocalStorePrefix).Next()), notOK: true}, | ||
| {span: s(nil, keys.StoreGossipKey()), notOK: true}, | ||
| {span: s(nil, keys.LocalStoreMax), notOK: true}, | ||
| } | ||
|
|
||
| for _, tc := range testCases { | ||
| t.Run("", func(t *testing.T) { | ||
| err := overlapsStoreLocalKeys(spanset.TrickySpan(tc.span)) | ||
| if tc.notOK { | ||
| require.Errorf(t, err, "expected error for span %s", tc.span) | ||
| } else { | ||
| require.NoErrorf(t, err, "expected no error for span %s", tc.span) | ||
| } | ||
|
Comment on lines
+15312
to
+15316
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optional (2 patterns too): require.Equal(t, tc.notOk, err != nil, tc.span)Same above. |
||
| }) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can return without checking:
Pretty sure
DecodeUvarintalready returns zero on error (it's conventional, so we can do it transitively), but even if not, no big deal.