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

decider: ignore EnsureSafeSplitKey on error #43078

Merged
merged 1 commit into from
Dec 10, 2019
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
14 changes: 10 additions & 4 deletions pkg/storage/split/decider.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,16 @@ func (d *Decider) MaybeSplitKey(now time.Time) roachpb.Key {
//
// We take the risk that the result may sometimes not be a good split
// point (or even in this range).
var err error
key, err = keys.EnsureSafeSplitKey(d.mu.splitFinder.Key())
if err != nil {
key = nil
//
// Note that we ignore EnsureSafeSplitKey when it returns an error since
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get it - the comment above says that we don't want to allow mid-row splits and that SQL even crashes.. If this changed we should update that comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, or we know for sure that in the error case the key is "in-between" rows? Seems like we should fix EnsureSafeSplitKey to not return an error at all, or at least explain this in its comment

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL sort of forces us to avoid mid-column family splits and we can't do so because you can't tell the column family suffix if you don't know the SQL schema. Also SQL issues plenty of scans that don't have the column family in the start key, so that's what the split finder sees. So when it sees a key that doesn't look like a SQL key, it has to assume that it doesn't cut columns in half, or it couldn't split most of the time (as we saw in the test this commit fixes). This probably holds but if you issued unfortunate batch requests you can definitely trick it into still splitting between col families.

I'm pretty unhappy about the situation in here and it seems reasonable to make SQL resilient to col families being split between ranges, not because I love that, but because I don't see any other way 😞

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bleah. I would put these details in an issue and mention the issue in the comment.

// that error only tells us that this key couldn't possibly be a SQL
// key. This is more common than one might think since SQL issues plenty
// of scans over all column families, meaning that we'll frequently find
// a key that has no column family suffix and thus errors out in
// EnsureSafeSplitKey.
key = d.mu.splitFinder.Key()
if safeKey, err := keys.EnsureSafeSplitKey(key); err == nil {
key = safeKey
}
}
d.mu.Unlock()
Expand Down
38 changes: 38 additions & 0 deletions pkg/storage/split/decider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package split

import (
"math"
"math/rand"
"testing"
"time"
Expand Down Expand Up @@ -206,3 +207,40 @@ func TestDeciderCallsEnsureSafeSplitKey(t *testing.T) {

require.Equal(t, expK, k)
}

func TestDeciderIgnoresEnsureSafeSplitKeyOnError(t *testing.T) {
defer leaktest.AfterTest(t)()
intn := rand.New(rand.NewSource(11)).Intn

var d Decider
Init(&d, intn, func() float64 { return 1.0 })

baseKey := keys.MakeTablePrefix(51)
for i := 0; i < 4; i++ {
baseKey = encoding.EncodeUvarintAscending(baseKey, uint64(52+i))
}
c0 := func() roachpb.Span {
return roachpb.Span{Key: append([]byte(nil), encoding.EncodeUvarintAscending(baseKey, math.MaxInt32+1)...)}
}
c1 := func() roachpb.Span {
return roachpb.Span{Key: append([]byte(nil), encoding.EncodeUvarintAscending(baseKey, math.MaxInt32+2)...)}
}

_, err := keys.EnsureSafeSplitKey(c1().Key)
require.Error(t, err)

var k roachpb.Key
var now time.Time
for i := 0; i < 2*int(minSplitSuggestionInterval/time.Second); i++ {
now = now.Add(500 * time.Millisecond)
d.Record(now, 1, c0)
now = now.Add(500 * time.Millisecond)
d.Record(now, 1, c1)
k = d.MaybeSplitKey(now)
if len(k) != 0 {
break
}
}

require.Equal(t, c1().Key, k)
}