summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Studer <greg@10gen.com>2013-12-05 13:51:02 -0500
committerGreg Studer <greg@10gen.com>2013-12-08 13:36:48 -0500
commite7f4f01001866bddd5a2d20f9f80e50c037f4fe6 (patch)
tree7b4b95588a59c9f257a1345c0609657ab911615e
parent9a1b20453b318801c344850879023427c812c047 (diff)
downloadmongo-e7f4f01001866bddd5a2d20f9f80e50c037f4fe6.tar.gz
SERVER-11869 support for external gle opTime for w > 1
-rw-r--r--jstests/replsets/gle_explicit_optime.js57
-rw-r--r--src/mongo/db/dbcommands.cpp13
2 files changed, 67 insertions, 3 deletions
diff --git a/jstests/replsets/gle_explicit_optime.js b/jstests/replsets/gle_explicit_optime.js
new file mode 100644
index 00000000000..77c526e981d
--- /dev/null
+++ b/jstests/replsets/gle_explicit_optime.js
@@ -0,0 +1,57 @@
+//
+// Tests the use of the wOpTime option in getLastError
+//
+
+var rst = new ReplSetTest({ nodes : 2 });
+rst.startSet();
+rst.initiate();
+
+var primary = rst.getPrimary();
+var secondary = rst.getSecondary();
+
+var coll = primary.getCollection( "foo.bar" );
+
+// Insert a doc and replicate it to two servers
+coll.insert({ some : "doc" });
+var gleObj = coll.getDB().getLastErrorObj( 2 ); // w : 2
+assert.eq( null, gleObj.err );
+var opTimeBeforeFailure = gleObj.lastOp;
+
+// Lock the secondary
+secondary.getDB("admin").fsyncLock();
+
+// Insert a doc and replicate it to the primary only
+coll.insert({ some : "doc" });
+gleObj = coll.getDB().getLastErrorObj( 1 ); // w : 1
+assert.eq( null, gleObj.err );
+var opTimeAfterFailure = gleObj.lastOp;
+
+printjson(opTimeBeforeFailure);
+printjson(opTimeAfterFailure);
+printjson( primary.getDB("admin").runCommand({ replSetGetStatus : true }) );
+
+// Create a new connection with new client and no opTime
+var newClientConn = new Mongo( primary.host );
+
+// New client has no set opTime, so w : 2 has no impact
+gleObj = newClientConn.getCollection( coll.toString() ).getDB().getLastErrorObj( 2 ); // w : 2
+assert.eq( null, gleObj.err );
+
+// Using an explicit optime on the new client should work if the optime is earlier than the
+// secondary was locked
+var gleOpTimeBefore = { getLastError : true, w : 2, wOpTime : opTimeBeforeFailure };
+gleObj = newClientConn.getCollection( coll.toString() ).getDB().runCommand( gleOpTimeBefore );
+assert.eq( null, gleObj.err );
+
+// Using an explicit optime on the new client should not work if the optime is later than the
+// secondary was locked
+var gleOpTimeAfter = { getLastError : true, w : 2, wtimeout : 1000, wOpTime : opTimeAfterFailure };
+gleObj = newClientConn.getCollection( coll.toString() ).getDB().runCommand( gleOpTimeAfter );
+assert.neq( null, gleObj.err );
+assert( gleObj.wtimeout );
+
+jsTest.log("DONE!");
+
+// Unlock the secondary
+secondary.getDB("admin").fsyncUnlock();
+rst.stopSet();
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 8b8252f68a6..fb6be132171 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -178,9 +178,9 @@ namespace mongo {
}
}
- if ( err ) {
+ if ( err && cmdObj["wOpTime"].eoo() ) {
// doesn't make sense to wait for replication
- // if there was an error
+ // if there was an error and we aren't explicitly waiting for another wOpTime
return true;
}
@@ -200,7 +200,14 @@ namespace mongo {
long long passes = 0;
char buf[32];
- OpTime op(c.getLastOp());
+
+ OpTime op;
+ if ( cmdObj["wOpTime"].type() == Timestamp ) {
+ op = OpTime( cmdObj["wOpTime"].date() );
+ }
+ else {
+ op = c.getLastOp();
+ }
if ( op.isNull() ) {
if ( anyReplEnabled() ) {