Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-52678

[SBE] multi-planner candidate plan may yield before being attached to the OperationContext

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 4.9.0
    • Affects Version/s: None
    • Component/s: Querying
    • None
    • Fully Compatible
    • ALL
    • Hide

      Start a server with test commands enabled:

      ./mongod --setParameter enableTestCommands=true
      

      Run the following script against the server:

      (function() {
      "use strict";
      
      // Turn on SBE.
      assert.commandWorked(
          db.adminCommand({setParameter: 1, internalQueryEnableSlotBasedExecutionEngine: true}));
      
      // Make yielding happen frequently.
      assert.commandWorked(db.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1}));
      
      db.c.drop();
      assert.commandWorked(db.c.createIndex({a: 1}));
      assert.commandWorked(db.c.createIndex({b: 1}));
      
      assert.commandWorked(db.c.insert([{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}]));
      
      // This query provokes the crash.
      assert.eq(3, db.c.find({a: 1, b: {$gt: 0}}).sort({b: 1}).itcount());
      }());
      
      Show
      Start a server with test commands enabled: ./mongod --setParameter enableTestCommands= true Run the following script against the server: (function() { "use strict" ; // Turn on SBE. assert .commandWorked( db.adminCommand({setParameter: 1, internalQueryEnableSlotBasedExecutionEngine: true })); // Make yielding happen frequently. assert .commandWorked(db.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1})); db.c.drop(); assert .commandWorked(db.c.createIndex({a: 1})); assert .commandWorked(db.c.createIndex({b: 1})); assert .commandWorked(db.c.insert([{a: 1, b: 1}, {a: 1, b: 2}, {a: 1, b: 3}])); // This query provokes the crash. assert .eq(3, db.c.find({a: 1, b: {$gt: 0}}).sort({b: 1}).itcount()); }());
    • Query 2020-11-30, Query 2020-12-14
    • 9

      This is a bug in the implementation of yielding during SBE runtime planning. Yielding during SBE runtime planning was implemented under related ticket SERVER-48555. See "Steps To Reproduce" for a reliable way to provoke the bug.

      The problem is as follows. When any of the candidate QuerySolutionNode trees is converted into a corresponding SBE execution plan, that plan is registered for yielding with the PlanYieldPolicySBE. At this point, however, the SBE tree has not yet been attached the OperationContext with a call to attachFromOperationContext().

      Once all the SBE plans are actually constructed, we call sbe::MultiPlanner::plan() in order to choose the winning plan. This involves executing the candidate plans, and of course the first step in doing so is to prepare and open the plans. Each candidate is prepared and opened one-by-one.

      The trouble is that we only attach the OperationContext to the plan immediately before opening it. Let's say that there are two candidate plans. We have attached the first to the OperationContext and are in the process of opening it. The second plan remains unattached and unopened. If a yield occurs during the open of the first candidate plan, then we attempt to save and restore each of the two candidate plans since both are registered for yielding. However, this invariant fails for the second (unattached) candidate plan because it expects the index scan stage to be attached to the OperationContext prior to yielding.

            Assignee:
            david.storch@mongodb.com David Storch
            Reporter:
            david.storch@mongodb.com David Storch
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: