summaryrefslogtreecommitdiff
path: root/src/mongo/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/tools')
-rw-r--r--src/mongo/tools/bridge.cpp102
-rw-r--r--src/mongo/tools/bsondump.cpp88
-rw-r--r--src/mongo/tools/bsondump_options.cpp108
-rw-r--r--src/mongo/tools/bsondump_options.h60
-rw-r--r--src/mongo/tools/bsondump_options_init.cpp60
-rw-r--r--src/mongo/tools/docgenerator.cpp60
-rw-r--r--src/mongo/tools/docgenerator.h80
-rw-r--r--src/mongo/tools/docgeneratormain.cpp150
-rw-r--r--src/mongo/tools/dump.cpp349
-rw-r--r--src/mongo/tools/export.cpp143
-rw-r--r--src/mongo/tools/files.cpp133
-rw-r--r--src/mongo/tools/import.cpp463
-rw-r--r--src/mongo/tools/loadgenerator.cpp417
-rw-r--r--src/mongo/tools/mongobridge_options.cpp93
-rw-r--r--src/mongo/tools/mongobridge_options.h70
-rw-r--r--src/mongo/tools/mongobridge_options_init.cpp61
-rw-r--r--src/mongo/tools/mongodump_options.cpp157
-rw-r--r--src/mongo/tools/mongodump_options.h64
-rw-r--r--src/mongo/tools/mongodump_options_init.cpp60
-rw-r--r--src/mongo/tools/mongoexport_options.cpp157
-rw-r--r--src/mongo/tools/mongoexport_options.h68
-rw-r--r--src/mongo/tools/mongoexport_options_init.cpp60
-rw-r--r--src/mongo/tools/mongofiles_options.cpp128
-rw-r--r--src/mongo/tools/mongofiles_options.h63
-rw-r--r--src/mongo/tools/mongofiles_options_init.cpp60
-rw-r--r--src/mongo/tools/mongoimport_options.cpp162
-rw-r--r--src/mongo/tools/mongoimport_options.h68
-rw-r--r--src/mongo/tools/mongoimport_options_init.cpp60
-rw-r--r--src/mongo/tools/mongooplog_options.cpp109
-rw-r--r--src/mongo/tools/mongooplog_options.h61
-rw-r--r--src/mongo/tools/mongooplog_options_init.cpp60
-rw-r--r--src/mongo/tools/mongorestore_options.cpp185
-rw-r--r--src/mongo/tools/mongorestore_options.h69
-rw-r--r--src/mongo/tools/mongorestore_options_init.cpp60
-rw-r--r--src/mongo/tools/mongostat_options.cpp168
-rw-r--r--src/mongo/tools/mongostat_options.h66
-rw-r--r--src/mongo/tools/mongostat_options_init.cpp60
-rw-r--r--src/mongo/tools/mongotop_options.cpp96
-rw-r--r--src/mongo/tools/mongotop_options.h60
-rw-r--r--src/mongo/tools/mongotop_options_init.cpp60
-rw-r--r--src/mongo/tools/oplog.cpp87
-rw-r--r--src/mongo/tools/restore.cpp744
-rw-r--r--src/mongo/tools/sniffer.cpp97
-rw-r--r--src/mongo/tools/stat.cpp211
-rw-r--r--src/mongo/tools/stat_util.cpp22
-rw-r--r--src/mongo/tools/stat_util.h12
-rw-r--r--src/mongo/tools/tool.cpp420
-rw-r--r--src/mongo/tools/tool.h111
-rw-r--r--src/mongo/tools/tool_logger.cpp144
-rw-r--r--src/mongo/tools/tool_logger.h58
-rw-r--r--src/mongo/tools/tool_options.cpp400
-rw-r--r--src/mongo/tools/tool_options.h120
-rw-r--r--src/mongo/tools/top.cpp86
53 files changed, 4959 insertions, 2151 deletions
diff --git a/src/mongo/tools/bridge.cpp b/src/mongo/tools/bridge.cpp
index 4d13b64a938..422237c5b00 100644
--- a/src/mongo/tools/bridge.cpp
+++ b/src/mongo/tools/bridge.cpp
@@ -1,5 +1,3 @@
-// bridge.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,35 +12,63 @@
*
* 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
*/
-#include "pch.h"
+#include "mongo/pch.h"
#include <boost/thread.hpp>
#include "mongo/base/initializer.h"
+#include "mongo/client/dbclientinterface.h"
#include "mongo/db/dbmessage.h"
+#include "mongo/tools/mongobridge_options.h"
#include "mongo/util/net/listen.h"
#include "mongo/util/net/message.h"
#include "mongo/util/stacktrace.h"
+#include "mongo/util/text.h"
+#include "mongo/util/timer.h"
using namespace mongo;
using namespace std;
-int port = 0;
-int delay = 0;
-string destUri;
void cleanup( int sig );
class Forwarder {
public:
Forwarder( MessagingPort &mp ) : mp_( mp ) {
}
+
void operator()() const {
DBClientConnection dest;
string errmsg;
- while( !dest.connect( destUri, errmsg ) )
- sleepmillis( 500 );
+
+ Timer connectTimer;
+ while (!dest.connect(mongoBridgeGlobalParams.destUri, errmsg)) {
+ // If we can't connect for the configured timeout, give up
+ //
+ if (connectTimer.seconds() >= mongoBridgeGlobalParams.connectTimeoutSec) {
+ cout << "Unable to establish connection from " << mp_.psock->remoteString()
+ << " to " << mongoBridgeGlobalParams.destUri
+ << " after " << connectTimer.seconds() << " seconds. Giving up." << endl;
+ mp_.shutdown();
+ return;
+ }
+
+ sleepmillis(500);
+ }
+
Message m;
while( 1 ) {
try {
@@ -52,7 +78,7 @@ public:
mp_.shutdown();
break;
}
- sleepmillis( delay );
+ sleepmillis(mongoBridgeGlobalParams.delay);
int oldId = m.header()->id;
if ( m.operation() == dbQuery || m.operation() == dbMsg || m.operation() == dbGetMore ) {
@@ -118,8 +144,7 @@ void cleanup( int sig ) {
}
#if !defined(_WIN32)
void myterminate() {
- rawOut( "bridge terminate() called, printing stack:" );
- printStackTrace();
+ printStackTrace(severe().stream() << "bridge terminate() called, printing stack:\n");
::abort();
}
@@ -137,47 +162,34 @@ void setupSignals() {
inline void setupSignals() {}
#endif
-void helpExit() {
- cout << "usage mongobridge --port <port> --dest <destUri> [ --delay <ms> ]" << endl;
- cout << " port: port to listen for mongo messages" << endl;
- cout << " destUri: uri of remote mongod instance" << endl;
- cout << " ms: transfer delay in milliseconds (default = 0)" << endl;
- ::_exit( -1 );
-}
-
-void check( bool b ) {
- if ( !b )
- helpExit();
-}
-
-int main( int argc, char **argv, char** envp ) {
+int toolMain( int argc, char **argv, char** envp ) {
mongo::runGlobalInitializersOrDie(argc, argv, envp);
static StaticObserver staticObserver;
setupSignals();
- check( argc == 5 || argc == 7 );
-
- for( int i = 1; i < argc; ++i ) {
- check( i % 2 != 0 );
- if ( strcmp( argv[ i ], "--port" ) == 0 ) {
- port = strtol( argv[ ++i ], 0, 10 );
- }
- else if ( strcmp( argv[ i ], "--dest" ) == 0 ) {
- destUri = argv[ ++i ];
- }
- else if ( strcmp( argv[ i ], "--delay" ) == 0 ) {
- delay = strtol( argv[ ++i ], 0, 10 );
- }
- else {
- check( false );
- }
- }
- check( port != 0 && !destUri.empty() );
-
- listener.reset( new MyListener( port ) );
+ listener.reset(new MyListener(mongoBridgeGlobalParams.port));
+ listener->setupSockets();
listener->initAndListen();
return 0;
}
+
+#if defined(_WIN32)
+// In Windows, wmain() is an alternate entry point for main(), and receives the same parameters
+// as main() but encoded in Windows Unicode (UTF-16); "wide" 16-bit wchar_t characters. The
+// WindowsCommandLine object converts these wide character strings to a UTF-8 coded equivalent
+// and makes them available through the argv() and envp() members. This enables toolMain()
+// to process UTF-8 encoded arguments and environment variables without regard to platform.
+int wmain(int argc, wchar_t* argvW[], wchar_t* envpW[]) {
+ WindowsCommandLine wcl(argc, argvW, envpW);
+ int exitCode = toolMain(argc, wcl.argv(), wcl.envp());
+ ::_exit(exitCode);
+}
+#else
+int main(int argc, char* argv[], char** envp) {
+ int exitCode = toolMain(argc, argv, envp);
+ ::_exit(exitCode);
+}
+#endif
diff --git a/src/mongo/tools/bsondump.cpp b/src/mongo/tools/bsondump.cpp
index 461737af739..ef0c02be5b3 100644
--- a/src/mongo/tools/bsondump.cpp
+++ b/src/mongo/tools/bsondump.cpp
@@ -1,5 +1,3 @@
-// restore.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,22 +12,32 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "../pch.h"
-#include "mongo/base/initializer.h"
-#include "mongo/client/dbclientcursor.h"
-#include "../util/mmap.h"
-#include "../util/text.h"
-#include "tool.h"
-
-#include <boost/program_options.hpp>
+#include "mongo/pch.h"
#include <fcntl.h>
-using namespace mongo;
+#include "mongo/client/dbclientcursor.h"
+#include "mongo/tools/bsondump_options.h"
+#include "mongo/tools/tool.h"
+#include "mongo/util/mmap.h"
+#include "mongo/util/options_parser/option_section.h"
+#include "mongo/util/text.h"
-namespace po = boost::program_options;
+using namespace mongo;
class BSONDump : public BSONTool {
@@ -37,38 +45,27 @@ class BSONDump : public BSONTool {
public:
- BSONDump() : BSONTool( "bsondump", NONE ) {
- add_options()
- ("type" , po::value<string>()->default_value("json") , "type of output: json,debug" )
- ;
- add_hidden_options()
- ("file" , po::value<string>() , ".bson file" )
- ;
- addPositionArg( "file" , 1 );
- _noconnection = true;
- }
+ BSONDump() : BSONTool() { }
- virtual void printExtraHelp(ostream& out) {
- out << "Display BSON objects in a data file.\n" << endl;
- out << "usage: " << _name << " [options] <bson filename>" << endl;
+ virtual void printHelp(ostream& out) {
+ printBSONDumpHelp(&out);
}
virtual int doRun() {
{
- string t = getParam( "type" );
- if ( t == "json" )
+ if (bsonDumpGlobalParams.type == "json")
_type = JSON;
- else if ( t == "debug" )
+ else if (bsonDumpGlobalParams.type == "debug")
_type = DEBUG;
else {
- cerr << "bad type: " << t << endl;
+ cerr << "bad type: " << bsonDumpGlobalParams.type << endl;
return 1;
}
}
- boost::filesystem::path root = getParam( "file" );
+ boost::filesystem::path root = bsonDumpGlobalParams.file;
if ( root == "" ) {
- printExtraHelp(cout);
+ printBSONDumpHelp(&std::cout);
return 1;
}
@@ -87,17 +84,31 @@ public:
try {
cout << prefix << "--- new object ---\n";
cout << prefix << "\t size : " << o.objsize() << "\n";
+
+ // Note: this will recursively check each level of the bson and will also be called by
+ // this function at each level. While inefficient, it shouldn't effect correctness.
+ const Status status = validateBSON(o.objdata(), o.objsize());
+ if (!status.isOK()) {
+ cout << prefix << "\t OBJECT IS INVALID: " << status.reason() << '\n'
+ << prefix << "\t attempting to print as much as possible" << endl;
+ }
+
BSONObjIterator i(o);
while ( i.more() ) {
- BSONElement e = i.next();
- cout << prefix << "\t\t " << e.fieldName() << "\n" << prefix << "\t\t\t type:" << setw(3) << e.type() << " size: " << e.size() << endl;
+ // This call verifies it is safe to call size() and fieldName() but doesn't check
+ // whether the element extends past the end of the object. That is done below.
+ BSONElement e = i.next(/*checkEnd=*/true);
+
+ cout << prefix << "\t\t " << e.fieldName() << "\n"
+ << prefix << "\t\t\t type:" << setw(3) << e.type() << " size: " << e.size()
+ << endl;
+
if ( ( read + e.size() ) > o.objsize() ) {
cout << prefix << " SIZE DOES NOT WORK" << endl;
return false;
}
read += e.size();
try {
- e.validate();
if ( e.isABSONObj() ) {
if ( ! debug( e.Obj() , depth + 1 ) ) {
//return false;
@@ -111,10 +122,9 @@ public:
else if ( e.type() == String && ! isValidUTF8( e.valuestr() ) ) {
cout << prefix << "\t\t\t" << "bad utf8 String!" << endl;
}
- else if ( logLevel > 0 ) {
+ else if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) ) {
cout << prefix << "\t\t\t" << e << endl;
}
-
}
catch ( std::exception& e ) {
cout << prefix << "\t\t\t bad value: " << e.what() << endl;
@@ -142,8 +152,4 @@ public:
}
};
-int main( int argc , char ** argv, char **envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- BSONDump dump;
- return dump.main( argc , argv );
-}
+REGISTER_MONGO_TOOL(BSONDump);
diff --git a/src/mongo/tools/bsondump_options.cpp b/src/mongo/tools/bsondump_options.cpp
new file mode 100644
index 00000000000..ebbd0e877e5
--- /dev/null
+++ b/src/mongo/tools/bsondump_options.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/bsondump_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ BSONDumpGlobalParams bsonDumpGlobalParams;
+
+ Status addBSONDumpOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addBSONToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("type", "type", moe::String, "type of output: json,debug")
+ .setDefault(moe::Value(std::string("json")));
+
+ options->addOptionChaining("file", "file", moe::String, "path to BSON file to dump")
+ .hidden()
+ .setSources(moe::SourceCommandLine)
+ .positional(1, 1);
+
+
+ return Status::OK();
+ }
+
+ void printBSONDumpHelp(std::ostream* out) {
+ *out << "Display BSON objects in a data file.\n" << std::endl;
+ *out << "usage: bsondump [options] <bson filename>" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationBSONDumpOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printBSONDumpHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeBSONDumpOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = storeBSONToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ // BSONDump never has a db connection
+ toolGlobalParams.noconnection = true;
+
+ bsonDumpGlobalParams.type = getParam("type");
+ bsonDumpGlobalParams.file = getParam("file");
+
+ // Make the default db "" if it was not explicitly set
+ if (!params.count("db")) {
+ toolGlobalParams.db = "";
+ }
+
+ // bsondump always outputs data to stdout, so we can't send messages there
+ toolGlobalParams.canUseStdout = false;
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/bsondump_options.h b/src/mongo/tools/bsondump_options.h
new file mode 100644
index 00000000000..b2e71a1a095
--- /dev/null
+++ b/src/mongo/tools/bsondump_options.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct BSONDumpGlobalParams {
+ std::string type;
+ std::string file;
+ };
+
+ extern BSONDumpGlobalParams bsonDumpGlobalParams;
+
+ Status addBSONDumpOptions(moe::OptionSection* options);
+
+ void printBSONDumpHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationBSONDumpOptions(const moe::Environment& params);
+
+ Status storeBSONDumpOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/bsondump_options_init.cpp b/src/mongo/tools/bsondump_options_init.cpp
new file mode 100644
index 00000000000..59d50d7e7cc
--- /dev/null
+++ b/src/mongo/tools/bsondump_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/bsondump_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(BSONDumpOptions)(InitializerContext* context) {
+ return addBSONDumpOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(BSONDumpOptions)(InitializerContext* context) {
+ if (!handlePreValidationBSONDumpOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(BSONDumpOptions)(InitializerContext* context) {
+ Status ret = storeBSONDumpOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/docgenerator.cpp b/src/mongo/tools/docgenerator.cpp
deleted file mode 100644
index ba614b53d8f..00000000000
--- a/src/mongo/tools/docgenerator.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/** @file docgenerator.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/tools/docgenerator.h"
-
-#include "mongo/util/assert_util.h"
-#include "mongo/util/md5.hpp"
-#include "mongo/util/mongoutils/str.h"
-
-namespace mongo {
-
- void DocumentGenerator::init( BSONObj& args ) {
- uassert( 16363, "_id is not a number", args["_id"].isNumber() );
- config.id = args["_id"].numberLong();
-
- uassert( 16364, "blob is not a string", (args["blob"].type() == String) );
- config.blob = args["blob"].String();
-
- uassert( 16365, "nestedDoc is not an object", (args["nestedDoc"].type() == Object) );
- config.nestedDoc = args["nestedDoc"].embeddedObject();
-
- uassert( 16366, "list is not an array", args["list"].type() == Array );
- BSONObj list = args["list"].embeddedObject();
- for( int i = 0; i < 10; i++ ) {
- uassert( 16367, "list member is not a string", list[i].type() == String );
- config.list.push_back( list[i].String() );
- }
-
- uassert( 16368, "counter is not a number", args["counter"].isNumber() );
- config.counter = args["counter"].numberLong();
- }
-
-
- BSONObj DocumentGenerator::createDocument() {
- BSONObjBuilder doc;
- doc.append( "_id", config.id );
- config.id++;
- doc.append( "blob", config.blob );
- doc.append( "nestedDoc", config.nestedDoc );
- doc.append( "list", config.list );
- doc.append( "counter", config.counter );
- config.counter++;
- return doc.obj();
- }
-}
-
diff --git a/src/mongo/tools/docgenerator.h b/src/mongo/tools/docgenerator.h
deleted file mode 100644
index 8ca2233947c..00000000000
--- a/src/mongo/tools/docgenerator.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/** @file docgenerator.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/>.
-*/
-
-/**
-* This is a simple document generator. It generates documents of the format
-* { _id: xxx, blob: "xxx", nestedDoc: {xxx}, list: [xxx,yyy,zzz], counter: xxx }
-*/
-
-#pragma once
-
-#include <string>
-#include <vector>
-
-#include "mongo/db/jsobj.h"
-
-namespace mongo {
-
- struct DocGeneratorOptions {
- DocGeneratorOptions() :
- hostname(""),
- dbSize( 0.0 ),
- numdbs( 0 ),
- prefix("")
- { }
- std::string hostname;
- double dbSize;
- int numdbs;
- std::string prefix;
- };
-
- struct DocConfig {
- DocConfig() :
- id( 0 ),
- blob( "" ),
- counter( 0 )
- { }
- long long id;
- std::string blob;
- BSONObj nestedDoc;
- std::vector<std::string> list;
- long long counter;
- };
-
- // Creates a documentGenerator that can be used to create sample documents
- class DocumentGenerator {
- public:
- DocumentGenerator( ) { }
- ~DocumentGenerator() { }
-
- void init( BSONObj& args );
- BSONObj createDocument();
-
- // caller is responsible for managing this raw pointer
- static DocumentGenerator* makeDocumentGenerator( BSONObj args ) {
- DocumentGenerator* runner = new DocumentGenerator() ;
- runner->init( args );
- return runner;
- }
- DocConfig config;
- };
-
-} // end namespace
-
-
-
-
diff --git a/src/mongo/tools/docgeneratormain.cpp b/src/mongo/tools/docgeneratormain.cpp
deleted file mode 100644
index 2cae11fa2e4..00000000000
--- a/src/mongo/tools/docgeneratormain.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/** @file docgeneratormain.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/>.
-*/
-
-/**
-* Uses the DocumentGenerator class to populate databases with documents of the format
-* { _id: xxx, blob: "xxx", nestedDoc: {xxx}, list: [xxx,yyy,zzz], counter: xxx }
-*
-*/
-
-#include <iostream>
-
-#include <boost/program_options.hpp>
-
-#include "mongo/base/initializer.h"
-#include "mongo/util/assert_util.h"
-#include "mongo/client/dbclientcursor.h"
-#include "mongo/tools/docgenerator.h"
-#include "mongo/db/jsobj.h"
-#include "mongo/util/mongoutils/str.h"
-
-using namespace mongo;
-using std::exception;
-using std::cout;
-
-namespace po = boost::program_options;
-
-//------------- Define globals and constants--------
-
-// global options object
-DocGeneratorOptions globalDocGenOption;
-
-//----------- End globals and constants------------
-
-int parseCmdLineOptions( int argc, char **argv ) {
-
- try {
- po::options_description general_options( "General options" );
- general_options.add_options()
- ( "help", "produce help message" )
- ( "hostname,H", po::value<string>() , "ip address of the host where mongod is running " )
- ( "dbSize", po::value<double>(), "size of each database in megabytes(MB)" )
- ( "numdbs", po::value<int>(), "number of databases you want" )
- ( "prefix", po::value<string>(),
- "prefix the resultant db name where the documents "
- "will be saved. DB's will be named prefix0, prefix1 etc." )
- ;
-
- po::variables_map params;
- po::store( po::parse_command_line(argc, argv, general_options), params );
- po::notify( params );
-
- // Parse the values if supplied by the user. No data sanity check is performed
- // here so meaningless values may result in unexpected behavior.
- // TODO: Perform data sanity check
- if ( params.count("help") ) {
- cout << general_options << "\n";
- return 1;
- }
- if ( params.count("hostname") ) {
- globalDocGenOption.hostname = params["hostname"].as<string>();
- }
- if ( params.count("dbSize") ) {
- globalDocGenOption.dbSize = params["dbSize"].as<double>();
- }
- if ( params.count("numdbs") ) {
- globalDocGenOption.numdbs = params["numdbs"].as<int>();
- }
- if ( params.count("prefix") ) {
- globalDocGenOption.prefix = params["prefix"].as<string>();
- }
- }
- catch(exception& e) {
- cerr << "error: " << e.what() << "\n";
- return 1;
- }
- return 0;
-}
-
-
-int main( int argc, char* argv[], char* envp[] ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- if( parseCmdLineOptions( argc, argv) )
- return 1;
-
- BSONObj nestedDoc = BSON("Firstname" << "David" <<
- "Lastname" << "Smith" <<
- "Address" << BSON( "Street" << "5th Av" <<
- "City" << "New York" )
- );
- std::vector<std::string> list;
- list.push_back("mongo new york city");
- list.push_back("mongo rome");
- list.push_back("mongo dublin");
- list.push_back("mongo seoul");
- list.push_back("mongo barcelona");
- list.push_back("mongo madrid");
- list.push_back("mongo chicago");
- list.push_back("mongo amsterdam");
- list.push_back("mongo delhi");
- list.push_back("mongo beijing");
-
- BSONObj args = BSONObjBuilder()
- .append( "_id", 0 )
- .append( "blob", "MongoDB is an open source document-oriented database "
- "system designed with scalability and developer." )
- .append( "nestedDoc", nestedDoc )
- .append( "list", list )
- .append( "counter", 0 ).obj();
-
- const int numDocsPerDB =
- static_cast<int>( globalDocGenOption.dbSize * 1024 * 1024 / args.objsize() );
- cout << "numDocsPerDB:" << numDocsPerDB << endl;
- try {
- DBClientConnection conn;
- conn.connect( globalDocGenOption.hostname );
- cout << "successfully connected to the host" << endl;
- for( int i=0; i < globalDocGenOption.numdbs; ++i ) {
- scoped_ptr<DocumentGenerator> docGen( DocumentGenerator::makeDocumentGenerator(args) );
- cout << "populating database " << globalDocGenOption.prefix << i << endl;
- long long j = 0;
- string ns = mongoutils::str::stream() << globalDocGenOption.prefix << i << ".sampledata";
- while( j != numDocsPerDB ) {
- BSONObj doc = docGen->createDocument();
- conn.insert( ns, doc );
- ++j;
- }
- BSONObj blobIndex = BSON("blob" << 1);
- conn.ensureIndex(ns, blobIndex);
- BSONObj listIndex = BSON("list" << 1);
- conn.ensureIndex(ns, listIndex);
- }
- } catch( DBException &e ) {
- cout << "caught " << e.what() << endl;
- }
- return 0;
-}
diff --git a/src/mongo/tools/dump.cpp b/src/mongo/tools/dump.cpp
index 93d0446c3cd..7f8c6b42f63 100644
--- a/src/mongo/tools/dump.cpp
+++ b/src/mongo/tools/dump.cpp
@@ -1,5 +1,3 @@
-// dump.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,27 +12,42 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
#include "mongo/pch.h"
-#include <fcntl.h>
-#include <map>
-#include <fstream>
-
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
+#include <fcntl.h>
+#include <fstream>
+#include <map>
-#include "mongo/base/initializer.h"
+#include "mongo/base/status.h"
+#include "mongo/client/auth_helpers.h"
#include "mongo/client/dbclientcursor.h"
+#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/db.h"
-#include "mongo/db/namespacestring.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/catalog/collection.h"
+#include "mongo/tools/mongodump_options.h"
#include "mongo/tools/tool.h"
+#include "mongo/util/options_parser/option_section.h"
+#include "mongo/util/mongoutils/str.h"
using namespace mongo;
-namespace po = boost::program_options;
-
class Dump : public Tool {
class FilePtr : boost::noncopyable {
public:
@@ -45,27 +58,10 @@ class Dump : public Tool {
FILE* _f;
};
public:
- Dump() : Tool( "dump" , ALL , "" , "" , true ) {
- add_options()
- ("out,o", po::value<string>()->default_value("dump"), "output directory or \"-\" for stdout")
- ("query,q", po::value<string>() , "json query" )
- ("oplog", "Use oplog for point-in-time snapshotting" )
- ("repair", "try to recover a crashed database" )
- ("forceTableScan", "force a table scan (do not use $snapshot)" )
- ;
- }
-
- virtual void preSetup() {
- string out = getParam("out");
- if ( out == "-" ) {
- // write output to standard error to avoid mangling output
- // must happen early to avoid sending junk to stdout
- useStandardOutput(false);
- }
- }
+ Dump() : Tool() { }
- virtual void printExtraHelp(ostream& out) {
- out << "Export MongoDB data to BSON files.\n" << endl;
+ virtual void printHelp(ostream& out) {
+ printMongoDumpHelp(&out);
}
// This is a functor that writes a BSONObj to a file
@@ -93,13 +89,12 @@ public:
ProgressMeter* _m;
};
- void doCollection( const string coll , FILE* out , ProgressMeter *m ) {
- Query q = _query;
-
+ void doCollection( const string coll , Query q, FILE* out , ProgressMeter *m,
+ bool usingMongos ) {
int queryOptions = QueryOption_SlaveOk | QueryOption_NoCursorTimeout;
- if (startsWith(coll.c_str(), "local.oplog."))
+ if (startsWith(coll.c_str(), "local.oplog.") && q.obj.hasField("ts"))
queryOptions |= QueryOption_OplogReplay;
- else if ( _query.isEmpty() && !hasParam("dbpath") && !hasParam("forceTableScan") ) {
+ else if (mongoDumpGlobalParams.snapShotQuery) {
q.snapshot();
}
@@ -107,7 +102,7 @@ public:
Writer writer(out, m);
// use low-latency "exhaust" mode if going over the network
- if (!_usingMongos && typeid(connBase) == typeid(DBClientConnection&)) {
+ if (!usingMongos && typeid(connBase) == typeid(DBClientConnection&)) {
DBClientConnection& conn = static_cast<DBClientConnection&>(connBase);
boost::function<void(const BSONObj&)> castedWriter(writer); // needed for overload resolution
conn.query( castedWriter, coll.c_str() , q , NULL, queryOptions | QueryOption_Exhaust);
@@ -121,24 +116,25 @@ public:
}
}
- void writeCollectionFile( const string coll , boost::filesystem::path outputFile ) {
- log() << "\t" << coll << " to " << outputFile.string() << endl;
+ void writeCollectionFile( const string coll , Query q, boost::filesystem::path outputFile,
+ bool usingMongos ) {
+ toolInfoLog() << "\t" << coll << " to " << outputFile.string() << std::endl;
FilePtr f (fopen(outputFile.string().c_str(), "wb"));
uassert(10262, errnoWithPrefix("couldn't open file"), f);
ProgressMeter m(conn(true).count(coll.c_str(), BSONObj(), QueryOption_SlaveOk));
m.setName("Collection File Writing Progress");
- m.setUnits("objects");
+ m.setUnits("documents");
- doCollection(coll, f, &m);
+ doCollection(coll, q, f, &m, usingMongos);
- log() << "\t\t " << m.done() << " objects" << endl;
+ toolInfoLog() << "\t\t " << m.done() << " documents" << std::endl;
}
void writeMetadataFile( const string coll, boost::filesystem::path outputFile,
map<string, BSONObj> options, multimap<string, BSONObj> indexes ) {
- log() << "\tMetadata for " << coll << " to " << outputFile.string() << endl;
+ toolInfoLog() << "\tMetadata for " << coll << " to " << outputFile.string() << std::endl;
bool hasOptions = options.count(coll) > 0;
bool hasIndexes = indexes.count(coll) > 0;
@@ -170,13 +166,18 @@ public:
- void writeCollectionStdout( const string coll ) {
- doCollection(coll, stdout, NULL);
+ void writeCollectionStdout( const string coll, const BSONObj& dumpQuery, bool usingMongos ) {
+ doCollection(coll, dumpQuery, stdout, NULL, usingMongos);
}
- void go( const string db , const boost::filesystem::path outdir ) {
- log() << "DATABASE: " << db << "\t to \t" << outdir.string() << endl;
-
+ void go(const string& db,
+ const string& coll,
+ const Query& query,
+ const boost::filesystem::path& outdir,
+ const string& outFilename,
+ bool usingMongos) {
+ // Can only provide outFilename if db and coll are provided
+ fassert(17368, outFilename.empty() || (!coll.empty() && !db.empty()));
boost::filesystem::create_directories( outdir );
map <string, BSONObj> collectionOptions;
@@ -202,81 +203,74 @@ public:
}
// skip namespaces with $ in them only if we don't specify a collection to dump
- if ( _coll == "" && name.find( ".$" ) != string::npos ) {
- LOG(1) << "\tskipping collection: " << name << endl;
+ if (coll == "" && name.find(".$") != string::npos) {
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ toolInfoLog() << "\tskipping collection: " << name << std::endl;
+ }
continue;
}
const string filename = name.substr( db.size() + 1 );
//if a particular collections is specified, and it's not this one, skip it
- if ( _coll != "" && db + "." + _coll != name && _coll != name )
+ if (coll != "" && db + "." + coll != name && coll != name) {
continue;
+ }
// raise error before writing collection with non-permitted filename chars in the name
size_t hasBadChars = name.find_first_of("/\0");
if (hasBadChars != string::npos){
- error() << "Cannot dump " << name << ". Collection has '/' or null in the collection name." << endl;
- continue;
+ toolError() << "Cannot dump " << name
+ << ". Collection has '/' or null in the collection name." << std::endl;
+ continue;
}
- if (NamespaceString(name).coll == "system.indexes") {
+ if (nsToCollectionSubstring(name) == "system.indexes") {
// Create system.indexes.bson for compatibility with pre 2.2 mongorestore
const string filename = name.substr( db.size() + 1 );
- writeCollectionFile( name.c_str() , outdir / ( filename + ".bson" ) );
+ writeCollectionFile( name.c_str(), query, outdir / ( filename + ".bson" ),
+ usingMongos );
// Don't dump indexes as *.metadata.json
continue;
}
-
- if ( _coll != "" && db + "." + _coll != name && _coll != name )
- continue;
-
+
+ if (nsToCollectionSubstring(name) == "system.users" &&
+ !mongoDumpGlobalParams.dumpUsersAndRoles) {
+ continue;
+ }
+
collections.push_back(name);
}
for (vector<string>::iterator it = collections.begin(); it != collections.end(); ++it) {
string name = *it;
- const string filename = name.substr( db.size() + 1 );
- writeCollectionFile( name , outdir / ( filename + ".bson" ) );
+ const string filename = outFilename != "" ? outFilename : name.substr( db.size() + 1 );
+ writeCollectionFile( name , query, outdir / ( filename + ".bson" ), usingMongos );
writeMetadataFile( name, outdir / (filename + ".metadata.json"), collectionOptions, indexes);
}
}
int repair() {
- if ( ! hasParam( "dbpath" ) ){
- log() << "repair mode only works with --dbpath" << endl;
- return -1;
- }
-
- if ( ! hasParam( "db" ) ){
- log() << "repair mode only works on 1 db at a time right now" << endl;
- return -1;
- }
-
- string dbname = getParam( "db" );
- log() << "going to try and recover data from: " << dbname << endl;
-
- return _repair( dbname );
+ toolInfoLog() << "going to try and recover data from: " << toolGlobalParams.db << std::endl;
+ return _repair(toolGlobalParams.db);
}
DiskLoc _repairExtent( Database* db , string ns, bool forward , DiskLoc eLoc , Writer& w ){
LogIndentLevel lil;
if ( eLoc.getOfs() <= 0 ){
- error() << "invalid extent ofs: " << eLoc.getOfs() << endl;
+ toolError() << "invalid extent ofs: " << eLoc.getOfs() << std::endl;
return DiskLoc();
}
-
-
- MongoDataFile * mdf = db->getFile( eLoc.a() );
- Extent * e = mdf->debug_getExtent( eLoc );
+ Extent * e = db->getExtentManager().getExtent( eLoc, false );
if ( ! e->isOk() ){
- warning() << "Extent not ok magic: " << e->magic << " going to try to continue" << endl;
+ toolError() << "Extent not ok magic: " << e->magic << " going to try to continue"
+ << std::endl;
}
-
- log() << "length:" << e->length << endl;
+
+ toolInfoLog() << "length:" << e->length << std::endl;
LogIndentLevel lil2;
@@ -286,34 +280,38 @@ public:
while ( ! loc.isNull() ){
if ( ! seen.insert( loc ).second ) {
- error() << "infinite loop in extent, seen: " << loc << " before" << endl;
+ toolError() << "infinite loop in extent, seen: " << loc << " before" << std::endl;
break;
}
if ( loc.getOfs() <= 0 ){
- error() << "offset is 0 for record which should be impossible" << endl;
+ toolError() << "offset is 0 for record which should be impossible" << std::endl;
break;
}
- LOG(1) << loc << endl;
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ toolInfoLog() << loc << std::endl;
+ }
Record* rec = loc.rec();
BSONObj obj;
try {
obj = loc.obj();
verify( obj.valid() );
- LOG(1) << obj << endl;
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ toolInfoLog() << obj << std::endl;
+ }
w( obj );
}
catch ( std::exception& e ) {
- log() << "found invalid document @ " << loc << " " << e.what() << endl;
+ toolError() << "found invalid document @ " << loc << " " << e.what() << std::endl;
if ( ! obj.isEmpty() ) {
try {
BSONElement e = obj.firstElement();
stringstream ss;
ss << "first element: " << e;
- log() << ss.str();
+ toolError() << ss.str() << std::endl;
}
catch ( std::exception& ) {
- log() << "unable to log invalid document @ " << loc << endl;
+ toolError() << "unable to log invalid document @ " << loc << std::endl;
}
}
}
@@ -326,76 +324,81 @@ public:
break;
}
}
- log() << "wrote " << seen.size() << " documents" << endl;
+ toolInfoLog() << "wrote " << seen.size() << " documents" << std::endl;
return forward ? e->xnext : e->xprev;
}
+ /*
+ * NOTE: The "outfile" parameter passed in should actually represent a directory, but it is
+ * called "outfile" because we append the filename and use it as our output file.
+ */
void _repair( Database* db , string ns , boost::filesystem::path outfile ){
- NamespaceDetails * nsd = nsdetails( ns );
- log() << "nrecords: " << nsd->stats.nrecords
- << " datasize: " << nsd->stats.datasize
- << " firstExtent: " << nsd->firstExtent
- << endl;
-
- if ( nsd->firstExtent.isNull() ){
- log() << " ERROR fisrtExtent is null" << endl;
+ Collection* collection = db->getCollection( ns );
+ const NamespaceDetails * nsd = collection->details();
+ toolInfoLog() << "nrecords: " << nsd->numRecords()
+ << " datasize: " << nsd->dataSize()
+ << " firstExtent: " << nsd->firstExtent()
+ << std::endl;
+
+ if ( nsd->firstExtent().isNull() ){
+ toolError() << " ERROR fisrtExtent is null" << std::endl;
return;
}
-
- if ( ! nsd->firstExtent.isValid() ){
- log() << " ERROR fisrtExtent is not valid" << endl;
+
+ if ( ! nsd->firstExtent().isValid() ){
+ toolError() << " ERROR fisrtExtent is not valid" << std::endl;
return;
}
outfile /= ( ns.substr( ns.find( "." ) + 1 ) + ".bson" );
- log() << "writing to: " << outfile.string() << endl;
-
+ toolInfoLog() << "writing to: " << outfile.string() << std::endl;
+
FilePtr f (fopen(outfile.string().c_str(), "wb"));
// init with double the docs count because we make two passes
- ProgressMeter m( nsd->stats.nrecords * 2 );
+ ProgressMeter m( nsd->numRecords() * 2 );
m.setName("Repair Progress");
- m.setUnits("objects");
-
+ m.setUnits("documents");
+
Writer w( f , &m );
try {
- log() << "forward extent pass" << endl;
+ toolInfoLog() << "forward extent pass" << std::endl;
LogIndentLevel lil;
- DiskLoc eLoc = nsd->firstExtent;
+ DiskLoc eLoc = nsd->firstExtent();
while ( ! eLoc.isNull() ){
- log() << "extent loc: " << eLoc << endl;
+ toolInfoLog() << "extent loc: " << eLoc << std::endl;
eLoc = _repairExtent( db , ns , true , eLoc , w );
}
}
catch ( DBException& e ){
- error() << "forward extent pass failed:" << e.toString() << endl;
+ toolError() << "forward extent pass failed:" << e.toString() << std::endl;
}
try {
- log() << "backwards extent pass" << endl;
+ toolInfoLog() << "backwards extent pass" << std::endl;
LogIndentLevel lil;
- DiskLoc eLoc = nsd->lastExtent;
+ DiskLoc eLoc = nsd->lastExtent();
while ( ! eLoc.isNull() ){
- log() << "extent loc: " << eLoc << endl;
+ toolInfoLog() << "extent loc: " << eLoc << std::endl;
eLoc = _repairExtent( db , ns , false , eLoc , w );
}
}
catch ( DBException& e ){
- error() << "ERROR: backwards extent pass failed:" << e.toString() << endl;
+ toolError() << "ERROR: backwards extent pass failed:" << e.toString() << std::endl;
}
- log() << "\t\t " << m.done() << " objects" << endl;
+ toolInfoLog() << "\t\t " << m.done() << " documents" << std::endl;
}
int _repair( string dbname ) {
Client::WriteContext cx( dbname );
Database * db = cx.ctx().db();
-
+
list<string> namespaces;
- db->namespaceIndex.getNamespaces( namespaces );
-
- boost::filesystem::path root = getParam( "out" );
+ db->namespaceIndex().getNamespaces( namespaces );
+
+ boost::filesystem::path root = mongoDumpGlobalParams.outputDirectory;
root /= dbname;
boost::filesystem::create_directories( root );
@@ -409,17 +412,19 @@ public:
if ( str::contains( ns , ".tmp.mr." ) )
continue;
- if ( _coll != "" && ! str::endsWith( ns , _coll ) )
+ if (toolGlobalParams.coll != "" &&
+ !str::endsWith(ns, toolGlobalParams.coll)) {
continue;
+ }
- log() << "trying to recover: " << ns << endl;
+ toolInfoLog() << "trying to recover: " << ns << std::endl;
LogIndentLevel lil2;
try {
_repair( db , ns , root );
}
catch ( DBException& e ){
- log() << "ERROR recovering: " << ns << " " << e.toString() << endl;
+ toolError() << "ERROR recovering: " << ns << " " << e.toString() << std::endl;
}
}
@@ -427,26 +432,34 @@ public:
}
int run() {
-
- if ( hasParam( "repair" ) ){
- warning() << "repair is a work in progress" << endl;
+ bool usingMongos = isMongos();
+ int serverAuthzVersion = 0;
+ BSONObj dumpQuery;
+
+ if (mongoDumpGlobalParams.repair){
return repair();
}
{
- string q = getParam("query");
- if ( q.size() )
- _query = fromjson( q );
+ if (mongoDumpGlobalParams.query.size()) {
+ dumpQuery = fromjson(mongoDumpGlobalParams.query);
+ }
+ }
+
+ if (mongoDumpGlobalParams.dumpUsersAndRoles) {
+ uassertStatusOK(auth::getRemoteStoredAuthorizationVersion(&conn(true),
+ &serverAuthzVersion));
+ uassert(17369,
+ mongoutils::str::stream() << "Backing up users and roles is only supported for "
+ "clusters with auth schema versions 1 or 3, found: " <<
+ serverAuthzVersion,
+ serverAuthzVersion == AuthorizationManager::schemaVersion24 ||
+ serverAuthzVersion == AuthorizationManager::schemaVersion26Final);
}
string opLogName = "";
unsigned long long opLogStart = 0;
- if (hasParam("oplog")) {
- if (hasParam("query") || hasParam("db") || hasParam("collection")) {
- log() << "oplog mode is only supported on full dumps" << endl;
- return -1;
- }
-
+ if (mongoDumpGlobalParams.useOplog) {
BSONObj isMaster;
conn("true").simpleCommand("admin", &isMaster, "isMaster");
@@ -457,14 +470,16 @@ public:
else {
opLogName = "local.oplog.$main";
if ( ! isMaster["ismaster"].trueValue() ) {
- log() << "oplog mode is only supported on master or replica set member" << endl;
+ toolError() << "oplog mode is only supported on master or replica set member"
+ << std::endl;
return -1;
}
}
BSONObj op = conn(true).findOne(opLogName, Query().sort("$natural", -1), 0, QueryOption_SlaveOk);
if (op.isEmpty()) {
- log() << "No operations in oplog. Please ensure you are connecting to a master." << endl;
+ toolError() << "No operations in oplog. Please ensure you are connecting to a "
+ << "master." << std::endl;
return -1;
}
@@ -473,34 +488,33 @@ public:
}
// check if we're outputting to stdout
- string out = getParam("out");
- if ( out == "-" ) {
- if ( _db != "" && _coll != "" ) {
- writeCollectionStdout( _db+"."+_coll );
+ if (mongoDumpGlobalParams.outputDirectory == "-") {
+ if (toolGlobalParams.db != "" && toolGlobalParams.coll != "") {
+ writeCollectionStdout(toolGlobalParams.db + "." + toolGlobalParams.coll, dumpQuery,
+ usingMongos);
return 0;
}
else {
- log() << "You must specify database and collection to print to stdout" << endl;
+ toolError() << "You must specify database and collection to print to stdout"
+ << std::endl;
return -1;
}
}
- _usingMongos = isMongos();
+ boost::filesystem::path root(mongoDumpGlobalParams.outputDirectory);
- boost::filesystem::path root( out );
- string db = _db;
-
- if ( db == "" ) {
- if ( _coll != "" ) {
- error() << "--db must be specified with --collection" << endl;
+ if (toolGlobalParams.db == "") {
+ if (toolGlobalParams.coll != "") {
+ toolError() << "--db must be specified with --collection" << std::endl;
return -1;
}
- log() << "all dbs" << endl;
+ toolInfoLog() << "all dbs" << std::endl;
BSONObj res = conn( true ).findOne( "admin.$cmd" , BSON( "listDatabases" << 1 ) );
if ( ! res["databases"].isABSONObj() ) {
- error() << "output of listDatabases isn't what we expected, no 'databases' field:\n" << res << endl;
+ toolError() << "output of listDatabases isn't what we expected, no 'databases' "
+ << "field:\n" << res << std::endl;
return -2;
}
BSONObj dbs = res["databases"].embeddedObjectUserCheck();
@@ -510,7 +524,8 @@ public:
string key = *i;
if ( ! dbs[key].isABSONObj() ) {
- error() << "database field not an object key: " << key << " value: " << dbs[key] << endl;
+ toolError() << "database field not an document key: " << key << " value: "
+ << dbs[key] << std::endl;
return -3;
}
@@ -520,31 +535,39 @@ public:
if ( (string)dbName == "local" )
continue;
- go ( dbName , root / dbName );
+ boost::filesystem::path outdir = root / dbName;
+ toolInfoLog() << "DATABASE: " << dbName << "\t to \t" << outdir.string()
+ << std::endl;
+ go ( dbName , "", dumpQuery, outdir, "", usingMongos );
}
}
else {
- go( db , root / db );
+ boost::filesystem::path outdir = root / toolGlobalParams.db;
+ toolInfoLog() << "DATABASE: " << toolGlobalParams.db << "\t to \t" << outdir.string()
+ << std::endl;
+ go(toolGlobalParams.db, toolGlobalParams.coll, dumpQuery, outdir, "", usingMongos);
+ if (mongoDumpGlobalParams.dumpUsersAndRoles &&
+ serverAuthzVersion == AuthorizationManager::schemaVersion26Final &&
+ toolGlobalParams.db != "admin") {
+ toolInfoLog() << "Backing up user and role data for the " << toolGlobalParams.db <<
+ " database";
+ Query query = Query(BSON("db" << toolGlobalParams.db));
+ go("admin", "system.users", query, outdir, "$admin.system.users", usingMongos);
+ go("admin", "system.roles", query, outdir, "$admin.system.roles", usingMongos);
+ }
}
if (!opLogName.empty()) {
BSONObjBuilder b;
b.appendTimestamp("$gt", opLogStart);
- _query = BSON("ts" << b.obj());
+ dumpQuery = BSON("ts" << b.obj());
- writeCollectionFile( opLogName , root / "oplog.bson" );
+ writeCollectionFile( opLogName , dumpQuery, root / "oplog.bson", usingMongos );
}
return 0;
}
-
- bool _usingMongos;
- BSONObj _query;
};
-int main( int argc , char ** argv, char ** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- Dump d;
- return d.main( argc , argv );
-}
+REGISTER_MONGO_TOOL(Dump);
diff --git a/src/mongo/tools/export.cpp b/src/mongo/tools/export.cpp
index ad2195846f0..75460f76a15 100644
--- a/src/mongo/tools/export.cpp
+++ b/src/mongo/tools/export.cpp
@@ -1,5 +1,3 @@
-// export.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,55 +12,42 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "pch.h"
-#include "db/json.h"
-#include "mongo/base/initializer.h"
-#include "mongo/client/dbclientcursor.h"
-
-#include "tool.h"
+#include "mongo/pch.h"
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/operations.hpp>
#include <fstream>
#include <iostream>
-#include <boost/filesystem/convenience.hpp>
-#include <boost/filesystem/operations.hpp>
-#include <boost/program_options.hpp>
+#include "mongo/client/dbclientcursor.h"
+#include "mongo/db/json.h"
+#include "mongo/tools/mongoexport_options.h"
+#include "mongo/tools/tool.h"
+#include "mongo/tools/tool_logger.h"
+#include "mongo/util/options_parser/option_section.h"
using namespace mongo;
-namespace po = boost::program_options;
-
class Export : public Tool {
public:
- Export() : Tool( "export" ) {
- addFieldOptions();
- add_options()
- ("query,q" , po::value<string>() , "query filter, as a JSON string" )
- ("csv","export to csv instead of json")
- ("out,o", po::value<string>(), "output file; if not specified, stdout is used")
- ("jsonArray", "output to a json array rather than one object per line")
- ("slaveOk,k", po::value<bool>()->default_value(true) , "use secondaries for export if available, default true")
- ("forceTableScan", "force a table scan (do not use $snapshot)" )
- ;
- _usesstdout = false;
- }
-
- virtual void preSetup() {
- if ( hasParam("out") ) {
- string out = getParam("out");
- if ( out != "-" ) {
- // we write output to standard error by default to avoid
- // mangling output, but we don't need to do this if an output
- // file was specified
- useStandardOutput(true);
- }
- }
- }
+ Export() : Tool() { }
- virtual void printExtraHelp( ostream & out ) {
- out << "Export MongoDB data to CSV, TSV or JSON files.\n" << endl;
+ virtual void printHelp( ostream & out ) {
+ printMongoExportHelp(&out);
}
// Turn every double quote character into two double quote characters
@@ -107,7 +92,10 @@ public:
case jstOID:
return "ObjectID(" + object.OID().toString() + ")"; // OIDs are always 24 bytes
case Date:
- return timeToISOString(object.Date() / 1000);
+ // We need to check if we can actually format this date. See SERVER-13760.
+ return object.Date().isFormatable() ?
+ dateToISOStringUTC(object.Date()) :
+ csvEscape(object.jsonString(Strict, false));
case Timestamp:
return csvEscape(object.jsonString(Strict, false));
case RegEx:
@@ -134,22 +122,19 @@ public:
int run() {
string ns;
- const bool csv = hasParam( "csv" );
- const bool jsonArray = hasParam( "jsonArray" );
ostream *outPtr = &cout;
- string outfile = getParam( "out" );
auto_ptr<ofstream> fileStream;
- if ( hasParam( "out" ) && outfile != "-" ) {
- size_t idx = outfile.rfind( "/" );
+ if (mongoExportGlobalParams.outputFileSpecified && mongoExportGlobalParams.outputFile != "-") {
+ size_t idx = mongoExportGlobalParams.outputFile.rfind("/");
if ( idx != string::npos ) {
- string dir = outfile.substr( 0 , idx + 1 );
+ string dir = mongoExportGlobalParams.outputFile.substr( 0 , idx + 1 );
boost::filesystem::create_directories( dir );
}
- ofstream * s = new ofstream( outfile.c_str() , ios_base::out );
+ ofstream * s = new ofstream(mongoExportGlobalParams.outputFile.c_str(), ios_base::out);
fileStream.reset( s );
outPtr = s;
if ( ! s->good() ) {
- cerr << "couldn't open [" << outfile << "]" << endl;
+ cerr << "couldn't open [" << mongoExportGlobalParams.outputFile << "]" << endl;
return -1;
}
}
@@ -166,18 +151,17 @@ public:
return 1;
}
- if ( hasParam( "fields" ) || csv ) {
- needFields();
+ if (toolGlobalParams.fieldsSpecified || mongoExportGlobalParams.csv) {
- // we can't use just _fieldsObj since we support everything getFieldDotted does
+ // we can't use just toolGlobalParams.fields since we support everything getFieldDotted
+ // does
set<string> seen;
BSONObjBuilder b;
- BSONObjIterator i( _fieldsObj );
- while ( i.more() ){
- BSONElement e = i.next();
- string f = str::before( e.fieldName() , '.' );
+ for (std::vector<std::string>::iterator i = toolGlobalParams.fields.begin();
+ i != toolGlobalParams.fields.end(); i++) {
+ std::string f = str::before(*i, '.');
if ( seen.insert( f ).second )
b.append( f , 1 );
}
@@ -187,38 +171,47 @@ public:
}
- if ( csv && _fields.size() == 0 ) {
+ if (mongoExportGlobalParams.csv && !toolGlobalParams.fieldsSpecified) {
cerr << "csv mode requires a field list" << endl;
return -1;
}
- Query q( getParam( "query" , "" ) );
- if ( q.getFilter().isEmpty() && !hasParam("dbpath") && !hasParam("forceTableScan") )
- q.snapshot();
+ Query q(mongoExportGlobalParams.query);
+ if (mongoExportGlobalParams.sort != "") {
+ BSONObj sortSpec = mongo::fromjson(mongoExportGlobalParams.sort);
+ q.sort(sortSpec);
+ }
- bool slaveOk = _params["slaveOk"].as<bool>();
+ if (mongoExportGlobalParams.snapShotQuery) {
+ q.snapshot();
+ }
- auto_ptr<DBClientCursor> cursor = conn().query( ns.c_str() , q , 0 , 0 , fieldsToReturn , ( slaveOk ? QueryOption_SlaveOk : 0 ) | QueryOption_NoCursorTimeout );
+ auto_ptr<DBClientCursor> cursor = conn().query(ns.c_str(), q,
+ mongoExportGlobalParams.limit, mongoExportGlobalParams.skip, fieldsToReturn,
+ (mongoExportGlobalParams.slaveOk ? QueryOption_SlaveOk : 0) |
+ QueryOption_NoCursorTimeout);
- if ( csv ) {
- for ( vector<string>::iterator i=_fields.begin(); i != _fields.end(); i++ ) {
- if ( i != _fields.begin() )
+ if (mongoExportGlobalParams.csv) {
+ for (std::vector<std::string>::iterator i = toolGlobalParams.fields.begin();
+ i != toolGlobalParams.fields.end(); i++) {
+ if (i != toolGlobalParams.fields.begin())
out << ",";
out << *i;
}
out << endl;
}
- if (jsonArray)
+ if (mongoExportGlobalParams.jsonArray)
out << '[';
long long num = 0;
while ( cursor->more() ) {
num++;
BSONObj obj = cursor->next();
- if ( csv ) {
- for ( vector<string>::iterator i=_fields.begin(); i != _fields.end(); i++ ) {
- if ( i != _fields.begin() )
+ if (mongoExportGlobalParams.csv) {
+ for (std::vector<std::string>::iterator i = toolGlobalParams.fields.begin();
+ i != toolGlobalParams.fields.end(); i++) {
+ if (i != toolGlobalParams.fields.begin())
out << ",";
const BSONElement & e = obj.getFieldDotted(i->c_str());
if ( ! e.eoo() ) {
@@ -228,27 +221,23 @@ public:
out << endl;
}
else {
- if (jsonArray && num != 1)
+ if (mongoExportGlobalParams.jsonArray && num != 1)
out << ',';
out << obj.jsonString();
- if (!jsonArray)
+ if (!mongoExportGlobalParams.jsonArray)
out << endl;
}
}
- if (jsonArray)
+ if (mongoExportGlobalParams.jsonArray)
out << ']' << endl;
- cerr << "exported " << num << " records" << endl;
+ toolInfoOutput() << "exported " << num << " records" << endl;
return 0;
}
};
-int main( int argc , char ** argv, char** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- Export e;
- return e.main( argc , argv );
-}
+REGISTER_MONGO_TOOL(Export);
diff --git a/src/mongo/tools/files.cpp b/src/mongo/tools/files.cpp
index 7170f57f764..6ae94fea8df 100644
--- a/src/mongo/tools/files.cpp
+++ b/src/mongo/tools/files.cpp
@@ -1,5 +1,3 @@
-// files.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,53 +12,40 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "pch.h"
-#include "client/gridfs.h"
-#include "mongo/base/initializer.h"
-#include "mongo/client/dbclientcursor.h"
-
-#include "tool.h"
-#include "pcrecpp.h"
+#include "mongo/pch.h"
#include <fstream>
#include <iostream>
+#include <pcrecpp.h>
-#include <boost/program_options.hpp>
+#include "mongo/client/dbclientcursor.h"
+#include "mongo/client/gridfs.h"
+#include "mongo/tools/mongofiles_options.h"
+#include "mongo/tools/tool.h"
+#include "mongo/util/options_parser/option_section.h"
using namespace mongo;
-namespace po = boost::program_options;
-
class Files : public Tool {
public:
- Files() : Tool( "files" ) {
- add_options()
- ( "local,l", po::value<string>(), "local filename for put|get (default is to use the same name as 'gridfs filename')")
- ( "type,t", po::value<string>(), "MIME type for put (default is to omit)")
- ( "replace,r", "Remove other files with same name after PUT")
- ;
- add_hidden_options()
- ( "command" , po::value<string>() , "command (list|search|put|get)" )
- ( "file" , po::value<string>() , "filename for get|put" )
- ;
- addPositionArg( "command" , 1 );
- addPositionArg( "file" , 2 );
- }
+ Files() : Tool() { }
- virtual void printExtraHelp( ostream & out ) {
- out << "Browse and modify a GridFS filesystem.\n" << endl;
- out << "usage: " << _name << " [options] command [gridfs filename]" << endl;
- out << "command:" << endl;
- out << " one of (list|search|put|get)" << endl;
- out << " list - list all files. 'gridfs filename' is an optional prefix " << endl;
- out << " which listed filenames must begin with." << endl;
- out << " search - search all files. 'gridfs filename' is a substring " << endl;
- out << " which listed filenames must contain." << endl;
- out << " put - add a file with filename 'gridfs filename'" << endl;
- out << " get - get a file with filename 'gridfs filename'" << endl;
- out << " delete - delete all files with filename 'gridfs filename'" << endl;
+ virtual void printHelp( ostream & out ) {
+ printMongoFilesHelp(&out);
}
void display( GridFS * grid , BSONObj obj ) {
@@ -75,95 +60,91 @@ public:
}
int run() {
- string cmd = getParam( "command" );
- if ( cmd.size() == 0 ) {
+ if (mongoFilesGlobalParams.command.size() == 0) {
cerr << "ERROR: need command" << endl << endl;
printHelp(cout);
return -1;
}
- GridFS g( conn() , _db );
-
- string filename = getParam( "file" );
+ GridFS g(conn(), toolGlobalParams.db);
- if ( cmd == "list" ) {
+ if (mongoFilesGlobalParams.command == "list") {
BSONObjBuilder b;
- if ( filename.size() ) {
+ if (mongoFilesGlobalParams.gridFSFilename.size()) {
b.appendRegex( "filename" , (string)"^" +
- pcrecpp::RE::QuoteMeta( filename ) );
+ pcrecpp::RE::QuoteMeta(mongoFilesGlobalParams.gridFSFilename) );
}
display( &g , b.obj() );
return 0;
}
- if ( filename.size() == 0 ) {
+ if (mongoFilesGlobalParams.gridFSFilename.size() == 0) {
cerr << "ERROR: need a filename" << endl << endl;
printHelp(cout);
return -1;
}
- if ( cmd == "search" ) {
+ if (mongoFilesGlobalParams.command == "search") {
BSONObjBuilder b;
- b.appendRegex( "filename" , filename );
+ b.appendRegex("filename", mongoFilesGlobalParams.gridFSFilename);
display( &g , b.obj() );
return 0;
}
- if ( cmd == "get" ) {
- GridFile f = g.findFile( filename );
+ if (mongoFilesGlobalParams.command == "get") {
+ GridFile f = g.findFile(mongoFilesGlobalParams.gridFSFilename);
if ( ! f.exists() ) {
cerr << "ERROR: file not found" << endl;
return -2;
}
- string out = getParam("local", f.getFilename());
- f.write( out );
+ f.write(mongoFilesGlobalParams.localFile);
- if (out != "-")
- cout << "done write to: " << out << endl;
+ if (mongoFilesGlobalParams.localFile != "-") {
+ toolInfoOutput() << "done write to: " << mongoFilesGlobalParams.localFile
+ << std::endl;
+ }
return 0;
}
- if ( cmd == "put" ) {
- const string& infile = getParam("local", filename);
- const string& type = getParam("type", "");
-
- BSONObj file = g.storeFile(infile, filename, type);
- cout << "added file: " << file << endl;
-
- if (hasParam("replace")) {
- auto_ptr<DBClientCursor> cursor = conn().query(_db+".fs.files", BSON("filename" << filename << "_id" << NE << file["_id"] ));
+ if (mongoFilesGlobalParams.command == "put") {
+ BSONObj file = g.storeFile(mongoFilesGlobalParams.localFile,
+ mongoFilesGlobalParams.gridFSFilename,
+ mongoFilesGlobalParams.contentType);
+ toolInfoOutput() << "added file: " << file << std::endl;
+
+ if (mongoFilesGlobalParams.replace) {
+ auto_ptr<DBClientCursor> cursor =
+ conn().query(toolGlobalParams.db + ".fs.files",
+ BSON("filename" << mongoFilesGlobalParams.gridFSFilename
+ << "_id" << NE << file["_id"] ));
while (cursor->more()) {
BSONObj o = cursor->nextSafe();
- conn().remove(_db+".fs.files", BSON("_id" << o["_id"]));
- conn().remove(_db+".fs.chunks", BSON("_id" << o["_id"]));
- cout << "removed file: " << o << endl;
+ conn().remove(toolGlobalParams.db + ".fs.files", BSON("_id" << o["_id"]));
+ conn().remove(toolGlobalParams.db + ".fs.chunks", BSON("_id" << o["_id"]));
+ toolInfoOutput() << "removed file: " << o << std::endl;
}
}
conn().getLastError();
- cout << "done!" << endl;
+ toolInfoOutput() << "done!" << std::endl;
return 0;
}
- if ( cmd == "delete" ) {
- g.removeFile(filename);
+ if (mongoFilesGlobalParams.command == "delete") {
+ g.removeFile(mongoFilesGlobalParams.gridFSFilename);
conn().getLastError();
- cout << "done!" << endl;
+ toolInfoOutput() << "done!" << std::endl;
return 0;
}
- cerr << "ERROR: unknown command '" << cmd << "'" << endl << endl;
+ cerr << "ERROR: unknown command '" << mongoFilesGlobalParams.command << "'" << endl << endl;
printHelp(cout);
return -1;
}
};
-int main( int argc , char ** argv, char** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- Files f;
- return f.main( argc , argv );
-}
+REGISTER_MONGO_TOOL(Files);
diff --git a/src/mongo/tools/import.cpp b/src/mongo/tools/import.cpp
index 61e23f01878..d87fe1209e2 100644
--- a/src/mongo/tools/import.cpp
+++ b/src/mongo/tools/import.cpp
@@ -1,5 +1,3 @@
-// import.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,37 +12,44 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "pch.h"
-#include "db/json.h"
-#include "tool.h"
-#include "../util/text.h"
-#include "mongo/base/initializer.h"
-#include <fstream>
-#include <iostream>
-#include <boost/program_options.hpp>
+#include "mongo/pch.h"
+
#include <boost/algorithm/string.hpp>
#include <boost/filesystem/operations.hpp>
+#include <fstream>
+#include <iostream>
+
+#include "mongo/base/initializer.h"
+#include "mongo/db/json.h"
+#include "mongo/tools/mongoimport_options.h"
+#include "mongo/tools/tool.h"
+#include "mongo/util/options_parser/option_section.h"
+#include "mongo/util/text.h"
using namespace mongo;
using std::string;
using std::stringstream;
-namespace po = boost::program_options;
-
class Import : public Tool {
enum Type { JSON , CSV , TSV };
Type _type;
const char * _sep;
- bool _ignoreBlanks;
- bool _headerLine;
- bool _upsert;
- bool _doimport;
- bool _jsonArray;
- vector<string> _upsertFields;
static const int BUF_SIZE;
void csvTokenizeRow(const string& row, vector<string>& tokens) {
@@ -93,7 +98,7 @@ class Import : public Tool {
}
void _append( BSONObjBuilder& b , const string& fieldName , const string& data ) {
- if ( _ignoreBlanks && data.size() == 0 )
+ if (mongoImportGlobalParams.ignoreBlanks && data.size() == 0)
return;
if ( b.appendAsNumber( fieldName , data ) )
@@ -109,23 +114,19 @@ class Import : public Tool {
* increment buf by this amount.
*/
int getLine(istream* in, char* buf) {
- if (_jsonArray) {
- in->read(buf, BUF_SIZE);
- uassert(13295, "JSONArray file too large", (in->rdstate() & ios_base::eofbit));
- buf[ in->gcount() ] = '\0';
+ in->getline( buf , BUF_SIZE );
+ if ((in->rdstate() & ios_base::eofbit) && (in->rdstate() & ios_base::failbit)) {
+ // this is the last line, and it's empty (not even a newline)
+ buf[0] = '\0';
+ return 0;
}
- else {
- in->getline( buf , BUF_SIZE );
- if ((in->rdstate() & ios_base::eofbit) && (in->rdstate() & ios_base::failbit)) {
- // this is the last line, and it's empty (not even a newline)
- buf[0] = '\0';
- return 0;
- }
- uassert(16329, str::stream() << "read error, or input line too long (max length: "
- << BUF_SIZE << ")", !(in->rdstate() & ios_base::failbit));
- LOG(1) << "got line:" << buf << endl;
+ uassert(16329, str::stream() << "read error, or input line too long (max length: "
+ << BUF_SIZE << ")", !(in->rdstate() & ios_base::failbit));
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ toolInfoLog() << "got line:" << buf << std::endl;
}
+
uassert( 10263 , "unknown error reading file" ,
(!(in->rdstate() & ios_base::badbit)) &&
(!(in->rdstate() & ios_base::failbit) || (in->rdstate() & ios_base::eofbit)) );
@@ -141,27 +142,44 @@ class Import : public Tool {
}
/*
- * Parses a BSON object out of a JSON array.
- * Returns number of bytes processed on success and -1 on failure.
+ * description:
+ * given a pointer into a JSON array, returns the next valid JSON object
+ * args:
+ * buf - pointer into the JSON array
+ * o - BSONObj to fill
+ * numBytesRead - return parameter for how far we read
+ * return:
+ * true if an object was successfully parsed
+ * false if there is no object left to parse
+ * throws:
+ * exception on parsing error
*/
- int parseJSONArray(char* buf, BSONObj& o) {
- int len = 0;
- while (buf[0] != '{' && buf[0] != '\0') {
- len++;
+ bool parseJSONArray(char* buf, BSONObj* o, int* numBytesRead) {
+
+ // Skip extra characters since fromjson must be passed a character buffer that starts with a
+ // valid JSON object, and does not accept JSON arrays.
+ // (NOTE: this doesn't catch all invalid JSON arrays, but does fail on invalid characters)
+ *numBytesRead = 0;
+ while (buf[0] == '[' ||
+ buf[0] == ']' ||
+ buf[0] == ',' ||
+ isspace(buf[0])) {
+ (*numBytesRead)++;
buf++;
}
+
if (buf[0] == '\0')
- return -1;
+ return false;
- int jslen;
try {
- o = fromjson(buf, &jslen);
+ int len = 0;
+ *o = fromjson(buf, &len);
+ (*numBytesRead) += len;
} catch ( MsgAssertionException& e ) {
- uasserted(13293, string("BSON representation of supplied JSON array is too large: ") + e.what());
+ uasserted(13293, string("Invalid JSON passed to mongoimport: ") + e.what());
}
- len += jslen;
- return len;
+ return true;
}
/*
@@ -218,7 +236,7 @@ class Import : public Tool {
line += num;
numBytesRead += num;
- uassert (15854, "CSV file ends while inside quoted field", line[0] != '\0');
+ uassert(15854, "CSV file ends while inside quoted field", line[0] != '\0');
numBytesRead += strlen( line );
} else {
break;
@@ -241,13 +259,13 @@ class Import : public Tool {
unsigned int pos=0;
for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it) {
string token = *it;
- if ( _headerLine ) {
- _fields.push_back(token);
+ if (mongoImportGlobalParams.headerLine) {
+ toolGlobalParams.fields.push_back(token);
}
else {
string name;
- if ( pos < _fields.size() ) {
- name = _fields[pos];
+ if (pos < toolGlobalParams.fields.size()) {
+ name = toolGlobalParams.fields[pos];
}
else {
stringstream ss;
@@ -264,36 +282,12 @@ class Import : public Tool {
}
public:
- Import() : Tool( "import" ) {
- addFieldOptions();
- add_options()
- ("ignoreBlanks","if given, empty fields in csv and tsv will be ignored")
- ("type",po::value<string>() , "type of file to import. default: json (json,csv,tsv)")
- ("file",po::value<string>() , "file to import from; if not specified stdin is used" )
- ("drop", "drop collection first " )
- ("headerline","first line in input file is a header (CSV and TSV only)")
- ("upsert", "insert or update objects that already exist" )
- ("upsertFields", po::value<string>(), "comma-separated fields for the query part of the upsert. You should make sure this is indexed" )
- ("stopOnError", "stop importing at first error rather than continuing" )
- ("jsonArray", "load a json array, not one item per line. Currently limited to 16MB." )
- ;
- add_hidden_options()
- ("noimport", "don't actually import. useful for benchmarking parser" )
- ;
- addPositionArg( "file" , 1 );
+ Import() : Tool() {
_type = JSON;
- _ignoreBlanks = false;
- _headerLine = false;
- _upsert = false;
- _doimport = true;
- _jsonArray = false;
}
- ;
- virtual void printExtraHelp( ostream & out ) {
- out << "Import CSV, TSV or JSON data into MongoDB.\n" << endl;
- out << "When importing JSON documents, each document must be a separate line of the input file.\n";
- out << "\nExample:\n";
- out << " mongoimport --host myhost --db my_cms --collection docs < mydocfile.json\n" << endl;
+
+ virtual void printHelp( ostream & out ) {
+ printMongoImportHelp(&out);
}
unsigned long long lastErrorFailures;
@@ -305,33 +299,57 @@ public:
if( str::contains(s,"uplicate") ) {
// we don't want to return an error from the mongoimport process for
// dup key errors
- log() << s << endl;
+ toolInfoLog() << s << endl;
}
else {
lastErrorFailures++;
- log() << "error: " << s << endl;
+ toolInfoLog() << "error: " << s << endl;
return false;
}
}
return true;
}
+ void importDocument (const std::string &ns, const BSONObj& o) {
+ bool doUpsert = mongoImportGlobalParams.upsert;
+ BSONObjBuilder b;
+ if (mongoImportGlobalParams.upsert) {
+ for (vector<string>::const_iterator it = mongoImportGlobalParams.upsertFields.begin(),
+ end = mongoImportGlobalParams.upsertFields.end(); it != end; ++it) {
+ BSONElement e = o.getFieldDotted(it->c_str());
+ if (e.eoo()) {
+ doUpsert = false;
+ break;
+ }
+ b.appendAs(e, *it);
+ }
+ }
+
+ if (doUpsert) {
+ conn().update(ns, Query(b.obj()), o, true);
+ }
+ else {
+ conn().insert(ns.c_str(), o);
+ }
+ }
+
int run() {
- string filename = getParam( "file" );
long long fileSize = 0;
int headerRows = 0;
istream * in = &cin;
- ifstream file( filename.c_str() , ios_base::in);
+ ifstream file(mongoImportGlobalParams.filename.c_str(), ios_base::in);
- if ( filename.size() > 0 && filename != "-" ) {
- if ( ! boost::filesystem::exists( filename ) ) {
- error() << "file doesn't exist: " << filename << endl;
+ if (mongoImportGlobalParams.filename.size() > 0 &&
+ mongoImportGlobalParams.filename != "-") {
+ if ( ! boost::filesystem::exists(mongoImportGlobalParams.filename) ) {
+ toolError() << "file doesn't exist: " << mongoImportGlobalParams.filename
+ << std::endl;
return -1;
}
in = &file;
- fileSize = boost::filesystem::file_size( filename );
+ fileSize = boost::filesystem::file_size(mongoImportGlobalParams.filename);
}
// check if we're actually talking to a machine that can write
@@ -345,156 +363,204 @@ public:
ns = getNS();
}
catch (...) {
- printHelp(cerr);
- return -1;
+ // The only time getNS throws is when the collection was not specified. In that case,
+ // check if the user specified a file name and use that as the collection name.
+ if (!mongoImportGlobalParams.filename.empty()) {
+ string oldCollName =
+ boost::filesystem::path(mongoImportGlobalParams.filename).leaf().string();
+ oldCollName = oldCollName.substr( 0 , oldCollName.find_last_of( "." ) );
+ cerr << "using filename '" << oldCollName << "' as collection." << endl;
+ ns = toolGlobalParams.db + "." + oldCollName;
+ }
+ else {
+ printHelp(cerr);
+ return -1;
+ }
}
- LOG(1) << "ns: " << ns << endl;
-
- if ( hasParam( "drop" ) ) {
- log() << "dropping: " << ns << endl;
- conn().dropCollection( ns.c_str() );
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ toolInfoLog() << "ns: " << ns << endl;
}
- if ( hasParam( "ignoreBlanks" ) ) {
- _ignoreBlanks = true;
+ if (mongoImportGlobalParams.drop) {
+ toolInfoLog() << "dropping: " << ns << endl;
+ conn().dropCollection(ns.c_str());
}
- if ( hasParam( "upsert" ) || hasParam( "upsertFields" )) {
- _upsert = true;
-
- string uf = getParam("upsertFields");
- if (uf.empty()) {
- _upsertFields.push_back("_id");
- }
- else {
- StringSplitter(uf.c_str(), ",").split(_upsertFields);
- }
+ if (mongoImportGlobalParams.type == "json")
+ _type = JSON;
+ else if (mongoImportGlobalParams.type == "csv") {
+ _type = CSV;
+ _sep = ",";
}
-
- if ( hasParam( "noimport" ) ) {
- _doimport = false;
+ else if (mongoImportGlobalParams.type == "tsv") {
+ _type = TSV;
+ _sep = "\t";
}
-
- if ( hasParam( "type" ) ) {
- string type = getParam( "type" );
- if ( type == "json" )
- _type = JSON;
- else if ( type == "csv" ) {
- _type = CSV;
- _sep = ",";
- }
- else if ( type == "tsv" ) {
- _type = TSV;
- _sep = "\t";
- }
- else {
- error() << "don't know what type [" << type << "] is" << endl;
- return -1;
- }
+ else {
+ toolError() << "don't know what type [" << mongoImportGlobalParams.type << "] is"
+ << std::endl;
+ return -1;
}
- if ( _type == CSV || _type == TSV ) {
- _headerLine = hasParam( "headerline" );
- if ( _headerLine ) {
+ if (_type == CSV || _type == TSV) {
+ if (mongoImportGlobalParams.headerLine) {
headerRows = 1;
}
else {
- needFields();
+ if (!toolGlobalParams.fieldsSpecified) {
+ throw UserException(9998, "You need to specify fields or have a headerline to "
+ "import this file type");
+ }
}
}
- if (_type == JSON && hasParam("jsonArray")) {
- _jsonArray = true;
- }
time_t start = time(0);
- LOG(1) << "filesize: " << fileSize << endl;
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ toolInfoLog() << "filesize: " << fileSize << endl;
+ }
ProgressMeter pm( fileSize );
int num = 0;
int lastNumChecked = num;
int errors = 0;
lastErrorFailures = 0;
int len = 0;
- // buffer and line are only used when parsing a jsonArray
- boost::scoped_array<char> buffer(new char[BUF_SIZE+2]);
- char* line = buffer.get();
- while ( _jsonArray || in->rdstate() == 0 ) {
- try {
- BSONObj o;
- if (_jsonArray) {
- int bytesProcessed = 0;
- if (line == buffer.get()) { // Only read on first pass - the whole array must be on one line.
- bytesProcessed = getLine(in, line);
- line += bytesProcessed;
- len += bytesProcessed;
- }
- if ((bytesProcessed = parseJSONArray(line, o)) < 0) {
- len += bytesProcessed;
+ // We have to handle jsonArrays differently since we can't read line by line
+ if (_type == JSON && mongoImportGlobalParams.jsonArray) {
+
+ // We cycle through these buffers in order to continuously read from the stream
+ boost::scoped_array<char> buffer1(new char[BUF_SIZE]);
+ boost::scoped_array<char> buffer2(new char[BUF_SIZE]);
+ char* current_buffer = buffer1.get();
+ char* next_buffer = buffer2.get();
+ char* temp_buffer;
+
+ // buffer_base_offset is the offset into the stream where our buffer starts, while
+ // input_stream_offset is the total number of bytes read from the stream
+ uint64_t buffer_base_offset = 0;
+ uint64_t input_stream_offset = 0;
+
+ // Fill our buffer
+ // NOTE: istream::get automatically appends '\0' at the end of what it reads
+ in->get(current_buffer, BUF_SIZE, '\0');
+ uassert(16808, str::stream() << "read error: " << strerror(errno), !in->fail());
+
+ // Record how far we read into the stream.
+ input_stream_offset += in->gcount();
+
+ while (true) {
+ try {
+
+ BSONObj o;
+
+ // Try to parse (parseJSONArray)
+ if (!parseJSONArray(current_buffer, &o, &len)) {
break;
}
- len += bytesProcessed;
- line += bytesProcessed;
- }
- else {
- if (!parseRow(in, o, len)) {
- continue;
+
+ // Import documents
+ if (mongoImportGlobalParams.doimport) {
+ importDocument(ns, o);
+
+ if (num < 10) {
+ // we absolutely want to check the first and last op of the batch. we do
+ // a few more as that won't be too time expensive.
+ checkLastError();
+ lastNumChecked = num;
+ }
+ }
+
+ // Copy over the part of buffer that was not parsed
+ strcpy(next_buffer, current_buffer + len);
+
+ // Advance our buffer base past what we've already parsed
+ buffer_base_offset += len;
+
+ // Fill up the end of our next buffer only if there is something in the stream
+ if (!in->eof()) {
+ // NOTE: istream::get automatically appends '\0' at the end of what it reads
+ in->get(next_buffer + (input_stream_offset - buffer_base_offset),
+ BUF_SIZE - (input_stream_offset - buffer_base_offset), '\0');
+ uassert(16809, str::stream() << "read error: "
+ << strerror(errno), !in->fail());
+
+ // Record how far we read into the stream.
+ input_stream_offset += in->gcount();
}
+
+ // Swap buffer pointers
+ temp_buffer = current_buffer;
+ current_buffer = next_buffer;
+ next_buffer = temp_buffer;
+
+ num++;
}
+ catch ( const std::exception& e ) {
+ toolError() << "exception: " << e.what()
+ << ", current buffer: " << current_buffer << std::endl;
+ errors++;
- if ( _headerLine ) {
- _headerLine = false;
+ // Since we only support JSON arrays all on one line, we might as well stop now
+ // because we can't read any more documents
+ break;
}
- else if (_doimport) {
- bool doUpsert = _upsert;
- BSONObjBuilder b;
- if (_upsert) {
- for (vector<string>::const_iterator it=_upsertFields.begin(), end=_upsertFields.end(); it!=end; ++it) {
- BSONElement e = o.getFieldDotted(it->c_str());
- if (e.eoo()) {
- doUpsert = false;
- break;
- }
- b.appendAs(e, *it);
- }
- }
- if (doUpsert) {
- conn().update(ns, Query(b.obj()), o, true);
+ if (!toolGlobalParams.quiet) {
+ if (pm.hit(len + 1)) {
+ log() << "\t\t\t" << num << "\t" << (num / (time(0) - start)) << "/second"
+ << std::endl;
}
- else {
- conn().insert( ns.c_str() , o );
+ }
+ }
+ }
+ else {
+ while (in->rdstate() == 0) {
+ try {
+ BSONObj o;
+
+ if (!parseRow(in, o, len)) {
+ continue;
}
- if( num < 10 ) {
- // we absolutely want to check the first and last op of the batch. we do
- // a few more as that won't be too time expensive.
- checkLastError();
- lastNumChecked = num;
+ if (mongoImportGlobalParams.headerLine) {
+ mongoImportGlobalParams.headerLine = false;
+ }
+ else if (mongoImportGlobalParams.doimport) {
+ importDocument(ns, o);
+
+ if (num < 10) {
+ // we absolutely want to check the first and last op of the batch. we do
+ // a few more as that won't be too time expensive.
+ checkLastError();
+ lastNumChecked = num;
+ }
}
- }
- num++;
- }
- catch ( std::exception& e ) {
- log() << "exception:" << e.what() << endl;
- log() << line << endl;
- errors++;
+ num++;
+ }
+ catch ( const std::exception& e ) {
+ toolError() << "exception:" << e.what() << std::endl;
+ errors++;
- if (hasParam("stopOnError") || _jsonArray)
- break;
- }
+ if (mongoImportGlobalParams.stopOnError)
+ break;
+ }
- if ( pm.hit( len + 1 ) ) {
- log() << "\t\t\t" << num << "\t" << ( num / ( time(0) - start ) ) << "/second" << endl;
+ if (!toolGlobalParams.quiet) {
+ if (pm.hit(len + 1)) {
+ log() << "\t\t\t" << num << "\t" << (num / (time(0) - start)) << "/second"
+ << std::endl;
+ }
+ }
}
}
// this is for two reasons: to wait for all operations to reach the server and be processed, and this will wait until all data reaches the server,
// and secondly to check if there were an error (on the last op)
if( lastNumChecked+1 != num ) { // avoid redundant log message if already reported above
- log() << "check " << lastNumChecked << " " << num << endl;
+ toolInfoLog() << "check " << lastNumChecked << " " << num << endl;
checkLastError();
}
@@ -502,20 +568,19 @@ public:
// the message is vague on lastErrorFailures as we don't call it on every single operation.
// so if we have a lastErrorFailure there might be more than just what has been counted.
- log() << (lastErrorFailures ? "tried to import " : "imported ") << ( num - headerRows ) << " objects" << endl;
+ toolInfoLog() << (lastErrorFailures ? "tried to import " : "imported ")
+ << (num - headerRows) << " objects" << std::endl;
if ( !hadErrors )
return 0;
- error() << "encountered " << (lastErrorFailures?"at least ":"") << lastErrorFailures+errors << " error(s)" << ( lastErrorFailures+errors == 1 ? "" : "s" ) << endl;
+ toolError() << "encountered " << (lastErrorFailures?"at least ":"")
+ << lastErrorFailures+errors << " error(s)"
+ << (lastErrorFailures+errors == 1 ? "" : "s") << std::endl;
return -1;
}
};
-int main( int argc , char ** argv, char** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- Import import;
- return import.main( argc , argv );
-}
-
const int Import::BUF_SIZE(1024 * 1024 * 16);
+
+REGISTER_MONGO_TOOL(Import);
diff --git a/src/mongo/tools/loadgenerator.cpp b/src/mongo/tools/loadgenerator.cpp
deleted file mode 100644
index 42e7ad8029e..00000000000
--- a/src/mongo/tools/loadgenerator.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/** @file loadgenerator.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/>.
- */
-
-/*
- * LoadGenerator drives a certain number (# threads) of simultaneous operation into a
- * specified number of databases as quickly as it can at a mongo instance,
- * continuously, for some number of seconds.
- *
- */
-
-/*
- * For internal reference:
- * Each document generated by the docgenerator.cpp is 176 bytes long
- * Number of documents per instance size :
- * small (500 MB) : 2978905 docs spread over 5 dbs (each db is 100 MB) Docs Per DB : 595781
- * medium (5 GB) : 30504030 docs spread over 5 dbs (each db is 1 GB) Docs Per DB : 6100806
- * large (25 GB) : 152520145 docs evenly spread over 5 dbs (each db is 5 GB) Docs Per DB : 30504029
- * vlarge (100 GB) : 621172954 docs evenly spread over 10 dbs (each db is 10 GB) Docs Per DB : 61008058
- *
- */
-
-#include <map>
-#include <string>
-
-#include <boost/program_options.hpp>
-#include <boost/scoped_ptr.hpp>
-
-#include "mongo/base/initializer.h"
-#include "mongo/util/assert_util.h"
-#include "mongo/scripting/bench.h"
-#include "mongo/client/dbclientinterface.h"
-#include "mongo/tools/docgenerator.h"
-#include "mongo/util/map_util.h"
-#include "mongo/util/md5.hpp"
-#include "mongo/util/mongoutils/str.h"
-
-using namespace std;
-
-using namespace mongo;
-
-namespace po = boost::program_options;
-
-namespace {
-
-struct LoadGeneratorOptions {
- LoadGeneratorOptions() :
- hostname("localhost"),
- type("query"),
- instanceSize( "large" ),
- numdbs( 5 ),
- resultNS( "" ),
- numOps( 60000 ),
- durationSeconds( 60 ),
- parallelThreads( 32 ),
- trials( 5 ),
- docsPerDB( 0 )
- { }
-
- string hostname;
- string type;
- string instanceSize;
- int numdbs;
- string resultNS;
- int numOps;
- double durationSeconds;
- int parallelThreads;
- int trials;
- unsigned long long docsPerDB;
-};
-
-
-struct OperationStats {
- OperationStats( const unsigned long long numEvents, const unsigned long long totalTimeMicros,
- const long long opcounter ) :
- numEvents( numEvents ),
- totalTimeMicros( totalTimeMicros ),
- opcounter( opcounter ) { }
- OperationStats() { }
-
- unsigned long long numEvents;
- unsigned long long totalTimeMicros;
- long long opcounter;
-};
-
-// ------Globals and typedefs----------
-LoadGeneratorOptions globalLoadGenOption;
-typedef std::map<std::string, OperationStats> OpStatsMap;
-
-double randomBetweenRange(const int& min, const int& max) {
- return rand() % (max - min) + min;
-}
-
-mongo::DBClientBase *getDBConnection() {
- string errmsg;
- mongo::ConnectionString connectionString = mongo::ConnectionString::parse(
- globalLoadGenOption.hostname, errmsg );
- mongo::fassert( 16265, connectionString.isValid() );
- mongo::DBClientBase *connection = connectionString.connect( errmsg );
- mongo::fassert( 16266, connection != NULL );
- return connection;
-}
-
-void dropNS(const string ns) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- connection->dropCollection( ns );
-}
-
-void dropDB(const string db) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- connection->dropDatabase( db );
-}
-
-void writeToNS(const string ns, const mongo::BSONObj bs) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- connection->insert( ns, bs );
- mongo::fassert( 16267, connection->getLastError().empty() );
-}
-
-// find the number of documents in a namespace
-void numDocsInNS(const string ns) {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- globalLoadGenOption.docsPerDB = connection->count( ns );
-}
-
-
-mongo::BSONArray generateInsertOps() {
-
- //create a document config object
- BSONObj args = BSONObjBuilder()
- .append( "blob", "MongoDB is an open source document-oriented database system." )
- .append( "md5seed", "newyork" )
- .append( "counterUp", 0 )
- .append( "counterDown", numeric_limits<long long>::max() ).obj();
-
- scoped_ptr<DocumentGenerator> docGen( DocumentGenerator::makeDocumentGenerator(args) );
- mongo::BSONArrayBuilder insertOps;
- for (int i = 0; i < globalLoadGenOption.numOps; ++i) {
-
- //insert into databases
- string insertNS = mongoutils::str::stream() << globalLoadGenOption.instanceSize << "DB" <<
- i % globalLoadGenOption.numdbs << "I.sampledata";
- BSONObj doc = docGen->createDocument();
- insertOps.append( BSON( "ns" << insertNS <<
- "op" << "insert" <<
- "doc" << doc <<
- "safe" << true ) );
- }
- return insertOps.arr();
-}
-
-
-mongo::BSONArray generateFindOneOps() {
-
- mongo::BSONArrayBuilder queryOps;
-
- // query a namespace and find the number of docs in that ns. All benchmark namespaces should have
- // the same number of docs.
- string queryNS = mongoutils::str::stream() << globalLoadGenOption.instanceSize
- << "DB0.sampledata";
- numDocsInNS( queryNS );
-
- // Now fill the queryOps array. The findOne query operations will be evenly distributed
- // across all databases. Thus it tries to find a random document from db1, then db2,
- // and so on and so forth.
- for (int i = 0; i < globalLoadGenOption.numOps; ++i) {
-
- queryNS = mongoutils::str::stream() << globalLoadGenOption.instanceSize
- << "DB"
- << i % globalLoadGenOption.numdbs
- << ".sampledata";
-
- // select a random document among all the documents
- unsigned long long centerQueryKey =
- ( randomBetweenRange(0, 100 ) * globalLoadGenOption.docsPerDB ) / 100;
-
- // cast to long long from unsigned long long as BSON didn't have the overloaded method
- mongo::BSONObj query =
- BSON( "counterUp" << static_cast<long long>( floor(centerQueryKey) ) );
-
- queryOps.append( BSON( "ns" << queryNS <<
- "op" << "findOne" <<
- "query" << query) );
- }
-
- return queryOps.arr();
-}
-
-
-mongo::BenchRunConfig *createBenchRunConfig() {
-
- BSONArray ops;
-
- if ( globalLoadGenOption.type == "findOne" )
- ops = generateFindOneOps();
- else if ( globalLoadGenOption.type == "insert" )
- ops = generateInsertOps();
-
- return mongo::BenchRunConfig::createFromBson(
- BSON( "ops" << ops <<
- "parallel" << globalLoadGenOption.parallelThreads <<
- "seconds" << globalLoadGenOption.durationSeconds <<
- "host"<< globalLoadGenOption.hostname ) );
-}
-
-/*
- * The stats object from benchRun has two sub-objects : findOneCounter and opcounters
- * This function creates a single map data structure to store all the info.
- */
-
-void collectAllStats( const BenchRunStats& stats, OpStatsMap& allStats ) {
-
- allStats.clear();
- allStats.insert( std::make_pair("findOne",
- OperationStats(stats.findOneCounter.getNumEvents(),
- stats.findOneCounter.getTotalTimeMicros(),
- mapFindWithDefault(stats.opcounters, "query", 0)
- )) );
- allStats.insert( std::make_pair("insert",
- OperationStats(stats.insertCounter.getNumEvents(),
- stats.insertCounter.getTotalTimeMicros(),
- mapFindWithDefault(stats.opcounters, "insert", 0)
- )) );
-
-}
-
-// add the result of this trial to the trials array
-BSONObj makeTrialDocument( const OpStatsMap& allStats ) {
-
- BSONObjBuilder outerBuilder;
- for (OpStatsMap::const_iterator it = allStats.begin(); it != allStats.end(); ++it) {
-
- unsigned long long numEvents = it->second.numEvents;
- unsigned long long totalTimeMicros = it->second.totalTimeMicros;
-
- BSONObjBuilder innerDocBuilder;
- innerDocBuilder.append("numEvents", static_cast<long long>(numEvents));
- innerDocBuilder.append("totalTimeMicros", static_cast<long long>(totalTimeMicros));
-
- if (numEvents)
- innerDocBuilder.append("latencyMicros", static_cast<double>(totalTimeMicros/numEvents));
-
- outerBuilder.append(it->first, innerDocBuilder.obj());
- }
- return outerBuilder.obj();
-}
-
-BSONObj buildInformation() {
- boost::scoped_ptr<mongo::DBClientBase> connection( getDBConnection() );
- BSONObj info;
- connection->simpleCommand("admin", &info, "buildinfo");
- return info;
-}
-
-BSONObj createResultDoc(const BSONArray& trialsArray) {
-
- return BSON( "name" << globalLoadGenOption.type <<
- "config" << BSON ( "hostname" << globalLoadGenOption.hostname <<
- "instanceSize" << globalLoadGenOption.instanceSize <<
- "durationSeconds" << globalLoadGenOption.durationSeconds <<
- "parallelThreads" << globalLoadGenOption.parallelThreads <<
- "numOps" << globalLoadGenOption.numOps <<
- "Date" << 10 <<
- "buildInfo" << buildInformation()
- ) <<
- "trials" << trialsArray );
-}
-
-void runTest() {
- stringstream oss;
- BSONArrayBuilder trialsBuilder;
-
- // drop any previous dbs with the same name
- for (int j=0; j < globalLoadGenOption.numdbs; ++j) {
- string insertTestDB = mongoutils::str::stream() << globalLoadGenOption.instanceSize <<
- "DB" << j <<"I" ;
- dropDB(insertTestDB);
- }
-
- for (int i = 0; i<globalLoadGenOption.trials; ++i) {
-
- BenchRunner runner( createBenchRunConfig() );
- runner.start();
- sleepmillis( 1000 * globalLoadGenOption.durationSeconds );
- runner.stop();
- BenchRunStats stats;
- runner.populateStats(&stats);
-
- // collate all the stats (and save it in a local allstats map
- std::map<std::string, OperationStats> allStats;
- collectAllStats(stats, allStats);
-
- trialsBuilder.append(makeTrialDocument(allStats));
-
- // print for now -- this is temporary and will be removed
- oss << allStats.find("insert")->second.totalTimeMicros / allStats.find("insert")->second.numEvents <<
- " " <<
- allStats.find("insert")->second.opcounter / globalLoadGenOption.durationSeconds <<
- " ";
-
- //clean up the newly created dbs for next trial
- for (int j=0; j < globalLoadGenOption.numdbs; ++j) {
- string insertTestDB = mongoutils::str::stream() << globalLoadGenOption.instanceSize <<
- "DB" << j <<"I" ;
- dropDB(insertTestDB);
- }
- }
- // Write the experiment document to the result NS. If the user did not pass a resultNS cmdline
- // parameter then we won't write the results to the database.
- // This is useful in cases where we just want to drive a constant load from a client and are
- // not really interested in the statistics from it and so don't really care to save the stats
- // to a db.
-
- string resultNS = globalLoadGenOption.resultNS;
- if( !resultNS.empty() ) {
- BSONObj resultDoc = createResultDoc(trialsBuilder.arr());
- writeToNS( resultNS, resultDoc );
- }
-
- // temp line -- will be removed
- cout << oss.str() << endl;
-}
-
-
-int parseCmdLineOptions(int argc, char **argv) {
-
- try {
-
- po::options_description general_options("General options");
-
- general_options.add_options()
- ("help", "produce help message")
- ("hostname,H", po::value<string>() , "ip address of the host where mongod is running" )
- ("type", po::value<string>() , "findOne/insert" )
- ("instanceSize,I", po::value<string>(), "DB type (small/medium/large/vlarge)" )
- ("numdbs", po::value<int>(), " number of databases in this instance" )
- ("trials", po::value<int>(), "number of trials")
- ("durationSeconds,D", po::value<double>(), "how long should each trial run")
- ("parallelThreads,P",po::value<int>(), "number of threads")
- ("numOps", po::value<int>(), "number of ops per thread")
- ("resultNS", po::value<string>(), "result NS where you would like to save the results."
- "If this parameter is empty results will not be written")
- ;
-
- po::variables_map params;
- po::store(po::parse_command_line(argc, argv, general_options), params);
- po::notify(params);
-
- // Parse the values if supplied by the user. No data sanity check is performed
- // here so meaningless values (for eg. passing --numdbs 0) can crash the program.
- // TODO: Perform data sanity check
-
- if(params.count("help")) {
- cout << general_options << "\n";
- return 1;
- }
- if (params.count("hostname")) {
- globalLoadGenOption.hostname = params["hostname"].as<string>();
- }
- if (params.count("type")) {
- globalLoadGenOption.type = params["type"].as<string>();
- }
- if (params.count("instanceSize")) {
- globalLoadGenOption.instanceSize = params["instanceSize"].as<string>();
- }
- if (params.count("numdbs")) {
- globalLoadGenOption.numdbs = params["numdbs"].as<int>();
- }
- if (params.count("trials")) {
- globalLoadGenOption.trials = params["trials"].as<int>();
- }
- if (params.count("durationSeconds")) {
- globalLoadGenOption.durationSeconds = params["durationSeconds"].as<double>();
- }
- if (params.count("parallelThreads")) {
- globalLoadGenOption.parallelThreads = params["parallelThreads"].as<int>();
- }
- if (params.count("numOps")) {
- globalLoadGenOption.numOps = params["numOps"].as<int>();
- }
- if (params.count("resultNS")) {
- globalLoadGenOption.resultNS = params["resultNS"].as<string>();
- }
- }
- catch(exception& e) {
- cerr << "error: " << e.what() << "\n";
- return 1;
- }
- return 0;
-}
-
-} // namespace
-
-
-int main(int argc, char **argv, char** envp) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- if( parseCmdLineOptions(argc, argv) )
- return 1;
-
- runTest();
- return 0;
-}
-
diff --git a/src/mongo/tools/mongobridge_options.cpp b/src/mongo/tools/mongobridge_options.cpp
new file mode 100644
index 00000000000..3275f135f25
--- /dev/null
+++ b/src/mongo/tools/mongobridge_options.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongobridge_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoBridgeGlobalParams mongoBridgeGlobalParams;
+
+ Status addMongoBridgeOptions(moe::OptionSection* options) {
+
+ options->addOptionChaining("help", "help", moe::Switch, "produce help message");
+
+
+ options->addOptionChaining("port", "port", moe::Int, "port to listen for mongo messages");
+
+
+ options->addOptionChaining("dest", "dest", moe::String, "uri of remote mongod instance");
+
+
+ options->addOptionChaining("delay", "delay", moe::Int,
+ "transfer delay in milliseconds (default = 0)")
+ .setDefault(moe::Value(0));
+
+
+ return Status::OK();
+ }
+
+ void printMongoBridgeHelp(std::ostream* out) {
+ *out << "Usage: mongobridge --port <port> --dest <dest> [ --delay <ms> ] [ --help ]"
+ << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoBridgeOptions(const moe::Environment& params) {
+ if (params.count("help")) {
+ printMongoBridgeHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoBridgeOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+
+ if (!params.count("port")) {
+ return Status(ErrorCodes::BadValue, "Missing required option: \"--port\"");
+ }
+
+ if (!params.count("dest")) {
+ return Status(ErrorCodes::BadValue, "Missing required option: \"--dest\"");
+ }
+
+ mongoBridgeGlobalParams.port = params["port"].as<int>();
+ mongoBridgeGlobalParams.destUri = params["dest"].as<std::string>();
+
+ if (params.count("delay")) {
+ mongoBridgeGlobalParams.delay = params["delay"].as<int>();
+ }
+
+ return Status::OK();
+ }
+
+} // namespace mongo
diff --git a/src/mongo/tools/mongobridge_options.h b/src/mongo/tools/mongobridge_options.h
new file mode 100644
index 00000000000..181bd273db4
--- /dev/null
+++ b/src/mongo/tools/mongobridge_options.h
@@ -0,0 +1,70 @@
+/*
+ * 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+
+namespace mongo {
+
+ namespace optionenvironment {
+ class OptionSection;
+ class Environment;
+ } // namespace optionenvironment
+
+ namespace moe = mongo::optionenvironment;
+
+ struct MongoBridgeGlobalParams {
+ int port;
+ int delay;
+ int connectTimeoutSec;
+ string destUri;
+
+ MongoBridgeGlobalParams() : port(0), delay(0), connectTimeoutSec(15) {}
+ };
+
+ extern MongoBridgeGlobalParams mongoBridgeGlobalParams;
+
+ Status addMongoBridgeOptions(moe::OptionSection* options);
+
+ void printMongoBridgeHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoBridgeOptions(const moe::Environment& params);
+
+ Status storeMongoBridgeOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongobridge_options_init.cpp b/src/mongo/tools/mongobridge_options_init.cpp
new file mode 100644
index 00000000000..5c530f95f27
--- /dev/null
+++ b/src/mongo/tools/mongobridge_options_init.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongobridge_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoBridgeOptions)(InitializerContext* context) {
+ return addMongoBridgeOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoBridgeOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoBridgeOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoBridgeOptions)(InitializerContext* context) {
+ Status ret = storeMongoBridgeOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
+
diff --git a/src/mongo/tools/mongodump_options.cpp b/src/mongo/tools/mongodump_options.cpp
new file mode 100644
index 00000000000..74d07c838fb
--- /dev/null
+++ b/src/mongo/tools/mongodump_options.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongodump_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/log.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoDumpGlobalParams mongoDumpGlobalParams;
+
+ Status addMongoDumpOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addLocalServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addSpecifyDBCollectionToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("out", "out,o", moe::String,
+ "output directory or \"-\" for stdout")
+ .setDefault(moe::Value(std::string("dump")));
+
+ options->addOptionChaining("query", "query,q", moe::String, "json query");
+
+ options->addOptionChaining("oplog", "oplog", moe::Switch,
+ "Use oplog for point-in-time snapshotting");
+
+ options->addOptionChaining("repair", "repair", moe::Switch,
+ "try to recover a crashed database");
+
+ options->addOptionChaining("forceTableScan", "forceTableScan", moe::Switch,
+ "force a table scan (do not use $snapshot)");
+
+ options->addOptionChaining("dumpDbUsersAndRoles", "dumpDbUsersAndRoles", moe::Switch,
+ "Dump user and role definitions for the given database")
+ .requires("db").incompatibleWith("collection");
+
+ return Status::OK();
+ }
+
+ void printMongoDumpHelp(std::ostream* out) {
+ *out << "Export MongoDB data to BSON files.\n" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoDumpOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoDumpHelp(&std::cout);
+ return false;;
+ }
+ return true;
+ }
+
+ Status storeMongoDumpOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ mongoDumpGlobalParams.repair = hasParam("repair");
+ if (mongoDumpGlobalParams.repair){
+ if (!hasParam("dbpath")) {
+ return Status(ErrorCodes::BadValue, "repair mode only works with --dbpath");
+ }
+
+ if (!hasParam("db")) {
+ return Status(ErrorCodes::BadValue,
+ "repair mode only works on 1 db at a time right now");
+ }
+ }
+ mongoDumpGlobalParams.query = getParam("query");
+ mongoDumpGlobalParams.useOplog = hasParam("oplog");
+ if (mongoDumpGlobalParams.useOplog) {
+ if (hasParam("query") || hasParam("db") || hasParam("collection")) {
+ return Status(ErrorCodes::BadValue, "oplog mode is only supported on full dumps");
+ }
+ }
+ mongoDumpGlobalParams.outputDirectory = getParam("out");
+ mongoDumpGlobalParams.snapShotQuery = false;
+ if (!hasParam("query") && !hasParam("dbpath") && !hasParam("forceTableScan")) {
+ mongoDumpGlobalParams.snapShotQuery = true;
+ }
+
+ // Make the default db "" if it was not explicitly set
+ if (!params.count("db")) {
+ toolGlobalParams.db = "";
+ }
+
+ if (hasParam("dumpDbUsersAndRoles") && toolGlobalParams.db == "admin") {
+ return Status(ErrorCodes::BadValue,
+ "Cannot provide --dumpDbUsersAndRoles when dumping the admin db as "
+ "user and role definitions for the whole server are dumped by default "
+ "when dumping the admin db");
+ }
+
+ // Always dump users and roles if doing a full dump. If doing a db dump, only dump users
+ // and roles if --dumpDbUsersAndRoles provided or you're dumping the admin db.
+ mongoDumpGlobalParams.dumpUsersAndRoles = hasParam("dumpDbUsersAndRoles") ||
+ (toolGlobalParams.db.empty() && toolGlobalParams.coll.empty()) ||
+ toolGlobalParams.db == "admin";
+
+ if (mongoDumpGlobalParams.outputDirectory == "-") {
+ // write output to standard error to avoid mangling output
+ // must happen early to avoid sending junk to stdout
+ toolGlobalParams.canUseStdout = false;
+ }
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongodump_options.h b/src/mongo/tools/mongodump_options.h
new file mode 100644
index 00000000000..117178d0234
--- /dev/null
+++ b/src/mongo/tools/mongodump_options.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoDumpGlobalParams {
+ std::string outputDirectory;
+ std::string query;
+ bool useOplog;
+ bool repair;
+ bool snapShotQuery;
+ bool dumpUsersAndRoles;
+ };
+
+ extern MongoDumpGlobalParams mongoDumpGlobalParams;
+
+ Status addMongoDumpOptions(moe::OptionSection* options);
+
+ void printMongoDumpHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoDumpOptions(const moe::Environment& params);
+
+ Status storeMongoDumpOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongodump_options_init.cpp b/src/mongo/tools/mongodump_options_init.cpp
new file mode 100644
index 00000000000..a8a9b34e270
--- /dev/null
+++ b/src/mongo/tools/mongodump_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongodump_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoDumpOptions)(InitializerContext* context) {
+ return addMongoDumpOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoDumpOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoDumpOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoDumpOptions)(InitializerContext* context) {
+ Status ret = storeMongoDumpOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/mongoexport_options.cpp b/src/mongo/tools/mongoexport_options.cpp
new file mode 100644
index 00000000000..71e952827f3
--- /dev/null
+++ b/src/mongo/tools/mongoexport_options.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongoexport_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoExportGlobalParams mongoExportGlobalParams;
+
+ Status addMongoExportOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addLocalServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addSpecifyDBCollectionToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addFieldOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("query", "query,q", moe::String,
+ "query filter, as a JSON string, e.g., '{x:{$gt:1}}'");
+
+ options->addOptionChaining("csv", "csv", moe::Switch, "export to csv instead of json");
+
+ options->addOptionChaining("out", "out,o", moe::String,
+ "output file; if not specified, stdout is used");
+
+ options->addOptionChaining("jsonArray", "jsonArray", moe::Switch,
+ "output to a json array rather than one object per line");
+
+ options->addOptionChaining("slaveOk", "slaveOk,k", moe::Bool,
+ "use secondaries for export if available, default true")
+ .setDefault(moe::Value(true));
+
+ options->addOptionChaining("forceTableScan", "forceTableScan", moe::Switch,
+ "force a table scan (do not use $snapshot)");
+
+ options->addOptionChaining("skip", "skip", moe::Int, "documents to skip, default 0")
+ .setDefault(moe::Value(0));
+
+ options->addOptionChaining("limit", "limit", moe::Int,
+ "limit the numbers of documents returned, default all")
+ .setDefault(moe::Value(0));
+
+ options->addOptionChaining("sort", "sort", moe::String,
+ "sort order, as a JSON string, e.g., '{x:1}'");
+
+
+ return Status::OK();
+ }
+
+ void printMongoExportHelp(std::ostream* out) {
+ *out << "Export MongoDB data to CSV, TSV or JSON files.\n" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoExportOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoExportHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoExportOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = storeFieldOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ mongoExportGlobalParams.outputFile = getParam("out");
+ mongoExportGlobalParams.outputFileSpecified = hasParam("out");
+ mongoExportGlobalParams.csv = hasParam("csv");
+ mongoExportGlobalParams.jsonArray = hasParam("jsonArray");
+ mongoExportGlobalParams.query = getParam("query", "");
+ mongoExportGlobalParams.snapShotQuery = false;
+
+ // Only allow snapshot query (requires _id idx scan) if following conditions are false
+ if (!hasParam("query") &&
+ !hasParam("sort") &&
+ !hasParam("dbpath") &&
+ !hasParam("forceTableScan")) {
+ mongoExportGlobalParams.snapShotQuery = true;
+ }
+
+ mongoExportGlobalParams.slaveOk = params["slaveOk"].as<bool>();
+ mongoExportGlobalParams.limit = getParam("limit", 0);
+ mongoExportGlobalParams.skip = getParam("skip", 0);
+ mongoExportGlobalParams.sort = getParam("sort", "");
+
+ // we write output to standard error by default to avoid mangling output, but we don't need
+ // to do this if an output file was specified
+ toolGlobalParams.canUseStdout = false;
+ if (mongoExportGlobalParams.outputFileSpecified) {
+ if (mongoExportGlobalParams.outputFile != "-") {
+ toolGlobalParams.canUseStdout = true;
+ }
+ }
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongoexport_options.h b/src/mongo/tools/mongoexport_options.h
new file mode 100644
index 00000000000..1db7206b462
--- /dev/null
+++ b/src/mongo/tools/mongoexport_options.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoExportGlobalParams {
+ std::string query;
+ bool csv;
+ std::string outputFile;
+ bool outputFileSpecified;
+ bool jsonArray;
+ bool slaveOk;
+ bool snapShotQuery;
+ unsigned int skip;
+ unsigned int limit;
+ std::string sort;
+ };
+
+ extern MongoExportGlobalParams mongoExportGlobalParams;
+
+ Status addMongoExportOptions(moe::OptionSection* options);
+
+ void printMongoExportHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoExportOptions(const moe::Environment& params);
+
+ Status storeMongoExportOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongoexport_options_init.cpp b/src/mongo/tools/mongoexport_options_init.cpp
new file mode 100644
index 00000000000..02c706a9a92
--- /dev/null
+++ b/src/mongo/tools/mongoexport_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongoexport_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoExportOptions)(InitializerContext* context) {
+ return addMongoExportOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoExportOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoExportOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoExportOptions)(InitializerContext* context) {
+ Status ret = storeMongoExportOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/mongofiles_options.cpp b/src/mongo/tools/mongofiles_options.cpp
new file mode 100644
index 00000000000..1e423449fe6
--- /dev/null
+++ b/src/mongo/tools/mongofiles_options.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongofiles_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoFilesGlobalParams mongoFilesGlobalParams;
+
+ Status addMongoFilesOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addLocalServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addSpecifyDBCollectionToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("local", "local,l", moe::String,
+ "local filename for put|get (default is to use the same name as "
+ "'gridfs filename')");
+
+ options->addOptionChaining("type", "type,t", moe::String,
+ "MIME type for put (default is to omit)");
+
+ options->addOptionChaining("replace", "replace,r", moe::Switch,
+ "Remove other files with same name after PUT");
+
+ options->addOptionChaining("command", "command", moe::String,
+ "gridfs command to run")
+ .hidden()
+ .setSources(moe::SourceCommandLine)
+ .positional(1, 1);
+
+ options->addOptionChaining("file", "file", moe::String,
+ "'gridfs filename' with a special meaning for various commands")
+ .hidden()
+ .setSources(moe::SourceCommandLine)
+ .positional(2, 2);
+
+
+ return Status::OK();
+ }
+
+ void printMongoFilesHelp(std::ostream* out) {
+ *out << "Browse and modify a GridFS filesystem.\n" << std::endl;
+ *out << "usage: mongofiles [options] command [gridfs filename]" << std::endl;
+ *out << "command:" << std::endl;
+ *out << " one of (list|search|put|get)" << std::endl;
+ *out << " list - list all files. 'gridfs filename' is an optional prefix " << std::endl;
+ *out << " which listed filenames must begin with." << std::endl;
+ *out << " search - search all files. 'gridfs filename' is a substring " << std::endl;
+ *out << " which listed filenames must contain." << std::endl;
+ *out << " put - add a file with filename 'gridfs filename'" << std::endl;
+ *out << " get - get a file with filename 'gridfs filename'" << std::endl;
+ *out << " delete - delete all files with filename 'gridfs filename'" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoFilesOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoFilesHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoFilesOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ mongoFilesGlobalParams.command = getParam("command");
+ mongoFilesGlobalParams.gridFSFilename = getParam("file");
+ mongoFilesGlobalParams.localFile = getParam("local", mongoFilesGlobalParams.gridFSFilename);
+ mongoFilesGlobalParams.contentType = getParam("type", "");
+ mongoFilesGlobalParams.replace = hasParam("replace");
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongofiles_options.h b/src/mongo/tools/mongofiles_options.h
new file mode 100644
index 00000000000..52a1ac9f187
--- /dev/null
+++ b/src/mongo/tools/mongofiles_options.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoFilesGlobalParams {
+ std::string localFile;
+ std::string contentType;
+ bool replace;
+ std::string command;
+ std::string gridFSFilename;
+ };
+
+ extern MongoFilesGlobalParams mongoFilesGlobalParams;
+
+ Status addMongoFilesOptions(moe::OptionSection* options);
+
+ void printMongoFilesHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoFilesOptions(const moe::Environment& params);
+
+ Status storeMongoFilesOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongofiles_options_init.cpp b/src/mongo/tools/mongofiles_options_init.cpp
new file mode 100644
index 00000000000..9116ff188b5
--- /dev/null
+++ b/src/mongo/tools/mongofiles_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongofiles_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoFilesOptions)(InitializerContext* context) {
+ return addMongoFilesOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoFilesOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoFilesOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoFilesOptions)(InitializerContext* context) {
+ Status ret = storeMongoFilesOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/mongoimport_options.cpp b/src/mongo/tools/mongoimport_options.cpp
new file mode 100644
index 00000000000..0c076594273
--- /dev/null
+++ b/src/mongo/tools/mongoimport_options.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongoimport_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/options_parser/startup_options.h"
+#include "mongo/util/text.h"
+
+namespace mongo {
+
+ MongoImportGlobalParams mongoImportGlobalParams;
+
+ Status addMongoImportOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addLocalServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addSpecifyDBCollectionToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addFieldOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("ignoreBlanks", "ignoreBlanks", moe::Switch,
+ "if given, empty fields in csv and tsv will be ignored");
+
+ options->addOptionChaining("type", "type", moe::String,
+ "type of file to import. default: json (json,csv,tsv)");
+
+ options->addOptionChaining("file", "file", moe::String,
+ "file to import from; if not specified stdin is used")
+ .positional(1, 1);
+
+ options->addOptionChaining("drop", "drop", moe::Switch, "drop collection first ");
+
+ options->addOptionChaining("headerline", "headerline", moe::Switch,
+ "first line in input file is a header (CSV and TSV only)");
+
+ options->addOptionChaining("upsert", "upsert", moe::Switch,
+ "insert or update objects that already exist");
+
+ options->addOptionChaining("upsertFields", "upsertFields", moe::String,
+ "comma-separated fields for the query part of the upsert. "
+ "You should make sure this is indexed");
+
+ options->addOptionChaining("stopOnError", "stopOnError", moe::Switch,
+ "stop importing at first error rather than continuing");
+
+ options->addOptionChaining("jsonArray", "jsonArray", moe::Switch,
+ "load a json array, not one item per line. Currently limited to 16MB.");
+
+
+ options->addOptionChaining("noimport", "noimport", moe::Switch,
+ "don't actually import. useful for benchmarking parser")
+ .hidden();
+
+
+ return Status::OK();
+ }
+
+ void printMongoImportHelp(std::ostream* out) {
+ *out << "Import CSV, TSV or JSON data into MongoDB.\n" << std::endl;
+ *out << "When importing JSON documents, each document must be a separate line of the input file.\n";
+ *out << "\nExample:\n";
+ *out << " mongoimport --host myhost --db my_cms --collection docs < mydocfile.json\n" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoImportOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoImportHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoImportOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = storeFieldOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ mongoImportGlobalParams.filename = getParam("file");
+ mongoImportGlobalParams.drop = hasParam("drop");
+ mongoImportGlobalParams.ignoreBlanks = hasParam("ignoreBlanks");
+
+ if (hasParam("upsert") || hasParam("upsertFields")) {
+ mongoImportGlobalParams.upsert = true;
+
+ string uf = getParam("upsertFields");
+ if (uf.empty()) {
+ mongoImportGlobalParams.upsertFields.push_back("_id");
+ }
+ else {
+ StringSplitter(uf.c_str(), ",").split(mongoImportGlobalParams.upsertFields);
+ }
+ }
+ else {
+ mongoImportGlobalParams.upsert = false;
+ }
+
+ mongoImportGlobalParams.doimport = !hasParam("noimport");
+ mongoImportGlobalParams.type = getParam("type", "json");
+ mongoImportGlobalParams.jsonArray = hasParam("jsonArray");
+ mongoImportGlobalParams.headerLine = hasParam("headerline");
+ mongoImportGlobalParams.stopOnError = hasParam("stopOnError");
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongoimport_options.h b/src/mongo/tools/mongoimport_options.h
new file mode 100644
index 00000000000..13bbd5f05a2
--- /dev/null
+++ b/src/mongo/tools/mongoimport_options.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoImportGlobalParams {
+ bool ignoreBlanks;
+ std::string type;
+ std::string filename;
+ bool drop;
+ bool headerLine;
+ bool upsert;
+ std::vector<std::string> upsertFields;
+ bool stopOnError;
+ bool jsonArray;
+ bool doimport;
+ };
+
+ extern MongoImportGlobalParams mongoImportGlobalParams;
+
+ Status addMongoImportOptions(moe::OptionSection* options);
+
+ void printMongoImportHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoImportOptions(const moe::Environment& params);
+
+ Status storeMongoImportOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongoimport_options_init.cpp b/src/mongo/tools/mongoimport_options_init.cpp
new file mode 100644
index 00000000000..c80d4ecc4b4
--- /dev/null
+++ b/src/mongo/tools/mongoimport_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongoimport_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoImportOptions)(InitializerContext* context) {
+ return addMongoImportOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoImportOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoImportOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoImportOptions)(InitializerContext* context) {
+ Status ret = storeMongoImportOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/mongooplog_options.cpp b/src/mongo/tools/mongooplog_options.cpp
new file mode 100644
index 00000000000..e67a33b9710
--- /dev/null
+++ b/src/mongo/tools/mongooplog_options.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongooplog_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/log.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoOplogGlobalParams mongoOplogGlobalParams;
+
+ Status addMongoOplogOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addLocalServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addSpecifyDBCollectionToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("seconds", "seconds,s", moe::Int,
+ "seconds to go back default:86400");
+
+ options->addOptionChaining("from", "from", moe::String, "host to pull from");
+
+ options->addOptionChaining("oplogns", "oplogns", moe::String, "ns to pull from")
+ .setDefault(moe::Value(std::string("local.oplog.rs")));
+
+
+ return Status::OK();
+ }
+
+ void printMongoOplogHelp(std::ostream* out) {
+ *out << "Pull and replay a remote MongoDB oplog.\n" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoOplogOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoOplogHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoOplogOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ if (!hasParam("from")) {
+ return Status(ErrorCodes::BadValue, "need to specify --from");
+ }
+ else {
+ mongoOplogGlobalParams.from = getParam("from");
+ }
+
+ mongoOplogGlobalParams.seconds = getParam("seconds", 86400);
+ mongoOplogGlobalParams.ns = getParam("oplogns");
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongooplog_options.h b/src/mongo/tools/mongooplog_options.h
new file mode 100644
index 00000000000..84d53f75a15
--- /dev/null
+++ b/src/mongo/tools/mongooplog_options.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoOplogGlobalParams {
+ int seconds;
+ std::string from;
+ std::string ns;
+ };
+
+ extern MongoOplogGlobalParams mongoOplogGlobalParams;
+
+ Status addMongoOplogOptions(moe::OptionSection* options);
+
+ void printMongoOplogHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoOplogOptions(const moe::Environment& params);
+
+ Status storeMongoOplogOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongooplog_options_init.cpp b/src/mongo/tools/mongooplog_options_init.cpp
new file mode 100644
index 00000000000..2e71d57bcf8
--- /dev/null
+++ b/src/mongo/tools/mongooplog_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongooplog_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoOplogOptions)(InitializerContext* context) {
+ return addMongoOplogOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoOplogOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoOplogOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoOplogOptions)(InitializerContext* context) {
+ Status ret = storeMongoOplogOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/mongorestore_options.cpp b/src/mongo/tools/mongorestore_options.cpp
new file mode 100644
index 00000000000..2ee83dbcfff
--- /dev/null
+++ b/src/mongo/tools/mongorestore_options.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongorestore_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoRestoreGlobalParams mongoRestoreGlobalParams;
+
+ Status addMongoRestoreOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addLocalServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addSpecifyDBCollectionToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addBSONToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("drop", "drop", moe::Switch,
+ "drop each collection before import");
+
+ options->addOptionChaining("oplogReplay", "oplogReplay", moe::Switch,
+ "replay oplog for point-in-time restore");
+
+ options->addOptionChaining("oplogLimit", "oplogLimit", moe::String,
+ "include oplog entries before the provided Timestamp "
+ "(seconds[:ordinal]) during the oplog replay; "
+ "the ordinal value is optional");
+
+ options->addOptionChaining("keepIndexVersion", "keepIndexVersion", moe::Switch,
+ "don't upgrade indexes to newest version");
+
+ options->addOptionChaining("noOptionsRestore", "noOptionsRestore", moe::Switch,
+ "don't restore collection options");
+
+ options->addOptionChaining("noIndexRestore", "noIndexRestore", moe::Switch,
+ "don't restore indexes");
+
+ options->addOptionChaining("restoreDbUsersAndRoles", "restoreDbUsersAndRoles", moe::Switch,
+ "Restore user and role definitions for the given database")
+ .requires("db").incompatibleWith("collection");
+
+ options->addOptionChaining(
+ "tempUsersCollection", "tempUsersCollection", moe::String,
+ "Collection in which to temporarily store user data during the restore")
+ .hidden()
+ .setDefault(moe::Value(
+ AuthorizationManager::defaultTempUsersCollectionNamespace.toString()));
+
+ options->addOptionChaining(
+ "tempRolesCollection", "tempRolesCollection", moe::String,
+ "Collection in which to temporarily store role data during the restore")
+ .hidden()
+ .setDefault(moe::Value(
+ AuthorizationManager::defaultTempRolesCollectionNamespace.toString()));
+
+ options->addOptionChaining("w", "w", moe::Int, "minimum number of replicas per write")
+ .setDefault(moe::Value(0));
+
+ options->addOptionChaining("dir", "dir", moe::String, "directory to restore from")
+ .hidden()
+ .setDefault(moe::Value(std::string("dump")))
+ .positional(1, 1);
+
+
+ // left in for backwards compatibility
+ options->addOptionChaining("indexesLast", "indexesLast", moe::Switch,
+ "wait to add indexes (now default)")
+ .hidden();
+
+
+ return Status::OK();
+ }
+
+ void printMongoRestoreHelp(std::ostream* out) {
+ *out << "Import BSON files into MongoDB.\n" << std::endl;
+ *out << "usage: mongorestore [options] [directory or filename to restore from]"
+ << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoRestoreOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoRestoreHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoRestoreOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = storeBSONToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ mongoRestoreGlobalParams.restoreDirectory = getParam("dir");
+ mongoRestoreGlobalParams.drop = hasParam("drop");
+ mongoRestoreGlobalParams.keepIndexVersion = hasParam("keepIndexVersion");
+ mongoRestoreGlobalParams.restoreOptions = !hasParam("noOptionsRestore");
+ mongoRestoreGlobalParams.restoreIndexes = !hasParam("noIndexRestore");
+ mongoRestoreGlobalParams.w = getParam( "w" , 0 );
+ mongoRestoreGlobalParams.oplogReplay = hasParam("oplogReplay");
+ mongoRestoreGlobalParams.oplogLimit = getParam("oplogLimit", "");
+ mongoRestoreGlobalParams.tempUsersColl = getParam("tempUsersCollection");
+ mongoRestoreGlobalParams.tempRolesColl = getParam("tempRolesCollection");
+
+ // Make the default db "" if it was not explicitly set
+ if (!params.count("db")) {
+ toolGlobalParams.db = "";
+ }
+
+ if (hasParam("restoreDbUsersAndRoles") && toolGlobalParams.db == "admin") {
+ return Status(ErrorCodes::BadValue,
+ "Cannot provide --restoreDbUsersAndRoles when restoring the admin db as "
+ "user and role definitions for the whole server are restored by "
+ "default (if present) when restoring the admin db");
+ }
+
+ // Always restore users and roles if doing a full restore. If doing a db restore, only
+ // restore users and roles if --restoreDbUsersAndRoles provided or you're restoring the
+ // admin db
+ mongoRestoreGlobalParams.restoreUsersAndRoles = hasParam("restoreDbUsersAndRoles") ||
+ (toolGlobalParams.db.empty() && toolGlobalParams.coll.empty()) ||
+ (toolGlobalParams.db == "admin" && toolGlobalParams.coll.empty());
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongorestore_options.h b/src/mongo/tools/mongorestore_options.h
new file mode 100644
index 00000000000..f0208952110
--- /dev/null
+++ b/src/mongo/tools/mongorestore_options.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoRestoreGlobalParams {
+ bool drop;
+ bool oplogReplay;
+ std::string oplogLimit;
+ bool keepIndexVersion;
+ bool restoreOptions;
+ bool restoreIndexes;
+ bool restoreUsersAndRoles;
+ int w;
+ std::string restoreDirectory;
+ std::string tempUsersColl;
+ std::string tempRolesColl;
+ };
+
+ extern MongoRestoreGlobalParams mongoRestoreGlobalParams;
+
+ Status addMongoRestoreOptions(moe::OptionSection* options);
+
+ void printMongoRestoreHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoRestoreOptions(const moe::Environment& params);
+
+ Status storeMongoRestoreOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongorestore_options_init.cpp b/src/mongo/tools/mongorestore_options_init.cpp
new file mode 100644
index 00000000000..f0a97bf390c
--- /dev/null
+++ b/src/mongo/tools/mongorestore_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongorestore_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoRestoreOptions)(InitializerContext* context) {
+ return addMongoRestoreOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoRestoreOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoRestoreOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoRestoreOptions)(InitializerContext* context) {
+ Status ret = storeMongoRestoreOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/mongostat_options.cpp b/src/mongo/tools/mongostat_options.cpp
new file mode 100644
index 00000000000..5a6174a9c9b
--- /dev/null
+++ b/src/mongo/tools/mongostat_options.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongostat_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoStatGlobalParams mongoStatGlobalParams;
+
+ Status addMongoStatOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("noheaders", "noheaders", moe::Switch,
+ "don't output column names");
+
+ options->addOptionChaining("rowcount", "rowcount,n", moe::Int,
+ "number of stats lines to print (0 for indefinite)")
+ .setDefault(moe::Value(0));
+
+ options->addOptionChaining("http", "http", moe::Switch,
+ "use http instead of raw db connection");
+
+ options->addOptionChaining("discover", "discover", moe::Switch,
+ "discover nodes and display stats for all");
+
+ options->addOptionChaining("all", "all", moe::Switch, "all optional fields");
+
+ options->addOptionChaining("sleep", "sleep", moe::Int, "seconds to sleep between samples")
+ .hidden()
+ .setSources(moe::SourceCommandLine)
+ .positional(1, 1);
+
+
+ return Status::OK();
+ }
+
+ void printMongoStatHelp(std::ostream* out) {
+ *out << "View live MongoDB performance statistics.\n" << std::endl;
+ *out << "usage: mongostat [options] [sleep time]" << std::endl;
+ *out << "sleep time: time to wait (in seconds) between calls" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << "\n";
+ *out << " Fields\n";
+ *out << " inserts \t- # of inserts per second (* means replicated op)\n";
+ *out << " query \t- # of queries per second\n";
+ *out << " update \t- # of updates per second\n";
+ *out << " delete \t- # of deletes per second\n";
+ *out << " getmore \t- # of get mores (cursor batch) per second\n";
+ *out << " command \t- # of commands per second, on a slave its local|replicated\n";
+ *out << " flushes \t- # of fsync flushes per second\n";
+ *out << " mapped \t- amount of data mmaped (total data size) megabytes\n";
+ *out << " vsize \t- virtual size of process in megabytes\n";
+ *out << " res \t- resident size of process in megabytes\n";
+ *out << " non-mapped \t- amount virtual memeory less mapped memory (only with --all)\n";
+ *out << " faults \t- # of pages faults per sec\n";
+ *out << " locked \t- name of and percent time for most locked database\n";
+ *out << " idx miss \t- percent of btree page misses (sampled)\n";
+ *out << " qr|qw \t- queue lengths for clients waiting (read|write)\n";
+ *out << " ar|aw \t- active clients (read|write)\n";
+ *out << " netIn \t- network traffic in - bytes\n";
+ *out << " netOut \t- network traffic out - bytes\n";
+ *out << " conn \t- number of open connections\n";
+ *out << " set \t- replica set name\n";
+ *out << " repl \t- replication type \n";
+ *out << " \t PRI - primary (master)\n";
+ *out << " \t SEC - secondary\n";
+ *out << " \t REC - recovering\n";
+ *out << " \t UNK - unknown\n";
+ *out << " \t SLV - slave\n";
+ *out << " b\t RTR - mongos process (\"router\")\n";
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoStatOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoStatHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoStatOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ if (hasParam("http")) {
+ mongoStatGlobalParams.http = true;
+ toolGlobalParams.noconnection = true;
+ }
+
+ if (hasParam("host") && getParam("host").find(',') != string::npos) {
+ toolGlobalParams.noconnection = true;
+ mongoStatGlobalParams.many = true;
+ }
+
+ if (hasParam("discover")) {
+ mongoStatGlobalParams.discover = true;
+ mongoStatGlobalParams.many = true;
+ }
+
+ mongoStatGlobalParams.showHeaders = !hasParam("noheaders");
+ mongoStatGlobalParams.rowCount = getParam("rowcount", 0);
+ mongoStatGlobalParams.sleep = getParam("sleep", 1);
+ mongoStatGlobalParams.allFields = hasParam("all");
+
+ // Make the default db "admin" if it was not explicitly set
+ if (!params.count("db")) {
+ toolGlobalParams.db = "admin";
+ }
+
+ // end of storage / start of validation
+
+ if (mongoStatGlobalParams.sleep <= 0) {
+ return Status(ErrorCodes::BadValue,
+ "Error parsing command line: --sleep must be greater than 0");
+ }
+
+ if (mongoStatGlobalParams.rowCount < 0) {
+ return Status(ErrorCodes::BadValue,
+ "Error parsing command line: --rowcount (-n) can't be negative");
+ }
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongostat_options.h b/src/mongo/tools/mongostat_options.h
new file mode 100644
index 00000000000..0787ed585d9
--- /dev/null
+++ b/src/mongo/tools/mongostat_options.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoStatGlobalParams {
+ bool showHeaders;
+ int rowCount;
+ bool http;
+ bool discover;
+ bool many;
+ bool allFields;
+ int sleep;
+ std::string url;
+ };
+
+ extern MongoStatGlobalParams mongoStatGlobalParams;
+
+ Status addMongoStatOptions(moe::OptionSection* options);
+
+ void printMongoStatHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoStatOptions(const moe::Environment& params);
+
+ Status storeMongoStatOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongostat_options_init.cpp b/src/mongo/tools/mongostat_options_init.cpp
new file mode 100644
index 00000000000..6f1eba04c82
--- /dev/null
+++ b/src/mongo/tools/mongostat_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongostat_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoStatOptions)(InitializerContext* context) {
+ return addMongoStatOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoStatOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoStatOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoStatOptions)(InitializerContext* context) {
+ Status ret = storeMongoStatOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/mongotop_options.cpp b/src/mongo/tools/mongotop_options.cpp
new file mode 100644
index 00000000000..4c128364d2f
--- /dev/null
+++ b/src/mongo/tools/mongotop_options.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongotop_options.h"
+
+#include "mongo/base/status.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+
+ MongoTopGlobalParams mongoTopGlobalParams;
+
+ Status addMongoTopOptions(moe::OptionSection* options) {
+ Status ret = addGeneralToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ ret = addRemoteServerToolOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ options->addOptionChaining("locks", "locks", moe::Switch,
+ "use db lock info instead of top");
+
+ options->addOptionChaining("sleep", "sleep", moe::Int, "seconds to sleep between samples")
+ .hidden()
+ .setSources(moe::SourceCommandLine)
+ .positional(1, 1);
+
+
+ return Status::OK();
+ }
+
+ void printMongoTopHelp(std::ostream* out) {
+ *out << "View live MongoDB collection statistics.\n" << std::endl;
+ *out << moe::startupOptions.helpString();
+ *out << std::flush;
+ }
+
+ bool handlePreValidationMongoTopOptions(const moe::Environment& params) {
+ if (!handlePreValidationGeneralToolOptions(params)) {
+ return false;
+ }
+ if (params.count("help")) {
+ printMongoTopHelp(&std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ Status storeMongoTopOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+ Status ret = storeGeneralToolOptions(params, args);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ mongoTopGlobalParams.sleep = getParam("sleep", 1);
+ mongoTopGlobalParams.useLocks = hasParam("locks");
+
+ // Make the default db "admin" if it was not explicitly set
+ if (!params.count("db")) {
+ toolGlobalParams.db = "admin";
+ }
+
+ return Status::OK();
+ }
+
+}
diff --git a/src/mongo/tools/mongotop_options.h b/src/mongo/tools/mongotop_options.h
new file mode 100644
index 00000000000..5f9e6b1fb4f
--- /dev/null
+++ b/src/mongo/tools/mongotop_options.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+#include "mongo/tools/tool_options.h"
+
+namespace mongo {
+
+ struct MongoTopGlobalParams {
+ bool useLocks;
+ int sleep;
+ };
+
+ extern MongoTopGlobalParams mongoTopGlobalParams;
+
+ Status addMongoTopOptions(moe::OptionSection* options);
+
+ void printMongoTopHelp(std::ostream* out);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationMongoTopOptions(const moe::Environment& params);
+
+ Status storeMongoTopOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/mongotop_options_init.cpp b/src/mongo/tools/mongotop_options_init.cpp
new file mode 100644
index 00000000000..965090029b7
--- /dev/null
+++ b/src/mongo/tools/mongotop_options_init.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/mongotop_options.h"
+
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/options_parser/startup_options.h"
+
+namespace mongo {
+ MONGO_GENERAL_STARTUP_OPTIONS_REGISTER(MongoTopOptions)(InitializerContext* context) {
+ return addMongoTopOptions(&moe::startupOptions);
+ }
+
+ MONGO_STARTUP_OPTIONS_VALIDATE(MongoTopOptions)(InitializerContext* context) {
+ if (!handlePreValidationMongoTopOptions(moe::startupOptionsParsed)) {
+ ::_exit(EXIT_SUCCESS);
+ }
+ Status ret = moe::startupOptionsParsed.validate();
+ if (!ret.isOK()) {
+ return ret;
+ }
+ return Status::OK();
+ }
+
+ MONGO_STARTUP_OPTIONS_STORE(MongoTopOptions)(InitializerContext* context) {
+ Status ret = storeMongoTopOptions(moe::startupOptionsParsed, context->args());
+ if (!ret.isOK()) {
+ std::cerr << ret.toString() << std::endl;
+ std::cerr << "try '" << context->args()[0] << " --help' for more information"
+ << std::endl;
+ ::_exit(EXIT_BADOPTIONS);
+ }
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/oplog.cpp b/src/mongo/tools/oplog.cpp
index ea7f2af5b13..d8eedb42f2e 100644
--- a/src/mongo/tools/oplog.cpp
+++ b/src/mongo/tools/oplog.cpp
@@ -1,5 +1,3 @@
-// oplog.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,76 +12,76 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "pch.h"
-#include "mongo/base/initializer.h"
-#include "db/json.h"
-#include "db/oplogreader.h"
-
-#include "tool.h"
+#include "mongo/pch.h"
#include <fstream>
#include <iostream>
-#include <boost/program_options.hpp>
+#include "mongo/db/json.h"
+#include "mongo/db/repl/oplogreader.h"
+#include "mongo/tools/mongooplog_options.h"
+#include "mongo/tools/tool.h"
+#include "mongo/util/options_parser/option_section.h"
using namespace mongo;
-namespace po = boost::program_options;
-
class OplogTool : public Tool {
public:
- OplogTool() : Tool( "oplog" ) {
- add_options()
- ("seconds,s" , po::value<int>() , "seconds to go back default:86400" )
- ("from", po::value<string>() , "host to pull from" )
- ("oplogns", po::value<string>()->default_value( "local.oplog.rs" ) , "ns to pull from" )
- ;
- }
+ OplogTool() : Tool() { }
- virtual void printExtraHelp(ostream& out) {
- out << "Pull and replay a remote MongoDB oplog.\n" << endl;
+ virtual void printHelp( ostream & out ) {
+ printMongoOplogHelp(&out);
}
int run() {
- if ( ! hasParam( "from" ) ) {
- log() << "need to specify --from" << endl;
- return -1;
- }
-
Client::initThread( "oplogreplay" );
- log() << "going to connect" << endl;
+ toolInfoLog() << "going to connect" << std::endl;
- OplogReader r(false);
+ OplogReader r;
r.setTailingQueryOptions( QueryOption_SlaveOk | QueryOption_AwaitData );
- r.connect( getParam( "from" ) );
+ r.connect(mongoOplogGlobalParams.from);
- log() << "connected" << endl;
+ toolInfoLog() << "connected" << std::endl;
- OpTime start( time(0) - getParam( "seconds" , 86400 ) , 0 );
- log() << "starting from " << start.toStringPretty() << endl;
+ OpTime start(time(0) - mongoOplogGlobalParams.seconds, 0);
+ toolInfoLog() << "starting from " << start.toStringPretty() << std::endl;
- string ns = getParam( "oplogns" );
- r.tailingQueryGTE( ns.c_str() , start );
+ r.tailingQueryGTE(mongoOplogGlobalParams.ns.c_str(), start);
int num = 0;
while ( r.more() ) {
BSONObj o = r.next();
- LOG(2) << o << endl;
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(2))) {
+ toolInfoLog() << o << std::endl;
+ }
if ( o["$err"].type() ) {
- log() << "error getting oplog" << endl;
- log() << o << endl;
+ toolError() << "error getting oplog" << std::endl;
+ toolError() << o << std::endl;
return -1;
}
bool print = ++num % 100000 == 0;
- if ( print )
- cout << num << "\t" << o << endl;
+ if (print) {
+ toolInfoLog() << num << "\t" << o << std::endl;
+ }
if ( o["op"].String() == "n" )
continue;
@@ -97,16 +95,15 @@ public:
BSONObj res;
bool ok = conn().runCommand( "admin" , c , res );
- if ( print || ! ok )
- log() << res << endl;
+ if (!ok) {
+ toolError() << res << std::endl;
+ } else if (print) {
+ toolInfoLog() << res << std::endl;
+ }
}
return 0;
}
};
-int main( int argc , char** argv, char** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- OplogTool t;
- return t.main( argc , argv );
-}
+REGISTER_MONGO_TOOL(OplogTool);
diff --git a/src/mongo/tools/restore.cpp b/src/mongo/tools/restore.cpp
index abd7f868afe..27cd6a2c785 100644
--- a/src/mongo/tools/restore.cpp
+++ b/src/mongo/tools/restore.cpp
@@ -1,5 +1,3 @@
-// @file restore.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,150 +12,230 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "pch.h"
+#include "mongo/pch.h"
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/operations.hpp>
-#include <boost/program_options.hpp>
-#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
+#include <boost/scoped_ptr.hpp>
#include <fcntl.h>
#include <fstream>
#include <set>
-#include "mongo/base/initializer.h"
-#include "mongo/db/namespacestring.h"
+#include "mongo/base/init.h"
+#include "mongo/bson/util/bson_extract.h"
+#include "mongo/client/auth_helpers.h"
+#include "mongo/client/dbclientcursor.h"
+#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_global.h"
+#include "mongo/db/auth/authz_manager_external_state_d.h"
+#include "mongo/db/auth/user_name.h"
+#include "mongo/db/auth/role_name.h"
+#include "mongo/db/json.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/tools/mongorestore_options.h"
#include "mongo/tools/tool.h"
#include "mongo/util/mmap.h"
+#include "mongo/util/options_parser/option_section.h"
#include "mongo/util/stringutils.h"
-#include "mongo/db/json.h"
-#include "mongo/client/dbclientcursor.h"
using namespace mongo;
-namespace po = boost::program_options;
-
namespace {
const char* OPLOG_SENTINEL = "$oplog"; // compare by ptr not strcmp
}
+MONGO_INITIALIZER_WITH_PREREQUISITES(RestoreAuthExternalState, ("ToolAuthExternalState"))(
+ InitializerContext* context) {
+ // Give restore the mongod implementation of AuthorizationManager so that it can run
+ // the _mergeAuthzCollections command directly against the data files
+ clearGlobalAuthorizationManager();
+ setGlobalAuthorizationManager(new AuthorizationManager(
+ new AuthzManagerExternalStateMongod()));
+
+ return Status::OK();
+}
+
class Restore : public BSONTool {
public:
- bool _drop;
- bool _keepIndexVersion;
- bool _restoreOptions;
- bool _restoreIndexes;
- int _w;
string _curns;
string _curdb;
string _curcoll;
- set<string> _users; // For restoring users with --drop
+ string _serverBinVersion; // Version identifier of the server we're restoring to
+ set<UserName> _users; // Holds users that are already in the cluster when restoring with --drop
+ set<RoleName> _roles; // Holds roles that are already in the cluster when restoring with --drop
scoped_ptr<Matcher> _opmatcher; // For oplog replay
scoped_ptr<OpTime> _oplogLimitTS; // for oplog replay (limit)
int _oplogEntrySkips; // oplog entries skipped
int _oplogEntryApplies; // oplog entries applied
- Restore() : BSONTool( "restore" ) , _drop(false) {
- // Default values set here will show up in help text, but will supercede any default value
- // used when calling getParam below.
- add_options()
- ("drop" , "drop each collection before import" )
- ("oplogReplay", "replay oplog for point-in-time restore")
- ("oplogLimit", po::value<string>(), "include oplog entries before the provided Timestamp "
- "(seconds[:ordinal]) during the oplog replay; the ordinal value is optional")
- ("keepIndexVersion" , "don't upgrade indexes to newest version")
- ("noOptionsRestore" , "don't restore collection options")
- ("noIndexRestore" , "don't restore indexes")
- ("w" , po::value<int>()->default_value(0) , "minimum number of replicas per write" )
- ;
- add_hidden_options()
- ("dir", po::value<string>()->default_value("dump"), "directory to restore from")
- ("indexesLast" , "wait to add indexes (now default)") // left in for backwards compatibility
- ;
- addPositionArg("dir", 1);
+ int _serverAuthzVersion; // authSchemaVersion of the cluster being restored into.
+ int _dumpFileAuthzVersion; // version extracted from admin.system.version file in dump.
+ bool _serverAuthzVersionDocExists; // Whether the remote cluster has an admin.system.version doc
+ Restore() : BSONTool(), _oplogEntrySkips(0), _oplogEntryApplies(0), _serverAuthzVersion(0),
+ _dumpFileAuthzVersion(0), _serverAuthzVersionDocExists(false) { }
+
+ virtual void printHelp(ostream& out) {
+ printMongoRestoreHelp(&out);
}
- virtual void printExtraHelp(ostream& out) {
- out << "Import BSON files into MongoDB.\n" << endl;
- out << "usage: " << _name << " [options] [directory or filename to restore from]" << endl;
+ void storeRemoteAuthzVersion() {
+ Status status = auth::getRemoteStoredAuthorizationVersion(&conn(),
+ &_serverAuthzVersion);
+ uassertStatusOK(status);
+ uassert(17370,
+ mongoutils::str::stream() << "Restoring users and roles is only supported for "
+ "clusters with auth schema versions " <<
+ AuthorizationManager::schemaVersion24 << " or " <<
+ AuthorizationManager::schemaVersion26Final << ", found: " <<
+ _serverAuthzVersion,
+ _serverAuthzVersion == AuthorizationManager::schemaVersion24 ||
+ _serverAuthzVersion == AuthorizationManager::schemaVersion26Final);
+
+ _serverAuthzVersionDocExists = !conn().findOne(
+ AuthorizationManager::versionCollectionNamespace,
+ AuthorizationManager::versionDocumentQuery).isEmpty();
}
virtual int doRun() {
- boost::filesystem::path root = getParam("dir");
+ boost::filesystem::path root = mongoRestoreGlobalParams.restoreDirectory;
// check if we're actually talking to a machine that can write
if (!isMaster()) {
return -1;
}
- if (isMongos() && _db == "" && exists(root / "config")) {
- log() << "Cannot do a full restore on a sharded system" << endl;
+ if (isMongos() && toolGlobalParams.db == "" && exists(root / "config")) {
+ toolError() << "Cannot do a full restore on a sharded system" << std::endl;
return -1;
}
- _drop = hasParam( "drop" );
- _keepIndexVersion = hasParam("keepIndexVersion");
- _restoreOptions = !hasParam("noOptionsRestore");
- _restoreIndexes = !hasParam("noIndexRestore");
- // Make sure default value set here stays in sync with the one set in the constructor above.
- _w = getParam( "w" , 0 );
+ {
+ // Store server's version
+ BSONObj out;
+ if (! conn().simpleCommand("admin", &out, "buildinfo")) {
+ toolError() << "buildinfo command failed: "
+ << out["errmsg"].String() << std::endl;
+ return -1;
+ }
+
+ _serverBinVersion = out["version"].String();
+ }
+
+ if (mongoRestoreGlobalParams.restoreUsersAndRoles) {
+ storeRemoteAuthzVersion(); // populate _serverAuthzVersion
+
+ if (_serverAuthzVersion == AuthorizationManager::schemaVersion26Final) {
+ uassert(17410,
+ mongoutils::str::stream() << mongoRestoreGlobalParams.tempUsersColl <<
+ " collection already exists, but is needed to restore user data. "
+ "Drop this collection or specify a different collection (via "
+ "--tempUsersColl) to use to temporarily hold user data during the "
+ "restore process",
+ !conn().exists(mongoRestoreGlobalParams.tempUsersColl));
+ uassert(17411,
+ mongoutils::str::stream() << mongoRestoreGlobalParams.tempRolesColl <<
+ " collection already exists, but is needed to restore role data. "
+ "Drop this collection or specify a different collection (via "
+ "--tempRolesColl) to use to temporarily hold role data during the "
+ "restore process",
+ !conn().exists(mongoRestoreGlobalParams.tempRolesColl));
+ }
- bool doOplog = hasParam( "oplogReplay" );
+ if (toolGlobalParams.db.empty() && toolGlobalParams.coll.empty() &&
+ exists(root / "admin" / "system.version.bson")) {
+ // Will populate _dumpFileAuthzVersion
+ processFileAndMetadata(root / "admin" / "system.version.bson",
+ "admin.system.version");
+ } else if (!toolGlobalParams.db.empty()) {
+ // DB-specific restore
+ if (exists(root / "$admin.system.users.bson")) {
+ uassert(17372,
+ mongoutils::str::stream() << "$admin.system.users.bson file found, "
+ "which implies that the dump was taken from a system with "
+ "schema version " << AuthorizationManager::schemaVersion26Final
+ << " users, but server has authorization schema version "
+ << _serverAuthzVersion,
+ _serverAuthzVersion == AuthorizationManager::schemaVersion26Final);
+ toolInfoLog() << "Restoring users for the " << toolGlobalParams.db <<
+ " database to admin.system.users" << endl;
+ processFileAndMetadata(root / "$admin.system.users.bson", "admin.system.users");
+ }
+ if (exists(root / "$admin.system.roles.bson")) {
+ uassert(17373,
+ mongoutils::str::stream() << "$admin.system.roles.bson file found, "
+ "which implies that the dump was taken from a system with "
+ "schema version " << AuthorizationManager::schemaVersion26Final
+ << " authorization data, but server has authorization schema "
+ "version " << _serverAuthzVersion,
+ _serverAuthzVersion == AuthorizationManager::schemaVersion26Final);
+ toolInfoLog() << "Restoring roles for the " << toolGlobalParams.db <<
+ " database to admin.system.roles" << endl;
+ processFileAndMetadata(root / "$admin.system.roles.bson", "admin.system.roles");
+ }
+ }
+ }
- if (doOplog) {
+ if (mongoRestoreGlobalParams.oplogReplay) {
// fail early if errors
- if (_db != "") {
- log() << "Can only replay oplog on full restore" << endl;
+ if (toolGlobalParams.db != "") {
+ toolError() << "Can only replay oplog on full restore" << std::endl;
return -1;
}
if ( ! exists(root / "oplog.bson") ) {
- log() << "No oplog file to replay. Make sure you run mongodump with --oplog." << endl;
- return -1;
- }
-
-
- BSONObj out;
- if (! conn().simpleCommand("admin", &out, "buildinfo")) {
- log() << "buildinfo command failed: " << out["errmsg"].String() << endl;
+ toolError() << "No oplog file to replay. Make sure you run mongodump with --oplog."
+ << std::endl;
return -1;
}
- StringData version = out["version"].valuestr();
- if (versionCmp(version, "1.7.4-pre-") < 0) {
- log() << "Can only replay oplog to server version >= 1.7.4" << endl;
+ if (versionCmp(_serverBinVersion, "1.7.4-pre-") < 0) {
+ toolError() << "Can only replay oplog to server version >= 1.7.4" << std::endl;
return -1;
}
- string oplogLimit = getParam( "oplogLimit", "" );
string oplogInc = "0";
- if(!oplogLimit.empty()) {
- size_t i = oplogLimit.find_first_of(':');
+ if(!mongoRestoreGlobalParams.oplogLimit.empty()) {
+ size_t i = mongoRestoreGlobalParams.oplogLimit.find_first_of(':');
if ( i != string::npos ) {
- if ( i + 1 < oplogLimit.length() ) {
- oplogInc = oplogLimit.substr(i + 1);
+ if (i + 1 < mongoRestoreGlobalParams.oplogLimit.length()) {
+ oplogInc = mongoRestoreGlobalParams.oplogLimit.substr(i + 1);
}
- oplogLimit = oplogLimit.substr(0, i);
+ mongoRestoreGlobalParams.oplogLimit =
+ mongoRestoreGlobalParams.oplogLimit.substr(0, i);
}
try {
_oplogLimitTS.reset(new OpTime(
- boost::lexical_cast<unsigned long>(oplogLimit.c_str()),
+ boost::lexical_cast<unsigned long>(
+ mongoRestoreGlobalParams.oplogLimit.c_str()),
boost::lexical_cast<unsigned long>(oplogInc.c_str())));
- } catch( const boost::bad_lexical_cast& error) {
- log() << "Could not parse oplogLimit into Timestamp from values ( "
- << oplogLimit << " , " << oplogInc << " )"
- << endl;
+ } catch( const boost::bad_lexical_cast& ) {
+ toolError() << "Could not parse oplogLimit into Timestamp from values ( "
+ << mongoRestoreGlobalParams.oplogLimit << " , " << oplogInc << " )"
+ << std::endl;
return -1;
}
- if (!oplogLimit.empty()) {
+ if (!mongoRestoreGlobalParams.oplogLimit.empty()) {
// Only for a replica set as master will have no-op entries so we would need to
// skip them all to find the real op
scoped_ptr<DBClientCursor> cursor(
@@ -168,9 +246,9 @@ public:
if (cursor->more()) {
tsOptime = cursor->next().getField("ts")._opTime();
if (tsOptime > *_oplogLimitTS.get()) {
- log() << "The oplogLimit is not newer than"
- << " the last oplog entry on the server."
- << endl;
+ toolError() << "The oplogLimit is not newer than"
+ << " the last oplog entry on the server."
+ << std::endl;
return -1;
}
}
@@ -183,17 +261,17 @@ public:
BSONObj query = BSON("ts" << tsRestrictBldr.obj());
if (!tsOptime.isNull()) {
- log() << "Latest oplog entry on the server is " << tsOptime.getSecs()
- << ":" << tsOptime.getInc() << endl;
- log() << "Only applying oplog entries matching this criteria: "
- << query.jsonString() << endl;
+ toolInfoLog() << "Latest oplog entry on the server is " << tsOptime.getSecs()
+ << ":" << tsOptime.getInc() << std::endl;
+ toolInfoLog() << "Only applying oplog entries matching this criteria: "
+ << query.jsonString() << std::endl;
}
_opmatcher.reset(new Matcher(query));
}
}
}
- /* If _db is not "" then the user specified a db name to restore as.
+ /* If toolGlobalParams.db is not "" then the user specified a db name to restore as.
*
* In that case we better be given either a root directory that
* contains only .bson files or a single .bson file (a db).
@@ -202,21 +280,22 @@ public:
* given either a root directory that contains only a single
* .bson file, or a single .bson file itself (a collection).
*/
- drillDown(root, _db != "", _coll != "", !(_oplogLimitTS.get() == NULL), true);
+ drillDown(root, toolGlobalParams.db != "", toolGlobalParams.coll != "",
+ !(_oplogLimitTS.get() == NULL), true);
// should this happen for oplog replay as well?
- string err = conn().getLastError(_db == "" ? "admin" : _db);
+ string err = conn().getLastError(toolGlobalParams.db == "" ? "admin" : toolGlobalParams.db);
if (!err.empty()) {
- error() << err;
+ toolError() << err << std::endl;
}
- if (doOplog) {
- log() << "\t Replaying oplog" << endl;
+ if (mongoRestoreGlobalParams.oplogReplay) {
+ toolInfoLog() << "\t Replaying oplog" << std::endl;
_curns = OPLOG_SENTINEL;
processFile( root / "oplog.bson" );
- log() << "Applied " << _oplogEntryApplies << " oplog entries out of "
- << _oplogEntryApplies + _oplogEntrySkips << " (" << _oplogEntrySkips
- << " skipped)." << endl;
+ toolInfoLog() << "Applied " << _oplogEntryApplies << " oplog entries out of "
+ << _oplogEntryApplies + _oplogEntrySkips << " (" << _oplogEntrySkips
+ << " skipped)." << std::endl;
}
return EXIT_CLEAN;
@@ -228,7 +307,9 @@ public:
bool oplogReplayLimit,
bool top_level=false) {
bool json_metadata = false;
- LOG(2) << "drillDown: " << root.string() << endl;
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(2))) {
+ toolInfoLog() << "drillDown: " << root.string() << std::endl;
+ }
// skip hidden files and directories
if (root.leaf().string()[0] == '.' && root.leaf().string() != ".")
@@ -244,18 +325,23 @@ public:
if (use_db) {
if (boost::filesystem::is_directory(p)) {
- error() << "ERROR: root directory must be a dump of a single database" << endl;
- error() << " when specifying a db name with --db" << endl;
- printHelp(cout);
+ toolError() << "ERROR: root directory must be a dump of a single database"
+ << std::endl;
+ toolError() << " when specifying a db name with --db" << std::endl;
+ toolError() << " use the --help option for more information"
+ << std::endl;
return;
}
}
if (use_coll) {
if (boost::filesystem::is_directory(p) || i != end) {
- error() << "ERROR: root directory must be a dump of a single collection" << endl;
- error() << " when specifying a collection name with --collection" << endl;
- printHelp(cout);
+ toolError() << "ERROR: root directory must be a dump of a single collection"
+ << std::endl;
+ toolError() << " when specifying a collection name with --collection"
+ << std::endl;
+ toolError() << " use the --help option for more information"
+ << std::endl;
return;
}
}
@@ -283,27 +369,16 @@ public:
return;
}
- if ( endsWith( root.string().c_str() , ".metadata.json" ) ) {
- // Metadata files are handled when the corresponding .bson file is handled
- return;
- }
-
- if ( ! ( endsWith( root.string().c_str() , ".bson" ) ||
- endsWith( root.string().c_str() , ".bin" ) ) ) {
- error() << "don't know what to do with file [" << root.string() << "]" << endl;
- return;
- }
-
- log() << root.string() << endl;
-
- if ( root.leaf() == "system.profile.bson" ) {
- log() << "\t skipping" << endl;
- return;
+ if (oplogReplayLimit) {
+ toolError() << "The oplogLimit option cannot be used if "
+ << "normal databases/collections exist in the dump directory."
+ << std::endl;
+ exit(EXIT_FAILURE);
}
string ns;
if (use_db) {
- ns += _db;
+ ns += toolGlobalParams.db;
}
else {
ns = root.parent_path().filename().string();
@@ -316,82 +391,224 @@ public:
string oldCollName = root.leaf().string(); // Name of the collection that was dumped from
oldCollName = oldCollName.substr( 0 , oldCollName.find_last_of( "." ) );
if (use_coll) {
- ns += "." + _coll;
+ ns += "." + toolGlobalParams.coll;
}
else {
ns += "." + oldCollName;
}
- if (oplogReplayLimit) {
- error() << "The oplogLimit option cannot be used if "
- << "normal databases/collections exist in the dump directory."
- << endl;
- exit(EXIT_FAILURE);
+ if ( endsWith( root.string().c_str() , ".metadata.json" ) ) {
+ // Metadata files are handled when the corresponding .bson file is handled
+ return;
}
- log() << "\tgoing into namespace [" << ns << "]" << endl;
+ if ((root.leaf() == "system.version.bson" && toolGlobalParams.db.empty()) ||
+ root.leaf() == "$admin.system.users.bson" ||
+ root.leaf() == "$admin.system.roles.bson") {
+ // These files were already explicitly handled at the beginning of the restore.
+ return;
+ }
- if ( _drop ) {
- if (root.leaf() != "system.users.bson" ) {
- log() << "\t dropping" << endl;
- conn().dropCollection( ns );
- } else {
- // Create map of the users currently in the DB
- BSONObj fields = BSON("user" << 1);
- scoped_ptr<DBClientCursor> cursor(conn().query(ns, Query(), 0, 0, &fields));
- while (cursor->more()) {
- BSONObj user = cursor->next();
- _users.insert(user["user"].String());
+ if ( ! ( endsWith( root.string().c_str() , ".bson" ) ||
+ endsWith( root.string().c_str() , ".bin" ) ) ) {
+ toolError() << "don't know what to do with file [" << root.string() << "]" << std::endl;
+ return;
+ }
+
+ toolInfoLog() << root.string() << std::endl;
+
+ if ( root.leaf() == "system.profile.bson" ) {
+ toolInfoLog() << "\t skipping system.profile.bson" << std::endl;
+ return;
+ }
+
+ processFileAndMetadata(root, ns);
+ }
+
+ static std::string getMessageAboutBrokenDBUserRestore(const StringData& serverBinVersion) {
+ return str::stream() << "Running mongorestore with --drop, --db, and "
+ "--restoreDbUsersAndRoles flags has erroneous behavior when the target server "
+ "version is between 2.6.0 and 2.6.3 (see SERVER-14212). Detected server version " <<
+ serverBinVersion << ". Aborting.";
+ }
+
+ /**
+ * 1) Drop collection if --drop was specified. For system.users or system.roles collections,
+ * however, you don't want to remove all the users/roles up front as some of them may be needed
+ * by the restore. Instead, keep a set of all the users/roles originally in the server, then
+ * after restoring the users/roles from the dump, remove any users roles that were present in
+ * the system originally but aren't in the dump.
+ *
+ * 2) Parse metadata file (if present) and if the collection doesn't exist (or was just dropped
+ * b/c we're using --drop), create the collection with the options from the metadata file
+ *
+ * 3) Restore the data from the dump file for this collection
+ *
+ * 4) If the user asked to drop this collection, then at this point the _users and _roles sets
+ * will contain users and roles that were in the collection but not in the dump we are
+ * restoring. Iterate these sets and delete any users and roles that are there.
+ *
+ * 5) Restore indexes based on index definitions from the metadata file.
+ */
+ void processFileAndMetadata(const boost::filesystem::path& root, const std::string& ns) {
+
+ _curns = ns;
+ _curdb = nsToDatabase(_curns);
+ _curcoll = nsToCollectionSubstring(_curns).toString();
+
+ toolInfoLog() << "\tgoing into namespace [" << _curns << "]" << std::endl;
+
+ // 1) Drop collection if needed. Save user and role data if this is a system.users or
+ // system.roles collection
+ if (mongoRestoreGlobalParams.drop) {
+ if (_curcoll == "system.users") {
+ if (_serverAuthzVersion == AuthorizationManager::schemaVersion24 ||
+ _curdb != "admin") {
+ // Restoring 2.4-style user docs so can't use the _mergeAuthzCollections command
+ // Create map of the users currently in the DB so the ones that don't show up in
+ // the dump file can be removed later.
+ BSONObj fields = BSON("user" << 1 << "userSource" << 1);
+ scoped_ptr<DBClientCursor> cursor(conn().query(_curns, Query(), 0, 0, &fields));
+ while (cursor->more()) {
+ BSONObj user = cursor->next();
+ string userDB;
+ uassertStatusOK(bsonExtractStringFieldWithDefault(user,
+ "userSource",
+ _curdb,
+ &userDB));
+ _users.insert(UserName(user["user"].String(), userDB));
+ }
}
}
+ else if (!startsWith(_curcoll, "system.")) { // Can't drop system collections
+ toolInfoLog() << "\t dropping" << std::endl;
+ conn().dropCollection( ns );
+ }
+ } else {
+ // If drop is not used, warn if the collection exists.
+ scoped_ptr<DBClientCursor> cursor(conn().query(_curdb + ".system.namespaces",
+ Query(BSON("name" << ns))));
+ if (cursor->more()) {
+ // collection already exists show warning
+ toolError() << "Restoring to " << ns << " without dropping. Restored data "
+ << "will be inserted without raising errors; check your server log"
+ << std::endl;
+ }
}
+ // 2) Create collection with options from metadata file if present
BSONObj metadataObject;
- if (_restoreOptions || _restoreIndexes) {
+ if (mongoRestoreGlobalParams.restoreOptions || mongoRestoreGlobalParams.restoreIndexes) {
+ string oldCollName = root.leaf().string(); // Name of collection that was dumped from
+ oldCollName = oldCollName.substr( 0 , oldCollName.find_last_of( "." ) );
boost::filesystem::path metadataFile = (root.branch_path() / (oldCollName + ".metadata.json"));
if (!boost::filesystem::exists(metadataFile.string())) {
// This is fine because dumps from before 2.1 won't have a metadata file, just print a warning.
// System collections shouldn't have metadata so don't warn if that file is missing.
if (!startsWith(metadataFile.leaf().string(), "system.")) {
- log() << metadataFile.string() << " not found. Skipping." << endl;
+ toolInfoLog() << metadataFile.string() << " not found. Skipping." << std::endl;
}
} else {
metadataObject = parseMetadataFile(metadataFile.string());
}
}
- _curns = ns.c_str();
- _curdb = NamespaceString(_curns).db;
- _curcoll = NamespaceString(_curns).coll;
-
- // If drop is not used, warn if the collection exists.
- if (!_drop) {
- scoped_ptr<DBClientCursor> cursor(conn().query(_curdb + ".system.namespaces",
- Query(BSON("name" << ns))));
- if (cursor->more()) {
- // collection already exists show warning
- warning() << "Restoring to " << ns << " without dropping. Restored data "
- "will be inserted without raising errors; check your server log"
- << endl;
- }
- }
-
- if (_restoreOptions && metadataObject.hasField("options")) {
+ if (mongoRestoreGlobalParams.restoreOptions && metadataObject.hasField("options")) {
// Try to create collection with given options
createCollectionWithOptions(metadataObject["options"].Obj());
}
+ // 3) Actually restore the BSONObjs inside the dump file
processFile( root );
- if (_drop && root.leaf() == "system.users.bson") {
- // Delete any users that used to exist but weren't in the dump file
- for (set<string>::iterator it = _users.begin(); it != _users.end(); ++it) {
- BSONObj userMatch = BSON("user" << *it);
- conn().remove(ns, Query(userMatch));
+
+ // 4) If running with --drop, remove any users/roles that were in the system at the
+ // beginning of the restore but weren't found in the dump file
+ if (_curcoll == "system.users") {
+ if ((_serverAuthzVersion == AuthorizationManager::schemaVersion24 ||
+ _curdb != "admin")) {
+ // Restoring 2.4 style user docs so don't use the _mergeAuthzCollections command
+ if (mongoRestoreGlobalParams.drop) {
+ // Delete any users that used to exist but weren't in the dump file
+ for (set<UserName>::iterator it = _users.begin(); it != _users.end(); ++it) {
+ const UserName& name = *it;
+ BSONObjBuilder queryBuilder;
+ queryBuilder << "user" << name.getUser();
+ if (name.getDB() == _curdb) {
+ // userSource field won't be present for v1 users docs in the same db as
+ // the user is defined on.
+ queryBuilder << "userSource" << BSONNULL;
+ } else {
+ queryBuilder << "userSource" << name.getDB();
+ }
+ conn().remove(_curns, Query(queryBuilder.done()));
+ }
+ _users.clear();
+ }
+ } else {
+ // Use _mergeAuthzCollections command to move into admin.system.users the user
+ // docs that were restored into the temp user collection
+ BSONObjBuilder cmdBuilder;
+ cmdBuilder.append("_mergeAuthzCollections", 1);
+ cmdBuilder.append("tempUsersCollection", mongoRestoreGlobalParams.tempUsersColl);
+ cmdBuilder.append("drop", mongoRestoreGlobalParams.drop);
+ cmdBuilder.append("writeConcern", BSON("w" << mongoRestoreGlobalParams.w));
+ if (versionCmp(_serverBinVersion, "2.6.4-pre-") < 0) {
+ uassert(18528,
+ getMessageAboutBrokenDBUserRestore(_serverBinVersion),
+ !mongoRestoreGlobalParams.drop ||
+ toolGlobalParams.db.empty() ||
+ toolGlobalParams.db == "admin");
+ } else {
+ // If we're doing a db-specific restore of the "admin" db, we want user data for
+ // *all* databases restored, not just the admin db, so we pass "" as the "db"
+ // param to _mergeAuthzCollections
+ cmdBuilder.append("db",
+ toolGlobalParams.db == "admin" ? "" : toolGlobalParams.db);
+ }
+
+ BSONObj res;
+ conn().runCommand("admin", cmdBuilder.done(), res);
+ uassert(17412,
+ mongoutils::str::stream() << "Cannot restore users because the "
+ "_mergeAuthzCollections command failed: " << res.toString(),
+ res["ok"].trueValue());
+
+ conn().dropCollection(mongoRestoreGlobalParams.tempUsersColl);
}
- _users.clear();
+ }
+ if (_curns == "admin.system.roles") {
+ // Use _mergeAuthzCollections command to move into admin.system.roles the role
+ // docs that were restored into the temp roles collection
+ BSONObjBuilder cmdBuilder;
+ cmdBuilder.append("_mergeAuthzCollections", 1);
+ cmdBuilder.append("tempRolesCollection", mongoRestoreGlobalParams.tempRolesColl);
+ cmdBuilder.append("drop", mongoRestoreGlobalParams.drop);
+ cmdBuilder.append("writeConcern", BSON("w" << mongoRestoreGlobalParams.w));
+ if (versionCmp(_serverBinVersion, "2.6.4-pre-") < 0) {
+ uassert(18529,
+ getMessageAboutBrokenDBUserRestore(_serverBinVersion),
+ !mongoRestoreGlobalParams.drop ||
+ toolGlobalParams.db.empty() ||
+ toolGlobalParams.db == "admin");
+ } else {
+ // If we're doing a db-specific restore of the "admin" db, we want role data for
+ // *all* databases restored, not just the admin db, so we pass "" as the "db"
+ // param to _mergeAuthzCollections
+ cmdBuilder.append("db", toolGlobalParams.db == "admin" ? "" : toolGlobalParams.db);
+ }
+
+ BSONObj res;
+ conn().runCommand("admin", cmdBuilder.done(), res);
+ uassert(17413,
+ mongoutils::str::stream() << "Cannot restore roles because the "
+ "_mergeAuthzCollections command failed: " << res.toString(),
+ res["ok"].trueValue());
+
+ conn().dropCollection(mongoRestoreGlobalParams.tempRolesColl);
}
- if (_restoreIndexes && metadataObject.hasField("indexes")) {
+ // 5) Restore indexes
+ if (mongoRestoreGlobalParams.restoreIndexes && metadataObject.hasField("indexes")) {
vector<BSONElement> indexes = metadataObject["indexes"].Array();
for (vector<BSONElement>::iterator it = indexes.begin(); it != indexes.end(); ++it) {
createIndex((*it).Obj(), false);
@@ -419,33 +636,129 @@ public:
_oplogEntryApplies++;
// wait for ops to propagate to "w" nodes (doesn't warn if w used without replset)
- if ( _w > 0 ) {
- string err = conn().getLastError(db, false, false, _w);
+ if (mongoRestoreGlobalParams.w > 0) {
+ string err = conn().getLastError(db, false, false, mongoRestoreGlobalParams.w);
if (!err.empty()) {
- error() << "Error while replaying oplog: " << err;
+ toolError() << "Error while replaying oplog: " << err << std::endl;
}
}
+ return;
}
- else if (NamespaceString(_curns).coll == "system.indexes") {
+
+ if (nsToCollectionSubstring(_curns) == "system.indexes") {
createIndex(obj, true);
}
- else if (_drop && endsWith(_curns.c_str(), ".system.users") && _users.count(obj["user"].String())) {
- // Since system collections can't be dropped, we have to manually
- // replace the contents of the system.users collection
- BSONObj userMatch = BSON("user" << obj["user"].String());
- conn().update(_curns, Query(userMatch), obj);
- _users.erase(obj["user"].String());
- } else {
- conn().insert( _curns , obj );
+ else if (_curns == "admin.system.roles") {
+ // To prevent modifying roles when other role modifications may be going on, restore
+ // the roles to a temporary collection and merge them into admin.system.roles later
+ // using the _mergeAuthzCollections command.
+ conn().insert(mongoRestoreGlobalParams.tempRolesColl, obj);
+ }
+ else if (_curcoll == "system.users") {
+ uassert(17416,
+ mongoutils::str::stream() << "Cannot modify user data on a server with version "
+ "greater than or equal to 2.5.4 that has not yet updated the "
+ "authorization data to schema version " <<
+ AuthorizationManager::schemaVersion26Final <<
+ ". Found server version " << _serverBinVersion << " with "
+ "authorization schema version " << _serverAuthzVersion,
+ _curdb != "admin" ||
+ versionCmp(_serverBinVersion, "2.5.4") < 0 ||
+ _serverAuthzVersion == AuthorizationManager::schemaVersion26Final);
+
+ if (obj.hasField("credentials")) {
+ if (_serverAuthzVersion == AuthorizationManager::schemaVersion24) {
+ // v3 user, v1 system
+ uasserted(17407,
+ mongoutils::str::stream()
+ << "Server has authorization schema version "
+ << AuthorizationManager::schemaVersion24
+ << ", but found a schema version "
+ << AuthorizationManager::schemaVersion26Final << " user: "
+ << obj.toString());
+ } else {
+ // v3 user, v3 system
+ uassert(17414,
+ mongoutils::str::stream() << "Found a schema version " <<
+ AuthorizationManager::schemaVersion26Final <<
+ " user when restoring to a non-admin db system.users "
+ "collection: " << obj.toString(),
+ _curdb == "admin");
+ // To prevent modifying users when other user modifications may be going on,
+ // restore the users to a temporary collection and merge them into
+ // admin.system.users later using the _mergeAuthzCollections command.
+ conn().insert(mongoRestoreGlobalParams.tempUsersColl, obj);
+ }
+ } else {
+ if (_curdb == "admin" &&
+ _serverAuthzVersion == AuthorizationManager::schemaVersion26Final &&
+ !_serverAuthzVersionDocExists) {
+ // server with schemaVersion26Final implies it is running 2.5.4 or greater.
+ uasserted(17415,
+ mongoutils::str::stream() << "Cannot restore users with schema " <<
+ "version " << AuthorizationManager::schemaVersion24 <<
+ " to a system with server version 2.5.4 or greater");
+ }
- // wait for insert to propagate to "w" nodes (doesn't warn if w used without replset)
- if ( _w > 0 ) {
- string err = conn().getLastError(_curdb, false, false, _w);
- if (!err.empty()) {
- error() << err;
+ if (_serverAuthzVersion == AuthorizationManager::schemaVersion24 ||
+ _curdb != "admin") { // Restoring 2.4 schema users to non-admin dbs is OK)
+ // v1 user, v1 system
+ string userDB;
+ uassertStatusOK(bsonExtractStringFieldWithDefault(obj,
+ "userSource",
+ _curdb,
+ &userDB));
+
+ if (mongoRestoreGlobalParams.drop && _users.count(UserName(obj["user"].String(),
+ userDB))) {
+ // Since system collections can't be dropped, we have to manually
+ // replace the contents of the system.users collection
+ BSONObj userMatch = BSON("user" << obj["user"].String() <<
+ "userSource" << userDB);
+ conn().update(_curns, Query(userMatch), obj);
+ _users.erase(UserName(obj["user"].String(), userDB));
+ } else {
+ conn().insert(_curns, obj);
+ }
+ } else {
+ // v1 user, v3 system
+ // TODO(spencer): SERVER-12491 Rather than failing here, we should convert the
+ // v1 user to an equivalent v3 schema user
+ uasserted(17408,
+ mongoutils::str::stream()
+ << "Server has authorization schema version "
+ << AuthorizationManager::schemaVersion26Final
+ << ", but found a schema version "
+ << AuthorizationManager::schemaVersion24 << " user: "
+ << obj.toString());
}
}
}
+ else {
+ if (_curns == "admin.system.version") {
+ long long authVersion;
+ uassertStatusOK(bsonExtractIntegerField(obj,
+ AuthorizationManager::schemaVersionFieldName,
+ &authVersion));
+ _dumpFileAuthzVersion = static_cast<int>(authVersion);
+ uassert(17371,
+ mongoutils::str::stream() << "Server's authorization data schema version "
+ "does not match that of the data in the dump file. Server's schema"
+ " version: " << _serverAuthzVersion << ", schema version in dump: "
+ << _dumpFileAuthzVersion,
+ _serverAuthzVersion == _dumpFileAuthzVersion);
+ }
+ conn().insert(_curns, obj);
+ }
+
+ // wait for insert (or update) to propagate to "w" nodes (doesn't warn if w used
+ // without replset)
+ if (mongoRestoreGlobalParams.w > 0) {
+ string err = conn().getLastError(_curdb, false, false, mongoRestoreGlobalParams.w);
+ if (!err.empty()) {
+ toolError() << err << std::endl;
+ }
+ }
}
private:
@@ -454,11 +767,13 @@ private:
long long fileSize = boost::filesystem::file_size(filePath);
ifstream file(filePath.c_str(), ios_base::in);
- scoped_ptr<char> buf(new char[fileSize]);
+ boost::scoped_array<char> buf(new char[fileSize + 1]);
file.read(buf.get(), fileSize);
+ buf[fileSize] = '\0';
+
int objSize;
BSONObj obj;
- obj = fromjson (buf.get(), &objSize);
+ obj = fromjson(buf.get(), &objSize);
return obj;
}
@@ -484,34 +799,30 @@ private:
return nfields == obj2.nFields();
}
- void createCollectionWithOptions(BSONObj cmdObj) {
+ void createCollectionWithOptions(BSONObj obj) {
+ BSONObjIterator i(obj);
- // Create a new cmdObj to skip undefined fields and fix collection name
+ // Rebuild obj as a command object for the "create" command.
+ // - {create: <name>} comes first, where <name> is the new name for the collection
+ // - elements with type Undefined get skipped over
BSONObjBuilder bo;
-
- // Add a "create" field if it doesn't exist
- if (!cmdObj.hasField("create")) {
- bo.append("create", _curcoll);
- }
-
- BSONObjIterator i(cmdObj);
- while ( i.more() ) {
+ bo.append("create", _curcoll);
+ while (i.more()) {
BSONElement e = i.next();
- // Replace the "create" field with the name of the collection we are actually creating
if (strcmp(e.fieldName(), "create") == 0) {
- bo.append("create", _curcoll);
+ continue;
}
- else {
- if (e.type() == Undefined) {
- log() << _curns << ": skipping undefined field: " << e.fieldName() << endl;
- }
- else {
- bo.append(e);
- }
+
+ if (e.type() == Undefined) {
+ toolInfoLog() << _curns << ": skipping undefined field: " << e.fieldName()
+ << std::endl;
+ continue;
}
+
+ bo.append(e);
}
- cmdObj = bo.obj();
+ obj = bo.obj();
BSONObj fields = BSON("options" << 1);
scoped_ptr<DBClientCursor> cursor(conn().query(_curdb + ".system.namespaces", Query(BSON("name" << _curns)), 0, 0, &fields));
@@ -519,9 +830,12 @@ private:
bool createColl = true;
if (cursor->more()) {
createColl = false;
- BSONObj obj = cursor->next();
- if (!obj.hasField("options") || !optionsSame(cmdObj, obj["options"].Obj())) {
- log() << "WARNING: collection " << _curns << " exists with different options than are in the metadata.json file and not using --drop. Options in the metadata file will be ignored." << endl;
+ BSONObj nsObj = cursor->next();
+ if (!nsObj.hasField("options") || !optionsSame(obj, nsObj["options"].Obj())) {
+ toolError() << "WARNING: collection " << _curns
+ << " exists with different options than are in the metadata.json file and"
+ << " not using --drop. Options in the metadata file will be ignored."
+ << std::endl;
}
}
@@ -530,10 +844,11 @@ private:
}
BSONObj info;
- if (!conn().runCommand(_curdb, cmdObj, info)) {
+ if (!conn().runCommand(_curdb, obj, info)) {
uasserted(15936, "Creating collection " + _curns + " failed. Errmsg: " + info["errmsg"].String());
} else {
- log() << "\tCreated collection " << _curns << " with options: " << cmdObj.jsonString() << endl;
+ toolInfoLog() << "\tCreated collection " << _curns << " with options: "
+ << obj.jsonString() << std::endl;
}
}
@@ -547,23 +862,26 @@ private:
BSONElement e = i.next();
if (strcmp(e.fieldName(), "ns") == 0) {
NamespaceString n(e.String());
- string s = _curdb + "." + (keepCollName ? n.coll : _curcoll);
+ string s = _curdb + "." + (keepCollName ? n.coll().toString() : _curcoll);
bo.append("ns", s);
}
- else if (strcmp(e.fieldName(), "v") != 0 || _keepIndexVersion) { // Remove index version number
+ // Remove index version number
+ else if (strcmp(e.fieldName(), "v") != 0 || mongoRestoreGlobalParams.keepIndexVersion) {
bo.append(e);
}
}
BSONObj o = bo.obj();
- LOG(0) << "\tCreating index: " << o << endl;
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(0))) {
+ toolInfoLog() << "\tCreating index: " << o << std::endl;
+ }
conn().insert( _curdb + ".system.indexes" , o );
// We're stricter about errors for indexes than for regular data
- BSONObj err = conn().getLastErrorDetailed(_curdb, false, false, _w);
+ BSONObj err = conn().getLastErrorDetailed(_curdb, false, false, mongoRestoreGlobalParams.w);
if (err.hasField("err") && !err["err"].isNull()) {
- if (err["err"].str() == "norepl" && _w > 1) {
- error() << "Cannot specify write concern for non-replicas" << endl;
+ if (err["err"].str() == "norepl" && mongoRestoreGlobalParams.w > 1) {
+ toolError() << "Cannot specify write concern for non-replicas" << std::endl;
}
else {
string errCode;
@@ -572,8 +890,8 @@ private:
errCode = str::stream() << err["code"].numberInt();
}
- error() << "Error creating index " << o["ns"].String() << ": "
- << errCode << " " << err["err"] << endl;
+ toolError() << "Error creating index " << o["ns"].String() << ": "
+ << errCode << " " << err["err"] << std::endl;
}
::abort();
@@ -584,8 +902,4 @@ private:
}
};
-int main( int argc , char ** argv, char ** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- Restore restore;
- return restore.main( argc , argv );
-}
+REGISTER_MONGO_TOOL(Restore);
diff --git a/src/mongo/tools/sniffer.cpp b/src/mongo/tools/sniffer.cpp
index 5e2ac66267b..2d57ef7af47 100644
--- a/src/mongo/tools/sniffer.cpp
+++ b/src/mongo/tools/sniffer.cpp
@@ -1,4 +1,3 @@
-// sniffer.cpp
/*
* Copyright (C) 2010 10gen Inc.
*
@@ -13,50 +12,62 @@
*
* 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
*/
-
/*
TODO:
large messages - need to track what's left and ignore
- single object over packet size - can only display begging of object
+ single object over packet size - can only display beginning of object
getmore
delete
killcursors
*/
-#include "../pch.h"
-#include <pcap.h>
+#include "mongo/pch.h"
#ifdef _WIN32
#undef min
#undef max
#endif
-#include "mongo/base/initializer.h"
-#include "../bson/util/builder.h"
-#include "../util/net/message.h"
-#include "../util/mmap.h"
-#include "../db/dbmessage.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
+#include <boost/shared_ptr.hpp>
#include <ctype.h>
#include <errno.h>
+#include <iostream>
+#include <map>
+#include <pcap.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <string.h>
#include <sys/types.h>
+
#ifndef _WIN32
-#include <sys/socket.h>
-#include <netinet/in.h>
#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
#endif
-#include <iostream>
-#include <map>
-#include <string>
-
-#include <boost/shared_ptr.hpp>
+#include "mongo/base/initializer.h"
+#include "mongo/bson/util/builder.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/dbmessage.h"
+#include "mongo/util/net/message.h"
+#include "mongo/util/mmap.h"
+#include "mongo/util/text.h"
using namespace std;
using mongo::Message;
@@ -68,8 +79,6 @@ using mongo::DBClientConnection;
using mongo::QueryResult;
using mongo::MemoryMappedFile;
-mongo::CmdLine mongo::cmdLine;
-
#define SNAP_LEN 65535
int captureHeaderSize;
@@ -329,9 +338,7 @@ void processMessage( Connection& c , Message& m ) {
break;
}
case mongo::dbKillCursors: {
- int *x = (int *) m.singleData()->_data;
- x++; // reserved
- int n = *x;
+ int n = d.pullInt();
out() << "\tkillCursors n: " << n << endl;
break;
}
@@ -357,7 +364,7 @@ void processMessage( Connection& c , Message& m ) {
if ( m.operation() == mongo::dbGetMore ) {
DbMessage d( m );
d.pullInt();
- long long &cId = d.pullInt64();
+ long long cId = d.pullInt64();
cId = mapCursor[ c ][ cId ];
}
Message response;
@@ -425,7 +432,8 @@ void processDiagLog( const char * file ) {
void usage() {
cout <<
- "Usage: mongosniff [--help] [--forward host:port] [--source (NET <interface> | (FILE | DIAGLOG) <filename>)] [<port0> <port1> ... ]\n"
+ "Usage: mongosniff [--help] [--forward host:port] [--objcheck] [--source (NET <interface> | (FILE | DIAGLOG) <filename>)] [<port0> <port1> ... ]\n"
+ "--help Print this help message.\n"
"--forward Forward all parsed request messages to mongod instance at \n"
" specified host:port\n"
"--source Source of traffic to sniff, either a network interface or a\n"
@@ -438,11 +446,10 @@ void usage() {
" when there are dropped tcp packets.\n"
"<port0>... These parameters are used to filter sniffing. By default, \n"
" only port 27017 is sniffed.\n"
- "--help Print this help message.\n"
<< endl;
}
-int main(int argc, char **argv, char** envp) {
+int toolMain(int argc, char **argv, char** envp) {
mongo::runGlobalInitializersOrDie(argc, argv, envp);
stringstream nullStream;
@@ -453,8 +460,14 @@ int main(int argc, char **argv, char** envp) {
pcap_t *handle;
struct bpf_program fp;
- bpf_u_int32 mask;
- bpf_u_int32 net;
+
+// PCAP_NETMASK_UNKNOWN was introduced in pcap 1.1.0, so work around earlier versions. See
+// http://anonsvn.wireshark.org/viewvc?revision=33461&view=revision for details.
+#if defined(PCAP_NETMASK_UNKNOWN)
+ bpf_u_int32 mask = PCAP_NETMASK_UNKNOWN;
+#else
+ bpf_u_int32 mask = 0;
+#endif
bool source = false;
bool replay = false;
@@ -523,6 +536,7 @@ int main(int argc, char **argv, char** envp) {
}
cout << "found device: " << dev << endl;
}
+ bpf_u_int32 net;
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
cerr << "can't get netmask: " << errbuf << endl;
return -1;
@@ -545,7 +559,7 @@ int main(int argc, char **argv, char** envp) {
cerr << "don't know how to handle datalink type: " << pcap_datalink( handle ) << endl;
}
- verify( pcap_compile(handle, &fp, const_cast< char * >( "tcp" ) , 0, net) != -1 );
+ verify( pcap_compile(handle, &fp, const_cast< char * >( "tcp" ) , 0, mask) != -1 );
verify( pcap_setfilter(handle, &fp) != -1 );
cout << "sniffing... ";
@@ -561,3 +575,20 @@ int main(int argc, char **argv, char** envp) {
return 0;
}
+#if defined(_WIN32)
+// In Windows, wmain() is an alternate entry point for main(), and receives the same parameters
+// as main() but encoded in Windows Unicode (UTF-16); "wide" 16-bit wchar_t characters. The
+// WindowsCommandLine object converts these wide character strings to a UTF-8 coded equivalent
+// and makes them available through the argv() and envp() members. This enables toolMain()
+// to process UTF-8 encoded arguments and environment variables without regard to platform.
+int wmain(int argc, wchar_t* argvW[], wchar_t* envpW[]) {
+ WindowsCommandLine wcl(argc, argvW, envpW);
+ int exitCode = toolMain(argc, wcl.argv(), wcl.envp());
+ ::_exit(exitCode);
+}
+#else
+int main(int argc, char* argv[], char** envp) {
+ int exitCode = toolMain(argc, argv, envp);
+ ::_exit(exitCode);
+}
+#endif
diff --git a/src/mongo/tools/stat.cpp b/src/mongo/tools/stat.cpp
index 07194444671..002d8a4a5f0 100644
--- a/src/mongo/tools/stat.cpp
+++ b/src/mongo/tools/stat.cpp
@@ -12,148 +12,92 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "pch.h"
-
-#include "mongo/tools/tool.h"
+#include "mongo/pch.h"
-#include <boost/program_options.hpp>
#include <boost/thread/thread.hpp>
#include <fstream>
#include <iostream>
-#include "mongo/base/initializer.h"
+#include "mongo/base/init.h"
#include "mongo/client/dbclientcursor.h"
+#include "mongo/client/sasl_client_authenticate.h"
#include "mongo/db/jsobjmanipulator.h"
#include "mongo/db/json.h"
#include "mongo/s/type_shard.h"
#include "mongo/tools/stat_util.h"
+#include "mongo/tools/mongostat_options.h"
+#include "mongo/tools/tool.h"
#include "mongo/util/net/httpclient.h"
+#include "mongo/util/options_parser/option_section.h"
#include "mongo/util/text.h"
-namespace po = boost::program_options;
-
namespace mongo {
class Stat : public Tool {
public:
- Stat() : Tool( "stat" , REMOTE_SERVER , "admin" ) {
- _http = false;
- _many = false;
-
- add_hidden_options()
- ( "sleep" , po::value<int>() , "time to sleep between calls" )
- ;
- add_options()
- ("noheaders", "don't output column names")
- ("rowcount,n", po::value<int>()->default_value(0), "number of stats lines to print (0 for indefinite)")
- ("http", "use http instead of raw db connection")
- ("discover" , "discover nodes and display stats for all" )
- ("all" , "all optional fields" )
- ;
-
- addPositionArg( "sleep" , 1 );
-
+ Stat() : Tool() {
_autoreconnect = true;
}
- virtual void printExtraHelp( ostream & out ) {
- out << "View live MongoDB performance statistics.\n" << endl;
- out << "usage: " << _name << " [options] [sleep time]" << endl;
- out << "sleep time: time to wait (in seconds) between calls" << endl;
- }
-
- virtual void printExtraHelpAfter( ostream & out ) {
- out << "\n";
- out << " Fields\n";
- out << " inserts \t- # of inserts per second (* means replicated op)\n";
- out << " query \t- # of queries per second\n";
- out << " update \t- # of updates per second\n";
- out << " delete \t- # of deletes per second\n";
- out << " getmore \t- # of get mores (cursor batch) per second\n";
- out << " command \t- # of commands per second, on a slave its local|replicated\n";
- out << " flushes \t- # of fsync flushes per second\n";
- out << " mapped \t- amount of data mmaped (total data size) megabytes\n";
- out << " vsize \t- virtual size of process in megabytes\n";
- out << " res \t- resident size of process in megabytes\n";
- out << " faults \t- # of pages faults per sec\n";
- out << " locked \t- name of and percent time for most locked database\n";
- out << " idx miss \t- percent of btree page misses (sampled)\n";
- out << " qr|qw \t- queue lengths for clients waiting (read|write)\n";
- out << " ar|aw \t- active clients (read|write)\n";
- out << " netIn \t- network traffic in - bits\n";
- out << " netOut \t- network traffic out - bits\n";
- out << " conn \t- number of open connections\n";
- out << " set \t- replica set name\n";
- out << " repl \t- replication type \n";
- out << " \t PRI - primary (master)\n";
- out << " \t SEC - secondary\n";
- out << " \t REC - recovering\n";
- out << " \t UNK - unknown\n";
- out << " \t SLV - slave\n";
- out << " \t RTR - mongos process (\"router\")\n";
+ virtual void printHelp( ostream & out ) {
+ printMongoStatHelp(&out);
}
BSONObj stats() {
- if ( _http ) {
+ if (mongoStatGlobalParams.http) {
HttpClient c;
HttpClient::Result r;
string url;
{
stringstream ss;
- ss << "http://" << _host;
- if ( _host.find( ":" ) == string::npos )
+ ss << "http://" << toolGlobalParams.connectionString;
+ if (toolGlobalParams.connectionString.find( ":" ) == string::npos)
ss << ":28017";
ss << "/_status";
url = ss.str();
}
if ( c.get( url , &r ) != 200 ) {
- cout << "error (http): " << r.getEntireResponse() << endl;
+ toolError() << "error (http): " << r.getEntireResponse() << std::endl;
return BSONObj();
}
BSONObj x = fromjson( r.getBody() );
BSONElement e = x["serverStatus"];
if ( e.type() != Object ) {
- cout << "BROKEN: " << x << endl;
+ toolError() << "BROKEN: " << x << std::endl;
return BSONObj();
}
return e.embeddedObjectUserCheck();
}
BSONObj out;
- if ( ! conn().simpleCommand( _db , &out , "serverStatus" ) ) {
- cout << "error: " << out << endl;
+ if (!conn().simpleCommand(toolGlobalParams.db, &out, "serverStatus")) {
+ toolError() << "error: " << out << std::endl;
return BSONObj();
}
return out.getOwned();
}
-
- virtual void preSetup() {
- if ( hasParam( "http" ) ) {
- _http = true;
- _noconnection = true;
- }
-
- if ( hasParam( "host" ) &&
- getParam( "host" ).find( ',' ) != string::npos ) {
- _noconnection = true;
- _many = true;
- }
-
- if ( hasParam( "discover" ) ) {
- _many = true;
- }
- }
-
int run() {
- _statUtil.setSeconds( getParam( "sleep" , 1 ) );
- _statUtil.setAll( hasParam( "all" ) );
- if ( _many )
+ _statUtil.setAll(mongoStatGlobalParams.allFields);
+ _statUtil.setSeconds(mongoStatGlobalParams.sleep);
+ if (mongoStatGlobalParams.many)
return runMany();
return runNormal();
}
@@ -200,8 +144,6 @@ namespace mongo {
}
int runNormal() {
- bool showHeaders = ! hasParam( "noheaders" );
- int rowCount = getParam( "rowcount" , 0 );
int rowNum = 0;
BSONObj prev = stats();
@@ -209,15 +151,17 @@ namespace mongo {
return -1;
int maxLockedDbWidth = 0;
+ bool warned = false;
- while ( rowCount == 0 || rowNum < rowCount ) {
+ while (mongoStatGlobalParams.rowCount == 0 ||
+ rowNum < mongoStatGlobalParams.rowCount) {
sleepsecs((int)ceil(_statUtil.getSeconds()));
BSONObj now;
try {
now = stats();
}
catch ( std::exception& e ) {
- cout << "can't get data: " << e.what() << endl;
+ toolError() << "can't get data: " << e.what() << std::endl;
continue;
}
@@ -226,11 +170,16 @@ namespace mongo {
try {
+ if ( !warned && now["storageEngine"].type() ) {
+ toolError() << "warning: detected a 3.0 mongod, some columns not applicable" << endl;
+ warned = true;
+ }
+
BSONObj out = _statUtil.doRow( prev , now );
// adjust width up as longer 'locked db' values appear
setMaxLockedDbWidth( &out, &maxLockedDbWidth );
- if ( showHeaders && rowNum % 10 == 0 ) {
+ if (mongoStatGlobalParams.showHeaders && rowNum % 10 == 0) {
printHeaders( out );
}
@@ -238,9 +187,9 @@ namespace mongo {
}
catch ( AssertionException& e ) {
- cout << "\nerror: " << e.what() << "\n"
- << now
- << endl;
+ toolError() << "\nerror: " << e.what() << "\n"
+ << now
+ << std::endl;
}
prev = now;
@@ -287,8 +236,9 @@ namespace mongo {
static void serverThread( shared_ptr<ServerState> state , int sleepTime) {
try {
+ bool warned = false;
DBClientConnection conn( true );
- conn._logLevel = 1;
+ conn._logLevel = logger::LogSeverity::Debug(1);
string errmsg;
if ( ! conn.connect( state->host , errmsg ) )
state->error = errmsg;
@@ -308,19 +258,28 @@ namespace mongo {
state->now = out.getOwned();
}
else {
+ str::stream errorStream;
+ errorStream << "serverStatus failed";
+ BSONElement errorField = out["errmsg"];
+ if (errorField.type() == String)
+ errorStream << ": " << errorField.str();
scoped_lock lk( state->lock );
- state->error = "serverStatus failed";
+ state->error = errorStream;
state->lastUpdate = time(0);
}
+ if ( !warned && out["storageEngine"].type() ) {
+ toolError() << "warning: detected a 3.0 mongod, some columns not applicable" << endl;
+ warned = true;
+ }
if ( out["shardCursorType"].type() == Object ||
- out["process"].String() == "mongos" ) {
+ out["process"].str() == "mongos" ) {
state->mongos = true;
if ( cycleNumber % 10 == 1 ) {
auto_ptr<DBClientCursor> c = conn.query( ShardType::ConfigNS , BSONObj() );
vector<BSONObj> shards;
while ( c->more() ) {
- shards.push_back( c->next().getOwned() );
+ shards.push_back( c->nextSafe().getOwned() );
}
scoped_lock lk( state->lock );
state->shards = shards;
@@ -338,10 +297,11 @@ namespace mongo {
}
catch ( std::exception& e ) {
- cout << "serverThread (" << state->host << ") fatal error : " << e.what() << endl;
+ toolError() << "serverThread (" << state->host << ") fatal error : " << e.what()
+ << std::endl;
}
catch ( ... ) {
- cout << "serverThread (" << state->host << ") fatal error" << endl;
+ toolError() << "serverThread (" << state->host << ") fatal error" << std::endl;
}
}
@@ -358,10 +318,11 @@ namespace mongo {
state->thr.reset( new boost::thread( boost::bind( serverThread,
state,
(int)ceil(_statUtil.getSeconds()) ) ) );
- state->authParams = BSON( "user" << _username <<
- "pwd" << _password <<
- "userSource" << getAuthenticationDatabase() <<
- "mechanism" << _authenticationMechanism );
+ state->authParams = BSON(saslCommandUserFieldName << toolGlobalParams.username
+ << saslCommandPasswordFieldName << toolGlobalParams.password
+ << saslCommandUserDBFieldName << getAuthenticationDatabase()
+ << saslCommandMechanismFieldName
+ << toolGlobalParams.authenticationMechanism);
return true;
}
@@ -401,7 +362,7 @@ namespace mongo {
string errmsg;
ConnectionString cs = ConnectionString::parse( x["host"].String() , errmsg );
if ( errmsg.size() ) {
- cerr << errmsg << endl;
+ toolError() << errmsg << std::endl;
continue;
}
@@ -420,12 +381,13 @@ namespace mongo {
StateMap threads;
{
- string orig = getParam( "host" );
+ string orig = "localhost";
bool showPorts = false;
- if ( orig == "" )
- orig = "localhost";
+ if (toolGlobalParams.hostSet) {
+ orig = toolGlobalParams.host;
+ }
- if ( orig.find( ":" ) != string::npos || hasParam( "port" ) )
+ if (orig.find(":") != string::npos || toolGlobalParams.portSet)
showPorts = true;
StringSplitter ss( orig.c_str() , "," );
@@ -433,10 +395,14 @@ namespace mongo {
string host = ss.next();
if ( showPorts && host.find( ":" ) == string::npos) {
// port supplied, but not for this host. use default.
- if ( hasParam( "port" ) )
- host += ":" + _params["port"].as<string>();
- else
- host += ":27017";
+ StringBuilder sb;
+ if (toolGlobalParams.portSet) {
+ sb << host << ":" << toolGlobalParams.port;
+ }
+ else {
+ sb << host << ":27017";
+ }
+ host = sb.str();
}
_add( threads , host );
}
@@ -445,10 +411,9 @@ namespace mongo {
sleepsecs(1);
int row = 0;
- bool discover = hasParam( "discover" );
int maxLockedDbWidth = 0;
- while ( 1 ) {
+ while (mongoStatGlobalParams.rowCount == 0 || row < mongoStatGlobalParams.rowCount) {
sleepsecs( (int)ceil(_statUtil.getSeconds()) );
// collect data
@@ -467,7 +432,7 @@ namespace mongo {
rows.push_back( Row( i->first , out ) );
}
- if ( discover && ! i->second->now.isEmpty() ) {
+ if (mongoStatGlobalParams.discover && ! i->second->now.isEmpty()) {
if ( _discover( threads , i->first , i->second ) )
break;
}
@@ -528,7 +493,7 @@ namespace mongo {
cout << endl;
// header
- if ( row++ % 5 == 0 && ! biggest.isEmpty() ) {
+ if (row++ % 5 == 0 && mongoStatGlobalParams.showHeaders && !biggest.isEmpty()) {
cout << setw( longestHost ) << "" << "\t";
printHeaders( biggest );
}
@@ -550,8 +515,6 @@ namespace mongo {
}
StatUtil _statUtil;
- bool _http;
- bool _many;
struct Row {
Row( string h , string e ) {
@@ -572,11 +535,5 @@ namespace mongo {
BSONObj data;
};
};
-
-}
-
-int main( int argc , char ** argv, char ** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- mongo::Stat stat;
- return stat.main( argc , argv );
+ REGISTER_MONGO_TOOL(Stat);
}
diff --git a/src/mongo/tools/stat_util.cpp b/src/mongo/tools/stat_util.cpp
index 26d62434770..d8d7c51e74b 100644
--- a/src/mongo/tools/stat_util.cpp
+++ b/src/mongo/tools/stat_util.cpp
@@ -14,8 +14,22 @@
*
* 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
*/
+#include <iomanip>
+
#include "stat_util.h"
#include "mongo/util/mongoutils/str.h"
@@ -317,9 +331,11 @@ namespace mongo {
NamespaceInfo& s = stats[e.fieldName()];
s.ns = e.fieldName();
- BSONObj temp = e.Obj()["timeLockedMicros"].Obj();
- s.read = ( temp["r"].numberLong() + temp["R"].numberLong() ) / 1000;
- s.write = ( temp["w"].numberLong() + temp["W"].numberLong() ) / 1000;
+ if ( e.Obj()["timeLockedMicros"].isABSONObj() ){
+ BSONObj temp = e.Obj()["timeLockedMicros"].Obj();
+ s.read = ( temp["r"].numberLong() + temp["R"].numberLong() ) / 1000;
+ s.write = ( temp["w"].numberLong() + temp["W"].numberLong() ) / 1000;
+ }
}
return stats;
diff --git a/src/mongo/tools/stat_util.h b/src/mongo/tools/stat_util.h
index 98275ae988e..c0ba9bade37 100644
--- a/src/mongo/tools/stat_util.h
+++ b/src/mongo/tools/stat_util.h
@@ -14,6 +14,18 @@
*
* 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
*/
#pragma once
diff --git a/src/mongo/tools/tool.cpp b/src/mongo/tools/tool.cpp
index 2539e5cacb4..c5e63723bf9 100644
--- a/src/mongo/tools/tool.cpp
+++ b/src/mongo/tools/tool.cpp
@@ -12,6 +12,18 @@
*
* 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
*/
// Tool.cpp
@@ -22,132 +34,48 @@
#include <fstream>
#include <iostream>
-#include "pcrecpp.h"
-
+#include "mongo/base/initializer.h"
+#include "mongo/base/init.h"
#include "mongo/client/dbclient_rs.h"
#include "mongo/client/sasl_client_authenticate.h"
+#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_global.h"
+#include "mongo/db/auth/authz_manager_external_state_mock.h"
#include "mongo/db/json.h"
-#include "mongo/db/namespace_details.h"
+#include "mongo/db/structure/catalog/namespace_details.h"
+#include "mongo/db/storage_options.h"
#include "mongo/platform/posix_fadvise.h"
+#include "mongo/util/exception_filter_win32.h"
#include "mongo/util/file_allocator.h"
+#include "mongo/util/options_parser/option_section.h"
#include "mongo/util/password.h"
+#include "mongo/util/net/ssl_options.h"
+#include "mongo/util/text.h"
#include "mongo/util/version.h"
using namespace std;
using namespace mongo;
-namespace po = boost::program_options;
-
namespace mongo {
- CmdLine cmdLine;
-
- Tool::Tool( string name , DBAccess access , string defaultDB ,
- string defaultCollection , bool usesstdout ) :
- _name( name ) , _db( defaultDB ) , _coll( defaultCollection ) ,
- _usesstdout(usesstdout), _noconnection(false), _autoreconnect(false), _conn(0), _slaveConn(0), _paired(false) {
-
- _options = new po::options_description( "options" );
- _options->add_options()
- ("help","produce help message")
- ("verbose,v", "be more verbose (include multiple times for more verbosity e.g. -vvvvv)")
- ("version", "print the program's version and exit" )
- ;
-
- if ( access & REMOTE_SERVER )
- _options->add_options()
- ("host,h",po::value<string>(), "mongo host to connect to ( <set name>/s1,s2 for sets)" )
- ("port",po::value<string>(), "server port. Can also use --host hostname:port" )
- ("ipv6", "enable IPv6 support (disabled by default)")
-#ifdef MONGO_SSL
- ("ssl", "use SSL for all connections")
-#endif
-
- ("username,u",po::value<string>(), "username" )
- ("password,p", new PasswordValue( &_password ), "password" )
- ("authenticationDatabase",
- po::value<string>(&_authenticationDatabase)->default_value(""),
- "user source (defaults to dbname)" )
- ("authenticationMechanism",
- po::value<string>(&_authenticationMechanism)->default_value("MONGODB-CR"),
- "authentication mechanism")
- ;
-
- if ( access & LOCAL_SERVER )
- _options->add_options()
- ("dbpath",po::value<string>(), "directly access mongod database "
- "files in the given path, instead of connecting to a mongod "
- "server - needs to lock the data directory, so cannot be "
- "used if a mongod is currently accessing the same path" )
- ("directoryperdb", "each db is in a separate directly (relevant only if dbpath specified)" )
- ("journal", "enable journaling (relevant only if dbpath specified)" )
- ;
-
- if ( access & SPECIFY_DBCOL )
- _options->add_options()
- ("db,d",po::value<string>(), "database to use" )
- ("collection,c",po::value<string>(), "collection to use (some commands)" )
- ;
-
- _hidden_options = new po::options_description( name + " hidden options" );
-
- /* support for -vv -vvvv etc. */
- for (string s = "vv"; s.length() <= 10; s.append("v")) {
- _hidden_options->add_options()(s.c_str(), "verbose");
- }
- }
+ Tool::Tool() :
+ _autoreconnect(false), _conn(0), _slaveConn(0) { }
Tool::~Tool() {
- delete( _options );
- delete( _hidden_options );
if ( _conn )
delete _conn;
}
- void Tool::printHelp(ostream &out) {
- printExtraHelp(out);
- _options->print(out);
- printExtraHelpAfter(out);
+ MONGO_INITIALIZER(ToolAuthExternalState)(InitializerContext*) {
+ setGlobalAuthorizationManager(new AuthorizationManager(
+ new AuthzManagerExternalStateMock()));
+ return Status::OK();
}
- void Tool::printVersion(ostream &out) {
- out << _name << " version " << mongo::versionString;
- if (mongo::versionString[strlen(mongo::versionString)-1] == '-')
- out << " (commit " << mongo::gitVersion() << ")";
- out << endl;
- }
- int Tool::main( int argc , char ** argv ) {
+ int Tool::main( int argc , char ** argv, char ** envp ) {
static StaticObserver staticObserver;
- cmdLine.prealloc = false;
-
- // The default value may vary depending on compile options, but for tools
- // we want durability to be disabled.
- cmdLine.dur = false;
-
- _name = argv[0];
-
- /* using the same style as db.cpp */
- int command_line_style = (((po::command_line_style::unix_style ^
- po::command_line_style::allow_guessing) |
- po::command_line_style::allow_long_disguise) ^
- po::command_line_style::allow_sticky);
- try {
- po::options_description all_options("all options");
- all_options.add(*_options).add(*_hidden_options);
-
- po::store( po::command_line_parser( argc , argv ).
- options(all_options).
- positional( _positonalOptions ).
- style(command_line_style).run() , _params );
-
- po::notify( _params );
- }
- catch (po::error &e) {
- cerr << "ERROR: " << e.what() << endl << endl;
- printHelp(cerr);
- ::_exit(EXIT_BADOPTIONS);
- }
+ mongo::runGlobalInitializersOrDie(argc, argv, envp);
// hide password from ps output
for (int i=0; i < (argc-1); ++i) {
@@ -159,89 +87,46 @@ namespace mongo {
}
}
- if ( _params.count( "help" ) ) {
- printHelp(cout);
- ::_exit(0);
- }
-
- if ( _params.count( "version" ) ) {
- printVersion(cout);
- ::_exit(0);
- }
-
- if ( _params.count( "verbose" ) ) {
- logLevel = 1;
- }
-
- for (string s = "vv"; s.length() <= 10; s.append("v")) {
- if (_params.count(s)) {
- logLevel = s.length();
- }
- }
-
-
-#ifdef MONGO_SSL
- if (_params.count("ssl")) {
- mongo::cmdLine.sslOnNormalPorts = true;
- }
-#endif
-
- preSetup();
-
- bool useDirectClient = hasParam( "dbpath" );
-
- if ( ! useDirectClient ) {
- _host = "127.0.0.1";
- if ( _params.count( "host" ) )
- _host = _params["host"].as<string>();
-
- if ( _params.count( "port" ) )
- _host += ':' + _params["port"].as<string>();
-
- if ( _noconnection ) {
+ if (!toolGlobalParams.useDirectClient) {
+ if (toolGlobalParams.noconnection) {
// do nothing
}
else {
string errmsg;
- ConnectionString cs = ConnectionString::parse( _host , errmsg );
+ ConnectionString cs = ConnectionString::parse(toolGlobalParams.connectionString,
+ errmsg);
if ( ! cs.isValid() ) {
- cerr << "invalid hostname [" << _host << "] " << errmsg << endl;
+ toolError() << "invalid hostname [" << toolGlobalParams.connectionString << "] "
+ << errmsg << std::endl;
::_exit(-1);
}
_conn = cs.connect( errmsg );
if ( ! _conn ) {
- cerr << "couldn't connect to [" << _host << "] " << errmsg << endl;
+ toolError() << "couldn't connect to [" << toolGlobalParams.connectionString
+ << "] " << errmsg << std::endl;
::_exit(-1);
}
- (_usesstdout ? cout : cerr ) << "connected to: " << _host << endl;
+ toolInfoOutput() << "connected to: " << toolGlobalParams.connectionString
+ << std::endl;
}
}
else {
- if ( _params.count( "directoryperdb" ) ) {
- directoryperdb = true;
- }
verify( lastError.get( true ) );
- if (_params.count("journal")){
- cmdLine.dur = true;
- }
-
Client::initThread("tools");
_conn = new DBDirectClient();
- _host = "DIRECT";
- static string myDbpath = getParam( "dbpath" );
- dbpath = myDbpath.c_str();
+ storageGlobalParams.dbpath = toolGlobalParams.dbpath;
try {
acquirePathLock();
}
catch ( DBException& ) {
- cerr << endl << "If you are running a mongod on the same "
- "path you should connect to that instead of direct data "
- "file access" << endl << endl;
+ toolError() << std::endl << "If you are running a mongod on the same "
+ "path you should connect to that instead of direct data "
+ "file access" << std::endl << std::endl;
dbexit( EXIT_FS );
::_exit(EXIT_FAILURE);
}
@@ -251,31 +136,14 @@ namespace mongo {
dur::startup();
}
- if ( _params.count( "db" ) )
- _db = _params["db"].as<string>();
-
- if ( _params.count( "collection" ) )
- _coll = _params["collection"].as<string>();
-
- if ( _params.count( "username" ) )
- _username = _params["username"].as<string>();
-
- if ( _params.count( "password" )
- && ( _password.empty() ) ) {
- _password = askPassword();
- }
-
- if (_params.count("ipv6"))
- enableIPv6();
-
int ret = -1;
try {
- if (!useDirectClient && !_noconnection)
+ if (!toolGlobalParams.useDirectClient && !toolGlobalParams.noconnection)
auth();
ret = run();
}
catch ( DBException& e ) {
- cerr << "assertion: " << e.toString() << endl;
+ toolError() << "assertion: " << e.toString() << std::endl;
ret = -1;
}
catch(const boost::filesystem::filesystem_error &fse) {
@@ -301,7 +169,7 @@ namespace mongo {
printHelp(cerr);
else
#endif // _WIN32
- cerr << "error: " << fse.what() << endl;
+ toolError() << "error: " << fse.what() << std::endl;
ret = -1;
}
@@ -309,7 +177,7 @@ namespace mongo {
if ( currentClient.get() )
currentClient.get()->shutdown();
- if ( useDirectClient )
+ if (toolGlobalParams.useDirectClient)
dbexit( EXIT_CLEAN );
fflush(stdout);
@@ -329,7 +197,7 @@ namespace mongo {
}
bool Tool::isMaster() {
- if ( hasParam("dbpath") ) {
+ if (toolGlobalParams.useDirectClient) {
return true;
}
@@ -338,8 +206,9 @@ namespace mongo {
bool ok = conn().isMaster(isMaster, &info);
if (ok && !isMaster) {
- cerr << "ERROR: trying to write to non-master " << conn().toString() << endl;
- cerr << "isMaster info: " << info << endl;
+ toolError() << "ERROR: trying to write to non-master " << conn().toString()
+ << std::endl;
+ toolError() << "isMaster info: " << info << std::endl;
return false;
}
@@ -353,66 +222,13 @@ namespace mongo {
return isdbgrid["isdbgrid"].trueValue();
}
- void Tool::addFieldOptions() {
- add_options()
- ("fields,f" , po::value<string>() , "comma separated list of field names e.g. -f name,age" )
- ("fieldFile" , po::value<string>() , "file with fields names - 1 per line" )
- ;
- }
-
- void Tool::needFields() {
-
- if ( hasParam( "fields" ) ) {
- BSONObjBuilder b;
-
- string fields_arg = getParam("fields");
- pcrecpp::StringPiece input(fields_arg);
-
- string f;
- pcrecpp::RE re("([#\\w\\.\\s\\-]+),?" );
- while ( re.Consume( &input, &f ) ) {
- _fields.push_back( f );
- b.append( f , 1 );
- }
-
- _fieldsObj = b.obj();
- return;
- }
-
- if ( hasParam( "fieldFile" ) ) {
- string fn = getParam( "fieldFile" );
- if ( ! boost::filesystem::exists( fn ) )
- throw UserException( 9999 , ((string)"file: " + fn ) + " doesn't exist" );
-
- const int BUF_SIZE = 1024;
- char line[ 1024 + 128];
- ifstream file( fn.c_str() );
-
- BSONObjBuilder b;
- while ( file.rdstate() == ios_base::goodbit ) {
- file.getline( line , BUF_SIZE );
- const char * cur = line;
- while ( isspace( cur[0] ) ) cur++;
- if ( cur[0] == '\0' )
- continue;
-
- _fields.push_back( cur );
- b.append( cur , 1 );
- }
- _fieldsObj = b.obj();
- return;
- }
-
- throw UserException( 9998 , "you need to specify fields" );
- }
-
std::string Tool::getAuthenticationDatabase() {
- if (!_authenticationDatabase.empty()) {
- return _authenticationDatabase;
+ if (!toolGlobalParams.authenticationDatabase.empty()) {
+ return toolGlobalParams.authenticationDatabase;
}
- if (!_db.empty()) {
- return _db;
+ if (!toolGlobalParams.db.empty()) {
+ return toolGlobalParams.db;
}
return "admin";
@@ -423,10 +239,10 @@ namespace mongo {
*/
void Tool::auth() {
- if ( _username.empty() ) {
+ if (toolGlobalParams.username.empty()) {
// Make sure that we don't need authentication to connect to this db
// findOne throws an AssertionException if it's not authenticated.
- if (_coll.size() > 0) {
+ if (toolGlobalParams.coll.size() > 0) {
// BSONTools don't have a collection
conn().findOne(getNS(), Query("{}"), 0, QueryOption_SlaveOk);
}
@@ -434,49 +250,51 @@ namespace mongo {
return;
}
- _conn->auth( BSON( saslCommandPrincipalSourceFieldName << getAuthenticationDatabase() <<
- saslCommandPrincipalFieldName << _username <<
- saslCommandPasswordFieldName << _password <<
- saslCommandMechanismFieldName << _authenticationMechanism ) );
- }
+ BSONObjBuilder authParams;
+ authParams <<
+ saslCommandUserDBFieldName << getAuthenticationDatabase() <<
+ saslCommandUserFieldName << toolGlobalParams.username <<
+ saslCommandPasswordFieldName << toolGlobalParams.password <<
+ saslCommandMechanismFieldName <<
+ toolGlobalParams.authenticationMechanism;
- BSONTool::BSONTool( const char * name, DBAccess access , bool objcheck )
- : Tool( name , access , "" , "" , false ) , _objcheck( objcheck ) {
+ if (!toolGlobalParams.gssapiServiceName.empty()) {
+ authParams << saslCommandServiceNameFieldName << toolGlobalParams.gssapiServiceName;
+ }
- add_options()
- ("objcheck" , "validate object before inserting (default)" )
- ("noobjcheck" , "don't validate object before inserting" )
- ("filter" , po::value<string>() , "filter to apply before inserting" )
- ;
+ if (!toolGlobalParams.gssapiHostName.empty()) {
+ authParams << saslCommandServiceHostnameFieldName << toolGlobalParams.gssapiHostName;
+ }
+
+ _conn->auth(authParams.obj());
}
+ BSONTool::BSONTool() : Tool() { }
int BSONTool::run() {
- if ( hasParam( "objcheck" ) )
- _objcheck = true;
- else if ( hasParam( "noobjcheck" ) )
- _objcheck = false;
- if ( hasParam( "filter" ) )
- _matcher.reset( new Matcher( fromjson( getParam( "filter" ) ) ) );
+ if (bsonToolGlobalParams.hasFilter) {
+ _matcher.reset(new Matcher(fromjson(bsonToolGlobalParams.filter)));
+ }
return doRun();
}
long long BSONTool::processFile( const boost::filesystem::path& root ) {
- _fileName = root.string();
+ std::string fileName = root.string();
unsigned long long fileLength = file_size( root );
if ( fileLength == 0 ) {
- out() << "file " << _fileName << " empty, skipping" << endl;
+ toolInfoOutput() << "file " << fileName << " empty, skipping" << std::endl;
return 0;
}
- FILE* file = fopen( _fileName.c_str() , "rb" );
+ FILE* file = fopen( fileName.c_str() , "rb" );
if ( ! file ) {
- log() << "error opening file: " << _fileName << " " << errnoWithDescription() << endl;
+ toolError() << "error opening file: " << fileName << " " << errnoWithDescription()
+ << std::endl;
return 0;
}
@@ -484,7 +302,9 @@ namespace mongo {
posix_fadvise(fileno(file), 0, fileLength, POSIX_FADV_SEQUENTIAL);
#endif
- LOG(1) << "\t file size: " << fileLength << endl;
+ if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) {
+ toolInfoOutput() << "\t file size: " << fileLength << std::endl;
+ }
unsigned long long read = 0;
unsigned long long num = 0;
@@ -494,8 +314,10 @@ namespace mongo {
boost::scoped_array<char> buf_holder(new char[BUF_SIZE]);
char * buf = buf_holder.get();
- ProgressMeter m( fileLength );
- m.setUnits( "bytes" );
+ ProgressMeter m(fileLength);
+ if (!toolGlobalParams.quiet) {
+ m.setUnits( "bytes" );
+ }
while ( read < fileLength ) {
size_t amt = fread(buf, 1, 4, file);
@@ -508,24 +330,27 @@ namespace mongo {
verify( amt == (size_t)( size - 4 ) );
BSONObj o( buf );
- if ( _objcheck && ! o.valid() ) {
- cerr << "INVALID OBJECT - going try and pring out " << endl;
- cerr << "size: " << size << endl;
- BSONObjIterator i(o);
- while ( i.more() ) {
- BSONElement e = i.next();
+ if (bsonToolGlobalParams.objcheck) {
+ const Status status = validateBSON(buf, size);
+ if (!status.isOK()) {
+ toolError() << "INVALID OBJECT - going to try and print out " << std::endl;
+ toolError() << "size: " << size << std::endl;
+ toolError() << "error: " << status.reason() << std::endl;
+
+ StringBuilder sb;
try {
- e.validate();
+ o.toString(sb); // using StringBuilder version to get as much as possible
+ } catch (...) {
+ toolError() << "object up to error: " << sb.str() << endl;
+ throw;
}
- catch ( ... ) {
- cerr << "\t\t NEXT ONE IS INVALID" << endl;
- }
- cerr << "\t name : " << e.fieldName() << " " << e.type() << endl;
- cerr << "\t " << e << endl;
+ toolError() << "complete object: " << sb.str() << endl;
+
+ // NOTE: continuing with object even though we know it is invalid.
}
}
- if ( _matcher.get() == 0 || _matcher->matches( o ) ) {
+ if (!bsonToolGlobalParams.hasFilter || _matcher->matches(o)) {
gotObject( o );
processed++;
}
@@ -533,16 +358,39 @@ namespace mongo {
read += o.objsize();
num++;
- m.hit( o.objsize() );
+ if (!toolGlobalParams.quiet) {
+ m.hit(o.objsize());
+ }
}
fclose( file );
- uassert( 10265 , "counts don't match" , m.done() == fileLength );
- (_usesstdout ? cout : cerr ) << m.hits() << " objects found" << endl;
- if ( _matcher.get() )
- (_usesstdout ? cout : cerr ) << processed << " objects processed" << endl;
+ uassert(10265, "counts don't match", read == fileLength);
+ toolInfoOutput() << num << " objects found" << std::endl;
+ if (bsonToolGlobalParams.hasFilter)
+ toolInfoOutput() << processed << " objects processed" << std::endl;
return processed;
}
}
+
+#if defined(_WIN32)
+// In Windows, wmain() is an alternate entry point for main(), and receives the same parameters
+// as main() but encoded in Windows Unicode (UTF-16); "wide" 16-bit wchar_t characters. The
+// WindowsCommandLine object converts these wide character strings to a UTF-8 coded equivalent
+// and makes them available through the argv() and envp() members. This enables toolMain()
+// to process UTF-8 encoded arguments and environment variables without regard to platform.
+int wmain(int argc, wchar_t* argvW[], wchar_t* envpW[]) {
+ setWindowsUnhandledExceptionFilter();
+ mongo::WindowsCommandLine wcl(argc, argvW, envpW);
+ auto_ptr<Tool> instance = (*Tool::createInstance)();
+ int exitCode = instance->main(argc, wcl.argv(), wcl.envp());
+ ::_exit(exitCode);
+}
+
+#else
+int main(int argc, char* argv[], char** envp) {
+ auto_ptr<Tool> instance = (*Tool::createInstance)();
+ ::_exit(instance->main(argc, argv, envp));
+}
+#endif
diff --git a/src/mongo/tools/tool.h b/src/mongo/tools/tool.h
index 2e7b0823d62..e5b627845bb 100644
--- a/src/mongo/tools/tool.h
+++ b/src/mongo/tools/tool.h
@@ -12,6 +12,18 @@
*
* 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
*/
// Tool.h
@@ -20,14 +32,15 @@
#include <string>
-#include <boost/program_options.hpp>
-
#if defined(_WIN32)
#include <io.h>
#endif
-#include "db/instance.h"
-#include "db/matcher.h"
+#include "mongo/db/instance.h"
+#include "mongo/db/matcher.h"
+#include "mongo/tools/tool_logger.h"
+#include "mongo/tools/tool_options.h"
+#include "mongo/util/options_parser/environment.h"
using std::string;
@@ -35,122 +48,50 @@ namespace mongo {
class Tool {
public:
- enum DBAccess {
- NONE = 0 ,
- REMOTE_SERVER = 1 << 1 ,
- LOCAL_SERVER = 1 << 2 ,
- SPECIFY_DBCOL = 1 << 3 ,
- ALL = REMOTE_SERVER | LOCAL_SERVER | SPECIFY_DBCOL
- };
-
- Tool( string name , DBAccess access=ALL, string defaultDB="test" ,
- string defaultCollection="", bool usesstdout=true);
+ Tool();
virtual ~Tool();
- int main( int argc , char ** argv );
-
- boost::program_options::options_description_easy_init add_options() {
- return _options->add_options();
- }
- boost::program_options::options_description_easy_init add_hidden_options() {
- return _hidden_options->add_options();
- }
- void addPositionArg( const char * name , int pos ) {
- _positonalOptions.add( name , pos );
- }
+ static auto_ptr<Tool> (*createInstance)();
- string getParam( string name , string def="" ) {
- if ( _params.count( name ) )
- return _params[name.c_str()].as<string>();
- return def;
- }
- int getParam( string name , int def ) {
- if ( _params.count( name ) )
- return _params[name.c_str()].as<int>();
- return def;
- }
- bool hasParam( string name ) {
- return _params.count( name );
- }
+ int main( int argc , char ** argv, char ** envp );
string getNS() {
- if ( _coll.size() == 0 ) {
+ if (toolGlobalParams.coll.size() == 0) {
cerr << "no collection specified!" << endl;
throw -1;
}
- return _db + "." + _coll;
+ return toolGlobalParams.db + "." + toolGlobalParams.coll;
}
string getAuthenticationDatabase();
- void useStandardOutput( bool mode ) {
- _usesstdout = mode;
- }
-
bool isMaster();
bool isMongos();
-
- virtual void preSetup() {}
virtual int run() = 0;
- virtual void printHelp(ostream &out);
-
- virtual void printExtraHelp( ostream & out ) {}
- virtual void printExtraHelpAfter( ostream & out ) {}
-
- virtual void printVersion(ostream &out);
+ virtual void printHelp(ostream &out) = 0;
protected:
mongo::DBClientBase &conn( bool slaveIfPaired = false );
- string _name;
-
- string _db;
- string _coll;
- string _fileName;
-
- string _username;
- string _password;
- string _authenticationDatabase;
- string _authenticationMechanism;
-
- bool _usesstdout;
- bool _noconnection;
bool _autoreconnect;
- void addFieldOptions();
- void needFields();
-
- vector<string> _fields;
- BSONObj _fieldsObj;
-
-
- string _host;
-
protected:
mongo::DBClientBase * _conn;
mongo::DBClientBase * _slaveConn;
- bool _paired;
-
- boost::program_options::options_description * _options;
- boost::program_options::options_description * _hidden_options;
- boost::program_options::positional_options_description _positonalOptions;
-
- boost::program_options::variables_map _params;
private:
void auth();
};
class BSONTool : public Tool {
- bool _objcheck;
auto_ptr<Matcher> _matcher;
public:
- BSONTool( const char * name , DBAccess access=ALL, bool objcheck = true );
+ BSONTool();
virtual int doRun() = 0;
virtual void gotObject( const BSONObj& obj ) = 0;
@@ -162,3 +103,7 @@ namespace mongo {
};
}
+
+#define REGISTER_MONGO_TOOL(TYPENAME) \
+ auto_ptr<Tool> createInstanceOfThisTool() {return auto_ptr<Tool>(new TYPENAME());} \
+ auto_ptr<Tool> (*Tool::createInstance)() = createInstanceOfThisTool;
diff --git a/src/mongo/tools/tool_logger.cpp b/src/mongo/tools/tool_logger.cpp
new file mode 100644
index 00000000000..fd906ef18d1
--- /dev/null
+++ b/src/mongo/tools/tool_logger.cpp
@@ -0,0 +1,144 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/tools/tool_logger.h"
+
+#include <iostream>
+
+#include "mongo/base/init.h"
+#include "mongo/logger/console_appender.h"
+#include "mongo/logger/log_manager.h"
+#include "mongo/logger/logger.h"
+#include "mongo/logger/message_event.h"
+#include "mongo/logger/message_event_utf8_encoder.h"
+#include "mongo/tools/tool_options.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+namespace {
+
+ /*
+ * Theory of operation:
+ *
+ * At process start, the loader initializes "consoleMutex" to NULL. At some point during static
+ * initialization, the static initialization process, running in the one and only extant thread,
+ * allocates a new boost::mutex on the heap and assigns consoleMutex to point to it. While
+ * consoleMutex is still NULL, we know that there is only one thread extant, so it is safe to
+ * skip locking the consoleMutex in the ErrorConsole constructor. Once the mutex is initialized,
+ * users of ErrorConsole can start acquiring it.
+ */
+
+ boost::mutex *consoleMutex = new boost::mutex;
+
+} // namespace
+
+ ErrorConsole::ErrorConsole() : _consoleLock() {
+ if (consoleMutex) {
+ boost::unique_lock<boost::mutex> lk(*consoleMutex);
+ lk.swap(_consoleLock);
+ }
+ }
+
+ std::ostream& ErrorConsole::out() { return std::cerr; }
+
+namespace {
+
+ logger::MessageLogDomain* toolErrorOutput = NULL;
+ logger::MessageLogDomain* toolNonErrorOutput = NULL;
+ logger::MessageLogDomain* toolNonErrorDecoratedOutput = NULL;
+
+} // namespace
+
+MONGO_INITIALIZER_GENERAL(ToolLogRedirection,
+ ("GlobalLogManager", "EndStartupOptionHandling"),
+ ("default"))(InitializerContext*) {
+
+ using logger::MessageEventEphemeral;
+ using logger::MessageEventDetailsEncoder;
+ using logger::MessageLogDomain;
+ using logger::ConsoleAppender;
+
+ toolErrorOutput = logger::globalLogManager()->getNamedDomain("toolErrorOutput");
+ toolNonErrorOutput = logger::globalLogManager()->getNamedDomain("toolNonErrorOutput");
+ toolNonErrorDecoratedOutput =
+ logger::globalLogManager()->getNamedDomain("toolNonErrorDecoratedOutput");
+
+ // Errors in the tools always go to stderr
+ toolErrorOutput->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
+ new logger::MessageEventUnadornedEncoder)));
+
+ // If we are outputting data to stdout, we may need to redirect all logging to stderr
+ if (!toolGlobalParams.canUseStdout) {
+ logger::globalLogDomain()->clearAppenders();
+ logger::globalLogDomain()->attachAppender(MessageLogDomain::AppenderAutoPtr(
+ new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
+ new MessageEventDetailsEncoder)));
+ }
+
+ // Only put an appender on our informational messages if we did not use --quiet
+ if (!toolGlobalParams.quiet) {
+ if (toolGlobalParams.canUseStdout) {
+ // If we can use stdout, we can use the ConsoleAppender with the default console
+ toolNonErrorOutput->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new ConsoleAppender<MessageEventEphemeral>(
+ new logger::MessageEventUnadornedEncoder)));
+
+ toolNonErrorDecoratedOutput->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new ConsoleAppender<MessageEventEphemeral>(
+ new logger::MessageEventDetailsEncoder)));
+ }
+ else {
+ // If we cannot use stdout, we have to use ErrorConsole to redirect informational
+ // messages to stderr
+ toolNonErrorOutput->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
+ new logger::MessageEventUnadornedEncoder)));
+
+ toolNonErrorDecoratedOutput->attachAppender(
+ MessageLogDomain::AppenderAutoPtr(
+ new ConsoleAppender<MessageEventEphemeral, ErrorConsole>(
+ new logger::MessageEventDetailsEncoder)));
+ }
+ }
+
+ return Status::OK();
+}
+
+ LogstreamBuilder toolInfoLog() {
+ return LogstreamBuilder(toolNonErrorDecoratedOutput,
+ "",
+ logger::LogSeverity::Log());
+ }
+
+ LogstreamBuilder toolInfoOutput() {
+ return LogstreamBuilder(toolNonErrorOutput,
+ "",
+ logger::LogSeverity::Log());
+ }
+
+ LogstreamBuilder toolError() {
+ return LogstreamBuilder(toolErrorOutput,
+ "",
+ logger::LogSeverity::Log());
+ }
+
+} // namespace mongo
diff --git a/src/mongo/tools/tool_logger.h b/src/mongo/tools/tool_logger.h
new file mode 100644
index 00000000000..6aac6217281
--- /dev/null
+++ b/src/mongo/tools/tool_logger.h
@@ -0,0 +1,58 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <boost/thread/mutex.hpp>
+#include <iosfwd>
+
+#include "mongo/logger/logstream_builder.h"
+
+namespace mongo {
+
+ /**
+ * This is a version of the Console class that uses stderr for output instead of stdout. See
+ * the description of the Console class for other details about how this class should operate
+ */
+ class ErrorConsole {
+ public:
+ ErrorConsole();
+
+ std::ostream& out();
+
+ private:
+ boost::unique_lock<boost::mutex> _consoleLock;
+ };
+
+ using logger::LogstreamBuilder;
+
+ /*
+ * Informational messages. Messages sent here will go to stdout normally, stderr if data is
+ * being sent to stdout, and be silenced if the user specifies --quiet.
+ */
+ LogstreamBuilder toolInfoOutput();
+ /*
+ * Informational messages. Messages sent here will go to stdout normally, stderr if data is
+ * being sent to stdout, and be silenced if the user specifies --quiet. Incudes extra log
+ * decoration.
+ */
+ LogstreamBuilder toolInfoLog();
+ /*
+ * Error messages. Messages sent here should always go to stderr and not be silenced by
+ * --quiet.
+ */
+ LogstreamBuilder toolError();
+
+} // namespace mongo
diff --git a/src/mongo/tools/tool_options.cpp b/src/mongo/tools/tool_options.cpp
new file mode 100644
index 00000000000..9aae245339e
--- /dev/null
+++ b/src/mongo/tools/tool_options.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#include "mongo/tools/tool_options.h"
+
+#include <boost/filesystem/operations.hpp>
+#include <fstream>
+#include "pcrecpp.h"
+
+#include "mongo/base/status.h"
+#include "mongo/client/sasl_client_authenticate.h"
+#include "mongo/db/storage_options.h"
+#include "mongo/util/log.h"
+#include "mongo/util/net/sock.h"
+#include "mongo/util/net/ssl_manager.h"
+#include "mongo/util/net/ssl_options.h"
+#include "mongo/util/options_parser/startup_options.h"
+#include "mongo/util/password.h"
+#include "mongo/util/text.h"
+#include "mongo/util/version.h"
+
+namespace mongo {
+
+ ToolGlobalParams toolGlobalParams;
+ BSONToolGlobalParams bsonToolGlobalParams;
+
+ Status addGeneralToolOptions(moe::OptionSection* options) {
+ options->addOptionChaining("help", "help", moe::Switch, "produce help message");
+
+ options->addOptionChaining("verbose", "verbose,v", moe::Switch,
+ "be more verbose (include multiple times "
+ "for more verbosity e.g. -vvvvv)");
+
+ options->addOptionChaining("quiet", "quiet", moe::Switch,
+ "silence all non error diagnostic messages");
+
+ options->addOptionChaining("version", "version", moe::Switch,
+ "print the program's version and exit");
+
+
+ /* support for -vv -vvvv etc. */
+ for (string s = "vv"; s.length() <= 10; s.append("v")) {
+ options->addOptionChaining(s.c_str(), s.c_str(), moe::Switch, "verbose")
+ .hidden();
+ }
+
+ return Status::OK();
+ }
+
+ Status addRemoteServerToolOptions(moe::OptionSection* options) {
+ options->addOptionChaining("host", "host,h", moe::String,
+ "mongo host to connect to ( <set name>/s1,s2 for sets)");
+
+ options->addOptionChaining("port", "port", moe::Int,
+ "server port. Can also use --host hostname:port")
+ .validRange(0, 65535);
+
+ options->addOptionChaining("ipv6", "ipv6", moe::Switch,
+ "enable IPv6 support (disabled by default)");
+
+
+#ifdef MONGO_SSL
+ Status ret = addSSLClientOptions(options);
+ if (!ret.isOK()) {
+ return ret;
+ }
+#endif
+
+ options->addOptionChaining("username", "username,u", moe::String,
+ "username");
+
+ // We ask a user for a password if they pass in an empty string or pass --password with no
+ // argument. This must be handled when the password value is checked.
+ //
+ // Desired behavior:
+ // --username test // Continue with username "test" and no password
+ // --username test --password test // Continue with username "test" and password "test"
+ // --username test --password // Continue with username "test" and prompt for password
+ // --username test --password "" // Continue with username "test" and prompt for password
+ //
+ // To do this we pass moe::Value(std::string("")) as the "implicit value" of this option
+ options->addOptionChaining("password", "password,p", moe::String, "password")
+ .setImplicit(moe::Value(std::string("")));
+
+ options->addOptionChaining("authenticationDatabase", "authenticationDatabase", moe::String,
+ "user source (defaults to dbname)")
+ .setDefault(moe::Value(std::string("")));
+
+ options->addOptionChaining("authenticationMechanism", "authenticationMechanism",
+ moe::String, "authentication mechanism")
+ .setDefault(moe::Value(std::string("MONGODB-CR")));
+
+ options->addOptionChaining("gssapiServiceName", "gssapiServiceName",
+ moe::String,
+ "Service name to use when authenticating using GSSAPI/Kerberos")
+ .setDefault(moe::Value(std::string(saslDefaultServiceName)));
+
+ options->addOptionChaining("gssapiHostName", "gssapiHostName", moe::String,
+ "Remote host name to use for purpose of GSSAPI/Kerberos authentication");
+
+ return Status::OK();
+ }
+
+ Status addLocalServerToolOptions(moe::OptionSection* options) {
+ options->addOptionChaining("dbpath", "dbpath", moe::String,
+ "directly access mongod database files in the given path, instead of "
+ "connecting to a mongod server - needs to lock the data directory, "
+ "so cannot be used if a mongod is currently accessing the same path");
+
+ options->addOptionChaining("directoryperdb", "directoryperdb", moe::Switch,
+ "each db is in a separate directory (relevant only if dbpath specified)");
+
+ options->addOptionChaining("journal", "journal", moe::Switch,
+ "enable journaling (relevant only if dbpath specified)");
+
+
+ return Status::OK();
+ }
+ Status addSpecifyDBCollectionToolOptions(moe::OptionSection* options) {
+ options->addOptionChaining("db", "db,d", moe::String, "database to use");
+
+ options->addOptionChaining("collection", "collection,c", moe::String,
+ "collection to use (some commands)");
+
+
+ return Status::OK();
+ }
+
+ Status addFieldOptions(moe::OptionSection* options) {
+ options->addOptionChaining("fields", "fields,f", moe::String,
+ "comma separated list of field names e.g. -f name,age");
+
+ options->addOptionChaining("fieldFile", "fieldFile", moe::String,
+ "file with field names - 1 per line");
+
+
+ return Status::OK();
+ }
+
+ Status addBSONToolOptions(moe::OptionSection* options) {
+ options->addOptionChaining("objcheck", "objcheck", moe::Switch,
+ "validate object before inserting (default)");
+
+ options->addOptionChaining("noobjcheck", "noobjcheck", moe::Switch,
+ "don't validate object before inserting");
+
+ options->addOptionChaining("filter", "filter", moe::String,
+ "filter to apply before inserting");
+
+
+ return Status::OK();
+ }
+
+ std::string getParam(std::string name, std::string def) {
+ if (moe::startupOptionsParsed.count(name)) {
+ return moe::startupOptionsParsed[name.c_str()].as<string>();
+ }
+ return def;
+ }
+ int getParam(std::string name, int def) {
+ if (moe::startupOptionsParsed.count(name)) {
+ return moe::startupOptionsParsed[name.c_str()].as<int>();
+ }
+ return def;
+ }
+ bool hasParam(std::string name) {
+ return moe::startupOptionsParsed.count(name);
+ }
+
+ void printToolVersionString(std::ostream &out) {
+ out << toolGlobalParams.name << " version " << mongo::versionString;
+ if (mongo::versionString[strlen(mongo::versionString)-1] == '-')
+ out << " (commit " << mongo::gitVersion() << ")";
+ out << std::endl;
+ }
+
+ bool handlePreValidationGeneralToolOptions(const moe::Environment& params) {
+ if (moe::startupOptionsParsed.count("version")) {
+ printToolVersionString(std::cout);
+ return false;
+ }
+ return true;
+ }
+
+ extern bool directoryperdb;
+
+ Status storeGeneralToolOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+
+ toolGlobalParams.name = args[0];
+
+ storageGlobalParams.prealloc = false;
+
+ // The default value may vary depending on compile options, but for tools
+ // we want durability to be disabled.
+ storageGlobalParams.dur = false;
+
+ // Set authentication parameters
+ if (params.count("authenticationDatabase")) {
+ toolGlobalParams.authenticationDatabase =
+ params["authenticationDatabase"].as<string>();
+ }
+
+ if (params.count("authenticationMechanism")) {
+ toolGlobalParams.authenticationMechanism =
+ params["authenticationMechanism"].as<string>();
+ }
+
+ if (params.count("gssapiServiceName")) {
+ toolGlobalParams.gssapiServiceName = params["gssapiServiceName"].as<string>();
+ }
+
+ if (params.count("gssapiHostName")) {
+ toolGlobalParams.gssapiHostName = params["gssapiHostName"].as<string>();
+ }
+ if (params.count("verbose")) {
+ logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(1));
+ }
+
+ for (string s = "vv"; s.length() <= 12; s.append("v")) {
+ if (params.count(s)) {
+ logger::globalLogDomain()->setMinimumLoggedSeverity(
+ logger::LogSeverity::Debug(s.length()));
+ }
+ }
+
+ toolGlobalParams.quiet = params.count("quiet");
+
+#ifdef MONGO_SSL
+ Status ret = storeSSLClientOptions(params);
+ if (!ret.isOK()) {
+ return ret;
+ }
+#endif
+
+ if (args.empty()) {
+ return Status(ErrorCodes::InternalError, "Cannot get binary name: argv array is empty");
+ }
+
+ // setup binary name
+ toolGlobalParams.name = args[0];
+ size_t i = toolGlobalParams.name.rfind('/');
+ if (i != string::npos) {
+ toolGlobalParams.name = toolGlobalParams.name.substr(i + 1);
+ }
+ toolGlobalParams.db = "test";
+ toolGlobalParams.coll = "";
+ toolGlobalParams.noconnection = false;
+
+ if (params.count("db"))
+ toolGlobalParams.db = params["db"].as<string>();
+
+ if (params.count("collection"))
+ toolGlobalParams.coll = params["collection"].as<string>();
+
+ if (params.count("username"))
+ toolGlobalParams.username = params["username"].as<string>();
+
+ if (params.count("password")) {
+ toolGlobalParams.password = params["password"].as<string>();
+ if (toolGlobalParams.password.empty()) {
+ toolGlobalParams.password = askPassword();
+ }
+ }
+
+ if (params.count("ipv6")) {
+ enableIPv6();
+ }
+
+ toolGlobalParams.dbpath = getParam("dbpath");
+ toolGlobalParams.useDirectClient = hasParam("dbpath");
+ if (toolGlobalParams.useDirectClient && params.count("journal")) {
+ storageGlobalParams.dur = true;
+ }
+
+ if (!toolGlobalParams.useDirectClient) {
+ toolGlobalParams.connectionString = "127.0.0.1";
+ if (params.count("host")) {
+ toolGlobalParams.hostSet = true;
+ toolGlobalParams.host = params["host"].as<string>();
+ toolGlobalParams.connectionString = params["host"].as<string>();
+ }
+
+ if (params.count("port")) {
+ toolGlobalParams.portSet = true;
+ toolGlobalParams.port = params["port"].as<int>();
+ StringBuilder sb;
+ sb << toolGlobalParams.connectionString << ':' << toolGlobalParams.port;
+ toolGlobalParams.connectionString = sb.str();
+ }
+ }
+ else {
+ if (params.count("directoryperdb")) {
+ storageGlobalParams.directoryperdb = true;
+ }
+
+ toolGlobalParams.connectionString = "DIRECT";
+ }
+
+ return Status::OK();
+ }
+
+ Status storeFieldOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+
+ toolGlobalParams.fieldsSpecified = false;
+
+ if (hasParam("fields")) {
+ toolGlobalParams.fieldsSpecified = true;
+
+ string fields_arg = getParam("fields");
+ pcrecpp::StringPiece input(fields_arg);
+
+ string f;
+ pcrecpp::RE re("([#\\w\\.\\s\\-]+),?" );
+ while ( re.Consume( &input, &f ) ) {
+ toolGlobalParams.fields.push_back( f );
+ }
+ return Status::OK();
+ }
+
+ if (hasParam("fieldFile")) {
+ toolGlobalParams.fieldsSpecified = true;
+
+ string fn = getParam("fieldFile");
+ if (!boost::filesystem::exists(fn)) {
+ StringBuilder sb;
+ sb << "file: " << fn << " doesn't exist";
+ return Status(ErrorCodes::InternalError, sb.str());
+ }
+
+ const int BUF_SIZE = 1024;
+ char line[1024 + 128];
+ std::ifstream file(fn.c_str());
+
+ while (file.rdstate() == std::ios_base::goodbit) {
+ file.getline(line, BUF_SIZE);
+ const char * cur = line;
+ while (isspace(cur[0])) cur++;
+ if (cur[0] == '\0')
+ continue;
+
+ toolGlobalParams.fields.push_back(cur);
+ }
+ return Status::OK();
+ }
+
+ return Status::OK();
+ }
+
+
+ Status storeBSONToolOptions(const moe::Environment& params,
+ const std::vector<std::string>& args) {
+
+ bsonToolGlobalParams.objcheck = true;
+
+ if (hasParam("objcheck") && hasParam("noobjcheck")) {
+ return Status(ErrorCodes::BadValue, "can't have both --objcheck and --noobjcheck");
+ }
+
+ if (hasParam("objcheck")) {
+ bsonToolGlobalParams.objcheck = true;
+ }
+ else if (hasParam("noobjcheck")) {
+ bsonToolGlobalParams.objcheck = false;
+ }
+
+ if (hasParam("filter")) {
+ bsonToolGlobalParams.hasFilter = true;
+ bsonToolGlobalParams.filter = getParam("filter");
+ }
+
+ return Status::OK();
+ }
+}
diff --git a/src/mongo/tools/tool_options.h b/src/mongo/tools/tool_options.h
new file mode 100644
index 00000000000..6644a0de58c
--- /dev/null
+++ b/src/mongo/tools/tool_options.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 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/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects
+ * for all of the code used other than as permitted herein. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you do not
+ * wish to do so, delete this exception statement from your version. If you
+ * delete this exception statement from all source files in the program,
+ * then also delete it in the license file.
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "mongo/base/status.h"
+
+namespace mongo {
+
+ namespace optionenvironment {
+ class OptionSection;
+ class Environment;
+ } // namespace optionenvironment
+
+ namespace moe = mongo::optionenvironment;
+
+ struct ToolGlobalParams {
+
+ ToolGlobalParams() : canUseStdout(true), hostSet(false), portSet(false) { }
+ std::string name;
+
+ std::string db;
+ std::string coll;
+
+ std::string username;
+ std::string password;
+ std::string authenticationDatabase;
+ std::string authenticationMechanism;
+ std::string gssapiServiceName;
+ std::string gssapiHostName;
+
+ bool quiet;
+ bool canUseStdout;
+ bool noconnection;
+
+ std::vector<std::string> fields;
+ bool fieldsSpecified;
+
+ std::string host; // --host
+ bool hostSet;
+ int port; // --port
+ bool portSet;
+ std::string connectionString; // --host and --port after processing
+ std::string dbpath;
+ bool useDirectClient;
+ };
+
+ extern ToolGlobalParams toolGlobalParams;
+
+ struct BSONToolGlobalParams {
+ bool objcheck;
+ std::string filter;
+ bool hasFilter;
+ };
+
+ extern BSONToolGlobalParams bsonToolGlobalParams;
+
+ Status addGeneralToolOptions(moe::OptionSection* options);
+
+ Status addRemoteServerToolOptions(moe::OptionSection* options);
+
+ Status addLocalServerToolOptions(moe::OptionSection* options);
+
+ Status addSpecifyDBCollectionToolOptions(moe::OptionSection* options);
+
+ Status addBSONToolOptions(moe::OptionSection* options);
+
+ Status addFieldOptions(moe::OptionSection* options);
+
+ // Legacy interface for getting options in tools
+ // TODO: Remove this when we use the new interface everywhere
+ std::string getParam(std::string name, string def="");
+ int getParam(std::string name, int def);
+ bool hasParam(std::string name);
+
+ /**
+ * Handle options that should come before validation, such as "help".
+ *
+ * Returns false if an option was found that implies we should prematurely exit with success.
+ */
+ bool handlePreValidationGeneralToolOptions(const moe::Environment& params);
+
+ Status storeGeneralToolOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+
+ Status storeFieldOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+
+ Status storeBSONToolOptions(const moe::Environment& params,
+ const std::vector<std::string>& args);
+}
diff --git a/src/mongo/tools/top.cpp b/src/mongo/tools/top.cpp
index a0af090c1c6..3b5c09dcbf1 100644
--- a/src/mongo/tools/top.cpp
+++ b/src/mongo/tools/top.cpp
@@ -1,5 +1,3 @@
-// top.cpp
-
/**
* Copyright (C) 2008 10gen Inc.
*
@@ -14,50 +12,46 @@
*
* 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/>.
+*
+* As a special exception, the copyright holders give permission to link the
+* code of portions of this program with the OpenSSL library under certain
+* conditions as described in each individual source file and distribute
+* linked combinations including the program with the OpenSSL library. You
+* must comply with the GNU Affero General Public License in all respects
+* for all of the code used other than as permitted herein. If you modify
+* file(s) with this exception, you may extend this exception to your
+* version of the file(s), but you are not obligated to do so. If you do not
+* wish to do so, delete this exception statement from your version. If you
+* delete this exception statement from all source files in the program,
+* then also delete it in the license file.
*/
-#include "pch.h"
+#include "mongo/pch.h"
-#include "mongo/base/initializer.h"
-#include "db/json.h"
-#include "../util/text.h"
-#include "tool.h"
-#include "stat_util.h"
#include <fstream>
#include <iostream>
-#include <boost/program_options.hpp>
-namespace po = boost::program_options;
+#include "mongo/db/json.h"
+#include "mongo/tools/stat_util.h"
+#include "mongo/tools/mongotop_options.h"
+#include "mongo/tools/tool.h"
+#include "mongo/util/options_parser/option_section.h"
namespace mongo {
class TopTool : public Tool {
public:
- TopTool() : Tool( "top" , REMOTE_SERVER , "admin" ) {
- _sleep = 1;
-
- add_hidden_options()
- ( "sleep" , po::value<int>() , "time to sleep between calls" )
- ;
- add_options()
- ( "locks" , "use db lock info instead of top" )
- ;
- addPositionArg( "sleep" , 1 );
-
+ TopTool() : Tool() {
_autoreconnect = true;
}
- virtual void printExtraHelp( ostream & out ) {
- out << "View live MongoDB collection statistics.\n" << endl;
- }
-
- bool useLocks() {
- return hasParam( "locks" );
+ virtual void printHelp( ostream & out ) {
+ printMongoTopHelp(&out);
}
NamespaceStats getData() {
- if ( useLocks() )
+ if (mongoTopGlobalParams.useLocks)
return getDataLocks();
return getDataTop();
}
@@ -65,8 +59,8 @@ namespace mongo {
NamespaceStats getDataLocks() {
BSONObj out;
- if ( ! conn().simpleCommand( _db , &out , "serverStatus" ) ) {
- cout << "error: " << out << endl;
+ if (!conn().simpleCommand(toolGlobalParams.db, &out, "serverStatus")) {
+ toolError() << "error: " << out << std::endl;
return NamespaceStats();
}
@@ -77,13 +71,13 @@ namespace mongo {
NamespaceStats stats;
BSONObj out;
- if ( ! conn().simpleCommand( _db , &out , "top" ) ) {
- cout << "error: " << out << endl;
+ if (!conn().simpleCommand(toolGlobalParams.db, &out, "top")) {
+ toolError() << "error: " << out << std::endl;
return stats;
}
if ( ! out["totals"].isABSONObj() ) {
- cout << "error: invalid top\n" << out << endl;
+ toolError() << "error: invalid top\n" << out << std::endl;
return stats;
}
@@ -117,7 +111,7 @@ namespace mongo {
for ( unsigned i=0; i < data.size(); i++ ) {
const string& ns = data[i].ns;
- if ( ! useLocks() && ns.find( '.' ) == string::npos )
+ if (!mongoTopGlobalParams.useLocks && ns.find('.') == string::npos)
continue;
if ( ns.size() > longest )
@@ -127,7 +121,7 @@ namespace mongo {
int numberWidth = 10;
cout << "\n"
- << setw(longest) << ( useLocks() ? "db" : "ns" )
+ << setw(longest) << (mongoTopGlobalParams.useLocks ? "db" : "ns")
<< setw(numberWidth+2) << "total"
<< setw(numberWidth+2) << "read"
<< setw(numberWidth+2) << "write"
@@ -135,7 +129,7 @@ namespace mongo {
<< endl;
for ( int i=data.size()-1; i>=0 && data.size() - i < 10 ; i-- ) {
- if ( ! useLocks() && data[i].ns.find( '.' ) == string::npos )
+ if (!mongoTopGlobalParams.useLocks && data[i].ns.find('.') == string::npos)
continue;
cout << setw(longest) << data[i].ns
@@ -148,24 +142,22 @@ namespace mongo {
}
int run() {
- _sleep = getParam( "sleep" , _sleep );
-
if (isMongos()) {
- log() << "mongotop only works on instances of mongod." << endl;
+ toolError() << "mongotop only works on instances of mongod." << std::endl;
return EXIT_FAILURE;
}
NamespaceStats prev = getData();
while ( true ) {
- sleepsecs( _sleep );
+ sleepsecs(mongoTopGlobalParams.sleep);
NamespaceStats now;
try {
now = getData();
}
catch ( std::exception& e ) {
- cout << "can't get data: " << e.what() << endl;
+ toolError() << "can't get data: " << e.what() << std::endl;
continue;
}
@@ -176,7 +168,7 @@ namespace mongo {
printDiff( prev , now );
}
catch ( AssertionException& e ) {
- cout << "\nerror: " << e.what() << endl;
+ toolError() << "\nerror: " << e.what() << std::endl;
}
prev = now;
@@ -184,16 +176,8 @@ namespace mongo {
return 0;
}
-
- private:
- int _sleep;
};
-}
+ REGISTER_MONGO_TOOL(TopTool);
-int main( int argc , char ** argv, char ** envp ) {
- mongo::runGlobalInitializersOrDie(argc, argv, envp);
- mongo::TopTool top;
- return top.main( argc , argv );
}
-