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

sql: add ALTER TABLE/INDEX .. UNSPLIT AT .. #37603

Merged
merged 1 commit into from
May 23, 2019

Conversation

jeffrey-xiao
Copy link
Contributor

Now that manual splits add a sticky bit to the range descriptor, and
the merge queue respects this sticky bit, we can expose functionality to
manually unset this sticky bit.

If the key to unsplit is not the start of a range, then the unsplit
command will throw an error. If the range was manually split (I.E. the
sticky bit is set), then the sticky bit will be unset. Otherwise, this
command is a no-op.

Syntactically, the unsplit command is identical to the split command.

Release note: None

@cockroach-teamcity
Copy link
Member

This change is Reviewable

@jeffrey-xiao jeffrey-xiao marked this pull request as ready for review May 20, 2019 19:04
@jeffrey-xiao jeffrey-xiao requested review from a team May 20, 2019 19:04
@jeffrey-xiao jeffrey-xiao changed the title sql: add ALTER TABLE/INDEX ... UNSPLIT AT command sql: add ALTER TABLE/INDEX .. UNSPLIT AT .. May 20, 2019
Copy link
Contributor

@ajwerner ajwerner left a comment

Choose a reason for hiding this comment

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

Reviewed 26 of 27 files at r1.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @jeffrey-xiao, and @nvanbenschoten)


pkg/sql/unsplit.go, line 115 at r1 (raw file):

	if err := params.extendedEvalCtx.ExecCfg.DB.AdminUnsplit(params.ctx, rowKey); err != nil {
		return false, err

Do we need to do any special error mapping here? Is it okay to just propagate the error directly? This isn't a question to which I know the answer.


pkg/sql/unsplit_test.go, line 96 at r1 (raw file):

		{
			in:    "ALTER TABLE d.t UNSPLIT AT VALUES (1, 'non-existent')",
			error: "unsplit key is not the start of a range",

This is the error case I'm worried about. I mean worst case is that it's just an XX00 SQL error but is that desirable?

Copy link
Contributor

@ajwerner ajwerner left a comment

Choose a reason for hiding this comment

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

Reviewed 1 of 27 files at r1.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @jeffrey-xiao and @nvanbenschoten)

Copy link
Member

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

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

Reviewed 26 of 27 files at r1.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @jeffrey-xiao)


pkg/internal/client/db.go, line 484 at r1 (raw file):

// AdminUnsplit removes the sticky bit of the range specified by splitKey.
//
// spanKey is the start key of the range whose sticky bit should be removed.

Comment about what happens if the sticky bit doesn't exist. Also, talk about what happens if the provided key is not the start key of the range.


pkg/roachpb/api.proto, line 672 at r1 (raw file):

}

Extra line.


pkg/sql/unsplit.go, line 101 at r1 (raw file):

