Uploaded image for project: 'C++ Driver'
  1. C++ Driver
  2. CXX-2028

Explicit write concern is incorrectly applied to collection::find_one_and_* methods

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Critical - P2
    • Resolution: Fixed
    • 3.2.0-rc0
    • 3.2.1, 3.3.2, 3.4.2, 3.5.1, 3.6.0-rc0, 3.6.0
    • None
    • None

    Description

      Summary
      collection::find_one_and_update(), collection::find_one_and_replace(), and collection::find_one_and_delete() accept an optional explicit write concern through the respective option classes: options::find_one_and_update, options::find_one_and_replace, and options::find_one_and_delete. The write concern is incorrectly applied to the command. MongoDB servers prior to 4.2 ignore the incorrectly applied fields, but 4.2+ servers explicitly reject the command.

      Any application passing an explicit write concern to the find_one_and_* functions may either upgrade to the patch releases with this fix applied or instead set a write concern on the collection/database object with collection::write_concern() or database::write_concern().

      Original description
      When journal option for write_concern is specified for find_and_modify (mongocxx v3.5.0 and MongoDB v4.2.6) it throws an error:

      terminate called after throwing an instance of 'mongocxx::v_noabi::write_exception'
        what():  BSON field 'j' is an unknown field.: generic server error
      

      Example code:

            auto criteria = make_document(kvp("x", "foo"));
            auto update = make_document(kvp("$set", make_document(kvp("x", "bar"))));
       
            auto write_concern = mongocxx::write_concern{};
            write_concern.journal(true);
            write_concern.acknowledge_level(
              mongocxx::write_concern::level::k_majority);
       
            std::cout << "Setting options" << std::endl;
            auto options = mongocxx::options::find_one_and_update()
              .write_concern(std::move(write_concern))
              .return_document(mongocxx::options::return_document::k_before);
       
            std::cout << "Invoking find_one_and_update" << std::endl;
            coll.find_one_and_update(
              criteria.view(),
              update.view(),
              options);
      

      Looking at the log generated in the server, the options for w and j is not enclosed in writeConcern document. i.e. w: "majority", j: true

      2020-05-27T17:31:17.811+1000 I  COMMAND  [conn7] command dbName.$cmd command: findAndModify { findAndModify: "collectionName", query: { x: "foo" }, update: { $set: { x: "bar" } }, w: "majority", j: true, $db: "test", lsid: { id: UUID("e3fcf2a5-f1c0-4026-b672-c13b27923119") }, txnNumber: 1, $clusterTime: { clusterTime: Timestamp(1590564675, 1), signature: { hash: BinData(0, 0000000000000000000000000000000000000000), keyId: 0 } } } numYields:0 ok:0 errMsg:"BSON field 'j' is an unknown field." errName:Location51177 errCode:51177 reslen:249 locks:{ ParallelBatchWriterMode: { acquireCount: { r: 1 } }, ReplicationStateTransition: { acquireCount: { w: 3 } }, Global: { acquireCount: { r: 2 } }, Database: { acquireCount: { r: 1 } }, Collection: { acquireCount: { r: 1 } }, Mutex: { acquireCount: { r: 1 } } } storage:{} protocol:op_msg 0ms
      

      Comparing to find_and_modify sent from PyMongo, the server command log shows {{writeConcern:

      { j: true, w: "majority" }

      }}

      2020-05-27T17:31:10.326+1000 I  COMMAND  [conn6] command dbName.collectionName command: findAndModify { findAndModify: "collectionName", query: { x: "foo" }, new: false, update: { $set: { x: "bar" } }, upsert: false, writeConcern: { j: true, w: "majority" }, lsid: { id: UUID("296a5316-c756-4099-ba45-e4a14a9380ac") }, txnNumber: 1, $clusterTime: { clusterTime: Timestamp(1590564665, 1), signature: { hash: BinData(0, 0000000000000000000000000000000000000000), keyId: 0 } }, $db: "dbName", $readPreference: { mode: "primary" } } planSummary: EOF keysExamined:0 docsExamined:0 nMatched:0 nModified:0 numYields:0 reslen:217 locks:{ ParallelBatchWriterMode: { acquireCount: { r: 2 } }, ReplicationStateTransition: { acquireCount: { w: 4 } }, Global: { acquireCount: { r: 2, w: 1 } }, Database: { acquireCount: { r: 1, w: 1 } }, Collection: { acquireCount: { r: 2, w: 1 } }, Mutex: { acquireCount: { r: 2 } } } flowControl:{ acquireCount: 1, timeAcquiringMicros: 1 } storage:{} protocol:op_msg 0ms
      

      Additional reference: findAndModify

      Looking at the server code, a change is introduced by SERVER-40005 to check for unknown field in find_and_modify. https://github.com/mongodb/mongo/blame/r4.2.6/src/mongo/db/query/find_and_modify_request.cpp#L252
      (Similar error is not thrown on MongoDB v4.0.x)

       

      Attachments

        Issue Links

          Activity

            People

              clyde.bazile@mongodb.com Clyde Bazile III (Inactive)
              wan.bachtiar@mongodb.com Wan Bachtiar
              Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: