-
Notifications
You must be signed in to change notification settings - Fork 5.7k
SERVER-32721 Explain output should indicate when a backup plan is used #1231
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
base: master
Are you sure you want to change the base?
Conversation
…with an underscore
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.
Lots of little changes requested, but overall this looks really good! The code is looking very clean and organized. You happened to copy some older code in the MultiPlanStage, so I understand some of the comments may be a surprise - sorry about that. We have different style standards today and the code you copied hadn't been updated in a while. I hope they most of them should be pretty easy to address.
Thanks for doing this!
(function() { | ||
"use strict"; | ||
|
||
db.foo.drop() let bulk = db.foo.initializeUnorderedBulkOp(); |
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.
Looks like you're missing a semi-colon after .drop()
here.
"use strict"; | ||
|
||
db.foo.drop() let bulk = db.foo.initializeUnorderedBulkOp(); | ||
for (let i = 0; i < 100000; ++i) { |
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.
This test is great, but we tend to favor tests that don't need as much data to be inserted, since they will execute faster. In this case you configure the maxBlockingSortBytes, so do you need this many documents?
|
||
bulk.execute(); | ||
db.foo | ||
.ensureIndex({x: 1}) |
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.
Missing semi-colon, also on line 23 and 27.
src/mongo/db/exec/multi_plan.cpp
Outdated
_backupPlanIdx = kNoSuchPlan; | ||
if (bestSolution->hasBlockingStage && (0 == alreadyProduced.size())) { | ||
LOG(5) << "Winner has blocking stage, looking for backup plan..."; | ||
|
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 a big deal, but try not to include unnecessary changes like this in your patch. This one isn't particularly offensive, but I'd still recommend reverting this change.
src/mongo/db/exec/multi_plan.h
Outdated
/** Return the index of the best plan chosen, for testing */ | ||
int bestPlanIdx() const; | ||
|
||
/** Return the index of the backup plan chosen, for testing */ |
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 know you just copied this from above, but in new code we tend to always prefer
/**
* This kind of syntax.
*/
instead of
/** This kind of syntax */
Also, these new methods are used for explain output, not just for testing. I'm pretty sure bestPlanIdx()
is as well, so you can remove that part of it.
Please update these, and any others in this file while you're at it.
src/mongo/db/exec/multi_plan.h
Outdated
int _bestPlanIdx; | ||
|
||
// index into _candidates, of the backup plan for sort | ||
// index into _candidates, of the backup of the plan competition |
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.
This still doesn't read particularly well. How about re-phrasing this to
The index within '_candidates' of the non-blocking backup plan which can be used if a blocking plan fails. This is set to 'kNoSuchPlan' if there is no backup plan, or when it is not yet known.
? I'd recommend a similar re-wording for the comment on '_originalWinningPlanIndex' below, with a mention that this is used to remember which plan one in the case that a backup plan took over.
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.
It looks like this still hasn't been addressed?
src/mongo/db/query/explain.cpp
Outdated
|
||
|
||
/** | ||
* Get PlanExecutor's original winning plan stats tree. |
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.
Please elaborate here that this will only be different from the actual winning plan if a non-blocking backup plan was used. How about Returns the root of the original winning plan used by 'exec'. This may be different than the final winning plan in the case that the MultiPlanStage selected a blocking plan which failed, and fell back to a non-blocking plan instead. If there is no MultiPlanStage in the tree, returns the root stage of 'exec'.
src/mongo/db/query/explain.cpp
Outdated
const auto mps = getMultiPlanStage(exec->getRootStage()); | ||
int originaWinningPlanIdx = static_cast<size_t>(mps->originalWinningPlanIdx()); | ||
|
||
if (originaWinningPlanIdx > -1) { |
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.
It looks like you never use the actual index, so how about changing line 658 to be
const bool usedBackupPlan = (static_cast<size_t>(mps->originalWinningPlanIdx()) > -1);
? That way you can collapse lines 660-664 into one line.
// This query will not use the backup plan, hence it generates only two stages: winningPlan and | ||
// rejectedPlans | ||
assert | ||
.commandWorked(db.foo.find({x: {$gte: 90}}).sort({_id: 1}).explain(true)) |
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.
Your comment here mentions what we expect, but you just assert that the command "worked", which just means it returned a document with an ok
field with a truthy value (usually 1
).
Check out the helper functions defined here: https://github.com/mongodb/mongo/blob/r3.7.2/jstests/libs/analyze_plan.js
I think you should add a helper there which gets the 'originalWinningPlan', and assert that it is null here, and non-null below.
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.
A couple comments, mostly about the wording. I do think there is one serious problem with the global variable.
// "executionStats" mode | ||
// This test was designed to reproduce SERVER-32721" | ||
|
||
load("jstests/libs/analyze_plan.js"); |
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.
Please put the contents of this test in an immediately-invoked-function-expression (https://en.wikipedia.org/wiki/Immediately-invoked_function_expression)
|
||
"use strict"; | ||
|
||
db.foo.drop(); |
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.
Use a more unique collection name, how about
const coll = db.explain_backup_plan;
coll.drop();
// Replace usages of 'db.foo' with 'coll' below.
db.foo.ensureIndex({x: 1}); | ||
|
||
// Configure log level and lower the sort bytes limit. | ||
db.setLogLevel(5, "query"); |
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.
You don't need to set the log level for the test, that was just for your personal info. Please remove this line so the test doesn't generate lots of logs. This will also change the setting for subsequent tests, so it would get quite noisy.
src/mongo/db/exec/multi_plan.h
Outdated
int _bestPlanIdx; | ||
|
||
// index into _candidates, of the backup plan for sort | ||
// index into _candidates, of the backup of the plan competition |
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.
It looks like this still hasn't been addressed?
src/mongo/db/exec/multi_plan.h
Outdated
// uses -1 / kNoSuchPlan when best plan is not (yet) known | ||
int _backupPlanIdx; | ||
|
||
// Index into _candidates, of the original winner of the plan which can be used if a blocking plan .fails |
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.
Use single-quotes to refer to the variable name: Index into '_candidates', ...
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, it looks like you don't need the comma here, and you should move the "." before 'fails' to be after it.
src/mongo/db/query/explain.cpp
Outdated
using std::unique_ptr; | ||
using std::vector; | ||
|
||
bool backupPlanUsed = false; |
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.
This should be passed as a parameter to the function. These helpers can be called by multiple threads, which would induce a race condition writing to the variable here.
src/mongo/db/query/explain.cpp
Outdated
} | ||
|
||
/** | ||
* Gather the PlanStages when a backup plan is used |
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.
This comment is confusing. What do we do when a backup plan is not used?
I'd actually recommend removing this method, and instead adding a 'bool backupPlanUsed' parameter to 'getRejectedPlansTrialStats'.
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.
If you do that, you should then extend the comment on that method to include something like "If a backup plan was used, include the stats of the new winning plan instead of the original winning plan. The original winning plan is expected to already be known by the caller, since it needs to be snapshotted and stored before execution completes."
src/mongo/db/query/explain.cpp
Outdated
|
||
|
||
/** | ||
* Returns the root of the roginal winning plan used by 'exec'. |
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.
original, not 'roginal'
src/mongo/db/query/explain.cpp
Outdated
* Returns the root of the roginal winning plan used by 'exec'. | ||
* This might be different than the final winning plan in the case that the MultiPlanStage selected a | ||
* blocking plan which failed, and fell back to a non-blocking plan instead. | ||
* If there is no MultiPlanStage in the tree, returns the root stage of 'exec' |
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.
Finish with a period.
src/mongo/db/query/explain.cpp
Outdated
|
||
auto winningPlanTrialStats = Explain::getWinningPlanTrialStats(exec); | ||
|
||
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.
Looks like a stray whitespace change (and also on line 916), can you please undo this?
I'm leaving this open since SERVER-32721 is still unresolved - could you double check this PR is up to date with master? Addtionally, if you're still looking to merge this, can you:
I checked in on this issue to see if it's something we're going to look at. |
No description provided.