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

Incompatible to update capped collection after upgrade to MongoDB-3.2

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Duplicate
    • Affects Version/s: 3.2.6
    • Fix Version/s: None
    • Component/s: Storage
    • Labels:
      None
    • Operating System:
      ALL
    • Steps To Reproduce:
      Hide

      use mongo shell to create a capped collection

      db.createCollection("capped", {capped: 1, max: 5000, size: 1000000})
      db.capped.insert({id: "test", x: 0})
      

      when use nodejs client to update this document, db.capped.update(

      {id: "test}

      , {$set: {x: 1}}), it will receive an error.

      Cannot change the size of a document in a capped collection: 33 != 29
      

      Show
      use mongo shell to create a capped collection db.createCollection("capped", {capped: 1, max: 5000, size: 1000000}) db.capped.insert({id: "test", x: 0}) when use nodejs client to update this document, db.capped.update( {id: "test} , {$set: {x: 1}}), it will receive an error. Cannot change the size of a document in a capped collection: 33 != 29

      Description

      Background

      Different drivers may have different way to encode a integer to BSON, eg: when insert a document

      {status: 1}

      * mongoshell encode 1 to a 8bytes data,  server received a request {status: 1.0}.
      * nodejs driver encode 1 to 4bytes data, server received a request {status: 1}
      
      

      MongoDB 3.2 behaivor

      MongoDB-3.2 added on a new condition check when update a capped collection, this is suitable for all storage engines. Which means user "Cannot change the size of a document in a capped collection".

      db/catalog/collection.cpp:556
          const auto oldSize = oldDoc.value().objsize();
          if (_recordStore->isCapped() && oldSize != newDoc.objsize())
              return {ErrorCodes::CannotGrowDocumentInCappedNamespace,
                      str::stream() << "Cannot change the size of a document in a capped collection: "
                                    << oldSize << " != " << newDoc.objsize()};
      

      MongoDB 3.0 behaivor

      In mongodb 3.0, only mmapv1 have limitation to update a capped collection, that is "objects in a capped ns cannot grow(no need have the same size with old document".

       
      if (isCapped())
              return StatusWith<RecordId>(
                  ErrorCodes::InternalError, "failing update: objects in a capped ns cannot grow", 10003);
      

        Issue Links

          Activity

          Hide
          ramon.fernandez Ramon Fernandez added a comment -

          Youdong Zhang, as per SERVER-20529 this is now expected behavior in 3.2. Unfortunately this backwards-breaking change is necessary to support replica sets with different storage engines.

          Regards,
          Ramón.

          Show
          ramon.fernandez Ramon Fernandez added a comment - Youdong Zhang , as per SERVER-20529 this is now expected behavior in 3.2. Unfortunately this backwards-breaking change is necessary to support replica sets with different storage engines. Regards, Ramón.
          Hide
          max.hirschhorn Max Hirschhorn added a comment -

          I'd also like to clarify what's happening with the mongo shell.

          * mongoshell encode 1 to a 8bytes data,  server received a request {status: 1.0}.
          

          This is because the representation for Number literals is as a double-precision 64-bit binary format IEEE 754 value. This is required by the ECMAScript specification: http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-number-value.

          The reason why 8 bytes of data are being sent to the server is because the number is encoded as a double (BSON type 0x01) and not a 32-bit integer (BSON type 0x10). If you want to use 32-bit integers within the mongo shell, you must use the NumberInt constructor. This is described in our documentation and an example can be seen below:

          > db.mycoll.insert({_id: 1})
          > db.mycoll.insert({_id: 2.0})
          > db.mycoll.insert({_id: NumberInt(3)})
          > db.mycoll.find()
          { "_id" : 1 }
          { "_id" : 2 }
          { "_id" : 3 }
          > db.mycoll.find({_id: {$type: 'double'}})
          { "_id" : 1 }
          { "_id" : 2 }
          > db.mycoll.find({_id: {$type: 'int'}})
          { "_id" : 3 }
          

          Show
          max.hirschhorn Max Hirschhorn added a comment - I'd also like to clarify what's happening with the mongo shell. * mongoshell encode 1 to a 8bytes data, server received a request {status: 1.0}. This is because the representation for Number literals is as a double-precision 64-bit binary format IEEE 754 value . This is required by the ECMAScript specification: http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-number-value . The reason why 8 bytes of data are being sent to the server is because the number is encoded as a double (BSON type 0x01) and not a 32-bit integer (BSON type 0x10). If you want to use 32-bit integers within the mongo shell, you must use the NumberInt constructor. This is described in our documentation and an example can be seen below: https://docs.mongodb.org/manual/core/shell-types/#numberint https://docs.mongodb.org/manual/core/shell-types/#numberlong > db.mycoll.insert({_id: 1}) > db.mycoll.insert({_id: 2.0}) > db.mycoll.insert({_id: NumberInt(3)}) > db.mycoll.find() { "_id" : 1 } { "_id" : 2 } { "_id" : 3 } > db.mycoll.find({_id: {$type: 'double'}}) { "_id" : 1 } { "_id" : 2 } > db.mycoll.find({_id: {$type: 'int'}}) { "_id" : 3 }

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              9 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: