diff options
author | Jason Rassi <rassi@10gen.com> | 2013-07-10 14:49:00 -0400 |
---|---|---|
committer | Jason Rassi <rassi@10gen.com> | 2013-07-10 14:49:00 -0400 |
commit | 089d5992f9000d618a59f79fa5dc1a3e818c2ad0 (patch) | |
tree | 66b109bdc0cb93115562e7b2117ec487a3c1975f /src | |
parent | 4f7713325020275578cce51dcd6ba7a1a19cfb22 (diff) | |
download | mongo-089d5992f9000d618a59f79fa5dc1a3e818c2ad0.tar.gz |
SERVER-9468 Pull out bulk of CmdGetLastError::run() into helper
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/dbcommands.cpp | 151 | ||||
-rw-r--r-- | src/mongo/db/write_concern.cpp | 182 | ||||
-rw-r--r-- | src/mongo/db/write_concern.h | 32 |
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 |