[SERVER-60909] Incorrect use of BSONObjBuilder in mongos explain Created: 21/Oct/21  Updated: 29/Oct/23  Resolved: 16/Aug/22

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: 5.0.3-rc0, 4.2.17, 4.4.10
Fix Version/s: 6.1.0-rc0

Type: Bug Priority: Minor - P4
Reporter: Ian Boros Assignee: Ted Tuckman
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
Related
related to SERVER-60910 Make BSONArrayBuilder/BSONObjBuilder ... Backlog
Backwards Compatibility: Fully Compatible
Operating System: ALL
Participants:
Linked BF Score: 23

 Description   

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();
}



 Comments   
Comment by Githook User [ 16/Aug/22 ]

Author:

{'name': 'Ted Tuckman', 'email': 'ted.tuckman@mongodb.com', 'username': 'TedTuckman'}

Message: SERVER-60909 Fix use of BSONArrayBuilder in cluster_explain
Branch: master
https://github.com/mongodb/mongo/commit/bd8d8c62dbe3a636ae03239ef94c3d219f8fdc5c

Generated at Thu Feb 08 05:51:03 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.