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

CheckpointHarness and analyzer mutexes #995

Merged
merged 57 commits into from
May 19, 2022
Merged

Conversation

max-hoffman
Copy link
Contributor

No description provided.

Copy link
Member

@zachmu zachmu left a comment

Choose a reason for hiding this comment

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

Not super happy with these interface choices. See the comments.

On a meta note, I think this is probably a lot cleaner if you separate out the changes to make things parallel and just focus on the checkpoint stuff for this PR.

I'll hold off reviewing the dolt PR until you respond to these comments unless you think I should look now.

enginetest/enginetests.go Show resolved Hide resolved
enginetest/enginetests.go Outdated Show resolved Hide resolved
enginetest/enginetests.go Outdated Show resolved Hide resolved
enginetest/enginetests.go Outdated Show resolved Hide resolved
enginetest/enginetests.go Outdated Show resolved Hide resolved
@@ -6863,6 +6761,111 @@ var KeylessQueries = []QueryTest{
},
}

var ParallelUnsafeQueries = []QueryTest{
Copy link
Member

Choose a reason for hiding this comment

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

Not at all obvious why most of these are unsafe to run in parallel

// createSubsetTestData creates test tables and data. Passing a non-nil slice for includedTables will restrict the
// table creation to just those tables named.
func CreateSubsetTestData(t *testing.T, harness Harness, includedTables []string) []sql.Database {
dbs := harness.NewDatabases("mydb", "foo")
if spatialSupported {
Copy link
Member

Choose a reason for hiding this comment

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

Do not do this

Either a) make the harness itself decide which tables to include in test setup in some way or b) figure out how to make this separable via a distinct test method, as it was before this

memory/table.go Outdated
@@ -61,6 +61,53 @@ type Table struct {
autoColIdx int
}

func CopyTable(t *Table) *Table {
Copy link
Member

Choose a reason for hiding this comment

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

Method doc

Copy link
Member

Choose a reason for hiding this comment

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

Still an issue

@@ -1863,6 +1913,8 @@ func (t *informationSchemaTable) Schema() Schema {
}

func (t *informationSchemaTable) AssignCatalog(cat Catalog) Table {
Copy link
Member

Choose a reason for hiding this comment

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

These changes are kind of nonsensical

It doesn't matter if you prevent a data race in assigning the catalog to these table objects if there is one global copy of each that gets used across all sessions / queries. Sure you are preventing literal races, but it's still the case that e.g. the same table object in use by one session about to start returning rows can have its catalog object re-assigned by another session. The mutex needs to guard the unit of work, which is the transaction. It's just not a workable solution in this context.

What you need to do return a new copy of each table every time when asked, rather than keeping a single global instance of each.

You can avoid doing this (I think) if you just back out the parallel changes for now.

type CheckpointHarness interface {
Harness
// RestoreCheckpoint resets the database to a saved point
RestoreCheckpoint(*sql.Context, *testing.T, *sqle.Engine) *sqle.Engine
Copy link
Member

Choose a reason for hiding this comment

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

Rather than this, make NewEngine the sole method in CheckpointHarness. Then in each test method, if the harness implements CheckpointHarness, get a new engine from that. Otherwise, call enginetests.NewEngine().

Then the lifecycle of these objects is clear: it does any initialization work (including data setup) at instantiation, and creates a new blank engine with that initial state every time this method is called. No need for explicit checkpoint restore operations.

Copy link
Member

Choose a reason for hiding this comment

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

Also document this lifecycle in these interfaces/

{"a2", "a3"},
{"a4", "a3"},
}, nil)

// Assert that query plan this follows correctly uses an IndexedTableAccess
Copy link
Contributor Author

Choose a reason for hiding this comment

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

super redundant test that I've had to fix 5-6 times

@@ -426,171 +434,6 @@ func TestIndexQueryPlans(t *testing.T) {
}
}

// This test will write a new set of query plan expected results to a file that you can copy and paste over the existing
Copy link
Contributor Author

Choose a reason for hiding this comment

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

moved to helper file

Copy link
Member

@zachmu zachmu left a comment

Choose a reason for hiding this comment

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

Overall this is quite good, so much better than what we had before.

My main concerns are 1) formalizing codegen of setup scripts and 2) getting rid of the old NewTable etc. methods from Harness. Both can happen on a second pass, you should get what you have in ASAP.

memory/table.go Outdated
@@ -61,6 +61,53 @@ type Table struct {
autoColIdx int
}

func CopyTable(t *Table) *Table {
Copy link
Member

Choose a reason for hiding this comment

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

Still an issue

sql/plan/show_indexes.go Outdated Show resolved Hide resolved
sql/plan/show_indexes.go Outdated Show resolved Hide resolved
// This test will write a new set of query plan expected results to a file that you can copy and paste over the existing
// query plan results. Handy when you've made a large change to the analyzer or node formatting, and you want to examine
// how query plans have changed without a lot of manual copying and pasting.
func TestWriteQueryPlans(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

I think I like this textual format better

But if we're going to go this route we need full code gen. Write a tool that takes the textual representations and transforms them into .go files with data structures

"insert into test.a values (0), (2), (4), (6), (8)",
"insert into test.b values (1), (3), (5), (7), (9)",
"use test",
"create table foo.a (x int primary key)",
Copy link
Member

Choose a reason for hiding this comment

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

Why change this? I can't create a database, or you just didn't think it was appropriate for this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

can't reset or clear a new database. I could do cartwheels in the reset scripts to get and delete unexpected dbs, but this was easier.

enginetest/enginetests.go Outdated Show resolved Hide resolved
enginetest/enginetests.go Outdated Show resolved Hide resolved
@@ -2045,13 +1793,13 @@ func TestScriptWithEnginePrepared(t *testing.T, e *sqle.Engine, harness Harness,
}

func TestTransactionScripts(t *testing.T, harness Harness) {
for _, script := range TransactionTests {
for _, script := range queries.TransactionTests {
Copy link
Member

Choose a reason for hiding this comment

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

no Setup() here?

})
}

func TestScripts(t *testing.T, harness Harness) {
for _, script := range ScriptTests {
for _, script := range queries.ScriptTests {
Copy link
Member

Choose a reason for hiding this comment

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

No Setup()?

Data() Testdata
}

type Testdata struct {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure how much of this is a draft

But this struct should be used solely for parsing the test data files / code gen. We should have generated golang data structures checked into source corresponding to each of the textual setup files

@max-hoffman max-hoffman merged commit 86955e3 into main May 19, 2022
@max-hoffman max-hoffman deleted the max/versioned-enginetests branch May 19, 2022 23:51
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.

2 participants