summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/replsets/get_last_error.js86
-rw-r--r--jstests/replsets/server_status_metrics.js25
-rw-r--r--src/mongo/db/dbcommands.cpp28
-rw-r--r--src/mongo/db/stats/timer_stats.cpp5
4 files changed, 137 insertions, 7 deletions
diff --git a/jstests/replsets/get_last_error.js b/jstests/replsets/get_last_error.js
new file mode 100644
index 00000000000..48eb81cb073
--- /dev/null
+++ b/jstests/replsets/get_last_error.js
@@ -0,0 +1,86 @@
+// Check that the wtime and writtenTo fields are set or unset depending on the writeConcern used.
+// First check on a replica set with different combinations of writeConcern
+var replTest = new ReplSetTest( {name: "SERVER-9005", oplogSize: 1, nodes: 2} );
+var nodes = replTest.startSet();
+replTest.initiate();
+var master = replTest.getMaster();
+var mdb = master.getDB("test");
+mdb.foo.insert({ _id: "1" });
+replTest.awaitReplication();
+
+var gle = master.getDB("test").runCommand({getLastError : 1, j : true, wtimeout : 60000});
+print('Trying j=true, 60000ms timeout');
+printjson(gle);
+assert.eq(gle.err, null);
+assert.eq(gle.writtenTo, null);
+assert.eq(gle.waited, null);
+assert.eq(gle.wtime, null);
+assert.eq(gle.wtimeout, null);
+
+gle = mdb.getLastErrorObj(1, 10);
+print('Trying w=1, 10ms timeout');
+printjson(gle);
+assert.eq(gle.err, null);
+assert.eq(gle.writtenTo, null);
+assert.eq(gle.wtime, null);
+assert.eq(gle.waited, null);
+assert.eq(gle.wtimeout, null);
+
+gle = mdb.getLastErrorObj(2, 100);
+print('Trying w=2, 100ms timeout.');
+printjson(gle);
+assert.eq(gle.err, null);
+assert.eq(gle.writtenTo.length, 2);
+assert.gte(gle.wtime, 0);
+assert.eq(gle.waited, null);
+assert.eq(gle.wtimeout, null);
+
+gle = mdb.getLastErrorObj(3, 100);
+print('Trying w=3, 100ms timeout. Should timeout.');
+printjson(gle);
+assert.eq(gle.err, "timeout");
+assert.eq(gle.writtenTo.length, 2);
+assert.eq(gle.wtime, null);
+assert.eq(gle.waited, 100);
+assert.eq(gle.wtimeout, true);
+
+gle = mdb.getLastErrorObj("majority", 100);
+print('Trying w=majority, 100ms timeout.');
+printjson(gle);
+assert.eq(gle.err, null);
+assert.eq(gle.writtenTo.length, 2);
+assert.eq(gle.wtime, 0);
+assert.eq(gle.waited, null);
+assert.eq(gle.wtimeout, null);
+
+replTest.stopSet();
+
+// Next check that it still works on a lone mongod
+// Need to start a single server manually to keep this test in the jstests/replsets test suite
+var port = allocatePorts(1)[0];
+var baseName = "SERVER-9005";
+var mongod = startMongod("--port", port, "--dbpath", "/data/db/" + baseName);
+var sdb = new Mongo("localhost:"+port).getDB("test");
+
+sdb.foo.drop();
+sdb.foo.insert({ _id: "1" });
+
+gle = sdb.getLastErrorObj(1);
+print('Trying standalone server with w=1.');
+printjson(gle);
+assert.eq(gle.err, null);
+assert.eq(gle.writtenTo, null);
+assert.eq(gle.wtime, null);
+assert.eq(gle.waited, null);
+assert.eq(gle.wtimeout, null);
+
+gle = sdb.getLastErrorObj(2, 10);
+print('Trying standalone server with w=2 and 10ms timeout.');
+printjson(gle);
+assert.eq(gle.err, "norepl");
+assert.eq(gle.writtenTo, null);
+assert.eq(gle.wtime, null);
+assert.eq(gle.waited, null);
+assert.eq(gle.wtimeout, null);
+
+stopMongod(port);
diff --git a/jstests/replsets/server_status_metrics.js b/jstests/replsets/server_status_metrics.js
index a697292cc2a..e5c62f4617a 100644
--- a/jstests/replsets/server_status_metrics.js
+++ b/jstests/replsets/server_status_metrics.js
@@ -63,4 +63,29 @@ testDB.getLastError(2);
testSecondaryMetrics(secondary, 20000, secondaryBaseOplogInserts -1);
+
+// Test getLastError.wtime and that it only records stats for w > 1, see SERVER-9005
+var startMillis = testDB.serverStatus().metrics.getLastError.wtime.totalMillis
+var startNum = testDB.serverStatus().metrics.getLastError.wtime.num
+
+printjson(primary.getDB("test").serverStatus().metrics);
+
+testDB.getLastError(1, 50 );
+assert.eq(testDB.serverStatus().metrics.getLastError.wtime.totalMillis, startMillis);
+assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum);
+
+testDB.getLastError(-11, 50 );
+assert.eq(testDB.serverStatus().metrics.getLastError.wtime.totalMillis, startMillis);
+assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum);
+
+testDB.getLastError(2, 50 );
+assert(testDB.serverStatus().metrics.getLastError.wtime.totalMillis >= startMillis);
+assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum + 1);
+
+testDB.getLastError(3, 50 );
+assert(testDB.serverStatus().metrics.getLastError.wtime.totalMillis >= startMillis + 50);
+assert.eq(testDB.serverStatus().metrics.getLastError.wtime.num, startNum + 2);
+
+printjson(primary.getDB("test").serverStatus().metrics);
+
rt.stopSet();
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 386f2fdbc26..0b3c1b97ba5 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -198,7 +198,21 @@ namespace mongo {
}
int timeout = cmdObj["wtimeout"].numberInt();
- TimerHolder timer( &gleWtimeStats );
+ scoped_ptr<TimerHolder> gleTimerHolder;
+ bool doTiming = false;
+ if ( e.isNumber() ) {
+ doTiming = e.numberInt() > 1;
+ }
+ else if ( e.type() == String ) {
+ doTiming = true;
+ }
+ TimerStats t;
+ if ( doTiming ) {
+ gleTimerHolder.reset( new TimerHolder( &gleWtimeStats ) );
+ }
+ else {
+ gleTimerHolder.reset( new TimerHolder( &t ) );
+ }
long long passes = 0;
char buf[32];
@@ -259,11 +273,11 @@ namespace mongo {
}
- if ( timeout > 0 && timer.millis() >= timeout ) {
+ if ( timeout > 0 && gleTimerHolder->millis() >= timeout ) {
gleWtimeouts.increment();
result.append( "wtimeout" , true );
errmsg = "timed out waiting for slaves";
- result.append( "waited" , timer.millis() );
+ result.append( "waited" , gleTimerHolder->millis() );
result.append("writtenTo", getHostsWrittenTo(op));
result.append( "err" , "timeout" );
return true;
@@ -275,9 +289,11 @@ namespace mongo {
killCurrentOp.checkForInterrupt();
}
- result.append("writtenTo", getHostsWrittenTo(op));
- int myMillis = timer.recordMillis();
- result.appendNumber( "wtime" , myMillis );
+ if ( doTiming ) {
+ result.append("writtenTo", getHostsWrittenTo(op));
+ int myMillis = gleTimerHolder->recordMillis();
+ result.appendNumber( "wtime" , myMillis );
+ }
}
result.appendNull( "err" );
diff --git a/src/mongo/db/stats/timer_stats.cpp b/src/mongo/db/stats/timer_stats.cpp
index 970f5671872..f0543b22123 100644
--- a/src/mongo/db/stats/timer_stats.cpp
+++ b/src/mongo/db/stats/timer_stats.cpp
@@ -31,7 +31,10 @@ namespace mongo {
int TimerHolder::recordMillis() {
_recorded = true;
- return _stats->record( _t );
+ if ( _stats ) {
+ return _stats->record( _t );
+ }
+ return _t.millis();
}
void TimerStats::recordMillis( int millis ) {