diff options
Diffstat (limited to 'src/mongo/db/db.cpp')
| -rw-r--r-- | src/mongo/db/db.cpp | 1257 |
1 files changed, 398 insertions, 859 deletions
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index 2361ec2a945..90a8013dba2 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -14,18 +14,38 @@ * * 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 <boost/shared_ptr.hpp> #include <boost/thread/thread.hpp> #include <boost/filesystem/operations.hpp> #include <fstream> +#include "mongo/base/init.h" #include "mongo/base/initializer.h" +#include "mongo/base/status.h" +#include "mongo/db/auth/auth_index_d.h" +#include "mongo/db/auth/authz_manager_external_state_d.h" +#include "mongo/db/auth/authorization_manager.h" +#include "mongo/db/auth/authorization_manager_global.h" +#include "mongo/db/catalog/index_catalog.h" +#include "mongo/db/catalog/index_key_validate.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" -#include "mongo/db/cmdline.h" #include "mongo/db/commands/server_status.h" #include "mongo/db/d_concurrency.h" #include "mongo/db/d_globals.h" @@ -33,33 +53,48 @@ #include "mongo/db/dbmessage.h" #include "mongo/db/dbwebserver.h" #include "mongo/db/dur.h" +#include "mongo/db/index_names.h" #include "mongo/db/index_rebuilder.h" #include "mongo/db/initialize_server_global_state.h" #include "mongo/db/instance.h" #include "mongo/db/introspect.h" #include "mongo/db/json.h" #include "mongo/db/kill_current_op.h" -#include "mongo/db/module.h" -#include "mongo/db/pdfile.h" -#include "mongo/db/repl.h" +#include "mongo/db/log_process_details.h" +#include "mongo/db/mongod_options.h" +#include "mongo/db/query/internal_plans.h" +#include "mongo/db/range_deleter_service.h" +#include "mongo/db/repair_database.h" +#include "mongo/db/repl/repl_start.h" +#include "mongo/db/repl/replication_server_status.h" #include "mongo/db/repl/rs.h" #include "mongo/db/restapi.h" +#include "mongo/db/startup_warnings.h" #include "mongo/db/stats/counters.h" #include "mongo/db/stats/snapshots.h" +#include "mongo/db/storage/storage_engine_metadata.h" +#include "mongo/db/storage_options.h" #include "mongo/db/ttl.h" +#include "mongo/platform/process_id.h" #include "mongo/s/d_writeback.h" #include "mongo/scripting/engine.h" #include "mongo/util/background.h" +#include "mongo/util/cmdline_utils/censor_cmdline.h" #include "mongo/util/concurrency/task.h" +#include "mongo/util/concurrency/thread_name.h" #include "mongo/util/exception_filter_win32.h" #include "mongo/util/file_allocator.h" #include "mongo/util/net/message_server.h" +#include "mongo/util/net/ssl_manager.h" #include "mongo/util/ntservice.h" +#include "mongo/util/options_parser/startup_options.h" #include "mongo/util/ramlog.h" +#include "mongo/util/scopeguard.h" +#include "mongo/util/signal_handlers.h" #include "mongo/util/stacktrace.h" #include "mongo/util/startup_test.h" #include "mongo/util/text.h" -#include "mongo/util/version.h" +#include "mongo/util/version_reporting.h" #if !defined(_WIN32) # include <sys/file.h> @@ -67,36 +102,24 @@ namespace mongo { - namespace dur { - extern unsigned long long DataLimitPerJournalFile; - } + void (*snmpInit)() = NULL; /* only off if --nohints */ extern bool useHints; extern int diagLogging; - extern unsigned lenForNewNsFiles; extern int lockFile; - extern string repairpath; - static void setupSignalHandlers(); - void startReplication(); - static void startSignalProcessingThread(); void exitCleanly( ExitCode code ); #ifdef _WIN32 ntservice::NtServiceDefaultStrings defaultServiceStrings = { L"MongoDB", - L"Mongo DB", - L"Mongo DB Server" + L"MongoDB", + L"MongoDB Server" }; #endif - CmdLine cmdLine; - static bool scriptingEnabled = true; - static bool noHttpInterface = false; - bool shouldRepairDatabases = 0; - static bool forceRepair = 0; Timer startupSrandTimer; const char *ourgetns() { @@ -156,19 +179,6 @@ namespace mongo { }; #endif - void sysRuntimeInfo() { - out() << "sysinfo:" << endl; -#if defined(_SC_PAGE_SIZE) - out() << " page size: " << (int) sysconf(_SC_PAGE_SIZE) << endl; -#endif -#if defined(_SC_PHYS_PAGES) - out() << " _SC_PHYS_PAGES: " << sysconf(_SC_PHYS_PAGES) << endl; -#endif -#if defined(_SC_AVPHYS_PAGES) - out() << " _SC_AVPHYS_PAGES: " << sysconf(_SC_AVPHYS_PAGES) << endl; -#endif - } - /* if server is really busy, wait a bit */ void beNice() { sleepmicros( Client::recommendedYieldMicros() ); @@ -232,7 +242,6 @@ namespace mongo { virtual void disconnected( AbstractMessagingPort* p ) { Client * c = currentClient.get(); if( c ) c->shutdown(); - globalScriptEngine->threadDone(); } }; @@ -245,12 +254,10 @@ namespace mongo { toLog.append( "hostname", getHostNameCached() ); toLog.appendTimeT( "startTime", time(0) ); - char buf[64]; - curTimeString( buf ); - toLog.append( "startTimeLocal", buf ); + toLog.append( "startTimeLocal", dateToCtimeString(curTimeMillis64()) ); - toLog.append( "cmdLine", CmdLine::getParsedOpts() ); - toLog.append( "pid", getpid() ); + toLog.append("cmdLine", serverGlobalParams.parsedOpts); + toLog.append( "pid", ProcessId::getCurrent().asLongLong() ); BSONObjBuilder buildinfo( toLog.subobjStart("buildinfo")); @@ -260,7 +267,6 @@ namespace mongo { BSONObj o = toLog.obj(); Lock::GlobalWrite lk; - Client::GodScope gs; DBDirectClient c; const char* name = "local.startup_log"; c.createCollection( name, 10 * 1024 * 1024, true ); @@ -271,15 +277,32 @@ namespace mongo { //testTheDb(); MessageServer::Options options; options.port = port; - options.ipList = cmdLine.bind_ip; + options.ipList = serverGlobalParams.bind_ip; MessageServer * server = createServer( options , new MyMessageHandler() ); server->setAsTimeTracker(); + // We must setupSockets for both the main server and the web server (if enabled) prior to + // calling logStartup() in order to avoid getting too high of a file descriptor for our + // calls to select (see SERVER-17653). + server->setupSockets(); + + boost::shared_ptr<DbWebServer> dbWebServer; + if (serverGlobalParams.isHttpInterfaceEnabled) { + dbWebServer.reset(new DbWebServer(serverGlobalParams.bind_ip, + serverGlobalParams.port + 1000, + new RestAdminAccess())); + dbWebServer->setupSockets(); + } + logStartup(); startReplication(); - if ( !noHttpInterface ) - boost::thread web( boost::bind(&webServerThread, new RestAdminAccess() /* takes ownership */)); + + if (serverGlobalParams.isHttpInterfaceEnabled) { + invariant(dbWebServer); + boost::thread web(boost::bind(&webServerListenThread, dbWebServer)); + web.detach(); + } #if(TESTEXHAUST) boost::thread thr(testExhaust); @@ -288,7 +311,7 @@ namespace mongo { } - bool doDBUpgrade( const string& dbName , string errmsg , DataFileHeader * h ) { + void doDBUpgrade( const string& dbName, DataFileHeader* h ) { static DBDirectClient db; if ( h->version == 4 && h->versionMinor == 4 ) { @@ -302,24 +325,56 @@ namespace mongo { BSONObj out; bool ok = db.runCommand( dbName , BSON( "reIndex" << c.substr( dbName.size() + 1 ) ) , out ); if ( ! ok ) { - errmsg = "reindex failed"; - log() << "\t\t reindex failed: " << out << endl; - return false; + log() << "\t\t reindex failed: " << out; + fassertFailed( 17393 ); } } getDur().writingInt(h->versionMinor) = 5; - return true; + return; } // do this in the general case - return repairDatabase( dbName.c_str(), errmsg ); + fassert( 17401, repairDatabase( dbName ) ); + } + + void checkForIdIndexes( Database* db ) { + + if ( db->name() == "local") { + // we do not need an _id index on anything in the local database + return; + } + + list<string> collections; + db->namespaceIndex().getNamespaces( collections ); + + // for each collection, ensure there is a $_id_ index + for (list<string>::iterator i = collections.begin(); i != collections.end(); ++i) { + const string& collectionName = *i; + NamespaceString ns( collectionName ); + if ( ns.isSystem() ) + continue; + + Collection* coll = db->getCollection( collectionName ); + if ( !coll ) + continue; + + if ( coll->getIndexCatalog()->findIdIndex() ) + continue; + + log() << "WARNING: the collection '" << *i + << "' lacks a unique index on _id." + << " This index is needed for replication to function properly" + << startupWarningsLog; + log() << "\t To fix this, you need to create a unique index on _id." + << " See http://dochub.mongodb.org/core/build-replica-set-indexes" + << startupWarningsLog; + } } // ran at startup. - static void repairDatabasesAndCheckVersion() { + static void repairDatabasesAndCheckVersion(bool shouldClearNonLocalTmpCollections) { // LastError * le = lastError.get( true ); - Client::GodScope gs; LOG(1) << "enter repairDatabases (to check pdfile version #)" << endl; Lock::GlobalWrite lk; @@ -328,10 +383,20 @@ namespace mongo { for ( vector< string >::iterator i = dbNames.begin(); i != dbNames.end(); ++i ) { string dbName = *i; LOG(1) << "\t" << dbName << endl; + Client::Context ctx( dbName ); - MongoDataFile *p = cc().database()->getFile( 0 ); + DataFile *p = ctx.db()->getExtentManager().getFile( 0 ); DataFileHeader *h = p->getHeader(); - if ( !h->isCurrentVersion() || forceRepair ) { + + if ( replSettings.usingReplSets() ) { + // we only care about the _id index if we are in a replset + checkForIdIndexes(ctx.db()); + } + + if (shouldClearNonLocalTmpCollections || dbName == "local") + ctx.db()->clearTmpCollections(); + + if (!h->isCurrentVersion() || mongodGlobalParams.repair) { if( h->version <= 0 ) { uasserted(14026, @@ -339,37 +404,40 @@ namespace mongo { << " info: " << h->versionMinor << ' ' << h->fileLength); } - log() << "****" << endl; - log() << "****" << endl; - log() << "need to upgrade database " << dbName << " " - << "with pdfile version " << h->version << "." << h->versionMinor << ", " - << "new version: " - << PDFILE_VERSION << "." << PDFILE_VERSION_MINOR_22_AND_OLDER - << endl; - if ( shouldRepairDatabases ) { + if ( !h->isCurrentVersion() ) { + log() << "****" << endl; + log() << "****" << endl; + log() << "need to upgrade database " << dbName << " " + << "with pdfile version " << h->version << "." << h->versionMinor << ", " + << "new version: " + << PDFILE_VERSION << "." << PDFILE_VERSION_MINOR_22_AND_OLDER + << endl; + } + + if (mongodGlobalParams.upgrade) { // QUESTION: Repair even if file format is higher version than code? - log() << "\t starting upgrade" << endl; - string errmsg; - verify( doDBUpgrade( dbName , errmsg , h ) ); + doDBUpgrade( dbName, h ); } else { log() << "\t Not upgrading, exiting" << endl; log() << "\t run --upgrade to upgrade dbs, then start again" << endl; log() << "****" << endl; dbexit( EXIT_NEED_UPGRADE ); - shouldRepairDatabases = 1; + mongodGlobalParams.upgrade = 1; return; } } else { - if (h->versionMinor == PDFILE_VERSION_MINOR_22_AND_OLDER) { - const string systemIndexes = cc().database()->name + ".system.indexes"; - shared_ptr<Cursor> cursor(theDataFileMgr.findAll(systemIndexes)); - for ( ; cursor && cursor->ok(); cursor->advance()) { - const BSONObj index = cursor->current(); - const BSONObj key = index.getObjectField("key"); - const string plugin = IndexPlugin::findPluginName(key); - if (IndexPlugin::existedBefore24(plugin)) + const string systemIndexes = cc().database()->name() + ".system.indexes"; + auto_ptr<Runner> runner(InternalPlanner::collectionScan(systemIndexes)); + BSONObj index; + Runner::RunnerState state; + while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&index, NULL))) { + const BSONObj key = index.getObjectField("key"); + const string plugin = IndexNames::findPluginName(key); + + if (!h->is24IndexClean()) { + if (IndexNames::existedBefore24(plugin)) continue; log() << "Index " << index << " claims to be of type '" << plugin << "', " @@ -378,14 +446,32 @@ namespace mongo { << "http://dochub.mongodb.org/core/upgrade-2.4" << startupWarningsLog; } + + const Status keyStatus = validateKeyPattern(key); + if (!keyStatus.isOK()) { + log() << "Problem with index " << index << ": " << keyStatus.reason() + << " This index can still be used however it cannot be rebuilt." + << " For more info see" + << " http://dochub.mongodb.org/core/index-validation" + << startupWarningsLog; + } + } + + if (Runner::RUNNER_EOF != state) { + warning() << "Internal error while reading collection " << systemIndexes; } - Database::closeDatabase( dbName.c_str(), dbpath ); + + // 2.4 does not properly drop indexes on collections named "system". Check for + // orphaned indexes and clean up any if found. + ctx.db()->cleanUpOrphanIndexesOnSystemCollection(); + + Database::closeDatabase(dbName.c_str(), storageGlobalParams.dbpath); } } LOG(1) << "done repairDatabases" << endl; - if ( shouldRepairDatabases ) { + if (mongodGlobalParams.upgrade) { log() << "finished checking dbs" << endl; cc().shutdown(); dbexit( EXIT_CLEAN ); @@ -393,7 +479,7 @@ namespace mongo { } void clearTmpFiles() { - boost::filesystem::path path( dbpath ); + boost::filesystem::path path(storageGlobalParams.dbpath); for ( boost::filesystem::directory_iterator i( path ); i != boost::filesystem::directory_iterator(); ++i ) { string fileName = boost::filesystem::path(*i).leaf().string(); @@ -412,8 +498,7 @@ namespace mongo { */ unsigned long long checkIfReplMissingFromCommandLine() { Lock::GlobalWrite lk; // this is helpful for the query below to work as you can't open files when readlocked - if( !cmdLine.usingReplSets() ) { - Client::GodScope gs; + if (!replSettings.usingReplSets()) { DBDirectClient c; return c.count("local.system.replset"); } @@ -438,22 +523,25 @@ namespace mongo { void run() { Client::initThread( name().c_str() ); - if( cmdLine.syncdelay == 0 ) + if (storageGlobalParams.syncdelay == 0) { log() << "warning: --syncdelay 0 is not recommended and can have strange performance" << endl; - else if( cmdLine.syncdelay == 1 ) + } + else if (storageGlobalParams.syncdelay == 1) { log() << "--syncdelay 1" << endl; - else if( cmdLine.syncdelay != 60 ) - LOG(1) << "--syncdelay " << cmdLine.syncdelay << endl; + } + else if (storageGlobalParams.syncdelay != 60) { + LOG(1) << "--syncdelay " << storageGlobalParams.syncdelay << endl; + } int time_flushing = 0; while ( ! inShutdown() ) { _diaglog.flush(); - if ( cmdLine.syncdelay == 0 ) { + if (storageGlobalParams.syncdelay == 0) { // in case at some point we add an option to change at runtime sleepsecs(5); continue; } - sleepmillis( (long long) std::max(0.0, (cmdLine.syncdelay * 1000) - time_flushing) ); + sleepmillis((long long) std::max(0.0, (storageGlobalParams.syncdelay * 1000) - time_flushing)); if ( inShutdown() ) { // occasional issue trying to flush during shutdown when sleep interrupted @@ -466,7 +554,7 @@ namespace mongo { _flushed(time_flushing); - if( logLevel >= 1 || time_flushing >= 10000 ) { + if( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) || time_flushing >= 10000 ) { log() << "flushing mmaps took " << time_flushing << "ms " << " for " << numFiles << " files" << endl; } } @@ -507,7 +595,7 @@ namespace mongo { int m = static_cast<int>(MemoryMappedFile::totalMappedLength() / ( 1024 * 1024 )); b.appendNumber( "mapped" , m ); - if ( cmdLine.dur ) { + if (storageGlobalParams.dur) { m *= 2; b.appendNumber( "mappedWithJournal" , m ); } @@ -529,39 +617,47 @@ namespace mongo { /// warn if readahead > 256KB (gridfs chunk size) static void checkReadAhead(const string& dir) { #ifdef __linux__ - const dev_t dev = getPartition(dir); - - // This path handles the case where the filesystem uses the whole device (including LVM) - string path = str::stream() << - "/sys/dev/block/" << major(dev) << ':' << minor(dev) << "/queue/read_ahead_kb"; - - if (!boost::filesystem::exists(path)){ - // This path handles the case where the filesystem is on a partition. - path = str::stream() - << "/sys/dev/block/" << major(dev) << ':' << minor(dev) // this is a symlink - << "/.." // parent directory of a partition is for the whole device - << "/queue/read_ahead_kb"; - } + try { + const dev_t dev = getPartition(dir); + + // This path handles the case where the filesystem uses the whole device (including LVM) + string path = str::stream() << + "/sys/dev/block/" << major(dev) << ':' << minor(dev) << "/queue/read_ahead_kb"; + + if (!boost::filesystem::exists(path)){ + // This path handles the case where the filesystem is on a partition. + path = str::stream() + << "/sys/dev/block/" << major(dev) << ':' << minor(dev) // this is a symlink + << "/.." // parent directory of a partition is for the whole device + << "/queue/read_ahead_kb"; + } - if (boost::filesystem::exists(path)) { - ifstream file (path.c_str()); - if (file.is_open()) { - int kb; - file >> kb; - if (kb > 256) { - log() << startupWarningsLog; + if (boost::filesystem::exists(path)) { + ifstream file (path.c_str()); + if (file.is_open()) { + int kb; + file >> kb; + if (kb > 256) { + log() << startupWarningsLog; - log() << "** WARNING: Readahead for " << dir << " is set to " << kb << "KB" - << startupWarningsLog; + log() << "** WARNING: Readahead for " << dir << " is set to " << kb << "KB" + << startupWarningsLog; - log() << "** We suggest setting it to 256KB (512 sectors) or less" - << startupWarningsLog; + log() << "** We suggest setting it to 256KB (512 sectors) or less" + << startupWarningsLog; - log() << "** http://dochub.mongodb.org/core/readahead" - << startupWarningsLog; + log() << "** http://dochub.mongodb.org/core/readahead" + << startupWarningsLog; + } } } } + catch (const std::exception& e) { + log() << "unable to validate readahead settings due to error: " << e.what() + << startupWarningsLog; + log() << "for more information, see http://dochub.mongodb.org/core/readahead" + << startupWarningsLog; + } #endif // __linux__ } @@ -569,59 +665,64 @@ namespace mongo { Client::initThread("initandlisten"); - Logstream::get().addGlobalTee( new RamLog("global") ); - bool is32bit = sizeof(int*) == 4; { -#if !defined(_WIN32) - pid_t pid = getpid(); -#else - DWORD pid=GetCurrentProcessId(); -#endif - Nullstream& l = log(); - l << "MongoDB starting : pid=" << pid << " port=" << cmdLine.port << " dbpath=" << dbpath; + ProcessId pid = ProcessId::getCurrent(); + LogstreamBuilder l = log(); + l << "MongoDB starting : pid=" << pid + << " port=" << serverGlobalParams.port + << " dbpath=" << storageGlobalParams.dbpath; if( replSettings.master ) l << " master=" << replSettings.master; if( replSettings.slave ) l << " slave=" << (int) replSettings.slave; l << ( is32bit ? " 32" : " 64" ) << "-bit host=" << getHostNameCached() << endl; } DEV log() << "_DEBUG build (which is slower)" << endl; - show_warnings(); - log() << mongodVersion() << endl; - printGitVersion(); - printSysInfo(); - printAllocator(); - printCommandLineOpts(); - + logStartupWarnings(); +#if defined(_WIN32) + printTargetMinOS(); +#endif + logProcessDetails(); { stringstream ss; ss << endl; ss << "*********************************************************************" << endl; - ss << " ERROR: dbpath (" << dbpath << ") does not exist." << endl; + ss << " ERROR: dbpath (" << storageGlobalParams.dbpath << ") does not exist." << endl; ss << " Create this directory or give existing directory in --dbpath." << endl; ss << " See http://dochub.mongodb.org/core/startingandstoppingmongo" << endl; ss << "*********************************************************************" << endl; - uassert( 10296 , ss.str().c_str(), boost::filesystem::exists( dbpath ) ); + uassert(10296, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.dbpath)); } { stringstream ss; - ss << "repairpath (" << repairpath << ") does not exist"; - uassert( 12590 , ss.str().c_str(), boost::filesystem::exists( repairpath ) ); + ss << "repairpath (" << storageGlobalParams.repairpath << ") does not exist"; + uassert(12590, ss.str().c_str(), + boost::filesystem::exists(storageGlobalParams.repairpath)); } + // Read storage engine metadata file (introduced in 2.8) if present. + // Do not start server if storage engine in metadata is not 'mmapv1'. + StorageEngineMetadata::validate(storageGlobalParams.dbpath, "mmapv1"); + // TODO check non-journal subdirs if using directory-per-db - checkReadAhead(dbpath); + checkReadAhead(storageGlobalParams.dbpath); - acquirePathLock(forceRepair); - boost::filesystem::remove_all( dbpath + "/_tmp/" ); + acquirePathLock(mongodGlobalParams.repair); + boost::filesystem::remove_all(storageGlobalParams.dbpath + "/_tmp/"); FileAllocator::get()->start(); + // TODO: This should go into a MONGO_INITIALIZER once we have figured out the correct + // dependencies. + if (snmpInit) { + snmpInit(); + } + MONGO_ASSERT_ON_EXCEPTION_WITH_MSG( clearTmpFiles(), "clear tmp files" ); dur::startup(); - if( cmdLine.durOptions & CmdLine::DurRecoverOnly ) + if (storageGlobalParams.durOptions & StorageGlobalParams::DurRecoverOnly) return; unsigned long long missingRepl = checkIfReplMissingFromCommandLine(); @@ -636,25 +737,35 @@ namespace mongo { log() << startupWarningsLog; } - Module::initAll(); - - if ( scriptingEnabled ) { + if (mongodGlobalParams.scriptingEnabled) { ScriptEngine::setup(); globalScriptEngine->setCheckInterruptCallback( jsInterruptCallback ); globalScriptEngine->setGetCurrentOpIdCallback( jsGetCurrentOpIdCallback ); } - repairDatabasesAndCheckVersion(); + // On replica set members we only clear temp collections on DBs other than "local" during + // promotion to primary. On pure slaves, they are only cleared when the oplog tells them to. + // The local DB is special because it is not replicated. See SERVER-10927 for more details. + const bool shouldClearNonLocalTmpCollections = !(missingRepl + || replSettings.usingReplSets() + || replSettings.slave == SimpleSlave); + repairDatabasesAndCheckVersion(shouldClearNonLocalTmpCollections); - if ( shouldRepairDatabases ) + if (mongodGlobalParams.upgrade) return; + uassertStatusOK(getGlobalAuthorizationManager()->initialize()); + /* this is for security on certain platforms (nonce generation) */ srand((unsigned) (curTimeMicros() ^ startupSrandTimer.micros())); - snapshotThread.go(); + // The snapshot thread provides historical collection level and lock statistics for use + // by the web interface. Only needed when HTTP is enabled. + if (serverGlobalParams.isHttpInterfaceEnabled) + snapshotThread.go(); + d.clientCursorMonitor.go(); - PeriodicTask::theRunner->go(); + PeriodicTask::startRunningPeriodicTasks(); if (missingRepl) { // a warning was logged earlier } @@ -663,23 +774,28 @@ namespace mongo { } #ifndef _WIN32 - CmdLine::launchOk(); + mongo::signalForkSuccess(); #endif - if( !noauth ) { + if(getGlobalAuthorizationManager()->isAuthEnabled()) { // open admin db in case we need to use it later. TODO this is not the right way to // resolve this. - Client::WriteContext c("admin", dbpath); + Client::WriteContext c("admin", storageGlobalParams.dbpath); } + authindex::configureSystemIndexes("admin"); + + getDeleter()->startWorkers(); + + // Starts a background thread that rebuilds all incomplete indices. + indexRebuilder.go(); + listen(listenPort); // listen() will return when exit code closes its socket. exitCleanly(EXIT_NET_ERROR); } - void testPretouch(); - void initAndListen(int listenPort) { try { _initAndListen(listenPort); @@ -706,7 +822,7 @@ namespace mongo { void initService() { ntservice::reportStatus( SERVICE_RUNNING ); log() << "Service running" << endl; - initAndListen( cmdLine.port ); + initAndListen(serverGlobalParams.port); } #endif @@ -714,547 +830,172 @@ namespace mongo { using namespace mongo; -#include <boost/program_options.hpp> - -namespace po = boost::program_options; - -void show_help_text(po::options_description options) { - cout << options << endl; -}; - static int mongoDbMain(int argc, char* argv[], char** envp); +#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 mongoDbMain() +// 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 = mongoDbMain(argc, wcl.argv(), wcl.envp()); + ::_exit(exitCode); +} +#else int main(int argc, char* argv[], char** envp) { int exitCode = mongoDbMain(argc, argv, envp); ::_exit(exitCode); } - -static void buildOptionsDescriptions(po::options_description *pVisible, - po::options_description *pHidden, - po::positional_options_description *pPositional) { - - po::options_description& visible_options = *pVisible; - po::options_description& hidden_options = *pHidden; - po::positional_options_description& positional_options = *pPositional; - - po::options_description general_options("General options"); -#if defined(_WIN32) - po::options_description windows_scm_options("Windows Service Control Manager options"); #endif - po::options_description ms_options("Master/slave options (old; use replica sets instead)"); - po::options_description rs_options("Replica set options"); - po::options_description replication_options("Replication options"); - po::options_description sharding_options("Sharding options"); - po::options_description hidden_sharding_options("Sharding options"); - po::options_description ssl_options("SSL options"); - - CmdLine::addGlobalOptions( general_options , hidden_options , ssl_options ); - - StringBuilder dbpathBuilder; - dbpathBuilder << "directory for datafiles - defaults to " << dbpath; - - general_options.add_options() - ("auth", "run with security") - ("cpu", "periodically show cpu and iowait utilization") - ("dbpath", po::value<string>() , dbpathBuilder.str().c_str()) - ("diaglog", po::value<int>(), "0=off 1=W 2=R 3=both 7=W+some reads") - ("directoryperdb", "each database will be stored in a separate directory") - ("ipv6", "enable IPv6 support (disabled by default)") - ("journal", "enable journaling") - ("journalCommitInterval", po::value<unsigned>(), "how often to group/batch commit (ms)") - ("journalOptions", po::value<int>(), "journal diagnostic options") - ("jsonp","allow JSONP access via http (has security implications)") - ("noauth", "run without security") - ("nohttpinterface", "disable http interface") - // SERVER-8536 - // ("noIndexBuildRetry", "don't retry any index builds that were interrupted by shutdown") - ("nojournal", "disable journaling (journaling is on by default for 64 bit)") - ("noprealloc", "disable data file preallocation - will often hurt performance") - ("noscripting", "disable scripting engine") - ("notablescan", "do not allow table scans") - ("nssize", po::value<int>()->default_value(16), ".ns file size (in MB) for new databases") - ("profile",po::value<int>(), "0=off 1=slow, 2=all") - ("quota", "limits each database to a certain number of files (8 default)") - ("quotaFiles", po::value<int>(), "number of files allowed per db, requires --quota") - ("repair", "run repair on all dbs") - ("repairpath", po::value<string>() , "root directory for repair files - defaults to dbpath" ) - ("rest","turn on simple rest api") -#if defined(__linux__) - ("shutdown", "kill a running server (for init scripts)") -#endif - ("slowms",po::value<int>(&cmdLine.slowMS)->default_value(100), "value of slow for profile and console log" ) - ("smallfiles", "use a smaller default file size") - ("syncdelay",po::value<double>(&cmdLine.syncdelay)->default_value(60), "seconds between disk syncs (0=never, but not recommended)") - ("sysinfo", "print some diagnostic system information") - ("upgrade", "upgrade db if needed") - ; -#if defined(_WIN32) - CmdLine::addWindowsOptions( windows_scm_options, hidden_options ); -#endif - - replication_options.add_options() - ("oplogSize", po::value<int>(), "size to use (in MB) for replication op log. default is 5% of disk space (i.e. large is good)") - ; - - ms_options.add_options() - ("master", "master mode") - ("slave", "slave mode") - ("source", po::value<string>(), "when slave: specify master as <server:port>") - ("only", po::value<string>(), "when slave: specify a single database to replicate") - ("slavedelay", po::value<int>(), "specify delay (in seconds) to be used when applying master ops to slave") - ("autoresync", "automatically resync if slave data is stale") - ; - - rs_options.add_options() - ("replSet", po::value<string>(), "arg is <setname>[/<optionalseedhostlist>]") - ("replIndexPrefetch", po::value<string>(), "specify index prefetching behavior (if secondary) [none|_id_only|all]") - ; - - sharding_options.add_options() - ("configsvr", "declare this is a config db of a cluster; default port 27019; default dir /data/configdb") - ("shardsvr", "declare this is a shard db of a cluster; default port 27018") - ; - - hidden_sharding_options.add_options() - ("noMoveParanoia" , "turn off paranoid saving of data for the moveChunk command; default" ) - ("moveParanoia" , "turn on paranoid saving of data during the moveChunk command (used for internal system diagnostics)" ) - ; - hidden_options.add(hidden_sharding_options); - - hidden_options.add_options() - ("fastsync", "indicate that this instance is starting from a dbpath snapshot of the repl peer") - ("pretouch", po::value<int>(), "n pretouch threads for applying replicationed operations") // experimental - ("command", po::value< vector<string> >(), "command") - ("cacheSize", po::value<long>(), "cache size (in MB) for rec store") - ("nodur", "disable journaling") - // things we don't want people to use - ("nohints", "ignore query hints") - ("nopreallocj", "don't preallocate journal files") - ("dur", "enable journaling") // old name for --journal - ("durOptions", po::value<int>(), "durability diagnostic options") // deprecated name - // deprecated pairing command line options - ("pairwith", "DEPRECATED") - ("arbiter", "DEPRECATED") - ("opIdMem", "DEPRECATED") - ; - - positional_options.add("command", 3); - visible_options.add(general_options); -#if defined(_WIN32) - visible_options.add(windows_scm_options); -#endif - visible_options.add(replication_options); - visible_options.add(ms_options); - visible_options.add(rs_options); - visible_options.add(sharding_options); -#ifdef MONGO_SSL - visible_options.add(ssl_options); -#endif - Module::addOptions( visible_options ); +MONGO_INITIALIZER_GENERAL(ForkServer, + ("EndStartupOptionHandling"), + ("default"))(InitializerContext* context) { + mongo::forkServerOrDie(); + return Status::OK(); } -static void processCommandLineOptions(const std::vector<std::string>& argv) { - po::options_description visible_options("Allowed options"); - po::options_description hidden_options("Hidden options"); - po::positional_options_description positional_options; - buildOptionsDescriptions(&visible_options, &hidden_options, &positional_options); - - { - po::variables_map params; - - if (!CmdLine::store(argv, - visible_options, - hidden_options, - positional_options, - params)) { - ::_exit(EXIT_FAILURE); - } - - if (params.count("help")) { - show_help_text(visible_options); - ::_exit(EXIT_SUCCESS); - } - if (params.count("version")) { - cout << mongodVersion() << endl; - printGitVersion(); - ::_exit(EXIT_SUCCESS); - } - if (params.count("sysinfo")) { - sysRuntimeInfo(); +/* + * This function should contain the startup "actions" that we take based on the startup config. It + * is intended to separate the actions from "storage" and "validation" of our startup configuration. + */ +static void startupConfigActions(const std::vector<std::string>& args) { + // The "command" option is deprecated. For backward compatibility, still support the "run" + // and "dbppath" command. The "run" command is the same as just running mongod, so just + // falls through. + if (moe::startupOptionsParsed.count("command")) { + vector<string> command = moe::startupOptionsParsed["command"].as< vector<string> >(); + + if (command[0].compare("dbpath") == 0) { + cout << storageGlobalParams.dbpath << endl; ::_exit(EXIT_SUCCESS); } - if ( params.count( "dbpath" ) ) { - dbpath = params["dbpath"].as<string>(); - if ( params.count( "fork" ) && dbpath[0] != '/' ) { - // we need to change dbpath if we fork since we change - // cwd to "/" - // fork only exists on *nix - // so '/' is safe - dbpath = cmdLine.cwd + "/" + dbpath; - } - } -#ifdef _WIN32 - if (dbpath.size() > 1 && dbpath[dbpath.size()-1] == '/') { - // size() check is for the unlikely possibility of --dbpath "/" - dbpath = dbpath.erase(dbpath.size()-1); + if (command[0].compare("run") != 0) { + cout << "Invalid command: " << command[0] << endl; + printMongodHelp(moe::startupOptions); + ::_exit(EXIT_FAILURE); } -#endif - if ( params.count("directoryperdb")) { - directoryperdb = true; - } - if (params.count("cpu")) { - cmdLine.cpu = true; - } - if (params.count("noauth")) { - noauth = true; - } - if (params.count("auth")) { - noauth = false; - } - if (params.count("quota")) { - cmdLine.quota = true; - } - if (params.count("quotaFiles")) { - cmdLine.quota = true; - cmdLine.quotaFiles = params["quotaFiles"].as<int>() - 1; - } - bool journalExplicit = false; - if( params.count("nodur") || params.count( "nojournal" ) ) { - journalExplicit = true; - cmdLine.dur = false; - } - if( params.count("dur") || params.count( "journal" ) ) { - if (journalExplicit) { - log() << "Can't specify both --journal and --nojournal options." << endl; - ::_exit(EXIT_BADOPTIONS); - } - journalExplicit = true; - cmdLine.dur = true; - } - if (params.count("durOptions")) { - cmdLine.durOptions = params["durOptions"].as<int>(); - } - if( params.count("journalCommitInterval") ) { - // don't check if dur is false here as many will just use the default, and will default to off on win32. - // ie no point making life a little more complex by giving an error on a dev environment. - cmdLine.journalCommitInterval = params["journalCommitInterval"].as<unsigned>(); - if( cmdLine.journalCommitInterval <= 1 || cmdLine.journalCommitInterval > 300 ) { - out() << "--journalCommitInterval out of allowed range (0-300ms)" << endl; - dbexit( EXIT_BADOPTIONS ); - } - } - if (params.count("journalOptions")) { - cmdLine.durOptions = params["journalOptions"].as<int>(); + if (command.size() > 1) { + cout << "Too many parameters to 'run' command" << endl; + printMongodHelp(moe::startupOptions); + ::_exit(EXIT_FAILURE); } - if (params.count("repairpath")) { - repairpath = params["repairpath"].as<string>(); - if (!repairpath.size()) { - out() << "repairpath is empty" << endl; - dbexit( EXIT_BADOPTIONS ); - } + } - if (cmdLine.dur && !str::startsWith(repairpath, dbpath)) { - out() << "You must use a --repairpath that is a subdirectory of --dbpath when using journaling" << endl; - dbexit( EXIT_BADOPTIONS ); - } - } - if (params.count("nohints")) { - useHints = false; - } - if (params.count("nopreallocj")) { - cmdLine.preallocj = false; - } - if (params.count("nohttpinterface")) { - noHttpInterface = true; - } - if (params.count("rest")) { - cmdLine.rest = true; - } - if (params.count("jsonp")) { - cmdLine.jsonp = true; - } - if (params.count("noscripting")) { - scriptingEnabled = false; - } - if (params.count("noprealloc")) { - cmdLine.prealloc = false; - cout << "note: noprealloc may hurt performance in many applications" << endl; - } - if (params.count("smallfiles")) { - cmdLine.smallfiles = true; - verify( dur::DataLimitPerJournalFile >= 128 * 1024 * 1024 ); - dur::DataLimitPerJournalFile = 128 * 1024 * 1024; - } - if (params.count("diaglog")) { - int x = params["diaglog"].as<int>(); - if ( x < 0 || x > 7 ) { - out() << "can't interpret --diaglog setting" << endl; - dbexit( EXIT_BADOPTIONS ); - } - _diaglog.setLevel(x); - } - if (params.count("repair")) { - if (journalExplicit && cmdLine.dur) { - log() << "Can't specify both --journal and --repair options." << endl; - ::_exit(EXIT_BADOPTIONS); - } +#ifdef _WIN32 + ntservice::configureService(initService, + moe::startupOptionsParsed, + defaultServiceStrings, + std::vector<std::string>(), + args); +#endif // _WIN32 - Record::MemoryTrackingEnabled = false; - shouldRepairDatabases = 1; - forceRepair = 1; - cmdLine.dur = false; - } - if (params.count("upgrade")) { - Record::MemoryTrackingEnabled = false; - shouldRepairDatabases = 1; - } - if (params.count("notablescan")) { - cmdLine.noTableScan = true; - } - if (params.count("master")) { - replSettings.master = true; - } - if (params.count("slave")) { - replSettings.slave = SimpleSlave; - } - if (params.count("slavedelay")) { - replSettings.slavedelay = params["slavedelay"].as<int>(); - } - if (params.count("fastsync")) { - replSettings.fastsync = true; - } - if (params.count("autoresync")) { - replSettings.autoresync = true; - if( params.count("replSet") ) { - out() << "--autoresync is not used with --replSet" << endl; - out() << "see http://dochub.mongodb.org/core/resyncingaverystalereplicasetmember" << endl; - dbexit( EXIT_BADOPTIONS ); - } - } - if (params.count("source")) { - /* specifies what the source in local.sources should be */ - cmdLine.source = params["source"].as<string>().c_str(); - } - if( params.count("pretouch") ) { - cmdLine.pretouch = params["pretouch"].as<int>(); - } - if (params.count("replSet")) { - if (params.count("slavedelay")) { - out() << "--slavedelay cannot be used with --replSet" << endl; - dbexit( EXIT_BADOPTIONS ); - } - else if (params.count("only")) { - out() << "--only cannot be used with --replSet" << endl; - dbexit( EXIT_BADOPTIONS ); - } - /* seed list of hosts for the repl set */ - cmdLine._replSet = params["replSet"].as<string>().c_str(); - } - if (params.count("replIndexPrefetch")) { - cmdLine.rsIndexPrefetch = params["replIndexPrefetch"].as<std::string>(); - } - if (params.count("noIndexBuildRetry")) { - cmdLine.indexBuildRetry = false; - } - if (params.count("only")) { - cmdLine.only = params["only"].as<string>().c_str(); - } - if( params.count("nssize") ) { - int x = params["nssize"].as<int>(); - if (x <= 0 || x > (0x7fffffff/1024/1024)) { - out() << "bad --nssize arg" << endl; - dbexit( EXIT_BADOPTIONS ); - } - lenForNewNsFiles = x * 1024 * 1024; - verify(lenForNewNsFiles > 0); - } - if (params.count("oplogSize")) { - long long x = params["oplogSize"].as<int>(); - if (x <= 0) { - out() << "bad --oplogSize arg" << endl; - dbexit( EXIT_BADOPTIONS ); - } - // note a small size such as x==1 is ok for an arbiter. - if( x > 1000 && sizeof(void*) == 4 ) { - out() << "--oplogSize of " << x << "MB is too big for 32 bit version. Use 64 bit build instead." << endl; - dbexit( EXIT_BADOPTIONS ); - } - cmdLine.oplogSize = x * 1024 * 1024; - verify(cmdLine.oplogSize > 0); - } - if (params.count("cacheSize")) { - long x = params["cacheSize"].as<long>(); - if (x <= 0) { - out() << "bad --cacheSize arg" << endl; - dbexit( EXIT_BADOPTIONS ); - } - log() << "--cacheSize option not currently supported" << endl; - } - if (params.count("port") == 0 ) { - if( params.count("configsvr") ) { - cmdLine.port = CmdLine::ConfigServerPort; - } - if( params.count("shardsvr") ) { - if( params.count("configsvr") ) { - log() << "can't do --shardsvr and --configsvr at the same time" << endl; - dbexit( EXIT_BADOPTIONS ); - } - cmdLine.port = CmdLine::ShardServerPort; - } - } - else { - if ( cmdLine.port <= 0 || cmdLine.port > 65535 ) { - out() << "bad --port number" << endl; - dbexit( EXIT_BADOPTIONS ); +#ifdef __linux__ + if (moe::startupOptionsParsed.count("shutdown")){ + bool failed = false; + + string name = (boost::filesystem::path(storageGlobalParams.dbpath) / "mongod.lock").string(); + if ( !boost::filesystem::exists( name ) || boost::filesystem::file_size( name ) == 0 ) + failed = true; + + pid_t pid; + string procPath; + if (!failed){ + try { + ifstream f (name.c_str()); + f >> pid; + procPath = (str::stream() << "/proc/" << pid); + if (!boost::filesystem::exists(procPath)) + failed = true; } - } - if ( params.count("configsvr" ) ) { - cmdLine.configsvr = true; - cmdLine.smallfiles = true; // config server implies small files - dur::DataLimitPerJournalFile = 128 * 1024 * 1024; - if (cmdLine.usingReplSets() || replSettings.master || replSettings.slave) { - log() << "replication should not be enabled on a config server" << endl; - ::_exit(-1); + catch (const std::exception& e){ + cerr << "Error reading pid from lock file [" << name << "]: " << e.what() << endl; + failed = true; } - if ( params.count( "nodur" ) == 0 && params.count( "nojournal" ) == 0 ) - cmdLine.dur = true; - if ( params.count( "dbpath" ) == 0 ) - dbpath = "/data/configdb"; - replSettings.master = true; - if ( params.count( "oplogSize" ) == 0 ) - cmdLine.oplogSize = 5 * 1024 * 1024; } - if ( params.count( "profile" ) ) { - cmdLine.defaultProfile = params["profile"].as<int>(); - } - if (params.count("ipv6")) { - enableIPv6(); - } - - if (params.count("noMoveParanoia") > 0 && params.count("moveParanoia") > 0) { - out() << "The moveParanoia and noMoveParanoia flags cannot both be set; please use only one of them." << endl; - ::_exit( EXIT_BADOPTIONS ); - } - - if (params.count("noMoveParanoia")) - cmdLine.moveParanoia = false; - if (params.count("moveParanoia")) - cmdLine.moveParanoia = true; - - if (params.count("pairwith") || params.count("arbiter") || params.count("opIdMem")) { - out() << "****" << endl; - out() << "Replica Pairs have been deprecated. Invalid options: --pairwith, --arbiter, and/or --opIdMem" << endl; - out() << "<http://dochub.mongodb.org/core/replicapairs>" << endl; - out() << "****" << endl; - dbexit( EXIT_BADOPTIONS ); + if (failed) { + std::cerr << "There doesn't seem to be a server running with dbpath: " + << storageGlobalParams.dbpath << std::endl; + ::_exit(EXIT_FAILURE); } - // needs to be after things like --configsvr parsing, thus here. - if( repairpath.empty() ) - repairpath = dbpath; - - // The "command" option is deprecated. For backward compatibility, still support the "run" - // and "dbppath" command. The "run" command is the same as just running mongod, so just - // falls through. - if (params.count("command")) { - vector<string> command = params["command"].as< vector<string> >(); - - if (command[0].compare("dbpath") == 0) { - cout << dbpath << endl; - ::_exit(EXIT_SUCCESS); - } - - if (command[0].compare("run") != 0) { - cout << "Invalid command: " << command[0] << endl; - cout << visible_options << endl; - ::_exit(EXIT_FAILURE); - } - - if (command.size() > 1) { - cout << "Too many parameters to 'run' command" << endl; - cout << visible_options << endl; - ::_exit(EXIT_FAILURE); - } + cout << "killing process with pid: " << pid << endl; + int ret = kill(pid, SIGTERM); + if (ret) { + int e = errno; + cerr << "failed to kill process: " << errnoWithDescription(e) << endl; + ::_exit(EXIT_FAILURE); } - if( cmdLine.pretouch ) - log() << "--pretouch " << cmdLine.pretouch << endl; - - if (sizeof(void*) == 4 && !journalExplicit){ - // trying to make this stand out more like startup warnings - log() << endl; - warning() << "32-bit servers don't have journaling enabled by default. Please use --journal if you want durability." << endl; - log() << endl; + while (boost::filesystem::exists(procPath)) { + sleepsecs(1); } - Module::configAll(params); - -#ifdef _WIN32 - ntservice::configureService(initService, - params, - defaultServiceStrings, - std::vector<std::string>(), - argv); -#endif // _WIN32 - -#ifdef __linux__ - if (params.count("shutdown")){ - bool failed = false; - - string name = ( boost::filesystem::path( dbpath ) / "mongod.lock" ).string(); - if ( !boost::filesystem::exists( name ) || boost::filesystem::file_size( name ) == 0 ) - failed = true; - - pid_t pid; - string procPath; - if (!failed){ - try { - ifstream f (name.c_str()); - f >> pid; - procPath = (str::stream() << "/proc/" << pid); - if (!boost::filesystem::exists(procPath)) - failed = true; - } - catch (const std::exception& e){ - cerr << "Error reading pid from lock file [" << name << "]: " << e.what() << endl; - failed = true; - } - } - - if (failed) { - cerr << "There doesn't seem to be a server running with dbpath: " << dbpath << endl; - ::_exit(EXIT_FAILURE); - } + ::_exit(EXIT_SUCCESS); + } +#endif +} - cout << "killing process with pid: " << pid << endl; - int ret = kill(pid, SIGTERM); - if (ret) { - int e = errno; - cerr << "failed to kill process: " << errnoWithDescription(e) << endl; - ::_exit(EXIT_FAILURE); - } +MONGO_INITIALIZER_GENERAL(CreateAuthorizationManager, + ("SetupInternalSecurityUser"), + MONGO_NO_DEPENDENTS) + (InitializerContext* context) { + AuthorizationManager* authzManager = + new AuthorizationManager(new AuthzManagerExternalStateMongod()); + setGlobalAuthorizationManager(authzManager); + return Status::OK(); +} - while (boost::filesystem::exists(procPath)) { - sleepsecs(1); - } +#ifdef MONGO_SSL +MONGO_INITIALIZER_GENERAL(setSSLManagerType, + MONGO_NO_PREREQUISITES, + ("SSLManager"))(InitializerContext* context) { + isSSLServer = true; + return Status::OK(); +} +#endif - ::_exit(EXIT_SUCCESS); +#if defined(_WIN32) +namespace mongo { + // the hook for mongoAbort + extern void (*reportEventToSystem)(const char *msg); + static void reportEventToSystemImpl(const char *msg) { + static ::HANDLE hEventLog = RegisterEventSource( NULL, TEXT("mongod") ); + if( hEventLog ) { + std::wstring s = toNativeString(msg); + LPCTSTR txt = s.c_str(); + BOOL ok = ReportEvent( + hEventLog, EVENTLOG_ERROR_TYPE, + 0, 0, NULL, + 1, + 0, + &txt, + 0); + wassert(ok); } -#endif } -} +} // namespace mongo +#endif // if defined(_WIN32) static int mongoDbMain(int argc, char* argv[], char **envp) { static StaticObserver staticObserver; +#if defined(_WIN32) + mongo::reportEventToSystem = &mongo::reportEventToSystemImpl; +#endif + getcurns = ourgetns; setupSignalHandlers(); + // Mongod shouldn't lazily kill cursors. It doesn't mix well with connection pooling. + DBClientConnection::setLazyKillCursor(false); + dbExecCommand = argv[0]; srand(curTimeMicros()); @@ -1271,10 +1012,14 @@ static int mongoDbMain(int argc, char* argv[], char **envp) { if( argc == 1 ) cout << dbExecCommand << " --help for help and startup options" << endl; + Status status = mongo::runGlobalInitializers(argc, argv, envp); + if (!status.isOK()) { + severe() << "Failed global initialization: " << status; + ::_exit(EXIT_FAILURE); + } - processCommandLineOptions(std::vector<std::string>(argv, argv + argc)); - mongo::runGlobalInitializersOrDie(argc, argv, envp); - CmdLine::censor(argc, argv); + startupConfigActions(std::vector<std::string>(argv, argv + argc)); + cmdline_utils::censorArgvArray(argc, argv); if (!initializeServerGlobalState()) ::_exit(EXIT_FAILURE); @@ -1293,213 +1038,7 @@ static int mongoDbMain(int argc, char* argv[], char **envp) { #endif StartupTest::runTests(); - initAndListen(cmdLine.port); + initAndListen(serverGlobalParams.port); dbexit(EXIT_CLEAN); return 0; } - -namespace mongo { - - string getDbContext(); - -#undef out - - -#if !defined(_WIN32) - -} // namespace mongo - -#include <signal.h> -#include <string.h> - -namespace mongo { - - void abruptQuit(int x) { - ostringstream ossSig; - ossSig << "Got signal: " << x << " (" << strsignal( x ) << ")." << endl; - rawOut( ossSig.str() ); - - /* - ostringstream ossOp; - ossOp << "Last op: " << currentOp.infoNoauth() << endl; - rawOut( ossOp.str() ); - */ - - ostringstream oss; - oss << "Backtrace:" << endl; - printStackTrace( oss ); - rawOut( oss.str() ); - - // Don't go through normal shutdown procedure. It may make things worse. - ::_exit(EXIT_ABRUPT); - - } - - void abruptQuitWithAddrSignal( int signal, siginfo_t *siginfo, void * ) { - ostringstream oss; - oss << "Invalid"; - if ( signal == SIGSEGV || signal == SIGBUS ) { - oss << " access"; - } else { - oss << " operation"; - } - oss << " at address: " << siginfo->si_addr << " from thread: " << getThreadName() << endl; - rawOut( oss.str() ); - abruptQuit( signal ); - } - - sigset_t asyncSignals; - // The signals in asyncSignals will be processed by this thread only, in order to - // ensure the db and log mutexes aren't held. - void signalProcessingThread() { - while (true) { - int actualSignal = 0; - int status = sigwait( &asyncSignals, &actualSignal ); - fassert(16781, status == 0); - switch (actualSignal) { - case SIGUSR1: - // log rotate signal - fassert(16782, rotateLogs()); - break; - default: - // interrupt/terminate signal - Client::initThread( "signalProcessingThread" ); - log() << "got signal " << actualSignal << " (" << strsignal( actualSignal ) - << "), will terminate after current cmd ends" << endl; - exitCleanly( EXIT_CLEAN ); - break; - } - } - } - - // this will be called in certain c++ error cases, for example if there are two active - // exceptions - void myterminate() { - rawOut( "terminate() called, printing stack (if implemented for platform):" ); - printStackTrace(); - ::abort(); - } - - // this gets called when new fails to allocate memory - void my_new_handler() { - rawOut( "out of memory, printing stack and exiting:" ); - printStackTrace(); - ::_exit(EXIT_ABRUPT); - } - - void setupSignals_ignoreHelper( int signal ) {} - - void setupSignalHandlers() { - setupCoreSignals(); - - struct sigaction addrSignals; - memset( &addrSignals, 0, sizeof( struct sigaction ) ); - addrSignals.sa_sigaction = abruptQuitWithAddrSignal; - sigemptyset( &addrSignals.sa_mask ); - addrSignals.sa_flags = SA_SIGINFO; - - verify( sigaction(SIGSEGV, &addrSignals, 0) == 0 ); - verify( sigaction(SIGBUS, &addrSignals, 0) == 0 ); - verify( sigaction(SIGILL, &addrSignals, 0) == 0 ); - verify( sigaction(SIGFPE, &addrSignals, 0) == 0 ); - - verify( signal(SIGABRT, abruptQuit) != SIG_ERR ); - verify( signal(SIGQUIT, abruptQuit) != SIG_ERR ); - verify( signal(SIGPIPE, SIG_IGN) != SIG_ERR ); - - setupSIGTRAPforGDB(); - - // asyncSignals is a global variable listing the signals that should be handled by the - // interrupt thread, once it is started via startSignalProcessingThread(). - sigemptyset( &asyncSignals ); - sigaddset( &asyncSignals, SIGHUP ); - sigaddset( &asyncSignals, SIGINT ); - sigaddset( &asyncSignals, SIGTERM ); - sigaddset( &asyncSignals, SIGUSR1 ); - - set_terminate( myterminate ); - set_new_handler( my_new_handler ); - } - - void startSignalProcessingThread() { - verify( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 ); - boost::thread it( signalProcessingThread ); - } - -#else // WIN32 - void consoleTerminate( const char* controlCodeName ) { - Client::initThread( "consoleTerminate" ); - log() << "got " << controlCodeName << ", will terminate after current cmd ends" << endl; - exitCleanly( EXIT_KILL ); - } - - BOOL WINAPI CtrlHandler( DWORD fdwCtrlType ) { - - switch( fdwCtrlType ) { - - case CTRL_C_EVENT: - rawOut( "Ctrl-C signal" ); - consoleTerminate( "CTRL_C_EVENT" ); - return TRUE ; - - case CTRL_CLOSE_EVENT: - rawOut( "CTRL_CLOSE_EVENT signal" ); - consoleTerminate( "CTRL_CLOSE_EVENT" ); - return TRUE ; - - case CTRL_BREAK_EVENT: - rawOut( "CTRL_BREAK_EVENT signal" ); - consoleTerminate( "CTRL_BREAK_EVENT" ); - return TRUE; - - case CTRL_LOGOFF_EVENT: - // only sent to services, and only in pre-Vista Windows; FALSE means ignore - return FALSE; - - case CTRL_SHUTDOWN_EVENT: - rawOut( "CTRL_SHUTDOWN_EVENT signal" ); - consoleTerminate( "CTRL_SHUTDOWN_EVENT" ); - return TRUE; - - default: - return FALSE; - } - } - - // called by mongoAbort() - extern void (*reportEventToSystem)(const char *msg); - void reportEventToSystemImpl(const char *msg) { - static ::HANDLE hEventLog = RegisterEventSource( NULL, TEXT("mongod") ); - if( hEventLog ) { - std::wstring s = toNativeString(msg); - LPCTSTR txt = s.c_str(); - BOOL ok = ReportEvent( - hEventLog, EVENTLOG_ERROR_TYPE, - 0, 0, NULL, - 1, - 0, - &txt, - 0); - wassert(ok); - } - } - - void myPurecallHandler() { - printStackTrace(); - mongoAbort("pure virtual"); - } - - void setupSignalHandlers() { - reportEventToSystem = reportEventToSystemImpl; - setWindowsUnhandledExceptionFilter(); - massert(10297, - "Couldn't register Windows Ctrl-C handler", - SetConsoleCtrlHandler(static_cast<PHANDLER_ROUTINE>(CtrlHandler), TRUE)); - _set_purecall_handler( myPurecallHandler ); - } - - void startSignalProcessingThread() {} - -#endif // if !defined(_WIN32) - -} // namespace mongo |
