Files
mongo/db/db.cpp

1309 lines
45 KiB
C++
Raw Normal View History

2010-11-04 10:27:40 -04:00
// @file db.cpp : Defines main() for the mongod program.
2008-06-06 09:43:15 -04:00
/**
* Copyright (C) 2008 10gen Inc.
2008-12-28 20:28:49 -05:00
*
* 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.
2008-12-28 20:28:49 -05:00
*
* 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.
2008-12-28 20:28:49 -05:00
*
* 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/>.
*/
2010-04-27 15:27:52 -04:00
#include "pch.h"
2008-06-06 09:43:15 -04:00
#include "db.h"
#include "introspect.h"
2008-07-28 17:52:44 -04:00
#include "repl.h"
#include "../util/unittest.h"
#include "../util/file_allocator.h"
#include "../util/background.h"
#include "../util/text.h"
2008-09-29 18:00:53 -04:00
#include "dbmessage.h"
2008-12-02 09:54:32 -08:00
#include "instance.h"
#include "clientcursor.h"
#include "pdfile.h"
2010-03-15 16:02:24 -04:00
#include "stats/counters.h"
2010-05-29 15:45:47 -04:00
#include "repl/rs.h"
#include "../scripting/engine.h"
2009-11-18 12:53:56 -05:00
#include "module.h"
2009-08-25 10:24:44 -04:00
#include "cmdline.h"
2010-02-02 17:16:25 -05:00
#include "stats/snapshots.h"
2010-05-17 18:06:53 -04:00
#include "../util/concurrency/task.h"
#include "../util/version.h"
#include "../util/ramlog.h"
#include "../util/net/message_server.h"
#include "client.h"
#include "restapi.h"
#include "dbwebserver.h"
2010-11-13 17:42:41 -05:00
#include "dur.h"
2010-11-27 15:25:08 -05:00
#include "concurrency.h"
2011-05-16 18:05:03 -04:00
#include "../s/d_writeback.h"
#if defined(_WIN32)
# include "../util/ntservice.h"
#else
# include <sys/file.h>
#endif
namespace mongo {
namespace dur {
extern unsigned long long DataLimitPerJournalFile;
}
/* only off if --nocursors which is for debugging. */
extern bool useCursors;
2009-03-10 10:54:00 -04:00
/* only off if --nohints */
extern bool useHints;
2009-11-11 13:54:05 -05:00
extern int diagLogging;
2010-09-09 07:46:22 -04:00
extern unsigned lenForNewNsFiles;
2009-04-01 13:48:02 -04:00
extern int lockFile;
2011-01-04 00:40:41 -05:00
extern bool checkNsFilesOnLoad;
extern string repairpath;
2009-07-08 14:15:14 -04:00
void setupSignals( bool inFork );
void startReplication();
void exitCleanly( ExitCode code );
CmdLine cmdLine;
2010-11-04 10:29:42 -04:00
static bool scriptingEnabled = true;
bool noHttpInterface = false;
bool shouldRepairDatabases = 0;
2010-11-04 17:43:02 -04:00
static bool forceRepair = 0;
Timer startupSrandTimer;
2011-01-04 00:40:41 -05:00
const char *ourgetns() {
2009-10-13 16:01:02 -04:00
Client *c = currentClient.get();
if ( ! c )
return "";
Client::Context* cc = c->getContext();
return cc ? cc->ns() : "";
2009-10-13 16:01:02 -04:00
}
struct MyStartupTests {
MyStartupTests() {
assert( sizeof(OID) == 12 );
}
} mystartupdbcpp;
2008-06-06 09:43:15 -04:00
QueryResult* emptyMoreResult(long long);
2008-06-06 09:43:15 -04:00
2011-01-04 00:40:41 -05:00
/* todo: make this a real test. the stuff in dbtests/ seem to do all dbdirectclient which exhaust doesn't support yet. */
2010-06-06 22:19:06 -04:00
// QueryOption_Exhaust
#define TESTEXHAUST 0
#if( TESTEXHAUST )
2011-01-04 00:40:41 -05:00
void testExhaust() {
2010-06-06 22:19:06 -04:00
sleepsecs(1);
unsigned n = 0;
2011-01-04 00:40:41 -05:00
auto f = [&n](const BSONObj& o) {
2010-06-06 22:19:06 -04:00
assert( o.valid() );
//cout << o << endl;
n++;
bool testClosingSocketOnError = false;
if( testClosingSocketOnError )
assert(false);
};
DBClientConnection db(false);
db.connect("localhost");
const char *ns = "local.foo";
if( db.count(ns) < 10000 )
2011-01-04 00:40:41 -05:00
for( int i = 0; i < 20000; i++ )
2010-06-06 22:19:06 -04:00
db.insert(ns, BSON("aaa" << 3 << "b" << "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
try {
db.query(f, ns, Query() );
}
2011-01-04 00:40:41 -05:00
catch(...) {
2010-06-06 22:19:06 -04:00
cout << "hmmm" << endl;
}
try {
db.query(f, ns, Query() );
}
2011-01-04 00:40:41 -05:00
catch(...) {
2010-06-06 22:19:06 -04:00
cout << "caught" << endl;
}
cout << n << endl;
};
#endif
void sysRuntimeInfo() {
2011-06-23 11:38:30 -04:00
out() << "sysinfo:" << endl;
2009-01-29 16:06:22 -05:00
#if defined(_SC_PAGE_SIZE)
out() << " page size: " << (int) sysconf(_SC_PAGE_SIZE) << endl;
2009-01-29 16:06:22 -05:00
#endif
#if defined(_SC_PHYS_PAGES)
out() << " _SC_PHYS_PAGES: " << sysconf(_SC_PHYS_PAGES) << endl;
2009-01-29 16:06:22 -05:00
#endif
#if defined(_SC_AVPHYS_PAGES)
out() << " _SC_AVPHYS_PAGES: " << sysconf(_SC_AVPHYS_PAGES) << endl;
2009-01-29 16:06:22 -05:00
#endif
}
2009-01-29 16:06:22 -05:00
2010-06-07 02:22:43 -04:00
/* if server is really busy, wait a bit */
void beNice() {
2010-06-10 11:24:52 -04:00
sleepmicros( Client::recommendedYieldMicros() );
2010-06-07 02:22:43 -04:00
}
2011-04-05 02:24:16 -04:00
class MyMessageHandler : public MessageHandler {
public:
virtual void connected( AbstractMessagingPort* p ) {
Client& c = Client::initThread("conn", p);
c.getAuthenticationInfo()->isLocalHost = p->remote().isLocalHost();
}
virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) {
while ( true ) {
if ( inShutdown() ) {
log() << "got request after shutdown()" << endl;
break;
}
lastError.startRequest( m , le );
DbResponse dbresponse;
assembleResponse( m, dbresponse, port->remote() );
if ( dbresponse.response ) {
port->reply(m, *dbresponse.response, dbresponse.responseTo);
if( dbresponse.exhaust ) {
MsgData *header = dbresponse.response->header();
QueryResult *qr = (QueryResult *) header;
long long cursorid = qr->cursorId;
if( cursorid ) {
assert( dbresponse.exhaust && *dbresponse.exhaust != 0 );
string ns = dbresponse.exhaust; // 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;
beNice();
continue; // this goes back to top loop
}
}
}
break;
}
}
virtual void disconnected( AbstractMessagingPort* p ) {
Client * c = currentClient.get();
if( c ) c->shutdown();
globalScriptEngine->threadDone();
}
};
2011-04-05 02:30:06 -04:00
void listen(int port) {
//testTheDb();
MessageServer::Options options;
options.port = port;
options.ipList = cmdLine.bind_ip;
2009-09-18 14:32:25 -04:00
2011-04-05 02:30:06 -04:00
MessageServer * server = createServer( options , new MyMessageHandler() );
server->setAsTimeTracker();
2011-04-05 02:30:06 -04:00
startReplication();
if ( !noHttpInterface )
boost::thread web( boost::bind(&webServerThread, new RestAdminAccess() /* takes ownership */));
2008-12-28 20:28:49 -05:00
2011-04-05 02:30:06 -04:00
#if(TESTEXHAUST)
boost::thread thr(testExhaust);
#endif
server->run();
}
2008-06-06 09:43:15 -04:00
2011-04-05 02:30:06 -04:00
2011-01-04 00:40:41 -05:00
bool doDBUpgrade( const string& dbName , string errmsg , DataFileHeader * h ) {
static DBDirectClient db;
2011-01-04 00:40:41 -05:00
if ( h->version == 4 && h->versionMinor == 4 ) {
assert( PDFILE_VERSION == 4 );
assert( PDFILE_VERSION_MINOR == 5 );
2011-01-04 00:40:41 -05:00
list<string> colls = db.getCollectionNames( dbName );
2011-01-04 00:40:41 -05:00
for ( list<string>::iterator i=colls.begin(); i!=colls.end(); i++) {
string c = *i;
log() << "\t upgrading collection:" << c << endl;
BSONObj out;
bool ok = db.runCommand( dbName , BSON( "reIndex" << c.substr( dbName.size() + 1 ) ) , out );
2011-01-04 00:40:41 -05:00
if ( ! ok ) {
errmsg = "reindex failed";
log() << "\t\t reindex failed: " << out << endl;
return false;
}
}
2011-01-04 00:40:41 -05:00
h->versionMinor = 5;
return true;
}
2011-01-04 00:40:41 -05:00
// do this in the general case
return repairDatabase( dbName.c_str(), errmsg );
}
2011-01-04 00:40:41 -05:00
2010-11-04 10:27:40 -04:00
// ran at startup.
static void repairDatabasesAndCheckVersion() {
2011-01-04 00:40:41 -05:00
// LastError * le = lastError.get( true );
Client::GodScope gs;
2010-07-16 10:16:37 -04:00
log(1) << "enter repairDatabases (to check pdfile version #)" << endl;
2011-01-04 00:40:41 -05:00
//assert(checkNsFilesOnLoad);
2010-01-21 13:40:18 -05:00
checkNsFilesOnLoad = false; // we are mainly just checking the header - don't scan the whole .ns file for every db here.
dblock lk;
vector< string > dbNames;
getDatabaseNames( dbNames );
for ( vector< string >::iterator i = dbNames.begin(); i != dbNames.end(); ++i ) {
string dbName = *i;
2009-11-03 13:01:07 -05:00
log(1) << "\t" << dbName << endl;
Client::Context ctx( dbName );
MongoDataFile *p = cc().database()->getFile( 0 );
2010-03-31 15:08:40 -04:00
DataFileHeader *h = p->getHeader();
2010-11-26 18:18:24 -05:00
if ( !h->isCurrentVersion() || forceRepair ) {
if( h->version <= 0 ) {
uasserted(14026,
str::stream() << "db " << dbName << " appears corrupt pdfile version: " << h->version
<< " info: " << h->versionMinor << ' ' << h->fileLength);
2010-11-26 18:18:24 -05:00
}
log() << "****" << endl;
log() << "****" << endl;
log() << "need to upgrade database " << dbName << " with pdfile version " << h->version << "." << h->versionMinor << ", "
<< "new version: " << PDFILE_VERSION << "." << PDFILE_VERSION_MINOR << endl;
2011-01-04 00:40:41 -05:00
if ( shouldRepairDatabases ) {
// QUESTION: Repair even if file format is higher version than code?
log() << "\t starting upgrade" << endl;
string errmsg;
assert( doDBUpgrade( dbName , errmsg , h ) );
}
else {
2010-11-04 10:27:40 -04:00
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;
return;
}
2011-01-04 00:40:41 -05:00
}
else {
2010-08-26 10:42:07 -04:00
Database::closeDatabase( dbName.c_str(), dbpath );
}
2008-12-28 20:28:49 -05:00
}
2009-11-03 13:01:07 -05:00
log(1) << "done repairDatabases" << endl;
2011-01-04 00:40:41 -05:00
if ( shouldRepairDatabases ) {
log() << "finished checking dbs" << endl;
cc().shutdown();
dbexit( EXIT_CLEAN );
}
2010-01-21 13:40:18 -05:00
checkNsFilesOnLoad = true;
2008-12-28 20:28:49 -05:00
}
void clearTmpFiles() {
boost::filesystem::path path( dbpath );
for ( boost::filesystem::directory_iterator i( path );
i != boost::filesystem::directory_iterator(); ++i ) {
2009-11-16 11:33:57 -05:00
string fileName = boost::filesystem::path(*i).leaf();
if ( boost::filesystem::is_directory( *i ) &&
2011-01-04 00:40:41 -05:00
fileName.length() && fileName[ 0 ] == '$' )
boost::filesystem::remove_all( *i );
}
2009-01-14 17:17:24 -05:00
}
2011-01-04 00:40:41 -05:00
2011-11-13 10:20:16 -05:00
void checkIfReplMissingFromCommandLine() {
if( !cmdLine.usingReplSets() ) {
Client::GodScope gs;
DBDirectClient c;
unsigned long long x =
c.count("local.system.replset");
if( x ) {
log() << endl;
log() << "** warning: mongod started without --replSet yet " << x << " documents are present in local.system.replset" << endl;
log() << "** restart with --replSet unless you are doing maintenance and no other clients are connected" << endl;
log() << endl;
}
}
}
2009-03-06 13:13:07 -05:00
void clearTmpCollections() {
2011-12-05 15:55:51 -05:00
writelock lk; // _openAllFiles is false at this point, so this is helpful for the query below to work as you can't open files when readlocked
Client::GodScope gs;
2009-03-06 13:13:07 -05:00
vector< string > toDelete;
DBDirectClient cli;
auto_ptr< DBClientCursor > c = cli.query( "local.system.namespaces", Query( fromjson( "{name:/^local.temp./}" ) ) );
2009-12-11 12:41:26 -05:00
while( c->more() ) {
BSONObj o = c->next();
toDelete.push_back( o.getStringField( "name" ) );
}
2009-03-06 13:13:07 -05:00
for( vector< string >::iterator i = toDelete.begin(); i != toDelete.end(); ++i ) {
log() << "Dropping old temporary collection: " << *i << endl;
cli.dropCollection( *i );
}
}
2011-01-04 00:40:41 -05:00
2009-11-27 22:28:56 -05:00
/**
* does background async flushes of mmapped files
*/
class DataFileSync : public BackgroundJob {
public:
2010-10-13 17:38:09 -04:00
string name() const { return "DataFileSync"; }
2011-01-04 00:40:41 -05:00
void run() {
if( cmdLine.syncdelay == 0 )
2010-06-29 15:14:00 -04:00
log() << "warning: --syncdelay 0 is not recommended and can have strange performance" << endl;
2011-01-04 00:40:41 -05:00
else if( cmdLine.syncdelay == 1 )
2010-06-29 15:14:00 -04:00
log() << "--syncdelay 1" << endl;
else if( cmdLine.syncdelay != 60 )
log(1) << "--syncdelay " << cmdLine.syncdelay << endl;
int time_flushing = 0;
2011-01-04 00:40:41 -05:00
while ( ! inShutdown() ) {
_diaglog.flush();
2011-01-04 00:40:41 -05:00
if ( cmdLine.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) );
2011-01-04 00:40:41 -05:00
if ( inShutdown() ) {
2010-04-02 14:49:45 -04:00
// occasional issue trying to flush during shutdown when sleep interrupted
break;
}
2011-01-04 00:40:41 -05:00
Date_t start = jsTime();
2010-07-26 16:07:07 -04:00
int numFiles = MemoryMappedFile::flushAll( true );
2010-03-22 10:39:01 -04:00
time_flushing = (int) (jsTime() - start);
2010-03-15 16:02:24 -04:00
globalFlushCounters.flushed(time_flushing);
if( logLevel >= 1 || time_flushing >= 10000 ) {
log() << "flushing mmaps took " << time_flushing << "ms " << " for " << numFiles << " files" << endl;
}
}
}
} dataFileSync;
2010-09-14 17:00:46 -07:00
const char * jsInterruptCallback() {
// should be safe to interrupt in js code, even if we have a write lock
return killCurrentOp.checkForInterruptNoAssert();
2010-09-14 17:00:46 -07:00
}
2011-01-04 00:40:41 -05:00
2010-09-23 14:36:04 -07:00
unsigned jsGetInterruptSpecCallback() {
return cc().curop()->opNum();
}
2011-01-04 00:40:41 -05:00
2011-03-11 11:55:46 -05:00
void _initAndListen(int listenPort ) {
Client::initThread("initandlisten");
Database::_openAllFiles = false;
Logstream::get().addGlobalTee( new RamLog("global") );
2009-08-11 10:28:32 -04:00
bool is32bit = sizeof(int*) == 4;
2010-05-05 12:01:20 -04:00
{
2010-06-03 18:49:08 -04:00
#if !defined(_WIN32)
pid_t pid = getpid();
#else
DWORD pid=GetCurrentProcessId();
#endif
2010-05-05 12:01:20 -04:00
Nullstream& l = log();
l << "MongoDB starting : pid=" << pid << " port=" << cmdLine.port << " dbpath=" << dbpath;
if( replSettings.master ) l << " master=" << replSettings.master;
if( replSettings.slave ) l << " slave=" << (int) replSettings.slave;
l << ( is32bit ? " 32" : " 64" ) << "-bit host=" << getHostNameCached() << endl;
2010-05-05 12:01:20 -04:00
}
DEV log() << "_DEBUG build (which is slower)" << endl;
2010-09-02 21:34:41 -04:00
show_warnings();
2010-05-04 09:58:55 -04:00
log() << mongodVersion() << endl;
printGitVersion();
printSysInfo();
printCommandLineOpts();
2009-07-08 14:15:14 -04:00
{
stringstream ss;
ss << endl;
ss << "*********************************************************************" << endl;
ss << " ERROR: dbpath (" << dbpath << ") does not exist." << endl;
ss << " Create this directory or give existing directory in --dbpath." << endl;
ss << " See http://www.mongodb.org/display/DOCS/Starting+and+Stopping+Mongo" << endl;
ss << "*********************************************************************" << endl;
2010-05-22 19:22:07 -04:00
uassert( 10296 , ss.str().c_str(), boost::filesystem::exists( dbpath ) );
}
{
stringstream ss;
ss << "repairpath (" << repairpath << ") does not exist";
2010-05-22 19:22:07 -04:00
uassert( 12590 , ss.str().c_str(), boost::filesystem::exists( repairpath ) );
}
2011-01-04 00:40:41 -05:00
acquirePathLock(forceRepair);
remove_all( dbpath + "/_tmp/" );
2009-07-08 14:15:14 -04:00
2011-01-09 01:45:11 -05:00
FileAllocator::get()->start();
2009-07-08 14:15:14 -04:00
MONGO_BOOST_CHECK_EXCEPTION_WITH_MSG( clearTmpFiles(), "clear tmp files" );
2009-07-08 14:15:14 -04:00
dur::startup();
2011-01-04 00:40:41 -05:00
if( cmdLine.durOptions & CmdLine::DurRecoverOnly )
return;
2010-12-15 10:48:55 -05:00
// comes after getDur().startup() because this reads from the database
2009-03-06 13:13:07 -05:00
clearTmpCollections();
2009-07-08 14:15:14 -04:00
2011-11-13 10:20:16 -05:00
checkIfReplMissingFromCommandLine();
2009-11-18 12:53:56 -05:00
Module::initAll();
2009-07-17 15:49:24 -04:00
2010-11-04 10:29:42 -04:00
if ( scriptingEnabled ) {
ScriptEngine::setup();
2010-09-14 17:00:46 -07:00
globalScriptEngine->setCheckInterruptCallback( jsInterruptCallback );
2010-09-23 14:36:04 -07:00
globalScriptEngine->setGetInterruptSpecCallback( jsGetInterruptSpecCallback );
}
2010-11-13 17:42:41 -05:00
repairDatabasesAndCheckVersion();
2010-11-04 17:43:02 -04:00
2011-04-04 17:22:43 -04:00
/* we didn't want to pre-open all files for the repair check above. for regular
operation we do for read/write lock concurrency reasons.
2011-01-04 00:40:41 -05:00
*/
Database::_openAllFiles = true;
if ( shouldRepairDatabases )
return;
2009-09-21 09:05:27 -04:00
/* this is for security on certain platforms (nonce generation) */
srand((unsigned) (curTimeMicros() ^ startupSrandTimer.micros()));
2009-07-08 14:15:14 -04:00
2010-02-02 17:16:25 -05:00
snapshotThread.go();
clientCursorMonitor.go();
PeriodicTask::theRunner->go();
2011-10-25 12:37:07 -04:00
#ifndef _WIN32
CmdLine::launchOk();
2011-10-25 12:37:07 -04:00
#endif
listen(listenPort);
2009-07-08 14:15:14 -04:00
// listen() will return when exit code closes its socket.
2010-06-03 20:11:11 -04:00
exitCleanly(EXIT_NET_ERROR);
}
2010-07-12 12:37:27 -04:00
void testPretouch();
2011-03-11 11:55:46 -05:00
void initAndListen(int listenPort) {
try {
_initAndListen(listenPort);
}
catch ( DBException &e ) {
log() << "exception in initAndListen: " << e.toString() << ", terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
2009-10-09 11:55:56 -04:00
catch ( std::exception &e ) {
2010-07-23 12:00:38 -04:00
log() << "exception in initAndListen std::exception: " << e.what() << ", terminating" << endl;
2009-10-09 11:55:56 -04:00
dbexit( EXIT_UNCAUGHT );
}
2011-01-04 00:40:41 -05:00
catch ( int& n ) {
2010-07-23 12:00:38 -04:00
log() << "exception in initAndListen int: " << n << ", terminating" << endl;
2009-10-09 11:55:56 -04:00
dbexit( EXIT_UNCAUGHT );
}
2009-07-08 14:15:14 -04:00
catch(...) {
2010-05-05 14:00:25 -04:00
log() << "exception in initAndListen, terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
}
2008-06-06 09:43:15 -04:00
2011-01-04 00:40:41 -05:00
#if defined(_WIN32)
bool initService() {
2009-07-08 14:15:14 -04:00
ServiceController::reportStatus( SERVICE_RUNNING );
2011-03-11 11:55:46 -05:00
initAndListen( cmdLine.port );
2009-07-08 14:15:14 -04:00
return true;
}
2011-01-04 00:40:41 -05:00
#endif
2009-01-14 17:09:51 -05:00
} // namespace mongo
using namespace mongo;
#include <boost/program_options.hpp>
2010-05-25 21:11:38 -04:00
#undef assert
#define assert MONGO_assert
namespace po = boost::program_options;
void show_help_text(po::options_description options) {
2010-09-02 21:34:41 -04:00
show_warnings();
2009-08-11 11:32:03 -04:00
cout << options << endl;
};
/* Return error string or "" if no errors. */
string arg_error_check(int argc, char* argv[]) {
return "";
}
2011-01-04 00:40:41 -05:00
int main(int argc, char* argv[]) {
static StaticObserver staticObserver;
2011-06-17 14:57:16 -04:00
doPreServerStatupInits();
2009-10-13 16:01:02 -04:00
getcurns = ourgetns;
po::options_description general_options("General options");
2011-01-04 00:40:41 -05:00
#if defined(_WIN32)
po::options_description windows_scm_options("Windows Service Control Manager options");
#endif
po::options_description replication_options("Replication options");
po::options_description ms_options("Master/slave options");
po::options_description rs_options("Replica set options");
po::options_description sharding_options("Sharding options");
po::options_description visible_options("Allowed options");
po::options_description hidden_options("Hidden options");
po::positional_options_description positional_options;
CmdLine::addGlobalOptions( general_options , hidden_options );
general_options.add_options()
("auth", "run with security")
("cpu", "periodically show cpu and iowait utilization")
2011-01-04 00:40:41 -05:00
("dbpath", po::value<string>() , "directory for datafiles")
("diaglog", po::value<int>(), "0=off 1=W 2=R 3=both 7=W+some reads")
2011-01-04 00:40:41 -05:00
("directoryperdb", "each database will be stored in a separate directory")
2011-03-11 16:38:50 -05:00
("journal", "enable journaling")
("journalOptions", po::value<int>(), "journal diagnostic options")
("journalCommitInterval", po::value<unsigned>(), "how often to group/batch commit (ms)")
("ipv6", "enable IPv6 support (disabled by default)")
("jsonp","allow JSONP access via http (has security implications)")
2011-01-04 00:40:41 -05:00
("noauth", "run without security")
("nohttpinterface", "disable http interface")
2011-07-31 08:36:46 -04:00
("nojournal", "disable journaling (journaling is on by default for 64 bit)")
2011-01-04 00:40:41 -05:00
("noprealloc", "disable data file preallocation - will often hurt performance")
("noscripting", "disable scripting engine")
2011-01-04 00:40:41 -05:00
("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 allower per db, requires --quota")
("rest","turn on simple rest api")
("repair", "run repair on all dbs")
("repairpath", po::value<string>() , "root directory for repair files - defaults to dbpath" )
("slowms",po::value<int>(&cmdLine.slowMS)->default_value(100), "value of slow for profile and console log" )
("smallfiles", "use a smaller default file size")
#if defined(__linux__)
("shutdown", "kill a running server (for init scripts)")
#endif
("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")
2011-01-04 00:40:41 -05:00
;
#if defined(_WIN32)
CmdLine::addWindowsOptions( windows_scm_options, hidden_options );
#endif
2011-01-04 00:40:41 -05:00
replication_options.add_options()
("oplogSize", po::value<int>(), "size limit (in MB) for op log")
;
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")
2011-01-04 00:40:41 -05:00
;
rs_options.add_options()
("replSet", po::value<string>(), "arg is <setname>[/<optionalseedhostlist>]")
;
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")
("noMoveParanoia" , "turn off paranoid saving of data for moveChunk. this is on by default for now, but default will switch" )
;
hidden_options.add_options()
2011-10-26 13:20:11 -04:00
("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
2011-01-04 00:40:41 -05:00
("command", po::value< vector<string> >(), "command")
("cacheSize", po::value<long>(), "cache size (in MB) for rec store")
("nodur", "disable journaling")
2011-03-11 12:05:05 -05:00
// things we don't want people to use
2011-03-11 11:52:41 -05:00
("nocursors", "diagnostic/debugging option that turns off cursors DO NOT USE IN PRODUCTION")
("nohints", "ignore query hints")
("nopreallocj", "don't preallocate journal files")
2011-10-26 13:20:11 -04:00
("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")
2011-01-04 00:40:41 -05:00
;
positional_options.add("command", 3);
visible_options.add(general_options);
2011-01-04 00:40:41 -05:00
#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);
2009-11-18 12:53:56 -05:00
Module::addOptions( visible_options );
setupCoreSignals();
setupSignals( false );
2009-07-08 14:15:14 -04:00
dbExecCommand = argv[0];
2009-07-08 14:15:14 -04:00
2009-01-18 12:19:26 -05:00
srand(curTimeMicros());
2011-03-03 10:15:10 -05:00
#if( BOOST_VERSION >= 104500 )
boost::filesystem::path::default_name_check( boost::filesystem2::no_check );
#else
2008-12-29 17:59:44 -05:00
boost::filesystem::path::default_name_check( boost::filesystem::no_check );
2011-03-03 10:15:10 -05:00
#endif
2009-01-14 17:17:24 -05:00
{
unsigned x = 0x12345678;
unsigned char& b = (unsigned char&) x;
2008-12-28 20:28:49 -05:00
if ( b != 0x78 ) {
out() << "big endian cpus not yet supported" << endl;
return 33;
}
}
2010-05-05 12:01:20 -04:00
if( argc == 1 )
cout << dbExecCommand << " --help for help and startup options" << endl;
{
po::variables_map params;
2011-01-04 00:40:41 -05:00
string error_message = arg_error_check(argc, argv);
if (error_message != "") {
cout << error_message << endl << endl;
show_help_text(visible_options);
return 0;
}
if ( ! CmdLine::store( argc , argv , visible_options , hidden_options , positional_options , params ) )
return 0;
2009-07-21 16:53:35 -04:00
if (params.count("help")) {
show_help_text(visible_options);
2008-12-28 20:28:49 -05:00
return 0;
}
2009-09-22 10:05:53 -04:00
if (params.count("version")) {
cout << mongodVersion() << endl;
printGitVersion();
return 0;
}
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;
}
}
else {
dbpath = "/data/db/";
}
#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);
}
#endif
2010-01-26 11:26:07 -08:00
if ( params.count("directoryperdb")) {
directoryperdb = true;
}
if (params.count("cpu")) {
2009-10-16 11:36:38 -04:00
cmdLine.cpu = true;
}
if (params.count("noauth")) {
noauth = true;
}
if (params.count("auth")) {
noauth = false;
}
if (params.count("quota")) {
2009-10-16 11:36:38 -04:00
cmdLine.quota = true;
}
2009-10-20 13:29:05 -04:00
if (params.count("quotaFiles")) {
cmdLine.quota = true;
cmdLine.quotaFiles = params["quotaFiles"].as<int>() - 1;
}
bool journalExplicit = false;
2011-03-16 17:02:29 -04:00
if( params.count("nodur") || params.count( "nojournal" ) ) {
journalExplicit = true;
cmdLine.dur = false;
}
2011-03-11 16:38:50 -05:00
if( params.count("dur") || params.count( "journal" ) ) {
if (journalExplicit) {
log() << "Can't specify both --journal and --nojournal options." << endl;
return EXIT_BADOPTIONS;
}
journalExplicit = true;
2010-11-28 10:13:01 -05:00
cmdLine.dur = true;
}
2010-12-13 14:47:11 -05:00
if (params.count("durOptions")) {
cmdLine.durOptions = params["durOptions"].as<int>();
2010-11-26 18:18:24 -05:00
}
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 );
}
}
2011-03-11 16:38:50 -05:00
if (params.count("journalOptions")) {
2011-03-16 01:39:30 -04:00
cmdLine.durOptions = params["journalOptions"].as<int>();
2011-03-11 16:38:50 -05:00
}
if (params.count("repairpath")) {
repairpath = params["repairpath"].as<string>();
if (!repairpath.size()) {
out() << "repairpath is empty" << endl;
dbexit( EXIT_BADOPTIONS );
}
2011-01-04 00:40:41 -05:00
}
if (params.count("nocursors")) {
useCursors = false;
}
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")) {
2010-11-04 10:29:42 -04:00
scriptingEnabled = false;
}
if (params.count("noprealloc")) {
2009-10-08 16:29:04 -04:00
cmdLine.prealloc = false;
cout << "note: noprealloc may hurt performance in many applications" << endl;
2009-10-08 16:29:04 -04:00
}
if (params.count("smallfiles")) {
cmdLine.smallfiles = true;
assert( dur::DataLimitPerJournalFile >= 128 * 1024 * 1024 );
dur::DataLimitPerJournalFile = 128 * 1024 * 1024;
}
2009-11-11 13:54:05 -05:00
if (params.count("diaglog")) {
int x = params["diaglog"].as<int>();
if ( x < 0 || x > 7 ) {
2009-11-11 13:54:05 -05:00
out() << "can't interpret --diaglog setting" << endl;
dbexit( EXIT_BADOPTIONS );
}
_diaglog.setLevel(x);
}
if (params.count("sysinfo")) {
sysRuntimeInfo();
2008-12-28 20:28:49 -05:00
return 0;
}
2009-10-09 15:32:05 -04:00
if (params.count("repair")) {
Record::MemoryTrackingEnabled = false;
2009-10-09 15:32:05 -04:00
shouldRepairDatabases = 1;
forceRepair = 1;
}
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;
}
2010-03-01 13:55:31 -08:00
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://www.mongodb.org/display/DOCS/Resyncing+a+Very+Stale+Replica+Set+Member" << endl;
dbexit( EXIT_BADOPTIONS );
}
}
if (params.count("source")) {
/* specifies what the source in local.sources should be */
2009-08-25 14:35:22 -04:00
cmdLine.source = params["source"].as<string>().c_str();
}
2011-01-04 00:40:41 -05:00
if( params.count("pretouch") ) {
2010-07-06 17:49:20 -04:00
cmdLine.pretouch = params["pretouch"].as<int>();
}
2010-04-13 13:22:42 -04:00
if (params.count("replSet")) {
if (params.count("slavedelay")) {
out() << "--slavedelay cannot be used with --replSet" << endl;
dbexit( EXIT_BADOPTIONS );
2011-01-04 00:40:41 -05:00
}
else if (params.count("only")) {
out() << "--only cannot be used with --replSet" << endl;
dbexit( EXIT_BADOPTIONS );
}
2010-04-13 13:22:42 -04:00
/* seed list of hosts for the repl set */
2010-08-02 15:21:26 -04:00
cmdLine._replSet = params["replSet"].as<string>().c_str();
2010-04-13 13:22:42 -04:00
}
if (params.count("only")) {
2009-08-25 14:35:22 -04:00
cmdLine.only = params["only"].as<string>().c_str();
}
2009-09-18 14:32:25 -04:00
if( params.count("nssize") ) {
2009-08-20 15:00:25 -04:00
int x = params["nssize"].as<int>();
if (x <= 0 || x > (0x7fffffff/1024/1024)) {
out() << "bad --nssize arg" << endl;
dbexit( EXIT_BADOPTIONS );
}
2009-09-18 14:32:25 -04:00
lenForNewNsFiles = x * 1024 * 1024;
2009-08-20 15:00:25 -04:00
assert(lenForNewNsFiles > 0);
2009-09-18 14:32:25 -04:00
}
if (params.count("oplogSize")) {
long long x = params["oplogSize"].as<int>();
if (x <= 0) {
out() << "bad --oplogSize arg" << endl;
dbexit( EXIT_BADOPTIONS );
}
2010-10-31 11:11:04 -04:00
// note a small size such as x==1 is ok for an arbiter.
2011-01-04 00:40:41 -05:00
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 );
}
2009-10-16 23:32:34 -04:00
cmdLine.oplogSize = x * 1024 * 1024;
assert(cmdLine.oplogSize > 0);
}
if (params.count("cacheSize")) {
long x = params["cacheSize"].as<long>();
if (x <= 0) {
out() << "bad --cacheSize arg" << endl;
dbexit( EXIT_BADOPTIONS );
}
2010-05-17 10:38:36 -04:00
log() << "--cacheSize option not currently supported" << endl;
}
2011-01-04 00:40:41 -05:00
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;
}
}
2011-01-04 00:40:41 -05:00
else {
if ( cmdLine.port <= 0 || cmdLine.port > 65535 ) {
2010-08-03 22:11:26 -04:00
out() << "bad --port number" << endl;
dbexit( EXIT_BADOPTIONS );
}
2010-07-20 14:58:51 -04:00
}
2011-01-04 00:40:41 -05:00
if ( params.count("configsvr" ) ) {
cmdLine.configsvr = true;
if (cmdLine.usingReplSets() || replSettings.master || replSettings.slave) {
log() << "replication should not be enabled on a config server" << endl;
::exit(-1);
}
if ( params.count( "nodur" ) == 0 && params.count( "nojournal" ) == 0 )
cmdLine.dur = true;
if ( params.count( "dbpath" ) == 0 )
dbpath = "/data/configdb";
2009-11-11 16:04:52 -05:00
}
2011-01-04 00:40:41 -05:00
if ( params.count( "profile" ) ) {
cmdLine.defaultProfile = params["profile"].as<int>();
}
2011-01-04 00:40:41 -05:00
if (params.count("ipv6")) {
enableIPv6();
}
2011-01-04 00:40:41 -05:00
if (params.count("noMoveParanoia")) {
cmdLine.moveParanoia = false;
}
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://www.mongodb.org/display/DOCS/Replica+Pairs>" << endl;
out() << "****" << endl;
dbexit( EXIT_BADOPTIONS );
}
2010-04-05 21:29:01 -04:00
// needs to be after things like --configsvr parsing, thus here.
if( repairpath.empty() )
repairpath = dbpath;
2009-11-18 12:53:56 -05:00
Module::configAll( params );
dataFileSync.go();
2009-07-17 15:49:24 -04:00
if (params.count("command")) {
vector<string> command = params["command"].as< vector<string> >();
2008-12-28 20:28:49 -05:00
if (command[0].compare("run") == 0) {
if (command.size() > 1) {
cout << "Too many parameters to 'run' command" << endl;
cout << visible_options << endl;
return 0;
2008-12-28 20:28:49 -05:00
}
2009-08-25 10:24:44 -04:00
initAndListen(cmdLine.port);
return 0;
2008-12-28 20:28:49 -05:00
}
2009-10-27 16:37:14 -04:00
if (command[0].compare("dbpath") == 0) {
cout << dbpath << endl;
return 0;
}
cout << "Invalid command: " << command[0] << endl;
cout << visible_options << endl;
return 0;
2008-06-06 09:43:15 -04:00
}
2009-07-21 16:53:35 -04:00
2010-09-04 09:16:31 +08:00
if( cmdLine.pretouch )
2011-01-04 00:40:41 -05:00
log() << "--pretouch " << cmdLine.pretouch << endl;
2010-09-04 09:16:31 +08:00
#ifdef __linux__
if (params.count("shutdown")){
bool failed = false;
string name = ( boost::filesystem::path( dbpath ) / "mongod.lock" ).native_file_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;
string exePath = procPath + "/exe";
if (boost::filesystem::exists(exePath)){
char buf[256];
int ret = readlink(exePath.c_str(), buf, sizeof(buf)-1);
buf[ret] = '\0'; // readlink doesn't terminate string
if (ret == -1) {
int e = errno;
cerr << "Error resolving " << exePath << ": " << errnoWithDescription(e);
failed = true;
}
else if (!endsWith(buf, "mongod")){
cerr << "Process " << pid << " is running " << buf << " not mongod" << endl;
::exit(-1);
}
}
}
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(-1);
}
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(-1);
}
while (boost::filesystem::exists(procPath)) {
sleepsecs(1);
}
::exit(0);
}
#endif
2009-08-11 14:29:03 -04:00
#if defined(_WIN32)
2010-09-04 09:16:31 +08:00
if (serviceParamsCheck( params, dbpath, argc, argv )) {
return 0;
}
2009-08-11 14:29:03 -04:00
#endif
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;
}
2009-09-18 14:32:25 -04:00
}
2008-06-06 09:43:15 -04:00
UnitTest::runTests();
2011-03-11 11:55:46 -05:00
initAndListen(cmdLine.port);
dbexit(EXIT_CLEAN);
2008-12-26 22:06:48 -05:00
return 0;
2008-06-06 09:43:15 -04:00
}
2009-01-14 17:09:51 -05:00
namespace mongo {
string getDbContext();
2009-01-18 11:53:33 -05:00
#undef out
2009-10-05 12:59:51 -04:00
#if !defined(_WIN32)
2009-01-14 17:09:51 -05:00
} // namespace mongo
#include <signal.h>
2009-03-12 17:36:46 -04:00
#include <string.h>
2009-01-14 17:09:51 -05:00
namespace mongo {
void pipeSigHandler( int signal ) {
#ifdef psignal
psignal( signal, "Signal Received : ");
#else
cout << "got pipe signal:" << signal << endl;
#endif
}
void abruptQuit(int x) {
2009-03-12 17:36:46 -04:00
ostringstream ossSig;
ossSig << "Got signal: " << x << " (" << strsignal( x ) << ")." << endl;
rawOut( ossSig.str() );
/*
2009-03-03 16:10:42 -05:00
ostringstream ossOp;
ossOp << "Last op: " << currentOp.infoNoauth() << endl;
rawOut( ossOp.str() );
*/
2009-03-12 17:36:46 -04:00
ostringstream oss;
2009-03-12 17:36:46 -04:00
oss << "Backtrace:" << endl;
printStackTrace( oss );
rawOut( oss.str() );
// Don't go through normal shutdown procedure. It may make things worse.
::exit(EXIT_ABRUPT);
}
2011-03-24 12:47:01 -07:00
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 << endl;
rawOut( oss.str() );
abruptQuit( signal );
}
sigset_t asyncSignals;
// The above signals will be processed by this thread only, in order to
// ensure the db and log mutexes aren't held.
void interruptThread() {
int x;
sigwait( &asyncSignals, &x );
2010-07-13 17:11:11 -04:00
log() << "got kill or ctrl c or hup signal " << x << " (" << strsignal( x ) << "), will terminate after current cmd ends" << endl;
Client::initThread( "interruptThread" );
exitCleanly( EXIT_KILL );
}
2009-07-08 14:15:14 -04:00
// this will be called in certain c++ error cases, for example if there are two active
// exceptions
void myterminate() {
rawOut( "terminate() called, printing stack:" );
printStackTrace();
::abort();
}
2011-01-04 00:40:41 -05:00
// 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);
}
2011-01-04 00:40:41 -05:00
void setupSignals_ignoreHelper( int signal ) {}
void setupSignals( bool inFork ) {
struct sigaction addrSignals;
2011-03-24 12:47:01 -07:00
memset( &addrSignals, 0, sizeof( struct sigaction ) );
addrSignals.sa_sigaction = abruptQuitWithAddrSignal;
sigemptyset( &addrSignals.sa_mask );
addrSignals.sa_flags = SA_SIGINFO;
assert( sigaction(SIGSEGV, &addrSignals, 0) == 0 );
assert( sigaction(SIGBUS, &addrSignals, 0) == 0 );
assert( sigaction(SIGILL, &addrSignals, 0) == 0 );
assert( sigaction(SIGFPE, &addrSignals, 0) == 0 );
assert( signal(SIGABRT, abruptQuit) != SIG_ERR );
2010-03-31 10:27:37 -04:00
assert( signal(SIGQUIT, abruptQuit) != SIG_ERR );
assert( signal(SIGPIPE, pipeSigHandler) != SIG_ERR );
2009-11-03 15:05:31 -05:00
setupSIGTRAPforGDB();
sigemptyset( &asyncSignals );
if ( inFork )
assert( signal( SIGHUP , setupSignals_ignoreHelper ) != SIG_ERR );
else
sigaddset( &asyncSignals, SIGHUP );
sigaddset( &asyncSignals, SIGINT );
sigaddset( &asyncSignals, SIGTERM );
assert( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 );
boost::thread it( interruptThread );
2011-01-04 00:40:41 -05:00
set_terminate( myterminate );
set_new_handler( my_new_handler );
}
#else
void consoleTerminate( const char* controlCodeName ) {
Client::initThread( "consoleTerminate" );
log() << "got " << controlCodeName << ", will terminate after current cmd ends" << endl;
2011-01-04 00:40:41 -05:00
exitCleanly( EXIT_KILL );
}
2011-01-04 00:40:41 -05:00
BOOL CtrlHandler( DWORD fdwCtrlType ) {
2011-01-04 00:40:41 -05:00
switch( fdwCtrlType ) {
2011-01-04 00:40:41 -05:00
case CTRL_C_EVENT:
rawOut( "Ctrl-C signal" );
consoleTerminate( "CTRL_C_EVENT" );
return TRUE ;
2011-01-04 00:40:41 -05:00
case CTRL_CLOSE_EVENT:
rawOut( "CTRL_CLOSE_EVENT signal" );
consoleTerminate( "CTRL_CLOSE_EVENT" );
return TRUE ;
2011-01-04 00:40:41 -05:00
case CTRL_BREAK_EVENT:
rawOut( "CTRL_BREAK_EVENT signal" );
consoleTerminate( "CTRL_BREAK_EVENT" );
2011-01-04 00:40:41 -05:00
return TRUE;
2011-01-04 00:40:41 -05:00
case CTRL_LOGOFF_EVENT:
rawOut( "CTRL_LOGOFF_EVENT signal" );
consoleTerminate( "CTRL_LOGOFF_EVENT" );
return TRUE;
2011-01-04 00:40:41 -05:00
case CTRL_SHUTDOWN_EVENT:
rawOut( "CTRL_SHUTDOWN_EVENT signal" );
consoleTerminate( "CTRL_SHUTDOWN_EVENT" );
return TRUE;
2011-01-04 00:40:41 -05:00
default:
return FALSE;
}
2009-09-18 14:32:25 -04:00
}
LPTOP_LEVEL_EXCEPTION_FILTER filtLast = 0;
::HANDLE standardOut = GetStdHandle(STD_OUTPUT_HANDLE);
2011-06-28 16:22:25 -04:00
LONG WINAPI exceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) {
{
// given the severity of the event we write to console in addition to the --logFile
// (rawOut writes to the logfile, if a special one were specified)
DWORD written;
WriteFile(standardOut, "unhandled windows exception\n", 20, &written, 0);
FlushFileBuffers(standardOut);
}
DWORD ec = ExceptionInfo->ExceptionRecord->ExceptionCode;
if( ec == EXCEPTION_ACCESS_VIOLATION ) {
rawOut("access violation");
}
else {
rawOut("unhandled windows exception");
char buf[64];
strcpy(buf, "ec=0x");
_ui64toa(ec, buf+5, 16);
rawOut(buf);
}
if( filtLast )
return filtLast(ExceptionInfo);
return EXCEPTION_EXECUTE_HANDLER;
}
// 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();
2011-06-28 16:22:25 -04:00
BOOL ok = ReportEvent(
hEventLog, EVENTLOG_ERROR_TYPE,
0, 0, NULL,
1,
0,
&txt,
0);
wassert(ok);
}
}
2010-04-08 12:58:36 -07:00
void myPurecallHandler() {
printStackTrace();
mongoAbort("pure virtual");
2010-04-08 12:58:36 -07:00
}
2011-01-04 00:40:41 -05:00
void setupSignals( bool inFork ) {
reportEventToSystem = reportEventToSystemImpl;
filtLast = SetUnhandledExceptionFilter(exceptionFilter);
2011-04-19 09:21:29 -04:00
massert(10297 , "Couldn't register Windows Ctrl-C handler", SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE));
2010-04-08 12:58:36 -07:00
_set_purecall_handler( myPurecallHandler );
2009-09-18 14:32:25 -04:00
}
#endif
2009-01-14 17:09:51 -05:00
} // namespace mongo