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

Incorrect use of BSONObjBuilder in mongos explain

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Minor - P4 Minor - P4
    • 6.1.0-rc0
    • Affects Version/s: 5.0.3-rc0, 4.2.17, 4.4.10
    • Component/s: None
    • None
    • Fully Compatible
    • ALL
    • 23

      In this mongos explain logic, we continue writing to a BSONArrayBuilder after calling done() on it, and further, after opening a new BSONArrayBuilder. This can cause mongos to return strange (and arguably, garbage) results, where a BSON array's first key is "1" instead of "0." We should change this logic in cluster_explain.cpp to use BSONArrayBuilder correctly.
       

      I've copied and pasted the code below and added my notes:

          BSONArrayBuilder execShardsBuilder(executionStagesBob.subarrayStart("shards"));
          for (size_t i = 0; i < shardResponses.size(); i++) {
              auto responseData = shardResponses[i].swResponse.getValue().data;
      
              BSONObjBuilder singleShardBob(execShardsBuilder.subobjStart());
              BSONObj execStats = responseData["executionStats"].Obj();
      
              singleShardBob.append("shardName", shardResponses[i].shardId.toString());
              appendElementsIfRoom(&singleShardBob, execStats);
              singleShardBob.doneFast();
          }
          execShardsBuilder.doneFast();
      
          executionStagesBob.doneFast();
      
          if (!firstShardResponseData["executionStats"].Obj().hasField("allPlansExecution")) {
              // The shards don't have execution stats for all plans, so we're done.
              executionStatsBob.doneFast();
              return;
          }
      
          // Add the allPlans stats from each shard.
          BSONArrayBuilder allPlansExecBob(executionStatsBob.subarrayStart("allPlansExecution"));    // NOTE(ianb): Notice how 'allPlansExecBob' is never used.
          for (size_t i = 0; i < shardResponses.size(); i++) {
              auto responseData = shardResponses[i].swResponse.getValue().data;
              // NOTE(ianb): Notice how we're using 'execShardsBuilder' even though we already called done() on that above.
              BSONObjBuilder singleShardBob(execShardsBuilder.subobjStart());
              singleShardBob.append("shardName", shardResponses[i].shardId.toString());
      
              BSONObj execStats = responseData["executionStats"].Obj();
              vector<BSONElement> allPlans = execStats["allPlansExecution"].Array();
      
              BSONArrayBuilder innerArrayBob(singleShardBob.subarrayStart("allPlans"));
              for (size_t j = 0; j < allPlans.size(); j++) {
                  appendToArrayIfRoom(&innerArrayBob, allPlans[j]);
              }
              innerArrayBob.done();
      
              singleShardBob.doneFast();
          }
          allPlansExecBob.doneFast();
      
          executionStatsBob.doneFast();
      }
      

            Assignee:
            ted.tuckman@mongodb.com Ted Tuckman
            Reporter:
            ian.boros@mongodb.com Ian Boros
            Votes:
            0 Vote for this issue
            Watchers:
            10 Start watching this issue

              Created:
              Updated:
              Resolved: