diff options
-rw-r--r-- | jstests/replsets/get_last_error.js | 86 | ||||
-rw-r--r-- | jstests/replsets/server_status_metrics.js | 25 | ||||
-rw-r--r-- | src/mongo/db/dbcommands.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/stats/timer_stats.cpp | 5 |
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 ) { |