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: expose mvcc timestamps to SQL #51494

Merged
merged 2 commits into from
Jul 21, 2020
Merged

Conversation

rohany
Copy link
Contributor

@rohany rohany commented Jul 16, 2020

Fixes #50102.

This PR adds introspection into the KV layer's concurrency control from
the SQL level. In particular, we now expose the MVCC HLC timestamp of a
row as a special system column on every table. This system column is
exposed as a decimal, and is computed as wall time * 10^10 + logical time.

To accomplish this, this PR adds planning and execution infrastructure
for implicit system columns that can be produced by the execution layer
for a particular row.

Release note (sql change): Expose the MVCC timestamp of each row as a
system column on tables. This column is named
crdb_internal_mvcc_timestamp and is accessible only in a limited set
of contexts.

@cockroach-teamcity
Copy link
Member

This change is Reviewable

@rohany rohany force-pushed the mvcc-col-again branch 2 times, most recently from 2750048 to 842cb0f Compare July 16, 2020 14:33
statement error pq: INSERT has more expressions than target columns, 4 expressions for 3 targets
INSERT INTO t VALUES (7, 8, 9, 1.0)

# TODO (rohany): I'm not sure how to disable returning the system columns. The way
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll need some pointers here.

└── scan · ·
· table t@primary
· spans FULL SCAN
· distribution local
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure why these changed, my changes shouldn't have affected the plans like this. Though the plan does seem reasonable since the in is a tautology?

// primary index. These columns are implicit and should not be part of the set
// of fetch columns, so we remove them here.
table := tabMeta.Table
for i := 0; i < table.ColumnCount(); i++ {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because of the API change, there isn't an easy way to iterate over only the system columns of a table. I'm not sure that is a big deal though.

@rohany rohany force-pushed the mvcc-col-again branch 2 times, most recently from 45f39c2 to d77df5d Compare July 16, 2020 17:25
@rohany
Copy link
Contributor Author

rohany commented Jul 16, 2020

cc @RaduBerinde @andy-kimball

I've updated this to be on top of radu's changes. I've omitted the commit on top of this that adds the system column to the test catalog and updates the various opt tests. I went through all uses of ColumnCount and made a decision about whether to include the system column or not. I'll need some double checking about whether those decisions were correct + how to write tests that tickle those specific pieces of code.

Copy link
Member

@RaduBerinde RaduBerinde left a comment

Choose a reason for hiding this comment

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

Thanks! Some initial comments about cat

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rohany)


pkg/sql/opt/cat/column.go, line 32 at r2 (raw file):

	DeleteOnly
	// SystemColumn columns are implicit columns that every physical table
	// contains. These columns can only be read from and must not be included

Add that they cannot be part of the key cols / lax key cols for indexes.


pkg/sql/opt/cat/column.go, line 33 at r2 (raw file):

	// SystemColumn columns are implicit columns that every physical table
	// contains. These columns can only be read from and must not be included
	// as part of mutations. These columns are synthesized entirely within the

"synthesized entirely within the optimizer" is confusing. They are synthesized in the catalog implementation, not the optimizer (and their values are also synthesized outside the optimizer). I would just keep this detail out, it's not relevant to comprehending the interface.


pkg/sql/opt/cat/column.go, line 35 at r2 (raw file):

	// as part of mutations. These columns are synthesized entirely within the
	// optimizer and are not part of the persisted table definition.
	SystemColumn

[nit] the other enums don't have Column. I'd keep just as System even if it's kind of generic


pkg/sql/opt/cat/index.go, line 58 at r2 (raw file):

	// excludes any system columns. These columns shouldn't be considered by
	// statistics when computing the cost of scanning an index.
	ColumnCountNoSystemColumns() int

I'd remove this if possible. Looks like we are using it in just one place (in the coster). We could easily go through the columns and check how many are system columns. I think that code will one day have to look at each column's average value size (or something like that) anyway.

Copy link
Contributor Author

@rohany rohany 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 @RaduBerinde)


pkg/sql/opt/cat/column.go, line 32 at r2 (raw file):

Previously, RaduBerinde wrote…

Add that they cannot be part of the key cols / lax key cols for indexes.

Done


pkg/sql/opt/cat/column.go, line 33 at r2 (raw file):

Previously, RaduBerinde wrote…

"synthesized entirely within the optimizer" is confusing. They are synthesized in the catalog implementation, not the optimizer (and their values are also synthesized outside the optimizer). I would just keep this detail out, it's not relevant to comprehending the interface.

Done


pkg/sql/opt/cat/column.go, line 35 at r2 (raw file):

Previously, RaduBerinde wrote…

[nit] the other enums don't have Column. I'd keep just as System even if it's kind of generic

Done


pkg/sql/opt/cat/index.go, line 58 at r2 (raw file):

Previously, RaduBerinde wrote…

I'd remove this if possible. Looks like we are using it in just one place (in the coster). We could easily go through the columns and check how many are system columns. I think that code will one day have to look at each column's average value size (or something like that) anyway.

I added this because I didn't know if it was acceptable in the coster to iterate over all of the columns in the index. If that's fine i wont add this.

Copy link
Member

@RaduBerinde RaduBerinde left a comment

Choose a reason for hiding this comment

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

In cat.Table we should document how system columns interact with column families (I assume they don't show up in any family?)

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rohany)


pkg/sql/logictest/testdata/logic_test/mvcc, line 111 at r1 (raw file):

Previously, rohany (Rohan Yadav) wrote…

I'll need some pointers here.

I think in mutationBuilder.buildReturning, we'd want that inScope.appendColumnsFromTable call inside to skip system columns (just like we skip mutation columns)


pkg/sql/opt/cat/index.go, line 57 at r3 (raw file):

	// ColumnCount returns the number of columns in the index. This includes
	// columns that were part of the index definition (including the STORING
	// clause), as well as implicitly added primary key columns. This also the

remove "also the"


pkg/sql/opt/exec/execbuilder/testdata/select_for_update, line 528 at r1 (raw file):

Previously, rohany (Rohan Yadav) wrote…

I'm not sure why these changed, my changes shouldn't have affected the plans like this. Though the plan does seem reasonable since the in is a tautology?

Not sure either.. I'll try to figure it out. In any case, maybe change to IN (SELECT b FROM t). Then it shouldn't be correct to drop the join


pkg/sql/opt/norm/prune_cols_funcs.go, line 191 at r1 (raw file):

Previously, rohany (Rohan Yadav) wrote…

Because of the API change, there isn't an easy way to iterate over only the system columns of a table. I'm not sure that is a big deal though.

I think this would be more clear if we just did this check above instead of cols.UnionWith(indexCols). I think that's the only way a system column would make its way into this set in the first place.

@rohany rohany force-pushed the mvcc-col-again branch 2 times, most recently from d17d080 to 136ba12 Compare July 17, 2020 03:46
Copy link
Contributor Author

@rohany rohany left a comment

Choose a reason for hiding this comment

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

Done, added a blurb on the System columnkind

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @RaduBerinde)


pkg/sql/logictest/testdata/logic_test/mvcc, line 111 at r1 (raw file):

Previously, RaduBerinde wrote…

I think in mutationBuilder.buildReturning, we'd want that inScope.appendColumnsFromTable call inside to skip system columns (just like we skip mutation columns)

That worked. I think that it is reasonable to skip system columns in appendColumnsFromTable so we don't accidentally add system columns.


pkg/sql/opt/cat/index.go, line 57 at r3 (raw file):

Previously, RaduBerinde wrote…

remove "also the"

done


pkg/sql/opt/exec/execbuilder/testdata/select_for_update, line 528 at r1 (raw file):

Previously, RaduBerinde wrote…

Not sure either.. I'll try to figure it out. In any case, maybe change to IN (SELECT b FROM t). Then it shouldn't be correct to drop the join

We produce joins with the select b from t.


pkg/sql/opt/norm/prune_cols_funcs.go, line 191 at r1 (raw file):

