Skip to content
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

storage: Splits get write locks on the entire span #14992

Merged
merged 1 commit into from
Apr 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions pkg/storage/replica_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,17 +563,20 @@ func declareKeysEndTransaction(

if et.InternalCommitTrigger != nil {
if st := et.InternalCommitTrigger.SplitTrigger; st != nil {
// Splits may read from the entire pre-split range and write to
// the right side's RangeID spans and abort cache.
// TODO(bdarnell): the only time we read from the right-hand
// side is when the existing stats contain estimates. We might
// be able to be smarter here and avoid declaring reads on RHS
// in most cases.
spans.Add(SpanReadOnly, roachpb.Span{
// Splits may read from the entire pre-split range (they read
// from the LHS in all cases, and the RHS only when the existing
// stats contain estimates), but they need to declare a write
// access to block all other concurrent writes. We block writes
// to the RHS because they will fail if applied after the split,
// and writes to the LHS because their stat deltas will
// interfere with the non-delta stats computed as a part of the
// split. (see
// https://github.com/cockroachdb/cockroach/issues/14881)
spans.Add(SpanReadWrite, roachpb.Span{
Key: st.LeftDesc.StartKey.AsRawKey(),
EndKey: st.RightDesc.EndKey.AsRawKey(),
})
spans.Add(SpanReadOnly, roachpb.Span{
spans.Add(SpanReadWrite, roachpb.Span{
Key: keys.MakeRangeKeyPrefix(st.LeftDesc.StartKey),
EndKey: keys.MakeRangeKeyPrefix(st.RightDesc.EndKey).PrefixEnd(),
})
Expand Down
33 changes: 33 additions & 0 deletions pkg/storage/replica_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,39 @@ func TestReplicaCommandQueueTimestampNonInterference(t *testing.T) {
}
}

// TestReplicaCommandQueueSplitDeclaresWrites verifies that split
// operations declare write access to their entire span. This is
// necessary to avoid conflicting changes to the range's stats, even
// though splits do not actually write to their data span (and
// therefore a failure to declare writes are not caught directly by
// any other test).
func TestReplicaCommandQueueSplitDeclaresWrites(t *testing.T) {
defer leaktest.AfterTest(t)()

var spans SpanSet
commands[roachpb.EndTransaction].DeclareKeys(
roachpb.RangeDescriptor{StartKey: roachpb.RKey("a"), EndKey: roachpb.RKey("d")},
roachpb.Header{},
&roachpb.EndTransactionRequest{
InternalCommitTrigger: &roachpb.InternalCommitTrigger{
SplitTrigger: &roachpb.SplitTrigger{
LeftDesc: roachpb.RangeDescriptor{
StartKey: roachpb.RKey("a"),
EndKey: roachpb.RKey("c"),
},
RightDesc: roachpb.RangeDescriptor{
StartKey: roachpb.RKey("c"),
EndKey: roachpb.RKey("d"),
},
},
},
},
&spans)
if err := spans.checkAllowed(SpanReadWrite, roachpb.Span{Key: roachpb.Key("b")}); err != nil {
t.Fatalf("expected declaration of write access, err=%s", err)
}
}

func SendWrapped(
ctx context.Context, sender client.Sender, header roachpb.Header, args roachpb.Request,
) (roachpb.Response, roachpb.BatchResponse_Header, *roachpb.Error) {
Expand Down