-
-
Notifications
You must be signed in to change notification settings - Fork 209
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
Conversation
e0074c8
to
608bef3
Compare
There was a problem hiding this 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/queries.go
Outdated
@@ -6863,6 +6761,111 @@ var KeylessQueries = []QueryTest{ | |||
}, | |||
} | |||
|
|||
var ParallelUnsafeQueries = []QueryTest{ |
There was a problem hiding this comment.
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
enginetest/testdata.go
Outdated
// 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 { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method doc
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
enginetest/harness.go
Outdated
type CheckpointHarness interface { | ||
Harness | ||
// RestoreCheckpoint resets the database to a saved point | ||
RestoreCheckpoint(*sql.Context, *testing.T, *sqle.Engine) *sqle.Engine |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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/
…ql-server into max/versioned-enginetests
This reverts commit 43194b9.
{"a2", "a3"}, | ||
{"a4", "a3"}, | ||
}, nil) | ||
|
||
// Assert that query plan this follows correctly uses an IndexedTableAccess |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to helper file
…ql-server into max/versioned-enginetests
There was a problem hiding this 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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still an issue
// 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) { |
There was a problem hiding this comment.
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)", |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
@@ -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 { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No Setup()
?
enginetest/file_setup.go
Outdated
Data() Testdata | ||
} | ||
|
||
type Testdata struct { |
There was a problem hiding this comment.
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
…ql-server into max/versioned-enginetests
No description provided.