[SERVER-20350] mongo shell has incorrect check for compatibility mode for write operations Created: 10/Sep/15  Updated: 11/Sep/15  Resolved: 11/Sep/15

Status: Closed
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Jon Rangel (Inactive) Assignee: Unassigned
Resolution: Cannot Reproduce Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Operating System: ALL
Participants:

 Description   

In 2.6+ versions of the mongo shell, there is the following check in the insert(), update() and remove() methods on the collection object:

   if ( this.getMongo().writeMode() != "legacy" ) {
        // use write commands
    else {
        // use legacy write op, followed by getLastError
    }

The problem is, with versions of the server prior to 2.6 this.getMongo().writeMode() returns "compatibility", NOT "legacy", so the 'else' block in the above code is never executed.

The impact is that the write concern passed in by the caller is not respected, since getLastError is not called.

A workaround is for the user is to make an explicit getLastError call (on the same line, if running an interactive shell):

e.g.

db.foo.remove({_id:1}); db.runCommand({getLastError:1, w:2})

The above code works with both 2.4 and 2.6+ versions of the server.



 Comments   
Comment by Scott Hernandez (Inactive) [ 11/Sep/15 ]

We use all of this extensively in jstests and this was given a lot of attention when we added the write commands and bulk api in the shell for correctness, esp. due to the fact we use it to test the server in jstests.

As Eric noted, the fact that the (extra) args may not error when unknown args are seen could be the issue, like this (which doesn't error or ensure a correct write):

db.a.insert({_id:1}, {w:"majority"}) // missing writeConcern
db.a.insert({_id:1}, {write_concern: {w:"majority"}}) // missing writeConcern
db.a.insert({_id:1}, {writeconcern: {w:"majority"}}) // missing writeConcern

Also, if you are not using the interactive shell, but a script then no error will be seen as the write methods don't throw error but instead return results which must be inspected manually (like via the assert.writeOK helper).

db.a.insert({_id:1}
db.a.insert({_id:1} // no error when run as a script
assert.writeOK(db.a.insert({_id:1}) // always does what is expected, and errors

Comment by Jon Rangel (Inactive) [ 10/Sep/15 ]

Hmmm, I think the return value of db.collection.getMongo().writeMode() was a red herring. It looks like the bulk API does downconvert to the legacy ops and getLastError, and I verified that write concern is respected for insert(), update() and remove()

https://github.com/mongodb/mongo/blob/789a8e2669c38ad5ebcbd07bff98d14d7354e421/src/mongo/shell/bulk_api.js#L1096

Not sure why it appeared to ignore write concern previously - maybe due to a typo.

Comment by Eric Milkie [ 10/Sep/15 ]

Note that providing the write concern as part of the options parameter to the shell write helpers can be tricky, as the options parameter is not checked for syntax – thus it is ignored if you don't specify it correctly.

Comment by Eric Milkie [ 10/Sep/15 ]

Are you sure the collection object functions use write commands? When I look at DBCollection.prototype.insert for example, it looks like if the writeMode is not "legacy", it then proceeds to use the bulk API, which may or may not use write commands. The bulk API might instead downconvert to using legacy ops and getLastError if the server does not support write commands.
Perhaps there is something else going on here?

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