summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2012-11-27 17:17:42 -0500
committerEliot Horowitz <eliot@10gen.com>2012-11-27 17:17:42 -0500
commit70c89035a57f2efffd240d93f938b46c001d610e (patch)
tree2ca72f0fc9b003667c559224ef4945256c486a39 /src/mongo
parent8d75e030e0e3de931e08996a2157491ed77fef9d (diff)
downloadmongo-70c89035a57f2efffd240d93f938b46c001d610e.tar.gz
SERVER-7778 : new parameter management system for runtime (command line later)
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/SConscript14
-rw-r--r--src/mongo/db/cmdline.cpp13
-rw-r--r--src/mongo/db/cmdline.h21
-rw-r--r--src/mongo/db/commands/parameters.cpp202
-rw-r--r--src/mongo/db/dbcommands_generic.cpp158
-rw-r--r--src/mongo/db/repl.cpp71
-rw-r--r--src/mongo/db/server_parameters.cpp64
-rw-r--r--src/mongo/db/server_parameters.h110
-rw-r--r--src/mongo/db/server_parameters_inline.h48
-rw-r--r--src/mongo/db/server_parameters_test.cpp54
10 files changed, 536 insertions, 219 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index bd4a4268de0..0c13b875ae9 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -163,6 +163,15 @@ env.CppUnitTest("processinfo_test",
["util/processinfo_test.cpp"],
LIBDEPS=["processinfo"])
+env.StaticLibrary("server_parameters",
+ ["db/server_parameters.cpp"],
+ LIBDEPS=["foundation","bson"])
+
+env.CppUnitTest("server_parameters_test",
+ [ "db/server_parameters_test.cpp" ],
+ LIBDEPS=["server_parameters"] )
+
+
env.StaticLibrary("fail_point",
["util/fail_point.cpp",
"util/fail_point_registry.cpp",
@@ -190,6 +199,7 @@ env.StaticLibrary("coredb", [
"db/commands/hashcmd.cpp",
"db/commands/isself.cpp",
"db/commands/server_status.cpp",
+ "db/commands/parameters.cpp",
"db/pipeline/pipeline.cpp",
"db/dbcommands_generic.cpp",
"db/dbwebserver.cpp",
@@ -232,7 +242,9 @@ env.StaticLibrary("coredb", [
"db/stats/top.cpp",
"s/shardconnection.cpp",
],
- LIBDEPS=['db/auth/auth', 'db/auth/serverauth'])
+ LIBDEPS=['db/auth/auth',
+ 'db/auth/serverauth',
+ 'server_parameters'])
coreServerFiles = [ "db/common.cpp",
"util/net/miniwebserver.cpp",
diff --git a/src/mongo/db/cmdline.cpp b/src/mongo/db/cmdline.cpp
index cd046c18e9f..105ac59435c 100644
--- a/src/mongo/db/cmdline.cpp
+++ b/src/mongo/db/cmdline.cpp
@@ -453,17 +453,4 @@ namespace {
void printCommandLineOpts() {
log() << "options: " << parsedOpts << endl;
}
-
- map<string,ParameterValidator*>* pv_all(NULL);
-
- ParameterValidator::ParameterValidator( const string& name ) : _name( name ) {
- if ( ! pv_all)
- pv_all = new map<string,ParameterValidator*>();
- (*pv_all)[_name] = this;
- }
-
- ParameterValidator* ParameterValidator::get( const string& name ) {
- return mapFindWithDefault(*pv_all, name, static_cast<ParameterValidator*>(NULL));
- }
-
}
diff --git a/src/mongo/db/cmdline.h b/src/mongo/db/cmdline.h
index 0396ede067b..2b56b51f958 100644
--- a/src/mongo/db/cmdline.h
+++ b/src/mongo/db/cmdline.h
@@ -219,26 +219,5 @@ namespace mongo {
extern CmdLine cmdLine;
void printCommandLineOpts();
-
- /**
- * used for setParameter command
- * so you can write validation code that lives with code using it
- * rather than all in the command place
- * also lets you have mongos or mongod specific code
- * without pulling it all sorts of things
- */
- class ParameterValidator {
- public:
- ParameterValidator( const std::string& name );
- virtual ~ParameterValidator() {}
-
- virtual bool isValid( BSONElement e , std::string& errmsg ) const = 0;
-
- static ParameterValidator * get( const std::string& name );
-
- private:
- const std::string _name;
- };
-
}
diff --git a/src/mongo/db/commands/parameters.cpp b/src/mongo/db/commands/parameters.cpp
new file mode 100644
index 00000000000..83b5efc1668
--- /dev/null
+++ b/src/mongo/db/commands/parameters.cpp
@@ -0,0 +1,202 @@
+// parameters.cpp
+
+/**
+* Copyright (C) 2012 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/pch.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/cmdline.h"
+#include "mongo/client/dbclient_rs.h"
+#include "mongo/db/server_parameters.h"
+
+namespace mongo {
+
+ const char* fetchReplIndexPrefetchParam();
+
+ class CmdGet : public Command {
+ public:
+ CmdGet() : Command( "getParameter" ) { }
+ virtual bool slaveOk() const { return true; }
+ virtual bool adminOnly() const { return true; }
+ virtual LockType locktype() const { return NONE; }
+ virtual void addRequiredPrivileges(const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* out) {
+ ActionSet actions;
+ actions.addAction(ActionType::getParameter);
+ out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ }
+ virtual void help( stringstream &help ) const {
+ help << "get administrative option(s)\nexample:\n";
+ help << "{ getParameter:1, notablescan:1 }\n";
+ help << "supported so far:\n";
+ help << " quiet\n";
+ help << " notablescan\n";
+ help << " logLevel\n";
+ help << " syncdelay\n";
+ help << "{ getParameter:'*' } to get everything\n";
+ }
+ bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
+ bool all = *cmdObj.firstElement().valuestrsafe() == '*';
+
+ int before = result.len();
+
+ if( all || cmdObj.hasElement("quiet") ) {
+ result.append("quiet", cmdLine.quiet );
+ }
+ if( all || cmdObj.hasElement("notablescan") ) {
+ result.append("notablescan", cmdLine.noTableScan);
+ }
+ if( all || cmdObj.hasElement("logLevel") ) {
+ result.append("logLevel", logLevel);
+ }
+ if( all || cmdObj.hasElement("syncdelay") ) {
+ result.append("syncdelay", cmdLine.syncdelay);
+ }
+ if (all || cmdObj.hasElement("replIndexPrefetch")) {
+ result.append("replIndexPrefetch", fetchReplIndexPrefetchParam());
+ }
+
+ const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap();
+ for ( ServerParameter::Map::const_iterator i = m.begin(); i != m.end(); ++i ) {
+ if ( all || cmdObj.hasElement( i->first.c_str() ) ) {
+ i->second->append( result );
+ }
+ }
+
+ if ( before == result.len() ) {
+ errmsg = "no option found to get";
+ return false;
+ }
+ return true;
+ }
+ } cmdGet;
+
+ // tempish
+ bool setParmsMongodSpecific(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl );
+
+ class CmdSet : public Command {
+ public:
+ CmdSet() : Command( "setParameter" ) { }
+ virtual bool slaveOk() const { return true; }
+ virtual bool adminOnly() const { return true; }
+ virtual LockType locktype() const { return NONE; }
+ virtual void addRequiredPrivileges(const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* out) {
+ ActionSet actions;
+ actions.addAction(ActionType::setParameter);
+ out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
+ }
+ virtual void help( stringstream &help ) const {
+ help << "set administrative option(s)\n";
+ help << "{ setParameter:1, <param>:<value> }\n";
+ help << "supported so far:\n";
+ help << " journalCommitInterval\n";
+ help << " logLevel\n";
+ help << " notablescan\n";
+ help << " quiet\n";
+ help << " syncdelay\n";
+ }
+ bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
+ int s = 0;
+ bool found = setParmsMongodSpecific(dbname, cmdObj, errmsg, result, fromRepl);
+ if( cmdObj.hasElement("journalCommitInterval") ) {
+ if( !cmdLine.dur ) {
+ errmsg = "journaling is off";
+ return false;
+ }
+ int x = (int) cmdObj["journalCommitInterval"].Number();
+ verify( x > 1 && x < 500 );
+ cmdLine.journalCommitInterval = x;
+ log() << "setParameter journalCommitInterval=" << x << endl;
+ s++;
+ }
+ if( cmdObj.hasElement("notablescan") ) {
+ verify( !cmdLine.isMongos() );
+ if( s == 0 )
+ result.append("was", cmdLine.noTableScan);
+ cmdLine.noTableScan = cmdObj["notablescan"].Bool();
+ s++;
+ }
+ if( cmdObj.hasElement("quiet") ) {
+ if( s == 0 )
+ result.append("was", cmdLine.quiet );
+ cmdLine.quiet = cmdObj["quiet"].Bool();
+ s++;
+ }
+ if( cmdObj.hasElement("syncdelay") ) {
+ verify( !cmdLine.isMongos() );
+ if( s == 0 )
+ result.append("was", cmdLine.syncdelay );
+ cmdLine.syncdelay = cmdObj["syncdelay"].Number();
+ s++;
+ }
+ if( cmdObj.hasElement( "logLevel" ) ) {
+ if( s == 0 )
+ result.append("was", logLevel );
+ logLevel = cmdObj["logLevel"].numberInt();
+ s++;
+ }
+ if( cmdObj.hasElement( "traceExceptions" ) ) {
+ if( s == 0 ) result.append( "was", DBException::traceExceptions );
+ DBException::traceExceptions = cmdObj["traceExceptions"].Bool();
+ s++;
+ }
+ if( cmdObj.hasElement( "replMonitorMaxFailedChecks" ) ) {
+ if( s == 0 ) result.append( "was", ReplicaSetMonitor::getMaxFailedChecks() );
+ ReplicaSetMonitor::setMaxFailedChecks(
+ cmdObj["replMonitorMaxFailedChecks"].numberInt() );
+ s++;
+ }
+
+ const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap();
+ BSONObjIterator i( cmdObj );
+ i.next(); // skip past command name
+ while ( i.more() ) {
+ BSONElement e = i.next();
+ ServerParameter::Map::const_iterator j = m.find( e.fieldName() );
+ if ( j == m.end() )
+ continue;
+
+ if ( ! j->second->allowedToChangeAtRuntime() ) {
+ errmsg = str::stream()
+ << "not allowed to change ["
+ << e.fieldName()
+ << "] at runtime";
+ return false;
+ }
+
+ Status status = j->second->set( e );
+ if ( status.isOK() ) {
+ s++;
+ continue;
+ }
+ errmsg = status.reason();
+ result.append( "code", status.code() );
+ return false;
+ }
+
+ if( s == 0 && !found ) {
+ errmsg = "no option found to set, use help:true to see options ";
+ return false;
+ }
+
+ return true;
+ }
+ } cmdSet;
+
+}
diff --git a/src/mongo/db/dbcommands_generic.cpp b/src/mongo/db/dbcommands_generic.cpp
index f0e762c053c..123fe1e314a 100644
--- a/src/mongo/db/dbcommands_generic.cpp
+++ b/src/mongo/db/dbcommands_generic.cpp
@@ -135,164 +135,6 @@ namespace mongo {
}
} cmdBuildInfo;
- /** experimental. either remove or add support in repl sets also. in a repl set, getting this setting from the
- repl set config could make sense.
- */
- unsigned replApplyBatchSize = 1;
-
- const char* fetchReplIndexPrefetchParam();
-
- class CmdGet : public Command {
- public:
- CmdGet() : Command( "getParameter" ) { }
- virtual bool slaveOk() const { return true; }
- virtual bool adminOnly() const { return true; }
- virtual LockType locktype() const { return NONE; }
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
- ActionSet actions;
- actions.addAction(ActionType::getParameter);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
- }
- virtual void help( stringstream &help ) const {
- help << "get administrative option(s)\nexample:\n";
- help << "{ getParameter:1, notablescan:1 }\n";
- help << "supported so far:\n";
- help << " quiet\n";
- help << " notablescan\n";
- help << " logLevel\n";
- help << " syncdelay\n";
- help << "{ getParameter:'*' } to get everything\n";
- }
- bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
- bool all = *cmdObj.firstElement().valuestrsafe() == '*';
-
- int before = result.len();
-
- if( all || cmdObj.hasElement("quiet") ) {
- result.append("quiet", cmdLine.quiet );
- }
- if( all || cmdObj.hasElement("notablescan") ) {
- result.append("notablescan", cmdLine.noTableScan);
- }
- if( all || cmdObj.hasElement("logLevel") ) {
- result.append("logLevel", logLevel);
- }
- if( all || cmdObj.hasElement("syncdelay") ) {
- result.append("syncdelay", cmdLine.syncdelay);
- }
- if( all || cmdObj.hasElement("replApplyBatchSize") ) {
- result.append("replApplyBatchSize", replApplyBatchSize);
- }
- if (all || cmdObj.hasElement("replIndexPrefetch")) {
- result.append("replIndexPrefetch", fetchReplIndexPrefetchParam());
- }
- if ( before == result.len() ) {
- errmsg = "no option found to get";
- return false;
- }
- return true;
- }
- } cmdGet;
-
- // tempish
- bool setParmsMongodSpecific(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl );
-
- class CmdSet : public Command {
- public:
- CmdSet() : Command( "setParameter" ) { }
- virtual bool slaveOk() const { return true; }
- virtual bool adminOnly() const { return true; }
- virtual LockType locktype() const { return NONE; }
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
- ActionSet actions;
- actions.addAction(ActionType::setParameter);
- out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
- }
- virtual void help( stringstream &help ) const {
- help << "set administrative option(s)\n";
- help << "{ setParameter:1, <param>:<value> }\n";
- help << "supported so far:\n";
- help << " journalCommitInterval\n";
- help << " logLevel\n";
- help << " notablescan\n";
- help << " quiet\n";
- help << " syncdelay\n";
- }
- bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
- int s = 0;
- bool found = setParmsMongodSpecific(dbname, cmdObj, errmsg, result, fromRepl);
- if( cmdObj.hasElement("journalCommitInterval") ) {
- if( !cmdLine.dur ) {
- errmsg = "journaling is off";
- return false;
- }
- int x = (int) cmdObj["journalCommitInterval"].Number();
- verify( x > 1 && x < 500 );
- cmdLine.journalCommitInterval = x;
- log() << "setParameter journalCommitInterval=" << x << endl;
- s++;
- }
- if( cmdObj.hasElement("notablescan") ) {
- verify( !cmdLine.isMongos() );
- if( s == 0 )
- result.append("was", cmdLine.noTableScan);
- cmdLine.noTableScan = cmdObj["notablescan"].Bool();
- s++;
- }
- if( cmdObj.hasElement("quiet") ) {
- if( s == 0 )
- result.append("was", cmdLine.quiet );
- cmdLine.quiet = cmdObj["quiet"].Bool();
- s++;
- }
- if( cmdObj.hasElement("syncdelay") ) {
- verify( !cmdLine.isMongos() );
- if( s == 0 )
- result.append("was", cmdLine.syncdelay );
- cmdLine.syncdelay = cmdObj["syncdelay"].Number();
- s++;
- }
- if( cmdObj.hasElement( "logLevel" ) ) {
- if( s == 0 )
- result.append("was", logLevel );
- logLevel = cmdObj["logLevel"].numberInt();
- s++;
- }
- if( cmdObj.hasElement( "replApplyBatchSize" ) ) {
- if( s == 0 )
- result.append("was", replApplyBatchSize );
- BSONElement e = cmdObj["replApplyBatchSize"];
- ParameterValidator * v = ParameterValidator::get( e.fieldName() );
- verify( v );
- if ( ! v->isValid( e , errmsg ) )
- return false;
- replApplyBatchSize = e.numberInt();
- s++;
- }
- if( cmdObj.hasElement( "traceExceptions" ) ) {
- if( s == 0 ) result.append( "was", DBException::traceExceptions );
- DBException::traceExceptions = cmdObj["traceExceptions"].Bool();
- s++;
- }
- if( cmdObj.hasElement( "replMonitorMaxFailedChecks" ) ) {
- if( s == 0 ) result.append( "was", ReplicaSetMonitor::getMaxFailedChecks() );
- ReplicaSetMonitor::setMaxFailedChecks(
- cmdObj["replMonitorMaxFailedChecks"].numberInt() );
- s++;
- }
-
- if( s == 0 && !found ) {
- errmsg = "no option found to set, use help:true to see options ";
- return false;
- }
-
- return true;
- }
- } cmdSet;
class PingCommand : public Command {
public:
diff --git a/src/mongo/db/repl.cpp b/src/mongo/db/repl.cpp
index c3b326683ee..5a66836bc42 100644
--- a/src/mongo/db/repl.cpp
+++ b/src/mongo/db/repl.cpp
@@ -50,6 +50,7 @@
#include "pcrecpp.h"
#include "mongo/db/commands/server_status.h"
#include "mongo/db/instance.h"
+#include "mongo/db/server_parameters.h"
#include "mongo/db/queryutil.h"
namespace mongo {
@@ -803,7 +804,49 @@ namespace mongo {
}
}
- extern unsigned replApplyBatchSize;
+ class ReplApplyBatchSize : public ServerParameter {
+ public:
+ ReplApplyBatchSize()
+ : ServerParameter( ServerParameterSet::getGlobal(), "replApplyBatchSize" ),
+ _value( 1 ) {
+ }
+
+ int get() const { return _value; }
+
+ virtual void append( BSONObjBuilder& b ) {
+ b.append( name(), _value );
+ }
+
+ virtual Status set( const BSONElement& newValuElement ) {
+ return set( newValuElement.numberInt() );
+ }
+
+ virtual Status set( int b ) {
+ if( b < 1 || b > 1024 ) {
+ return Status( ErrorCodes::BadValue,
+ "replApplyBatchSize has to be >= 1 and < 1024" );
+ }
+
+ if ( replSettings.slavedelay != 0 && b > 1 ) {
+ return Status( ErrorCodes::BadValue,
+ "can't use a batch size > 1 with slavedelay" );
+ }
+ if ( ! replSettings.slave ) {
+ return Status( ErrorCodes::BadValue,
+ "can't set replApplyBatchSize on a non-slave machine" );
+ }
+
+ _value = b;
+ return Status::OK();
+ }
+
+ virtual Status setFromString( const string& str ) {
+ return set( atoi( str.c_str() ) );
+ }
+
+ int _value;
+
+ } replApplyBatchSize;
/* slave: pull some data from the master's oplog
note: not yet in db mutex at this point.
@@ -1008,7 +1051,7 @@ namespace mongo {
BSONObj op = oplogReader.next();
- unsigned b = replApplyBatchSize;
+ int b = replApplyBatchSize.get();
bool justOne = b == 1;
scoped_ptr<Lock::GlobalWrite> lk( justOne ? 0 : new Lock::GlobalWrite() );
while( 1 ) {
@@ -1541,30 +1584,6 @@ namespace mongo {
tp.join();
}
- class ReplApplyBatchSizeValidator : public ParameterValidator {
- public:
- ReplApplyBatchSizeValidator() : ParameterValidator( "replApplyBatchSize" ) {}
-
- virtual bool isValid( BSONElement e , string& errmsg ) const {
- int b = e.numberInt();
- if( b < 1 || b > 1024 ) {
- errmsg = "replApplyBatchSize has to be >= 1 and < 1024";
- return false;
- }
-
- if ( replSettings.slavedelay != 0 && b > 1 ) {
- errmsg = "can't use a batch size > 1 with slavedelay";
- return false;
- }
- if ( ! replSettings.slave ) {
- errmsg = "can't set replApplyBatchSize on a non-slave machine";
- return false;
- }
-
- return true;
- }
- } replApplyBatchSizeValidator;
-
/** we allow queries to SimpleSlave's */
void replVerifyReadsOk(const ParsedQuery* pq) {
if( replSet ) {
diff --git a/src/mongo/db/server_parameters.cpp b/src/mongo/db/server_parameters.cpp
new file mode 100644
index 00000000000..05565a79044
--- /dev/null
+++ b/src/mongo/db/server_parameters.cpp
@@ -0,0 +1,64 @@
+// server_parameters.cpp
+
+/**
+* Copyright (C) 2012 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/pch.h"
+
+#include "mongo/db/server_parameters.h"
+
+namespace mongo {
+
+ namespace {
+ ServerParameterSet* GLOBAL = NULL;
+ }
+
+ ServerParameter::ServerParameter( ServerParameterSet* sps, const std::string& name )
+ : _name( name ) {
+
+ if ( sps ) {
+ sps->add( this );
+ }
+ }
+
+ ServerParameter::~ServerParameter() {
+ }
+
+ ServerParameterSet* ServerParameterSet::getGlobal() {
+ if ( !GLOBAL ) {
+ GLOBAL = new ServerParameterSet();
+ }
+ return GLOBAL;
+ }
+
+ void ServerParameterSet::add( ServerParameter* sp ) {
+ ServerParameter*& x = _map[sp->name()];
+ if ( x ) abort();
+ x = sp;
+ }
+
+
+ // obviously this is a sample, not real
+ // below this is all samples and won't be in the real one
+
+ ExportedServerParameter<int> logLevelParam( ServerParameterSet::getGlobal(), "logLevel", &logLevel );
+
+ string x = "a";
+ ExportedServerParameter<string> xxx( ServerParameterSet::getGlobal(), "xxx", &x );
+
+ MONGO_EXPORT_SERVER_PARAMETER( y, string, "hh" );
+
+}
diff --git a/src/mongo/db/server_parameters.h b/src/mongo/db/server_parameters.h
new file mode 100644
index 00000000000..c1368a979df
--- /dev/null
+++ b/src/mongo/db/server_parameters.h
@@ -0,0 +1,110 @@
+// server_parameters.h
+
+/**
+* Copyright (C) 2012 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
+
+#include <string>
+#include <map>
+
+#include "mongo/base/status.h"
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+ class ServerParameterSet;
+
+ /**
+ * Lets you make server level settings easily configurable.
+ * Hooks into (set|get)Paramter, as well as command line processing
+ */
+ class ServerParameter {
+ public:
+ typedef std::map< std::string, ServerParameter* > Map;
+
+ ServerParameter( ServerParameterSet* sps, const std::string& name );
+ virtual ~ServerParameter();
+
+ std::string name() const { return _name; }
+
+ /**
+ * @return if you can set on command line or config file
+ */
+ virtual bool allowedToChangeAtStartup() const { return true; }
+
+ /**
+ * @param if you can use (get|set)Parameter
+ */
+ virtual bool allowedToChangeAtRuntime() const { return true; }
+
+
+ virtual void append( BSONObjBuilder& b ) = 0;
+
+ virtual Status set( const BSONElement& newValueElement ) = 0;
+
+ virtual Status setFromString( const string& str ) = 0;
+
+ private:
+ string _name;
+ };
+
+ class ServerParameterSet {
+ public:
+ typedef std::map< std::string, ServerParameter* > Map;
+
+ void add( ServerParameter* sp );
+
+ const Map& getMap() const { return _map; }
+
+ static ServerParameterSet* getGlobal();
+
+ private:
+ Map _map;
+ };
+
+ template<typename T>
+ class ExportedServerParameter : public ServerParameter {
+ public:
+ ExportedServerParameter( ServerParameterSet* sps, const std::string& name, T* value )
+ : ServerParameter( sps, name ), _value( value ) {}
+ virtual ~ExportedServerParameter() {}
+
+ virtual void append( BSONObjBuilder& b ) {
+ b.append( name(), *_value );
+ }
+
+ virtual Status set( const BSONElement& newValueElement );
+ virtual Status set( const T& newValue );
+
+ virtual const T& get() const { return *_value; }
+
+ virtual Status setFromString( const string& str );
+
+ protected:
+
+ virtual Status validate( const T& potentialNewValue ){ return Status::OK(); }
+
+ T* _value; // owned elsewhere
+ };
+
+#define MONGO_EXPORT_SERVER_PARAMETER( NAME, TYPE, INITIAL_VALUE ) \
+ TYPE NAME = INITIAL_VALUE; \
+ ExportedServerParameter<TYPE> _##NAME( ServerParameterSet::getGlobal(), #NAME, &NAME );
+
+}
+
+#include "server_parameters_inline.h"
diff --git a/src/mongo/db/server_parameters_inline.h b/src/mongo/db/server_parameters_inline.h
new file mode 100644
index 00000000000..6e8764e17dd
--- /dev/null
+++ b/src/mongo/db/server_parameters_inline.h
@@ -0,0 +1,48 @@
+// server_parameters_inline.h
+
+#include "mongo/util/stringutils.h"
+
+namespace mongo {
+
+ template<typename T>
+ inline Status ExportedServerParameter<T>::set( const BSONElement& newValueElement ) {
+ T newValue;
+
+ if ( !newValueElement.coerce( &newValue) )
+ return Status( ErrorCodes::BadValue, "can't set value" );
+
+ return set( newValue );
+ }
+
+ template<typename T>
+ inline Status ExportedServerParameter<T>::set( const T& newValue ) {
+
+ Status v = validate( newValue );
+ if ( !v.isOK() )
+ return v;
+
+ *_value = newValue;
+ return Status::OK();
+ }
+
+ template<>
+ inline Status ExportedServerParameter<int>::setFromString( const string& str ) {
+ return set( atoi(str.c_str() ) );
+ }
+
+ template<>
+ inline Status ExportedServerParameter<string>::setFromString( const string& str ) {
+ return set( str );
+ }
+
+
+ template<>
+ inline Status ExportedServerParameter< vector<string> >::setFromString( const string& str ) {
+ vector<string> v;
+ splitStringDelim( str, &v, ',' );
+ return set( v );
+ }
+
+
+
+}
diff --git a/src/mongo/db/server_parameters_test.cpp b/src/mongo/db/server_parameters_test.cpp
new file mode 100644
index 00000000000..04fe1eaf2a5
--- /dev/null
+++ b/src/mongo/db/server_parameters_test.cpp
@@ -0,0 +1,54 @@
+// server_parameters_test.cpp
+
+#include "mongo/unittest/unittest.h"
+
+#include "mongo/db/server_parameters.h"
+
+namespace mongo {
+
+ TEST( ServerParameters, Simple1 ) {
+ int f = 5;
+ ExportedServerParameter<int> ff( NULL, "ff", &f );
+ ASSERT_EQUALS( "ff" , ff.name() );
+ ASSERT_EQUALS( 5, ff.get() );
+
+ ff.set( 6 );
+ ASSERT_EQUALS( 6, ff.get() );
+ ASSERT_EQUALS( 6, f );
+
+ ff.set( BSON( "x" << 7 ).firstElement() );
+ ASSERT_EQUALS( 7, ff.get() );
+ ASSERT_EQUALS( 7, f );
+
+ ff.setFromString( "8" );
+ ASSERT_EQUALS( 8, ff.get() );
+ ASSERT_EQUALS( 8, f );
+
+ }
+
+ TEST( ServerParameters, Vector1 ) {
+ vector<string> v;
+
+ ExportedServerParameter< vector<string> > vv( NULL, "vv", &v );
+
+ BSONObj x = BSON( "x" << BSON_ARRAY( "a" << "b" << "c" ) );
+ vv.set( x.firstElement() );
+
+ ASSERT_EQUALS( 3U, v.size() );
+ ASSERT_EQUALS( "a", v[0] );
+ ASSERT_EQUALS( "b", v[1] );
+ ASSERT_EQUALS( "c", v[2] );
+
+ BSONObjBuilder b;
+ vv.append( b );
+ BSONObj y = b.obj();
+ ASSERT( x.firstElement().woCompare( y.firstElement(), false ) == 0 );
+
+
+ vv.setFromString( "d,e" );
+ ASSERT_EQUALS( 2U, v.size() );
+ ASSERT_EQUALS( "d", v[0] );
+ ASSERT_EQUALS( "e", v[1] );
+ }
+
+}