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

keys: Clean up MakeRowSentinelKey and EnsureSafeSplitKey #16344

Closed
bdarnell opened this issue Jun 5, 2017 · 6 comments
Closed

keys: Clean up MakeRowSentinelKey and EnsureSafeSplitKey #16344

bdarnell opened this issue Jun 5, 2017 · 6 comments
Assignees
Milestone

Comments

@bdarnell
Copy link
Contributor

bdarnell commented Jun 5, 2017

Our mechanisms for avoiding splits in the middle of a row are a bit of a mess (see #16008 (comment)). AdminSplit does not split at the requested key: if the key points to the /Table keyspace then it removes a trailing integer from the key which is assumed to be the column family ID. This is fine when splitting at a key that actually exists (which is true for all size-based splits), but it is difficult to synthesize keys that work correctly in this model (e.g. at table boundaries).

We currently use MakeRowSentinelKey to add a dummy column family ID with a value of 0 (in config.go and restore.go), but this is not really correct. It works OK in config.go where it applies at the table level (and the added zero sorts before all the index IDs that are the normal inhabitants of this level), but in restore.go this zero is intermingled with actual row data, and it sorts higher than any negative values that may be stored in the primary key (assuming an integer PK).

We should fix this by making AdminSplit act on the requested key as given. The key selection process is responsible for choosing a key that is not in the middle of a row. That is, MVCCFindSplitKey and the SQL SPLIT AT command should remove the column family ID from the keys that they use, and splits at the boundaries of tables and indexes should not add them.

Compatibility notes: Splits performed by the split queue are always executed on the same node that selects the keys, so the split queue is safe in mixed-version environments as this change rolls out. The SPLIT AT and RESTORE commands execute splits remotely, which requires some care (or a warning in the release notes that these commands may not be used during a rolling upgrade).

@bdarnell bdarnell added this to the 1.1 milestone Jun 5, 2017
benesch added a commit to benesch/cockroach that referenced this issue Jun 7, 2017
This is a quick fix; cockroachdb#16344 is tracking the longer-term cleanup.

In short, `AdminSplit` does not actually split at the requested key, but
rather runs the key through `keys.EnsureSafeSplitKey` first. This means
that whoever calls `AdminSplit` with a table key needs to adjust the
split key to account for `EnsureSafeSplitKey`'s modification by running
the key through `keys.MakeRowSentinelKey`. When using row keys like
`/Table/51/` or `/Table/51/1`, this is perfectly safe. In RESTORE,
though, we call `MakeRowSentinelKey` on longer keys, like
`/Table/51/1/0`. This can create a key in a *different* range, because
e.g. negative primary keys may have caused a split at `/Table/51/1/-10`,
so the request gets routed to the wrong range even though
`EnsureSafeSplitKey` would have selected the right key had the request
been routed to the right range. See cockroachdb#16008 for a more detailed
explanation.

This commit solves the issue by adjusting `AdminSplit` to take both a
"span key" and a "split key". The span key is used to route the request
to the right range, while the split key contains the
`MakeRowSentinelKey` modifications that will be undone by
`MakeRowSentinelKey` on the receiver.

Fixes cockroachdb#16008.
benesch added a commit to benesch/cockroach that referenced this issue Jun 7, 2017
This is a quick fix; cockroachdb#16344 is tracking the longer-term cleanup.

In short, `AdminSplit` does not actually split at the requested key, but
rather runs the key through `keys.EnsureSafeSplitKey` first. This means
that whoever calls `AdminSplit` with a table key needs to adjust the
split key to account for `EnsureSafeSplitKey`'s modification by running
the key through `keys.MakeRowSentinelKey`. When using row keys like
`/Table/51/` or `/Table/51/1`, this is perfectly safe. In RESTORE,
though, we call `MakeRowSentinelKey` on longer keys, like
`/Table/51/1/0`. This can create a key in a *different* range, because
e.g. negative primary keys may have caused a split at `/Table/51/1/-10`,
so the request gets routed to the wrong range even though
`EnsureSafeSplitKey` would have selected the right key had the request
been routed to the right range. See cockroachdb#16008 for a more detailed
explanation.

This commit solves the issue by adjusting `AdminSplit` to take both a
"span key" and a "split key". The span key is used to route the request
to the right range, while the split key contains the
`MakeRowSentinelKey` modifications that will be undone by
`MakeRowSentinelKey` on the receiver.

Fixes cockroachdb#16008.
@a6802739
Copy link
Contributor

@bdarnell Maybe I could have a try for this.

@bdarnell
Copy link
Contributor Author

@a6802739 Go ahead!

@a6802739
Copy link
Contributor

@bdarnell, So we need to cleanup the usage of MakeRowSentinelKey?

I have a confusion here, after we call MakeRowSentinelKey for the splitKey, EnsureSafeSplitKey guarantee remove the family ID, so why should we need to remove the usage of MakeRowSentinelKey ?

@bdarnell
Copy link
Contributor Author

The problem is that the way we're using EnsureSafeSplitKey, it removes something, but it's not always the family ID. We want to get rid of most uses of both of these functions. I think what we want to do is remove the calls to MakeRowSentinelKey from config.go and restore.go and the call to EnsureSafeSplitKey in AdminSplit. MVCCFindSplitKey should call both MakeRowSentinelKey and EnsureSafeSplitKey to get a valid split key, and the SQL SPLIT AT statement also needs to do call EnsureSafeSplitKey (I think. I'm less familiar with this code).

@a6802739
Copy link
Contributor

@bdarnell So MVCCFindSplitKey should call EnsureSafeSplitKey to get the row key(removed family ID) and use MakeRowSentinelKey to get the RowSentinelKey(add family ID 0 in the tail)?

@bdarnell
Copy link
Contributor Author

I said earlier that MVCCFindSplitKey should do both, but now I think that was a mistake. MVCCFindSplitKey should only call EnsureSafeSplitKey to remove the family ID from the key on disk.

tbg added a commit to tbg/cockroach that referenced this issue Nov 29, 2019
We could end up splitting between column families of the same row,
which is illegal. Unfortunately the KV layer has to uphold invariants
here that it doesn't quite have introspection into, but after this
commit it hopefully stops breaking them.

See cockroachdb#16344 for some
additional history.

Possibly the solution for cockroachdb#39794.
Possibly the solution for cockroachdb#36834.
Possibly the solution for cockroachdb#36356.

(Intentionally not closing the above; leaving that to the SQL folks).

Closes cockroachdb#42056 (which is the go-to for reading up on this issue).

Release note (bug fix): prevent a number of panics from the SQL layer
caused by an invalid range split. These would usually manifest with
messages mentioning encoding errors ("found null on not null column" but
also possibly various others).
tbg added a commit to tbg/cockroach that referenced this issue Dec 2, 2019
We could end up splitting between column families of the same row,
which is illegal. Unfortunately the KV layer has to uphold invariants
here that it doesn't quite have introspection into, but after this
commit it hopefully stops breaking them.

See cockroachdb#16344 for some
additional history.

Possibly the solution for cockroachdb#39794.
Possibly the solution for cockroachdb#36834.
Possibly the solution for cockroachdb#36356.

(Intentionally not closing the above; leaving that to the SQL folks).

Closes cockroachdb#42056 (which is the go-to for reading up on this issue).

Release note (bug fix): prevent a number of panics from the SQL layer
caused by an invalid range split. These would usually manifest with
messages mentioning encoding errors ("found null on not null column" but
also possibly various others).
craig bot pushed a commit that referenced this issue Dec 2, 2019
42833: storage: call EnsureSafeSplitKey during load-based splits r=bdarnell a=tbg

We could end up splitting between column families of the same row,
which is illegal. Unfortunately the KV layer has to uphold invariants
here that it doesn't quite have introspection into, but after this
commit it hopefully stops breaking them.

See #16344 for some
additional history.

Possibly the solution for #39794.
Possibly the solution for #36834.
Possibly the solution for #36356.

(Intentionally not closing the above; leaving that to the SQL folks).

Closes #42056 (which is the go-to for reading up on this issue).

Release note (bug fix): prevent a number of panics from the SQL layer
caused by an invalid range split. These would usually manifest with
messages mentioning encoding errors ("found null on not null column" but
also possibly various others).

Co-authored-by: Tobias Schottdorf <[email protected]>
tbg added a commit to tbg/cockroach that referenced this issue Dec 3, 2019
We could end up splitting between column families of the same row,
which is illegal. Unfortunately the KV layer has to uphold invariants
here that it doesn't quite have introspection into, but after this
commit it hopefully stops breaking them.

See cockroachdb#16344 for some
additional history.

Possibly the solution for cockroachdb#39794.
Possibly the solution for cockroachdb#36834.
Possibly the solution for cockroachdb#36356.

(Intentionally not closing the above; leaving that to the SQL folks).

Closes cockroachdb#42056 (which is the go-to for reading up on this issue).

Release note (bug fix): prevent a number of panics from the SQL layer
caused by an invalid range split. These would usually manifest with
messages mentioning encoding errors ("found null on not null column" but
also possibly various others).
nvanbenschoten added a commit to nvanbenschoten/cockroach that referenced this issue Jun 5, 2020
This argument was added in 9234460 as a fix for cockroachdb#16008 and a short-term
workaround for the cleanup in cockroachdb#16344. That cleanup was addressed in cockroachdb#16649,
which removed the one place where spanKey and splitKey diverged
(https://github.com/cockroachdb/cockroach/pull/16649/files#diff-6955fb0c3216b1d7d4292ccdf2e18dcf).
They have been identical in all uses of AdminSplit ever since.
nvanbenschoten added a commit to nvanbenschoten/cockroach that referenced this issue Jun 9, 2020
This argument was added in 9234460 as a fix for cockroachdb#16008 and a short-term
workaround for the cleanup in cockroachdb#16344. That cleanup was addressed in cockroachdb#16649,
which removed the one place where spanKey and splitKey diverged
(https://github.com/cockroachdb/cockroach/pull/16649/files#diff-6955fb0c3216b1d7d4292ccdf2e18dcf).
They have been identical in all uses of AdminSplit ever since.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants