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,sqlbase,client: bootstrap TableDescriptor timestamps from MVCC #40793

Conversation

ajwerner
Copy link
Contributor

@ajwerner ajwerner commented Sep 16, 2019

This PR adds back the changes in #40581 and deals with the fallout that led to #40781 in the 3rd commit.

Release Justification: Fixes a bug formerly considered to be a release blocker.

@ajwerner ajwerner requested a review from a team as a code owner September 16, 2019 13:52
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@ajwerner ajwerner force-pushed the ajwerner/add-back-table-descriptor-change-with-fix branch 3 times, most recently from 9fe1b55 to 170f106 Compare September 16, 2019 15:08
@ajwerner
Copy link
Contributor Author

There was some churn here because of a discovery: before 19.1 we did not set the ModificationTime on Version 1 of table descriptors and the CreateAsOfTime did not exist.

The logic in TableDescriptor.maybeSetTimeFromMVCCTimestamp() has been updated to reflect my now better understanding of CreateAsOfTime and the logic in restore has been made robust to missing values with a perhaps crude but effective fix in the last commit that now includes testing.

I'm hopeful we can agree to still put in this change as it's a real customer pain point and I understand that this revealed some added risk.

@ajwerner ajwerner force-pushed the ajwerner/add-back-table-descriptor-change-with-fix branch from 170f106 to a7bdba9 Compare September 16, 2019 15:15
Copy link
Contributor

@thoszhang thoszhang 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, @andreimatei, and @lucy-zhang)


pkg/ccl/backupccl/restore.go, line 48 at r3 (raw file):

	"github.com/cockroachdb/cockroach/pkg/util/tracing"
	"github.com/cockroachdb/errors"
	opentracing "github.com/opentracing/opentracing-go"

This got added again.


pkg/ccl/backupccl/restore.go, line 78 at r3 (raw file):

			return nil, errors.Wrapf(err, "failed to read backup descriptor")
		}
		for _, d := range desc.Descriptors {

I think all this should actually go in readBackupDescriptor(), which is ultimately what gets called whenever we read a backup descriptor (which happens in a few other places besides this one).


pkg/ccl/backupccl/restore.go, line 91 at r3 (raw file):

			if t := d.GetTable(); t == nil {
				continue
			} else if t.Version == 1 && t.ModificationTime.IsEmpty() {

I had thought that we would never make a >=19.1 backup of a table descriptor without a ModificationTime. Even in 19.2, a table descriptor must be read before it is written to the backup descriptor, at which point a timestamp would have been set if it hadn't been set already, right?

(Also, is it possible to just indiscriminately set the ModificationTime to 1 whenever we restored a table? Is there any advantage to keeping the old timestamp?)


pkg/sql/sqlbase/structured.go, line 3305 at r3 (raw file):

func (desc *TableDescriptor) maybeSetTimeFromMVCCTimestamp(ts hlc.Timestamp) {
	// CreateAsOfTime is used for CREATE TABLE ... AS SELECT ... and was
	// introduced in v19.1. In general it is not critical to set and we definitely

Sorry I forgot about the CREATE TABLE AS complications in my earlier review. I think this comment could be clearer about CreateAsOfTime being set if and only if the table was created from CREATE TABLE AS. (Though in practice I think it's harmless if the timestamp isn't set as long as the table isn't in the ADD state anymore. We only use it as a transaction timestamp when filling in the table.)

Along those same lines, maybe there should be an assertion that if table.Adding() && table.IsAs(), we either have the timestamp already set or have a value to set it to.


pkg/sql/sqlbase/structured.proto, line 826 at r3 (raw file):

  // version of a table and is populated from the MVCC timestamp of the read
  // like ModificationTime. See Descriptor.Table().
  // CreateAsOfSystemTime is used for CREATE TABLE ... AS SELECT ... and was

nit: CREATE TABLE ... AS ...

@ajwerner ajwerner force-pushed the ajwerner/add-back-table-descriptor-change-with-fix branch 2 times, most recently from 982c6eb to 7df3d2f Compare September 17, 2019 13:55
Copy link
Contributor Author

@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.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @andreimatei and @lucy-zhang)


pkg/ccl/backupccl/restore.go, line 48 at r3 (raw file):

Previously, lucy-zhang (Lucy Zhang) wrote…

This got added again.

Done.


pkg/ccl/backupccl/restore.go, line 78 at r3 (raw file):

Previously, lucy-zhang (Lucy Zhang) wrote…

I think all this should actually go in readBackupDescriptor(), which is ultimately what gets called whenever we read a backup descriptor (which happens in a few other places besides this one).

Done.


pkg/ccl/backupccl/restore.go, line 91 at r3 (raw file):

I had thought that we would never make a >=19.1 backup of a table descriptor without a ModificationTime.

True but we need to support restoring from backups made from any version.

(Also, is it possible to just indiscriminately set the ModificationTime to 1 whenever we restored a table? Is there any advantage to keeping the old timestamp?)

Seems like it should be. The main value of the old timestamp as far as I can tell is that it will correspond to the MVCC time range of keys which contain that physical format. It's totally possible that I misunderstand how restoring a table interacts with MVCC but my expectation is that the restored keys will carry the same timestamp as when they were exported. If that's false then I feel way less strongly about preserving the ModificationTime.


pkg/sql/sqlbase/structured.go, line 3305 at r3 (raw file):

Previously, lucy-zhang (Lucy Zhang) wrote…

Sorry I forgot about the CREATE TABLE AS complications in my earlier review. I think this comment could be clearer about CreateAsOfTime being set if and only if the table was created from CREATE TABLE AS. (Though in practice I think it's harmless if the timestamp isn't set as long as the table isn't in the ADD state anymore. We only use it as a transaction timestamp when filling in the table.)

Along those same lines, maybe there should be an assertion that if table.Adding() && table.IsAs(), we either have the timestamp already set or have a value to set it to.

Done.


pkg/sql/sqlbase/structured.proto, line 826 at r3 (raw file):

Previously, lucy-zhang (Lucy Zhang) wrote…

nit: CREATE TABLE ... AS ...

Done.

Copy link
Contributor

@andreimatei andreimatei left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @ajwerner, @andreimatei, and @lucy-zhang)


pkg/ccl/backupccl/restore.go, line 80 at r6 (raw file):

		backupDescs[i] = desc
	}

nit: spurious diff


pkg/ccl/backupccl/restore_old_versions_test.go, line 38 at r6 (raw file):

	for _, dir := range dirs {
		require.True(t, dir.IsDir())
		t.Run(dir.Name(), restoreOldVersionTest(dir.Name()))

nit: pass path.join(exportDirs, dir) and localize exportDirs and testdataBase to this function.


pkg/ccl/backupccl/testdata/restore_old_versions/create.sql, line 1 at r6 (raw file):

-- The below SQL is used to create the data that is then exported with BACKUP

I'm really happy that you wrote these tests, but can you please also paste in here somewhere the exact commands to produce the ssts?


pkg/sql/sqlbase/structured.go, line 3318 at r6 (raw file):

		desc.CreateAsOfTime = ts
	}

spurious diff

@ajwerner ajwerner force-pushed the ajwerner/add-back-table-descriptor-change-with-fix branch from 7df3d2f to c32024f Compare September 17, 2019 14:41
Copy link
Contributor Author

@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.

TFTR!

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @andreimatei and @lucy-zhang)


pkg/ccl/backupccl/restore.go, line 80 at r6 (raw file):

Previously, andreimatei (Andrei Matei) wrote…

nit: spurious diff

Done.


pkg/ccl/backupccl/restore_old_versions_test.go, line 38 at r6 (raw file):

Previously, andreimatei (Andrei Matei) wrote…

nit: pass path.join(exportDirs, dir) and localize exportDirs and testdataBase to this function.

Done.


pkg/ccl/backupccl/testdata/restore_old_versions/create.sql, line 1 at r6 (raw file):

Previously, andreimatei (Andrei Matei) wrote…

I'm really happy that you wrote these tests, but can you please also paste in here somewhere the exact commands to produce the ssts?

Added it to the test comment.


pkg/sql/sqlbase/structured.go, line 3318 at r6 (raw file):

Previously, andreimatei (Andrei Matei) wrote…

spurious diff

I think I like this one.

@ajwerner ajwerner force-pushed the ajwerner/add-back-table-descriptor-change-with-fix branch 2 times, most recently from cd97539 to 622a081 Compare September 17, 2019 15:30
@ajwerner
Copy link
Contributor Author

@lucy-zhang can I have your stamp on this before I bors it?

Copy link
Contributor

@thoszhang thoszhang 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, @andreimatei, and @lucy-zhang)


pkg/ccl/backupccl/restore.go, line 91 at r3 (raw file):

True but we need to support restoring from backups made from any version.

Yeah, agreed, I actually just misread the comment/code previously.


pkg/sql/sqlbase/structured.go, line 3323 at r7 (raw file):

	if desc.Adding() && desc.IsAs() && desc.CreateAsOfTime.IsEmpty() {
		log.Fatalf(context.TODO(), "table descriptor for %q (%d.%d) is in the "+
			"ADD state and was creates with CREATE TABLE ... AS but does not have a "+

created

Using the MVCC timestamp of the value for table descriptors has long been
theorized as the right mechanism to eliminate the need for transactions
which update a table descriptor version to observe their commit timestamp
(see cockroachdb#17698 (comment)).

The challenge was presumed to be the need to expose MVCC timestamps in our
client library. It turns out we seem to do that already (how did nobody know
that?!).

This commit avoids using the CommitTimestamp by using the MVCC timestamp on
the read path. In order to make this setting of the timestamp less of a footgun
we add a `(*Descriptor).Table(hlc.Timestamp)` method which forces anybody who
extracts a `TableDescriptor` from a `Descriptor` to pass in a timestamp which
may be used to set `ModificationTime` and `CreateAsOfTime`. A linter in the
following commit enforces this proper usage.

The below SQL would always fail before this change and now passes:

```
CREATE TABLE foo ( k INT PRIMARY KEY );
BEGIN;
DROP TABLE foo;
<wait a while>
COMMIT;
```

Similarly the TestImportData seems to pass under stressrace with a 5s
`kv.closed_timestamp.target_duration`.

Release justification: fixes a release blocker and known customer issue.

References cockroachdb#37083.

Release note: None
Callers should use sqlbase.Descriptor.Table() instead.

Release justification: This is a linter for the first commit which is an
approved change.

Release note: None
… versions

This PR ensures that the now logic to set the TableDescriptor timestamps
from MVCC timestamps works in the face of table descriptors created in previous
versions. There are two main hazards which this commit addresses:

1) Tables created before 19.1 will not carry a CreateAsOfTimestamp.
   This field is not important to set on these tables as they certainly
   were not relying on this value for a CTAS.

2) Ensure that TableDescriptors from a backup contain a non-zero
   ModificationTime. Before 19.1 we created Version 1 of tables with
   a zero ModificationTime. When restoring such a table we set its
   ModificationTime to hlc.Timestamp{WallTime: 1}. This prevents any
   invariants from being violated.

This commit also adds a test to backupccl which restores a database
from all previous major versions to ensure that the restore works
properly.

Release Justification: Fixes a bug in a PR which was approved for release
and adds testing.

Release note: None
@ajwerner ajwerner force-pushed the ajwerner/add-back-table-descriptor-change-with-fix branch from 622a081 to 05a000a Compare September 17, 2019 20:41
Copy link
Contributor Author

@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.

TFTR!

bors r+

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @ajwerner, @andreimatei, and @lucy-zhang)


pkg/sql/sqlbase/structured.go, line 3323 at r7 (raw file):

Previously, lucy-zhang (Lucy Zhang) wrote…

created

Done.

craig bot pushed a commit that referenced this pull request Sep 17, 2019
40793: sql,sqlbase,client: bootstrap TableDescriptor timestamps from MVCC r=ajwerner a=ajwerner

This PR adds back the changes in #40581 and deals with the fallout that led to #40781 in the 3rd commit.

Release Justification: Fixes a bug formerly considered to be a release blocker. 


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

craig bot commented Sep 17, 2019

Build succeeded

@craig craig bot merged commit 05a000a into cockroachdb:master Sep 17, 2019
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