func (n *unsplitNode) startExec(params runParams) error {
	return nil

We'll need to check the cluster version to see if VersionStickyBit is active. If not, we'll want to reject the statement.


pkg/sql/unsplit.go, line 124 at r1 (raw file):

func (n *unsplitNode) Values() tree.Datums {
	return tree.Datums{

I'm curious whether you think this is what a user will be interested in as the result of an UNSPLIT AT statement. Should we return the split point that we removed? The new start of the range? A boolean saying whether the split point was removed or not? I haven't thought much into the desired UX here. Having written this all up and used it in a few tests, do you have any thoughts about this?


pkg/sql/unsplit_test.go, line 64 at r1 (raw file):

	}

	tests := []struct {

Nice tests!

There are a few other logic_tests that we'll want to add as well. To start, I think we'll want to add some basic tests to alter_table. Next, we'll want to expand on the crdb_internal tests that we added last time. Finally, the ranges test seems like an appropriate place to add some higher-level functional tests.


pkg/storage/client_merge_test.go, line 3434 at r1 (raw file):

		verifyUnmerged(t)

		// TODO(jeffreyxiao): Use same mechanism as ALTER TABLE ... UNSPLIT AT

Very satisfying.


pkg/storage/replica_command.go, line 384 at r1 (raw file):

// AdminUnsplit removes the sticky bit of the range specified by the
// splitKey

s/splitKey/args.Key/ right?

Also, period at the end.


pkg/storage/replica_command.go, line 385 at r1 (raw file):

// AdminUnsplit removes the sticky bit of the range specified by the
// splitKey
func (r *Replica) AdminUnsplit(

For now, this is probably fine, but at some point we'll probably need a retry loop like we have for AdminSplit.


pkg/storage/replica_command.go, line 403 at r1 (raw file):

	if err := r.store.DB().Txn(ctx, func(ctx context.Context, txn *client.Txn) error {
		b := txn.NewBatch()
		desc := *r.Desc()

We already have a desc in scope, so no need to shadow it.


pkg/storage/replica_command.go, line 419 at r1 (raw file):

			InternalCommitTrigger: &roachpb.InternalCommitTrigger{
				StickyBitTrigger: &roachpb.StickyBitTrigger{
					StickyBit: nil,

Leave a comment noting that this removes the sticky bit. It's always a little strange seeing a field set to nil in a constructor.

Copy link
Contributor Author

@jeffrey-xiao jeffrey-xiao left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @jeffrey-xiao, and @nvanbenschoten)


pkg/sql/unsplit.go, line 115 at r1 (raw file):

Previously, ajwerner wrote…

Do we need to do any special error mapping here? Is it okay to just propagate the error directly? This isn't a question to which I know the answer.

I've now wrapped it in a pgerror.CodeDataExceptionError.


pkg/sql/unsplit.go, line 124 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

I'm curious whether you think this is what a user will be interested in as the result of an UNSPLIT AT statement. Should we return the split point that we removed? The new start of the range? A boolean saying whether the split point was removed or not? I haven't thought much into the desired UX here. Having written this all up and used it in a few tests, do you have any thoughts about this?

I think returning the split point we removed makes sense and it's symmetric with that we return with an SPLIT AT statement (even in the no-op case the unsplit/split key is returned). The new start of the range is misleading because it's not guaranteed that unsplitting the range will result in the range being merged.


pkg/sql/unsplit_test.go, line 96 at r1 (raw file):

Previously, ajwerner wrote…

This is the error case I'm worried about. I mean worst case is that it's just an XX00 SQL error but is that desirable?

I've now wrapped it in a pgerror.CodeDataExceptionError.


pkg/storage/client_merge_test.go, line 3434 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Very satisfying.

:)

Copy link
Member

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

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

Reviewed 1 of 2 files at r2, 7 of 7 files at r3.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner and @jeffrey-xiao)


pkg/internal/client/db.go, line 486 at r3 (raw file):

// splitKey is the start key of the range whose sticky bit should be removed.
//
// If spanKey is not the start key of a range, then this method will throw an

"If splitKey"


pkg/sql/unsplit.go, line 124 at r1 (raw file):

Previously, jeffrey-xiao (Jeffrey Xiao) wrote…

I think returning the split point we removed makes sense and it's symmetric with that we return with an SPLIT AT statement (even in the no-op case the unsplit/split key is returned). The new start of the range is misleading because it's not guaranteed that unsplitting the range will result in the range being merged.

Ok, that all sounds reasonable.


pkg/storage/replica_command.go, line 392 at r3 (raw file):

	desc := *r.Desc()
	if !bytes.Equal(desc.StartKey.AsRawKey(), args.Header().Key) {
		return reply, roachpb.NewError(fmt.Errorf("key is not the start of a range"))

Why did this change?


pkg/storage/replica_command.go, line 425 at r3 (raw file):

		return txn.Run(ctx, b)
	}); err != nil {
		return reply, roachpb.NewError(errors.Wrapf(err, "unsplit at key %s failed", args.Key))

Does NewErrorf not work here?

Copy link
Contributor Author

@jeffrey-xiao jeffrey-xiao left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @jeffrey-xiao, and @nvanbenschoten)


pkg/storage/replica_command.go, line 392 at r3 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Why did this change?

Originally, I wanted it not to print the file and line number, but since that's fine, I've changed it back.


pkg/storage/replica_command.go, line 425 at r3 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Does NewErrorf not work here?

I'm wrapping another error and it doesn't seem like roachpb has a Wrapf.

Copy link
Contributor

@ajwerner ajwerner left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewed 2 of 2 files at r4.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @jeffrey-xiao and @nvanbenschoten)


pkg/storage/replica_command.go, line 425 at r3 (raw file):

Previously, jeffrey-xiao (Jeffrey Xiao) wrote…

I'm wrapping another error and it doesn't seem like roachpb has a Wrapf.

This roachpb.NewError is going to serialize the error to a string so the wrapping for use with Cause doesn't matter.

@jeffrey-xiao jeffrey-xiao force-pushed the sql-unsplit branch 2 times, most recently from 0d131b9 to b858290 Compare May 23, 2019 15:46
Copy link
Contributor Author

@jeffrey-xiao jeffrey-xiao left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @ajwerner, @jeffrey-xiao, and @nvanbenschoten)


pkg/storage/replica_command.go, line 425 at r3 (raw file):

Previously, ajwerner wrote…

This roachpb.NewError is going to serialize the error to a string so the wrapping for use with Cause doesn't matter.

I see, I've changed it to a NewErrorf.

@jeffrey-xiao jeffrey-xiao force-pushed the sql-unsplit branch 2 times, most recently from c6bade0 to 802550f Compare May 23, 2019 17:53
Now that manual splits add a sticky bit to the range descriptor, and
the merge queue respects this sticky bit, we can expose functionality to
manually unset this sticky bit.

If the key to unsplit is not the start of a range, then the unsplit
command will throw an error. If the range was manually split (I.E. the
sticky bit is set), then the sticky bit will be unset. Otherwise, this
command is a no-op.

Syntactically, the unsplit command is identical to the split command.

Release note (sql change): Add ALTER TABLE/INDEX .. UNSPLIT AT ..
Copy link
Contributor Author

@jeffrey-xiao jeffrey-xiao left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @ajwerner and @nvanbenschoten)


pkg/sql/unsplit_test.go, line 64 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Nice tests!

There are a few other logic_tests that we'll want to add as well. To start, I think we'll want to add some basic tests to alter_table. Next, we'll want to expand on the crdb_internal tests that we added last time. Finally, the ranges test seems like an appropriate place to add some higher-level functional tests.

I can't add tests to ranges until manual_split_time is added to SHOW EXPERIMENTAL_RANGES, but I can do this in a follow-up PR.


pkg/storage/replica_command.go, line 385 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

For now, this is probably fine, but at some point we'll probably need a retry loop like we have for AdminSplit.

Left a TODO

Copy link
Member

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewed 1 of 2 files at r5, 8 of 8 files at r6.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (and 1 stale) (waiting on @nvanbenschoten)

@jeffrey-xiao
Copy link
Contributor Author

bors r+

@craig
Copy link
Contributor

craig bot commented May 23, 2019

Build failed (retrying...)

craig bot pushed a commit that referenced this pull request May 23, 2019
37492: roachprod: create geo-distributed clusters with extra nodes placed at the end r=nvanbenschoten a=ajwerner

roachprod: create geo-distributed clusters with extra nodes placed at the end                                                                                                                                      
                                                                                                                                                                                                                   
Prior to this change, roachprod would create geo-distributed clusters by                                                                                                                                           
placing nodes in AZs in contiguous chunks. If the number of total nodes                                                                                                                                            
was not evenly divisible by the number of regions, the first regions                                                                                                                                               
would be allocated one additional node. This allocation pattern is                                                                                                                                                 
rarely desirable. A user will commonly allocate a single extra node as a                                                                                                                                           
load generator and would generally like that load node to be the final                                                                                                                                             
node and for that final node to be the extra node.                                                                                                                                                                 
                                                                                                                                                                                                                   
This changes the allocation where the extra nodes are placed in the same                                                                                                                                           
regions as before but are given node indices at the end rather than with                                                                                                                                           
the other nodes in their region.                                                                                                                                                                                   
                                                                                                                                                                                                                   
After this change a cluster created with `roachprod create $CLUSTER -n 7 --geo`                                                                                                                                    
will look like:                                                                                                                                                                                                    
                                                                                                                                                                                                                   
```                                                                                                                                                                                                                
ajwerner-test-roachprod-gce: [gce] 12h47m58s remaining                                                                                                                                                             
  ajwerner-test-roachprod-gce-0001      ajwerner-test-roachprod-gce-0001.us-east1-b.cockroach-ephemeral 10.142.0.70      34.74.58.108                                                                              
  ajwerner-test-roachprod-gce-0002      ajwerner-test-roachprod-gce-0002.us-east1-b.cockroach-ephemeral 10.142.0.5       35.237.74.155                                                                             
  ajwerner-test-roachprod-gce-0003      ajwerner-test-roachprod-gce-0003.us-west1-b.cockroach-ephemeral 10.138.0.99      35.199.159.104                                                                            
  ajwerner-test-roachprod-gce-0004      ajwerner-test-roachprod-gce-0004.us-west1-b.cockroach-ephemeral 10.138.0.100     35.197.94.83                                                                              
  ajwerner-test-roachprod-gce-0005      ajwerner-test-roachprod-gce-0005.europe-west2-b.cockroach-ephemeral      10.154.15.237   35.230.143.190                                                                    
  ajwerner-test-roachprod-gce-0006      ajwerner-test-roachprod-gce-0006.europe-west2-b.cockroach-ephemeral      10.154.15.236   35.234.156.121                                                                    
  ajwerner-test-roachprod-gce-0007      ajwerner-test-roachprod-gce-0007.us-east1-b.cockroach-ephemeral 10.142.0.33      35.185.62.76                                                                              
```                                                                                                                                                                                                                
                                                                                                                                                                                                                   
Instead of the previous:                                                                                                                                                                                           
                                                                                                                                                                                                                   
```                                                                                                                                                                                                                
ajwerner-test-old: [gce] 12h19m21s remaining                                                                                                                                                                       
  ajwerner-test-old-0001        ajwerner-test-old-0001.us-east1-b.cockroach-ephemeral   10.142.0.139    34.74.150.216                                                                                              
  ajwerner-test-old-0002        ajwerner-test-old-0002.us-east1-b.cockroach-ephemeral   10.142.0.140    34.73.154.246                                                                                              
  ajwerner-test-old-0003        ajwerner-test-old-0003.us-east1-b.cockroach-ephemeral   10.142.0.141    35.243.176.131                                                                                             
  ajwerner-test-old-0004        ajwerner-test-old-0004.us-west1-b.cockroach-ephemeral   10.138.0.71     34.83.16.1                                                                                                 
  ajwerner-test-old-0005        ajwerner-test-old-0005.us-west1-b.cockroach-ephemeral   10.138.0.60     34.83.78.172                                                                                               
  ajwerner-test-old-0006        ajwerner-test-old-0006.europe-west2-b.cockroach-ephemeral       10.154.15.200    35.234.148.191                                                                                    
  ajwerner-test-old-0007        ajwerner-test-old-0007.europe-west2-b.cockroach-ephemeral       10.154.15.199    35.242.179.144                                                                                    
```                  
Fixes #35866.

Release note: None


37603: sql: add ALTER TABLE/INDEX .. UNSPLIT AT .. r=jeffrey-xiao a=jeffrey-xiao

Now that manual splits add a sticky bit to the range descriptor, and
the merge queue respects this sticky bit, we can expose functionality to
manually unset this sticky bit.

If the key to unsplit is not the start of a range, then the unsplit
command will throw an error. If the range was manually split (I.E. the
sticky bit is set), then the sticky bit will be unset. Otherwise, this
command is a no-op.

Syntactically, the unsplit command is identical to the split command.

Release note: None

Co-authored-by: Andrew Werner <[email protected]>
Co-authored-by: Jeffrey Xiao <[email protected]>
@craig
Copy link
Contributor

craig bot commented May 23, 2019

Build succeeded

@craig craig bot merged commit d68329f into cockroachdb:master May 23, 2019
@jeffrey-xiao jeffrey-xiao deleted the sql-unsplit branch June 19, 2019 19:29
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

Successfully merging this pull request may close these issues.

4 participants