summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJason Rassi <rassi@10gen.com>2013-07-10 14:49:00 -0400
committerJason Rassi <rassi@10gen.com>2013-07-10 14:49:00 -0400
commit089d5992f9000d618a59f79fa5dc1a3e818c2ad0 (patch)
tree66b109bdc0cb93115562e7b2117ec487a3c1975f /src
parent4f7713325020275578cce51dcd6ba7a1a19cfb22 (diff)
downloadmongo-089d5992f9000d618a59f79fa5dc1a3e818c2ad0.tar.gz
SERVER-9468 Pull out bulk of CmdGetLastError::run() into helper
Diffstat (limited to 'src')
-rw-r--r--src/mongo/SConscript1
-rw-r--r--src/mongo/db/dbcommands.cpp151
-rw-r--r--src/mongo/db/write_concern.cpp182
-rw-r--r--src/mongo/db/write_concern.h32
4 files changed, 217 insertions, 149 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index 754d13f3dd3..4adc150dc5b 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -523,6 +523,7 @@ serverOnlyFiles = [ "db/curop.cpp",
"db/dbcommands.cpp",
"db/compact.cpp",
"db/dbcommands_admin.cpp",
+ "db/write_concern.cpp",
# most commands are only for mongod
"db/commands/apply_ops.cpp",
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 8fa0c7d9442..23e1d67a4d1 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -25,7 +25,6 @@
#include <time.h>
-#include "mongo/base/counter.h"
#include "mongo/base/init.h"
#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
@@ -55,8 +54,7 @@
#include "mongo/db/query_optimizer.h"
#include "mongo/db/repl/is_master.h"
#include "mongo/db/repl/oplog.h"
-#include "mongo/db/repl/write_concern.h"
-#include "mongo/db/stats/timer_stats.h"
+#include "mongo/db/write_concern.h"
#include "mongo/s/d_writeback.h"
#include "mongo/s/stale_exception.h" // for SendStaleConfigException
#include "mongo/scripting/engine.h"
@@ -104,12 +102,6 @@ namespace mongo {
*/
BSONObj *getLastErrorDefault = 0;
- static TimerStats gleWtimeStats;
- static ServerStatusMetricField<TimerStats> displayGleLatency( "getLastError.wtime", &gleWtimeStats );
-
- static Counter64 gleWtimeouts;
- static ServerStatusMetricField<Counter64> gleWtimeoutsDisplay( "getLastError.wtimeouts", &gleWtimeouts );
-
class CmdGetLastError : public Command {
public:
CmdGetLastError() : Command("getLastError", false, "getlasterror") { }
@@ -158,146 +150,7 @@ namespace mongo {
}
}
- if ( cmdObj["j"].trueValue() ) {
- if( !getDur().awaitCommit() ) {
- // --journal is off
- result.append("jnote", "journaling not enabled on this server");
- }
- if( cmdObj["fsync"].trueValue() ) {
- errmsg = "fsync and j options are not used together";
- return false;
- }
- }
- else if ( cmdObj["fsync"].trueValue() ) {
- Timer t;
- if( !getDur().awaitCommit() ) {
- // if get here, not running with --journal
- log() << "fsync from getlasterror" << endl;
- result.append( "fsyncFiles" , MemoryMappedFile::flushAll( true ) );
- }
- else {
- // this perhaps is temp. how long we wait for the group commit to occur.
- result.append( "waited", t.millis() );
- }
- }
-
- if ( err ) {
- // doesn't make sense to wait for replication
- // if there was an error
- return true;
- }
-
- BSONElement e = cmdObj["w"];
- if ( e.ok() ) {
-
- if ( cmdLine.configsvr && (!e.isNumber() || e.numberInt() > 1) ) {
- // w:1 on config servers should still work, but anything greater than that
- // should not.
- result.append( "wnote", "can't use w on config servers" );
- result.append( "err", "norepl" );
- return true;
- }
-
- int timeout = cmdObj["wtimeout"].numberInt();
- scoped_ptr<TimerHolder> gleTimerHolder;
- bool doTiming = false;
- if ( e.isNumber() ) {
- doTiming = e.numberInt() > 1;
- }
- else if ( e.type() == String ) {
- doTiming = true;
- }
- if ( doTiming ) {
- gleTimerHolder.reset( new TimerHolder( &gleWtimeStats ) );
- }
- else {
- gleTimerHolder.reset( new TimerHolder( NULL ) );
- }
-
- long long passes = 0;
- char buf[32];
- OpTime op(c.getLastOp());
-
- if ( op.isNull() ) {
- if ( anyReplEnabled() ) {
- result.append( "wnote" , "no write has been done on this connection" );
- }
- else if ( e.isNumber() && e.numberInt() <= 1 ) {
- // don't do anything
- // w=1 and no repl, so this is fine
- }
- else if (e.type() == mongo::String &&
- str::equals(e.valuestrsafe(), "majority")) {
- // don't do anything
- // w=majority and no repl, so this is fine
- }
- else {
- // w=2 and no repl
- stringstream errmsg;
- errmsg << "no replication has been enabled, so w=" <<
- e.toString(false) << " won't work";
- result.append( "wnote" , errmsg.str() );
- result.append( "err", "norepl" );
- return true;
- }
-
- result.appendNull( "err" );
- return true;
- }
-
- if ( !theReplSet && !e.isNumber() ) {
- result.append( "wnote", "cannot use non integer w values for non-replica sets" );
- result.append( "err", "noreplset" );
- return true;
- }
-
- while ( 1 ) {
-
- if ( !_isMaster() ) {
- // this should be in the while loop in case we step down
- errmsg = "not master";
- result.append( "wnote", "no longer primary" );
- result.append( "code" , 10990 );
- return false;
- }
-
- // check this first for w=0 or w=1
- if ( opReplicatedEnough( op, e ) ) {
- break;
- }
-
- // if replication isn't enabled (e.g., config servers)
- if ( ! anyReplEnabled() ) {
- result.append( "err", "norepl" );
- return true;
- }
-
-
- if ( timeout > 0 && gleTimerHolder->millis() >= timeout ) {
- gleWtimeouts.increment();
- result.append( "wtimeout" , true );
- errmsg = "timed out waiting for slaves";
- result.append( "waited" , gleTimerHolder->millis() );
- result.append("writtenTo", getHostsWrittenTo(op));
- result.append( "err" , "timeout" );
- return true;
- }
-
- verify( sprintf( buf , "w block pass: %lld" , ++passes ) < 30 );
- c.curop()->setMessage( buf );
- sleepmillis(1);
- killCurrentOp.checkForInterrupt();
- }
-
- if ( doTiming ) {
- result.append("writtenTo", getHostsWrittenTo(op));
- int myMillis = gleTimerHolder->recordMillis();
- result.appendNumber( "wtime" , myMillis );
- }
- }
-
- result.appendNull( "err" );
- return true;
+ return waitForWriteConcern(cmdObj, err, &result, &errmsg);
}
} cmdGetLastError;
diff --git a/src/mongo/db/write_concern.cpp b/src/mongo/db/write_concern.cpp
new file mode 100644
index 00000000000..53ff7d83f5c
--- /dev/null
+++ b/src/mongo/db/write_concern.cpp
@@ -0,0 +1,182 @@
+/**
+ * Copyright (C) 2013 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mongo/base/counter.h"
+#include "mongo/db/commands/server_status.h"
+#include "mongo/db/lasterror.h"
+#include "mongo/db/kill_current_op.h"
+#include "mongo/db/repl/is_master.h"
+#include "mongo/db/repl/replication_server_status.h"
+#include "mongo/db/repl/write_concern.h"
+#include "mongo/db/stats/timer_stats.h"
+
+namespace mongo {
+
+ static TimerStats gleWtimeStats;
+ static ServerStatusMetricField<TimerStats> displayGleLatency( "getLastError.wtime", &gleWtimeStats );
+
+ static Counter64 gleWtimeouts;
+ static ServerStatusMetricField<Counter64> gleWtimeoutsDisplay( "getLastError.wtimeouts", &gleWtimeouts );
+
+ bool waitForWriteConcern(const BSONObj& cmdObj,
+ bool err,
+ BSONObjBuilder* result,
+ string* errmsg) {
+ Client& c = cc();
+
+ if ( cmdObj["j"].trueValue() ) {
+ if( !getDur().awaitCommit() ) {
+ // --journal is off
+ result->append("jnote", "journaling not enabled on this server");
+ }
+ if( cmdObj["fsync"].trueValue() ) {
+ *errmsg = "fsync and j options are not used together";
+ return false;
+ }
+ }
+ else if ( cmdObj["fsync"].trueValue() ) {
+ Timer t;
+ if( !getDur().awaitCommit() ) {
+ // if get here, not running with --journal
+ log() << "fsync from getlasterror" << endl;
+ result->append( "fsyncFiles" , MemoryMappedFile::flushAll( true ) );
+ }
+ else {
+ // this perhaps is temp. how long we wait for the group commit to occur.
+ result->append( "waited", t.millis() );
+ }
+ }
+
+ if ( err ) {
+ // doesn't make sense to wait for replication
+ // if there was an error
+ return true;
+ }
+
+ BSONElement e = cmdObj["w"];
+ if ( e.ok() ) {
+
+ if ( cmdLine.configsvr && (!e.isNumber() || e.numberInt() > 1) ) {
+ // w:1 on config servers should still work, but anything greater than that
+ // should not.
+ result->append( "wnote", "can't use w on config servers" );
+ result->append( "err", "norepl" );
+ return true;
+ }
+
+ int timeout = cmdObj["wtimeout"].numberInt();
+ scoped_ptr<TimerHolder> gleTimerHolder;
+ bool doTiming = false;
+ if ( e.isNumber() ) {
+ doTiming = e.numberInt() > 1;
+ }
+ else if ( e.type() == String ) {
+ doTiming = true;
+ }
+ if ( doTiming ) {
+ gleTimerHolder.reset( new TimerHolder( &gleWtimeStats ) );
+ }
+ else {
+ gleTimerHolder.reset( new TimerHolder( NULL ) );
+ }
+
+ long long passes = 0;
+ char buf[32];
+ OpTime op(c.getLastOp());
+
+ if ( op.isNull() ) {
+ if ( anyReplEnabled() ) {
+ result->append( "wnote" , "no write has been done on this connection" );
+ }
+ else if ( e.isNumber() && e.numberInt() <= 1 ) {
+ // don't do anything
+ // w=1 and no repl, so this is fine
+ }
+ else if (e.type() == mongo::String &&
+ str::equals(e.valuestrsafe(), "majority")) {
+ // don't do anything
+ // w=majority and no repl, so this is fine
+ }
+ else {
+ // w=2 and no repl
+ stringstream errmsg;
+ errmsg << "no replication has been enabled, so w=" <<
+ e.toString(false) << " won't work";
+ result->append( "wnote" , errmsg.str() );
+ result->append( "err", "norepl" );
+ return true;
+ }
+
+ result->appendNull( "err" );
+ return true;
+ }
+
+ if ( !theReplSet && !e.isNumber() ) {
+ result->append( "wnote", "cannot use non integer w values for non-replica sets" );
+ result->append( "err", "noreplset" );
+ return true;
+ }
+
+ while ( 1 ) {
+
+ if ( !_isMaster() ) {
+ // this should be in the while loop in case we step down
+ *errmsg = "not master";
+ result->append( "wnote", "no longer primary" );
+ result->append( "code" , 10990 );
+ return false;
+ }
+
+ // check this first for w=0 or w=1
+ if ( opReplicatedEnough( op, e ) ) {
+ break;
+ }
+
+ // if replication isn't enabled (e.g., config servers)
+ if ( ! anyReplEnabled() ) {
+ result->append( "err", "norepl" );
+ return true;
+ }
+
+
+ if ( timeout > 0 && gleTimerHolder->millis() >= timeout ) {
+ gleWtimeouts.increment();
+ result->append( "wtimeout" , true );
+ *errmsg = "timed out waiting for slaves";
+ result->append( "waited" , gleTimerHolder->millis() );
+ result->append("writtenTo", getHostsWrittenTo(op));
+ result->append( "err" , "timeout" );
+ return true;
+ }
+
+ verify( sprintf( buf , "w block pass: %lld" , ++passes ) < 30 );
+ c.curop()->setMessage( buf );
+ sleepmillis(1);
+ killCurrentOp.checkForInterrupt();
+ }
+
+ if ( doTiming ) {
+ result->append("writtenTo", getHostsWrittenTo(op));
+ int myMillis = gleTimerHolder->recordMillis();
+ result->appendNumber( "wtime" , myMillis );
+ }
+ }
+
+ result->appendNull( "err" );
+ return true;
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/write_concern.h b/src/mongo/db/write_concern.h
new file mode 100644
index 00000000000..1087ed3c123
--- /dev/null
+++ b/src/mongo/db/write_concern.h
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2013 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+namespace mongo {
+
+ /**
+ * Helper method for commands to call. Blocks until write concern (as specified in "cmdObj")
+ * is satisfied. "err" should be set to true if the last operation succeeded, otherwise false.
+ * "result" will be filled with write concern results. Returns false and sets "errmsg" on
+ * failure.
+ */
+ bool waitForWriteConcern(const BSONObj& cmdObj,
+ bool err,
+ BSONObjBuilder* result,
+ string* errmsg);
+
+} // namespace mongo