Skip to content

Conversation

d-d-ddl
Copy link
Contributor

@d-d-ddl d-d-ddl commented Mar 27, 2018

No description provided.

@cswanson310 cswanson310 self-assigned this Apr 3, 2018
@cswanson310 cswanson310 self-requested a review April 3, 2018 02:25
Copy link
Contributor

@cswanson310 cswanson310 left a 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();
Copy link
Contributor

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) {
Copy link
Contributor

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})
Copy link
Contributor

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.

_backupPlanIdx = kNoSuchPlan;
if (bestSolution->hasBlockingStage && (0 == alreadyProduced.size())) {
LOG(5) << "Winner has blocking stage, looking for backup plan...";

Copy link
Contributor

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.

/** Return the index of the best plan chosen, for testing */
int bestPlanIdx() const;

/** Return the index of the backup plan chosen, for testing */
Copy link
Contributor

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.

int _bestPlanIdx;

// index into _candidates, of the backup plan for sort
// index into _candidates, of the backup of the plan competition
Copy link
Contributor

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.

Copy link
Contributor

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?



/**
* Get PlanExecutor's original winning plan stats tree.
Copy link
Contributor

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

const auto mps = getMultiPlanStage(exec->getRootStage());
int originaWinningPlanIdx = static_cast<size_t>(mps->originalWinningPlanIdx());

if (originaWinningPlanIdx > -1) {
Copy link
Contributor

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))
Copy link
Contributor

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.

Copy link
Contributor

@cswanson310 cswanson310 left a 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");
Copy link
Contributor

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();
Copy link
Contributor

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");
Copy link
Contributor

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.

int _bestPlanIdx;

// index into _candidates, of the backup plan for sort
// index into _candidates, of the backup of the plan competition
Copy link
Contributor

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?

// 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
Copy link
Contributor

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', ...

Copy link
Contributor

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.

using std::unique_ptr;
using std::vector;

bool backupPlanUsed = false;
Copy link
Contributor

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.

}

/**
* Gather the PlanStages when a backup plan is used
Copy link
Contributor

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

Copy link
Contributor

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



/**
* Returns the root of the roginal winning plan used by 'exec'.
Copy link
Contributor

Choose a reason for hiding this comment

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

original, not 'roginal'

* 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'
Copy link
Contributor

Choose a reason for hiding this comment

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

Finish with a period.


auto winningPlanTrialStats = Explain::getWinningPlanTrialStats(exec);

Copy link
Contributor

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?

@kelly-cs
Copy link
Contributor

kelly-cs commented Oct 3, 2025

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:

  1. Sign our Contributor's Agreement.

I checked in on this issue to see if it's something we're going to look at.

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.

3 participants