Previously, RaduBerinde wrote…

I think this would be more clear if we just did this check above instead of cols.UnionWith(indexCols). I think that's the only way a system column would make its way into this set in the first place.

Done

Copy link
Member

@RaduBerinde RaduBerinde 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 @RaduBerinde and @rohany)


pkg/sql/logictest/testdata/logic_test/mvcc, line 111 at r1 (raw file):

Previously, rohany (Rohan Yadav) wrote…

That worked. I think that it is reasonable to skip system columns in appendColumnsFromTable so we don't accidentally add system columns.

Looks like that would be correct for all call sites, maybe rename to appendOrdinaryColumnsFromTable

@RaduBerinde
Copy link
Member


pkg/sql/opt/exec/execbuilder/testdata/select_for_update, line 528 at r1 (raw file):

Previously, rohany (Rohan Yadav) wrote…

We produce joins with the select b from t.

I've been trying to figure this out. I can't find a rule that would do this transformation (though we'll probably add it in the future), so something fishy must be going on. I can't use optsteps reproduce inside opt tests without the testcatalog change. I've been trying to hack the planning code but it's hard. I can try again once you get the testcatalog working too.

@RaduBerinde
Copy link
Member


pkg/sql/opt/exec/execbuilder/testdata/select_for_update, line 528 at r1 (raw file):

Previously, RaduBerinde wrote…

I've been trying to figure this out. I can't find a rule that would do this transformation (though we'll probably add it in the future), so something fishy must be going on. I can't use optsteps reproduce inside opt tests without the testcatalog change. I've been trying to hack the planning code but it's hard. I can try again once you get the testcatalog working too.

Ah, I think I figured it out. We have a rule EliminateJoinUnderProjectLeft that would do this if there is a Project on top. With your change, we have a Project to eliminate the system column. I was able to get the same plan on master with SELECT a instead of SELECT *. So it's all good.

@rohany
Copy link
Contributor Author

rohany commented Jul 17, 2020

Ah, I think I figured it out. We have a rule EliminateJoinUnderProjectLeft that would do this if there is a Project on top. With your change, we have a Project to eliminate the system column. I was able to get the same plan on master with SELECT a instead of SELECT *. So it's all good.

Nice. Why does that rule need a projection to fire though?

@RaduBerinde
Copy link
Member

Nice. Why does that rule need a projection to fire though?

We are just missing a corresponding (simpler) rule when there is no projection. The rule with the projection does more things than eliminate an unnecessary semi-join.

@rohany
Copy link
Contributor Author

rohany commented Jul 17, 2020

that makes sense. @RaduBerinde do you think it's reasonable for me to start updating the opt tests, or there are more things here that you want to change?

@RaduBerinde
Copy link
Member

Let me look over it more, I didn't get a chance to look at all the changes.

Copy link
Member

@RaduBerinde RaduBerinde left a comment

Choose a reason for hiding this comment

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

opt part LGTM. Unfortunately you will have to merge with Andy's changes in 51574.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rohany)


pkg/sql/opt/cat/utils.go, line 287 at r4 (raw file):

}

func formatColumn(col Column, isMutationCol bool, isSystemCol bool, buf *bytes.Buffer) {

[nit] should just pass the cat.ColumnKind

@rohany
Copy link
Contributor Author

rohany commented Jul 20, 2020

I rebased on top of andy's change by adding a system bool to the scopeColumn and not adding those columns to the fetchColIDs list. Let me know if that doesn't sound ideal.

I'll begin editing the opt tests as CI comes in.

Copy link
Member

@RaduBerinde RaduBerinde left a comment

Choose a reason for hiding this comment

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

LGTM, just some minor nits

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rohany)


pkg/sql/opt/optbuilder/fk_cascade.go, line 116 at r5 (raw file):

	// Set list of columns that will be fetched by the input expression.
	for i := range mb.outScope.cols {
		// Ensure that we don't add system columns to the fetch ords.

[nit] "fetch ords" is no longer a thing, maybe "fetch columns" (+2 more times in this file)


pkg/sql/opt/optbuilder/insert.go, line 521 at r5 (raw file):

	for i, n := 0, mb.tab.ColumnCount(); i < n && numCols < maxCols; i++ {
		// Skip mutation, hidden or system columns.
		if cat.IsMutationColumn(mb.tab, i) || mb.tab.Column(i).IsHidden() || cat.IsSystemColumn(mb.tab, i) {

maybe it's cleaner to check that the kind is Ordinary (same below)


pkg/sql/opt/optbuilder/mutation_builder.go, line 244 at r5 (raw file):

	// Set list of columns that will be fetched by the input expression.
	for i := range mb.outScope.cols {
		// Ensure that we don't add system columns to the fetch ords.

"fetch columns"


pkg/sql/opt/optbuilder/mutation_builder.go, line 371 at r5 (raw file):

	// Set list of columns that will be fetched by the input expression.
	for i := range mb.outScope.cols {
		// Ensure that we don't add system columns to the fetch ords.

"fetch columns"


pkg/sql/opt/optbuilder/mutation_builder.go, line 836 at r5 (raw file):

		private.ReturnCols = make(opt.ColList, mb.tab.ColumnCount())
		for i, n := 0, mb.tab.ColumnCount(); i < n; i++ {
			if cat.IsMutationColumn(mb.tab, i) || cat.IsSystemColumn(mb.tab, i) {

[nit] kind == Ordinary


pkg/sql/opt/optbuilder/scope.go, line 230 at r5 (raw file):

	}
	for i, n := 0, tab.ColumnCount(); i < n; i++ {
		if cat.IsMutationColumn(tab, i) || cat.IsSystemColumn(tab, i) {

Kind == Ordinary (I'd definitely do this here where the function name specifically mentions Ordinary)


pkg/sql/opt/optbuilder/scope_column.go, line 48 at r5 (raw file):

	// system is true if the column is an implicit system column. It should not
	// be included in mutations.
	system bool

[nit] We could also store the ColumnKind here instead. Not sure if that is better or worse though, your call

@rohany
Copy link
Contributor Author

rohany commented Jul 20, 2020

[nit] "fetch ords" is no longer a thing, maybe "fetch columns" (+2 more times in this file)

Done woops.

Updated all of these checks to check != cat.Ordinary

[nit] We could also store the ColumnKind here instead. Not sure if that is better or worse though, your call

I think this one is easier to keep as the booleans.

@rohany rohany marked this pull request as ready for review July 21, 2020 03:52
@rohany rohany requested a review from a team July 21, 2020 03:52
@rohany rohany requested a review from a team as a code owner July 21, 2020 03:52
@rohany rohany requested review from pbardea and removed request for a team July 21, 2020 03:52
@rohany rohany changed the title WIP (different approach) sql: expose mvcc timestamps to SQL sql: expose mvcc timestamps to SQL Jul 21, 2020
@pbardea pbardea removed their request for review July 21, 2020 12:52
Fixes cockroachdb#50102.

This PR adds introspection into the KV layer's concurrency control from
the SQL level. In particular, we now expose the MVCC HLC timestamp of a
row as a special system column on every table. This system column is
exposed as a decimal, and is computed as `wall time * 10^10 + logical time`.

To accomplish this, this PR adds planning and execution infrastructure
for implicit system columns that can be produced by the execution layer
for a particular row.

Release note (sql change): Expose the MVCC timestamp of each row as a
system column on tables. This column is named
`crdb_internal_mvcc_timestamp` and is accessible only in a limited set
of contexts.
This commit adds the MVCC timestamp system column to the test catalog
and updates all of the tests with the change.

Release note: None
@rohany
Copy link
Contributor Author

rohany commented Jul 21, 2020

Alright, I've got the LGTM from @RaduBerinde. Going to merge this now!

bors r=raduberinde

@craig
Copy link
Contributor

craig bot commented Jul 21, 2020

Build succeeded

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.

sql: expose MVCC timestamps to SQL
3 participants