// @file db.cpp : Defines main() for the mongod program. /** * Copyright (C) 2008-2014 MongoDB 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 . * * 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/platform/basic.h" #include #include #include #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/authorization_manager.h" #include "mongo/db/auth/authorization_manager_global.h" #include "mongo/db/auth/authz_manager_external_state_d.h" #include "mongo/db/catalog/database_catalog_entry.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/commands/server_status.h" #include "mongo/db/commands/server_status_metric.h" #include "mongo/db/d_concurrency.h" #include "mongo/db/d_globals.h" #include "mongo/db/db.h" #include "mongo/db/dbmessage.h" #include "mongo/db/dbwebserver.h" #include "mongo/db/global_environment_d.h" #include "mongo/db/global_environment_experiment.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/log_process_details.h" #include "mongo/db/mongod_options.h" #include "mongo/db/operation_context_impl.h" #include "mongo/db/pdfile_version.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/network_interface_impl.h" #include "mongo/db/repl/repl_coordinator_global.h" #include "mongo/db/repl/repl_coordinator_impl.h" #include "mongo/db/repl/repl_coordinator_legacy.h" #include "mongo/db/repl/repl_settings.h" #include "mongo/db/repl/rs.h" #include "mongo/db/repl/topology_coordinator_impl.h" #include "mongo/db/restapi.h" #include "mongo/db/server_parameters.h" #include "mongo/db/startup_warnings.h" #include "mongo/db/stats/counters.h" #include "mongo/db/stats/snapshots.h" #include "mongo/db/storage/mmap_v1/dur.h" #include "mongo/db/storage/storage_engine.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/exit.h" #include "mongo/util/file_allocator.h" #include "mongo/util/log.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_reporting.h" #if !defined(_WIN32) # include #endif namespace mongo { MONGO_LOG_DEFAULT_COMPONENT_FILE(::mongo::logger::LogComponent::kStorage); void (*snmpInit)() = NULL; extern int diagLogging; extern int lockFile; #ifdef _WIN32 ntservice::NtServiceDefaultStrings defaultServiceStrings = { L"MongoDB", L"MongoDB", L"MongoDB Server" }; #endif Timer startupSrandTimer; struct MyStartupTests { MyStartupTests() { verify( sizeof(OID) == 12 ); } } mystartupdbcpp; QueryResult* emptyMoreResult(long long); /* todo: make this a real test. the stuff in dbtests/ seem to do all dbdirectclient which exhaust doesn't support yet. */ // QueryOption_Exhaust #define TESTEXHAUST 0 #if( TESTEXHAUST ) void testExhaust() { sleepsecs(1); unsigned n = 0; auto f = [&n](const BSONObj& o) { verify( o.valid() ); //cout << o << endl; n++; bool testClosingSocketOnError = false; if( testClosingSocketOnError ) verify(false); }; DBClientConnection db(false); db.connect("localhost"); const char *ns = "local.foo"; if( db.count(ns) < 10000 ) for( int i = 0; i < 20000; i++ ) db.insert(ns, BSON("aaa" << 3 << "b" << "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")); try { db.query(f, ns, Query() ); } catch(...) { cout << "hmmm" << endl; } try { db.query(f, ns, Query() ); } catch(...) { cout << "caught" << endl; } cout << n << endl; }; #endif class MyMessageHandler : public MessageHandler { public: virtual void connected( AbstractMessagingPort* p ) { Client::initThread("conn", p); } virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) { OperationContextImpl txn; while ( true ) { if ( inShutdown() ) { log() << "got request after shutdown()" << endl; break; } lastError.startRequest( m , le ); DbResponse dbresponse; assembleResponse( &txn, m, dbresponse, port->remote() ); if ( dbresponse.response ) { port->reply(m, *dbresponse.response, dbresponse.responseTo); if( dbresponse.exhaustNS.size() > 0 ) { MsgData *header = dbresponse.response->header(); QueryResult *qr = (QueryResult *) header; long long cursorid = qr->cursorId; if( cursorid ) { verify( dbresponse.exhaustNS.size() && dbresponse.exhaustNS[0] ); string ns = dbresponse.exhaustNS; // before reset() free's it... m.reset(); BufBuilder b(512); b.appendNum((int) 0 /*size set later in appendData()*/); b.appendNum(header->id); b.appendNum(header->responseTo); b.appendNum((int) dbGetMore); b.appendNum((int) 0); b.appendStr(ns); b.appendNum((int) 0); // ntoreturn b.appendNum(cursorid); m.appendData(b.buf(), b.len()); b.decouple(); DEV log() << "exhaust=true sending more" << endl; continue; // this goes back to top loop } } } break; } } virtual void disconnected( AbstractMessagingPort* p ) { Client * c = currentClient.get(); if( c ) c->shutdown(); } }; static void logStartup() { BSONObjBuilder toLog; stringstream id; id << getHostNameCached() << "-" << jsTime(); toLog.append( "_id", id.str() ); toLog.append( "hostname", getHostNameCached() ); toLog.appendTimeT( "startTime", time(0) ); toLog.append( "startTimeLocal", dateToCtimeString(curTimeMillis64()) ); toLog.append("cmdLine", serverGlobalParams.parsedOpts); toLog.append( "pid", ProcessId::getCurrent().asLongLong() ); BSONObjBuilder buildinfo( toLog.subobjStart("buildinfo")); appendBuildInfo(buildinfo); buildinfo.doneFast(); BSONObj o = toLog.obj(); OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); // No WriteUnitOfWork, as DirectClient creates its own units of work DBDirectClient c(&txn); static const char* name = "local.startup_log"; c.createCollection( name, 10 * 1024 * 1024, true ); c.insert( name, o); } static void listen(int port) { //testTheDb(); MessageServer::Options options; options.port = port; options.ipList = serverGlobalParams.bind_ip; MessageServer * server = createServer( options , new MyMessageHandler() ); server->setAsTimeTracker(); // we must setupSockets prior to logStartup() to avoid getting too high // a file descriptor for our calls to select() server->setupSockets(); logStartup(); repl::getGlobalReplicationCoordinator()->startReplication( new repl::TopologyCoordinatorImpl(), new repl::NetworkInterfaceImpl()); if (serverGlobalParams.isHttpInterfaceEnabled) boost::thread web(stdx::bind(&webServerThread, new RestAdminAccess())); // takes ownership #if(TESTEXHAUST) boost::thread thr(testExhaust); #endif server->run(); } void checkForIdIndexes( OperationContext* txn, Database* db ) { if ( db->name() == "local") { // we do not need an _id index on anything in the local database return; } list collections; db->getDatabaseCatalogEntry()->getCollectionNamespaces( &collections ); // for each collection, ensure there is a $_id_ index for (list::iterator i = collections.begin(); i != collections.end(); ++i) { const string& collectionName = *i; NamespaceString ns( collectionName ); if ( ns.isSystem() ) continue; Collection* coll = db->getCollection( txn, 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(bool shouldClearNonLocalTmpCollections) { LOG(1) << "enter repairDatabases (to check pdfile version #)" << endl; OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); WriteUnitOfWork wunit(txn.recoveryUnit()); vector< string > dbNames; globalStorageEngine->listDatabases( &dbNames ); for ( vector< string >::iterator i = dbNames.begin(); i != dbNames.end(); ++i ) { string dbName = *i; LOG(1) << "\t" << dbName << endl; Client::Context ctx(&txn, dbName ); if (repl::getGlobalReplicationCoordinator()->getSettings().usingReplSets()) { // we only care about the _id index if we are in a replset checkForIdIndexes(&txn, ctx.db()); } if (shouldClearNonLocalTmpCollections || dbName == "local") ctx.db()->clearTmpCollections(&txn); if ( mongodGlobalParams.repair ) { fassert(18506, globalStorageEngine->repairDatabase(&txn, dbName)); } else if (!ctx.db()->getDatabaseCatalogEntry()->currentFilesCompatible(&txn)) { log() << "****"; log() << "cannot do this upgrade without an upgrade in the middle"; log() << "please do a --repair with 2.6 and then start this version"; dbexit( EXIT_NEED_UPGRADE ); invariant( false ); return; } else { // major versions match, check indexes const string systemIndexes = ctx.db()->name() + ".system.indexes"; Collection* coll = ctx.db()->getCollection( &txn, systemIndexes ); auto_ptr runner(InternalPlanner::collectionScan(&txn, systemIndexes,coll)); 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 (ctx.db()->getDatabaseCatalogEntry()->isOlderThan24(&txn)) { if (IndexNames::existedBefore24(plugin)) continue; log() << "Index " << index << " claims to be of type '" << plugin << "', " << "which is either invalid or did not exist before v2.4. " << "See the upgrade section: " << "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(&txn, dbName.c_str()); } } wunit.commit(); LOG(1) << "done repairDatabases" << endl; } void clearTmpFiles() { 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(); if ( boost::filesystem::is_directory( *i ) && fileName.length() && fileName[ 0 ] == '$' ) boost::filesystem::remove_all( *i ); } } /** * Checks if this server was started without --replset but has a config in local.system.replset * (meaning that this is probably a replica set member started in stand-alone mode). * * @returns the number of documents in local.system.replset or 0 if this was started with * --replset. */ static unsigned long long checkIfReplMissingFromCommandLine() { OperationContextImpl txn; // This is helpful for the query below to work as you can't open files when readlocked Lock::GlobalWrite lk(txn.lockState()); if (!repl::getGlobalReplicationCoordinator()->getSettings().usingReplSets()) { DBDirectClient c(&txn); return c.count("local.system.replset"); } return 0; } /** * does background async flushes of mmapped files */ class DataFileSync : public BackgroundJob , public ServerStatusSection { public: DataFileSync() : ServerStatusSection( "backgroundFlushing" ), _total_time( 0 ), _flushes( 0 ), _last() { } virtual bool includeByDefault() const { return true; } string name() const { return "DataFileSync"; } void run() { Client::initThread( name().c_str() ); if (storageGlobalParams.syncdelay == 0) { log() << "warning: --syncdelay 0 is not recommended and can have strange performance" << endl; } else if (storageGlobalParams.syncdelay == 1) { log() << "--syncdelay 1" << endl; } else if (storageGlobalParams.syncdelay != 60) { LOG(1) << "--syncdelay " << storageGlobalParams.syncdelay << endl; } int time_flushing = 0; while ( ! inShutdown() ) { _diaglog.flush(); 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, (storageGlobalParams.syncdelay * 1000) - time_flushing)); if ( inShutdown() ) { // occasional issue trying to flush during shutdown when sleep interrupted break; } Date_t start = jsTime(); int numFiles = globalStorageEngine->flushAllFiles( true ); time_flushing = (int) (jsTime() - start); _flushed(time_flushing); if( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) || time_flushing >= 10000 ) { log() << "flushing mmaps took " << time_flushing << "ms " << " for " << numFiles << " files" << endl; } } } BSONObj generateSection(const BSONElement& configElement) const { BSONObjBuilder b; b.appendNumber( "flushes" , _flushes ); b.appendNumber( "total_ms" , _total_time ); b.appendNumber( "average_ms" , (_flushes ? (_total_time / double(_flushes)) : 0.0) ); b.appendNumber( "last_ms" , _last_time ); b.append("last_finished", _last); return b.obj(); } private: void _flushed(int ms) { _flushes++; _total_time += ms; _last_time = ms; _last = jsTime(); } long long _total_time; long long _flushes; int _last_time; Date_t _last; } dataFileSync; namespace { class MemJournalServerStatusMetric : public ServerStatusMetric { public: MemJournalServerStatusMetric() : ServerStatusMetric(".mem.mapped") {} virtual void appendAtLeaf( BSONObjBuilder& b ) const { int m = static_cast(MemoryMappedFile::totalMappedLength() / ( 1024 * 1024 )); b.appendNumber( "mapped" , m ); if (storageGlobalParams.dur) { m *= 2; b.appendNumber( "mappedWithJournal" , m ); } } } memJournalServerStatusMetric; } #if 0 // TODO SERVER-14143 figure out something better. For now just disabling js interruption. const char * jsInterruptCallback() { // should be safe to interrupt in js code, even if we have a write lock return killCurrentOp.checkForInterruptNoAssert(); } unsigned jsGetCurrentOpIdCallback() { return cc().curop()->opNum(); } #endif /// warn if readahead > 256KB (gridfs chunk size) static void checkReadAhead(const string& dir) { #ifdef __linux__ 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; log() << "** WARNING: Readahead for " << dir << " is set to " << kb << "KB" << startupWarningsLog; log() << "** We suggest setting it to 256KB (512 sectors) or less" << 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__ } static void _initAndListen(int listenPort ) { Client::initThread("initandlisten"); bool is32bit = sizeof(int*) == 4; const repl::ReplSettings& replSettings = repl::getGlobalReplicationCoordinator()->getSettings(); { 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; logStartupWarnings(); #if defined(_WIN32) printTargetMinOS(); #endif logProcessDetails(); { stringstream ss; ss << endl; ss << "*********************************************************************" << 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(storageGlobalParams.dbpath)); } { stringstream ss; ss << "repairpath (" << storageGlobalParams.repairpath << ") does not exist"; uassert(12590, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.repairpath)); } // TODO check non-journal subdirs if using directory-per-db checkReadAhead(storageGlobalParams.dbpath); 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 (storageGlobalParams.durOptions & StorageGlobalParams::DurRecoverOnly) return; unsigned long long missingRepl = checkIfReplMissingFromCommandLine(); if (missingRepl) { log() << startupWarningsLog; log() << "** WARNING: mongod started without --replSet yet " << missingRepl << " documents are present in local.system.replset" << startupWarningsLog; log() << "** Restart with --replSet unless you are doing maintenance and no" << " other clients are connected." << startupWarningsLog; log() << "** The TTL collection monitor will not start because of this." << startupWarningsLog; log() << "** For more info see http://dochub.mongodb.org/core/ttlcollections" << startupWarningsLog; log() << startupWarningsLog; } if (mongodGlobalParams.scriptingEnabled) { ScriptEngine::setup(); #if 0 // TODO SERVER-14143 figure out something better. For now just disabling js interruption. globalScriptEngine->setCheckInterruptCallback( jsInterruptCallback ); globalScriptEngine->setGetCurrentOpIdCallback( jsGetCurrentOpIdCallback ); #endif } // 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 == repl::SimpleSlave); repairDatabasesAndCheckVersion(shouldClearNonLocalTmpCollections); if (mongodGlobalParams.upgrade) { log() << "finished checking dbs" << endl; cc().shutdown(); exitCleanly(EXIT_CLEAN); } uassertStatusOK(getGlobalAuthorizationManager()->initialize()); /* this is for security on certain platforms (nonce generation) */ srand((unsigned) (curTimeMicros() ^ startupSrandTimer.micros())); // 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::startRunningPeriodicTasks(); if (missingRepl) { // a warning was logged earlier } else { startTTLBackgroundJob(); } #ifndef _WIN32 mongo::signalForkSuccess(); #endif { OperationContextImpl txn; 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 ctx(&txn, "admin"); } authindex::configureSystemIndexes(&txn, "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); } static void initAndListen(int listenPort) { try { _initAndListen(listenPort); } catch ( DBException &e ) { log() << "exception in initAndListen: " << e.toString() << ", terminating" << endl; dbexit( EXIT_UNCAUGHT ); } catch ( std::exception &e ) { log() << "exception in initAndListen std::exception: " << e.what() << ", terminating" << endl; dbexit( EXIT_UNCAUGHT ); } catch ( int& n ) { log() << "exception in initAndListen int: " << n << ", terminating" << endl; dbexit( EXIT_UNCAUGHT ); } catch(...) { log() << "exception in initAndListen, terminating" << endl; dbexit( EXIT_UNCAUGHT ); } } #if defined(_WIN32) void initService() { ntservice::reportStatus( SERVICE_RUNNING ); log() << "Service running" << endl; initAndListen(serverGlobalParams.port); } #endif } // namespace mongo using namespace mongo; 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); } #endif MONGO_INITIALIZER_GENERAL(ForkServer, ("EndStartupOptionHandling"), ("default"))(InitializerContext* context) { mongo::forkServerOrDie(); return Status::OK(); } /* * 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& 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 command = moe::startupOptionsParsed["command"].as< vector >(); if (command[0].compare("dbpath") == 0) { cout << storageGlobalParams.dbpath << endl; ::_exit(EXIT_SUCCESS); } if (command[0].compare("run") != 0) { cout << "Invalid command: " << command[0] << endl; printMongodHelp(moe::startupOptions); ::_exit(EXIT_FAILURE); } if (command.size() > 1) { cout << "Too many parameters to 'run' command" << endl; printMongodHelp(moe::startupOptions); ::_exit(EXIT_FAILURE); } } #ifdef _WIN32 ntservice::configureService(initService, moe::startupOptionsParsed, defaultServiceStrings, std::vector(), args); #endif // _WIN32 #ifdef __linux__ if (moe::startupOptionsParsed.count("shutdown") && moe::startupOptionsParsed["shutdown"].as() == true) { 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; } catch (const std::exception& e){ cerr << "Error reading pid from lock file [" << name << "]: " << e.what() << endl; failed = true; } } if (failed) { std::cerr << "There doesn't seem to be a server running with dbpath: " << storageGlobalParams.dbpath << std::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); } while (boost::filesystem::exists(procPath)) { sleepsecs(1); } ::_exit(EXIT_SUCCESS); } #endif } MONGO_INITIALIZER_GENERAL(CreateAuthorizationManager, ("SetupInternalSecurityUser"), MONGO_NO_DEPENDENTS) (InitializerContext* context) { AuthorizationManager* authzManager = new AuthorizationManager(new AuthzManagerExternalStateMongod()); setGlobalAuthorizationManager(authzManager); return Status::OK(); } MONGO_INITIALIZER(SetGlobalConfigExperiment)(InitializerContext* context) { setGlobalEnvironment(new GlobalEnvironmentMongoD()); return Status::OK(); } namespace { // TODO(spencer): Remove this startup parameter once the new ReplicationCoordinator is fully // working MONGO_EXPORT_STARTUP_SERVER_PARAMETER(useNewReplCoordinator, bool, false); } // namespace namespace { repl::ReplSettings replSettings; } // namespace namespace mongo { void setGlobalReplSettings(const repl::ReplSettings& settings) { replSettings = settings; } } // namespace mongo MONGO_INITIALIZER(CreateReplicationCoordinator)(InitializerContext* context) { if (useNewReplCoordinator) { repl::setGlobalReplicationCoordinator( new repl::ReplicationCoordinatorImpl(replSettings)); } else { repl::setGlobalReplicationCoordinator( new repl::LegacyReplicationCoordinator(replSettings)); } return Status::OK(); } #ifdef MONGO_SSL MONGO_INITIALIZER_GENERAL(setSSLManagerType, MONGO_NO_PREREQUISITES, ("SSLManager"))(InitializerContext* context) { isSSLServer = true; return Status::OK(); } #endif #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); } } } // 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 setupSignalHandlers(false); dbExecCommand = argv[0]; srand(curTimeMicros()); { unsigned x = 0x12345678; unsigned char& b = (unsigned char&) x; if ( b != 0x78 ) { log() << "big endian cpus not yet supported" << endl; return 33; } } 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); } startupConfigActions(std::vector(argv, argv + argc)); cmdline_utils::censorArgvArray(argc, argv); if (!initializeServerGlobalState()) ::_exit(EXIT_FAILURE); // Per SERVER-7434, startSignalProcessingThread() must run after any forks // (initializeServerGlobalState()) and before creation of any other threads. startSignalProcessingThread(); dataFileSync.go(); #if defined(_WIN32) if (ntservice::shouldStartService()) { ntservice::startService(); // exits directly and so never reaches here either. } #endif StartupTest::runTests(); initAndListen(serverGlobalParams.port); fassertFailed(18000); }