Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bail when traversing === groups (#1294)
This is the second part of the fix for the performance regression seen in #1250. In #1217, for correctness reasons, we're now traversing all the conditional groups. This means that we're now in O(n^2). But, in practice, many of those groups are === between each others. So we only need to recurse through one of the instances to know if it's going to break. This makes the first example go from not terminating to being instant. The second one going from not terminating to taking ~1s. We can also make it instant by tweaking the printing phase, but that's for another PR.
- Loading branch information
Showing
5 changed files
with
351 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`nested.js 1`] = ` | ||
someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
anotherFunction(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
return someObject.someFunction().then(function() { | ||
anotherFunction(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
`; | ||
|
||
exports[`nested-real.js 1`] = ` | ||
tap.test("RecordImport.advance", (t) => { | ||
const checkStates = (batches, states) => { | ||
t.equal(batches.length, states.length); | ||
for (const batch of batches) { | ||
t.equal(batch.state, states.shift()); | ||
t.ok(batch.getCurState().name(i18n)); | ||
} | ||
}; | ||
const batch = init.getRecordBatch(); | ||
const dataFile = path.resolve(process.cwd(), "testData", "default.json"); | ||
const getBatches = (callback) => { | ||
RecordImport.find({}, "", {}, (err, batches) => { | ||
callback(null, batches.filter((batch) => (batch.state !== "error" && | ||
batch.state !== "completed"))); | ||
}); | ||
}; | ||
mockFS((callback) => { | ||
batch.setResults([fs.createReadStream(dataFile)], (err) => { | ||
t.error(err, "Error should be empty."); | ||
t.equal(batch.results.length, 6, "Check number of results"); | ||
for (const result of batch.results) { | ||
t.equal(result.result, "unknown"); | ||
t.ok(result.data); | ||
t.equal(result.data.lang, "en"); | ||
} | ||
getBatches((err, batches) => { | ||
checkStates(batches, ["started"]); | ||
RecordImport.advance((err) => { | ||
t.error(err, "Error should be empty."); | ||
getBatches((err, batches) => { | ||
checkStates(batches, ["process.completed"]); | ||
// Need to manually move to the next step | ||
batch.importRecords((err) => { | ||
t.error(err, "Error should be empty."); | ||
getBatches((err, batches) => { | ||
checkStates(batches, ["import.completed"]); | ||
RecordImport.advance((err) => { | ||
t.error(err, "Error should be empty."); | ||
getBatches((err, batches) => { | ||
checkStates(batches, | ||
["similarity.sync.completed"]); | ||
RecordImport.advance((err) => { | ||
t.error(err, | ||
"Error should be empty."); | ||
t.ok(batch.getCurState() | ||
.name(i18n)); | ||
getBatches((err, batches) => { | ||
checkStates(batches, []); | ||
t.end(); | ||
callback(); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
}); | ||
}); | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
tap.test("RecordImport.advance", t => { | ||
const checkStates = (batches, states) => { | ||
t.equal(batches.length, states.length); | ||
for (const batch of batches) { | ||
t.equal(batch.state, states.shift()); | ||
t.ok(batch.getCurState().name(i18n)); | ||
} | ||
}; | ||
const batch = init.getRecordBatch(); | ||
const dataFile = path.resolve(process.cwd(), "testData", "default.json"); | ||
const getBatches = callback => { | ||
RecordImport.find({}, "", {}, (err, batches) => { | ||
callback( | ||
null, | ||
batches.filter( | ||
batch => batch.state !== "error" && batch.state !== "completed" | ||
) | ||
); | ||
}); | ||
}; | ||
mockFS(callback => { | ||
batch.setResults([fs.createReadStream(dataFile)], err => { | ||
t.error(err, "Error should be empty."); | ||
t.equal(batch.results.length, 6, "Check number of results"); | ||
for (const result of batch.results) { | ||
t.equal(result.result, "unknown"); | ||
t.ok(result.data); | ||
t.equal(result.data.lang, "en"); | ||
} | ||
getBatches((err, batches) => { | ||
checkStates(batches, ["started"]); | ||
RecordImport.advance(err => { | ||
t.error(err, "Error should be empty."); | ||
getBatches((err, batches) => { | ||
checkStates(batches, ["process.completed"]); | ||
// Need to manually move to the next step | ||
batch.importRecords(err => { | ||
t.error(err, "Error should be empty."); | ||
getBatches((err, batches) => { | ||
checkStates(batches, ["import.completed"]); | ||
RecordImport.advance(err => { | ||
t.error(err, "Error should be empty."); | ||
getBatches((err, batches) => { | ||
checkStates(batches, ["similarity.sync.completed"]); | ||
RecordImport.advance(err => { | ||
t.error(err, "Error should be empty."); | ||
t.ok(batch.getCurState().name(i18n)); | ||
getBatches((err, batches) => { | ||
checkStates(batches, []); | ||
t.end(); | ||
callback(); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
}); | ||
}); | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
run_spec(__dirname); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
tap.test("RecordImport.advance", (t) => { | ||
const checkStates = (batches, states) => { | ||
t.equal(batches.length, states.length); | ||
for (const batch of batches) { | ||
t.equal(batch.state, states.shift()); | ||
t.ok(batch.getCurState().name(i18n)); | ||
} | ||
}; | ||
|
||
const batch = init.getRecordBatch(); | ||
const dataFile = path.resolve(process.cwd(), "testData", "default.json"); | ||
|
||
const getBatches = (callback) => { | ||
RecordImport.find({}, "", {}, (err, batches) => { | ||
callback(null, batches.filter((batch) => (batch.state !== "error" && | ||
batch.state !== "completed"))); | ||
}); | ||
}; | ||
|
||
mockFS((callback) => { | ||
batch.setResults([fs.createReadStream(dataFile)], (err) => { | ||
t.error(err, "Error should be empty."); | ||
t.equal(batch.results.length, 6, "Check number of results"); | ||
for (const result of batch.results) { | ||
t.equal(result.result, "unknown"); | ||
t.ok(result.data); | ||
t.equal(result.data.lang, "en"); | ||
} | ||
|
||
getBatches((err, batches) => { | ||
checkStates(batches, ["started"]); | ||
|
||
RecordImport.advance((err) => { | ||
t.error(err, "Error should be empty."); | ||
|
||
getBatches((err, batches) => { | ||
checkStates(batches, ["process.completed"]); | ||
|
||
// Need to manually move to the next step | ||
batch.importRecords((err) => { | ||
t.error(err, "Error should be empty."); | ||
|
||
getBatches((err, batches) => { | ||
checkStates(batches, ["import.completed"]); | ||
|
||
RecordImport.advance((err) => { | ||
t.error(err, "Error should be empty."); | ||
|
||
getBatches((err, batches) => { | ||
checkStates(batches, | ||
["similarity.sync.completed"]); | ||
|
||
RecordImport.advance((err) => { | ||
t.error(err, | ||
"Error should be empty."); | ||
|
||
t.ok(batch.getCurState() | ||
.name(i18n)); | ||
|
||
getBatches((err, batches) => { | ||
checkStates(batches, []); | ||
t.end(); | ||
callback(); | ||
}); | ||
}); | ||
|
||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
|
||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
|
||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
|
||
t.ok(batch.getCurState().name(i18n)); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.