Fix standalone BatchedDelete large _ids edge case

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Fixed
    • Priority: Major - P3
    • 8.2.0-rc0, 8.1.2, 8.0.13, 7.0.26
    • Affects Version/s: 7.0.17, 8.0.6
    • Component/s: None
    • None
    • Query Execution
    • Fully Compatible
    • ALL
    • v8.1, v8.0, v7.0, v6.0
    • QE 2025-03-03, QE 2025-03-17, QE 2025-03-31, QE 2025-04-14, QE 2025-04-28, QE 2025-05-12, QE 2025-05-26, QE 2025-06-09, QE 2025-06-23
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      When running the following shell code against a replica set or standalone (cluster not validated), mongod crashes with an invariant failure [here](https://github.com/10gen/mongo/blob/7ca242fa77c2a15f3a3628db2a2cf1c14c6c7231/src/mongo/db/exec/batched_delete_stage.cpp#L418):

      kCollName = "boom"; 
      db[kCollName].insert({_id: "X".repeat(16776704)});
      db[kCollName].remove({});
      
      Error: network error while attempting to run command 'delete' on host '127.0.0.1:27017'  :: caused by :: dbclient error communicating with server 127.0.0.1:27017 :: caused by :: futurize :: caused by :: Connection closed by peer :
      

      Log output from mongod:

      {"t":{"$date":"2025-02-21T14:11:16.083+00:00"},"s":"F",  "c":"ASSERT",   "id":23079,   "ctx":"conn1","msg":"Invariant failure","attr":{"expr":"*bufferOffset > 0","location":"src/mongo/db/exec/batched_delete_stage.cpp:418:40:long long mongo::BatchedDeleteStage::_commitBatch(WorkingSetID *, std::set<WorkingSetID> *, unsigned int *, unsigned int *, unsigned int *)"}}
      {"t":{"$date":"2025-02-21T14:11:16.083+00:00"},"s":"F",  "c":"ASSERT",   "id":23080,   "ctx":"conn1","msg":"\n\n***aborting after invariant() failure\n\n"}
      

      Note that the _id value of the inserted document is quite large (a 16776704 bytes long string).
      This if condition and block in batched_delete_stage.cpp are likely wrong, as they do not take into account that already a batch with a single document can trigger it.

      At this point, applyOpsBytes is 512 bytes (2 * kApplyOpsNonArrayEntryPaddingBytes plus the size of the _id field's BSONElement. The BSONElement size is the length of the field name plus the length of the value plus some BSON overhead. Together with the 512 bytes overhead added before, this is larger than BSONObjMaxUserSize, so the if branch is taken here.

      This is reproducible in master, but likely also in previous versions.

            Assignee:
            Evan Bergeron
            Reporter:
            Jan Steemann
            Votes:
            0 Vote for this issue
            Watchers:
            10 Start watching this issue

              Created:
              Updated:
              Resolved: