0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 01:21:03 +01:00
mongodb/db/db.cpp
2010-05-10 17:13:21 -04:00

1136 lines
37 KiB
C++

// db.cpp : Defines the entry point for the console application.
//
/**
* Copyright (C) 2008 10gen Inc.info
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pch.h"
#include "db.h"
#include "query.h"
#include "introspect.h"
#include "repl.h"
#include "../util/unittest.h"
#include "../util/file_allocator.h"
#include "../util/background.h"
#include "dbmessage.h"
#include "instance.h"
#include "clientcursor.h"
#include "pdfile.h"
#include "stats/counters.h"
#include "repl/replset.h"
#if !defined(_WIN32)
#include <sys/file.h>
#endif
#if defined(_WIN32)
#include "../util/ntservice.h"
#endif
#include "../scripting/engine.h"
#include "module.h"
#include "cmdline.h"
#include "stats/snapshots.h"
namespace mongo {
CmdLine cmdLine;
bool useJNI = true;
/* only off if --nocursors which is for debugging. */
extern bool useCursors;
/* only off if --nohints */
extern bool useHints;
bool noHttpInterface = false;
extern string bind_ip;
extern char *appsrvPath;
extern int diagLogging;
extern int lenForNewNsFiles;
extern int lockFile;
extern string repairpath;
#if defined(_WIN32)
std::wstring windowsServiceName = L"MongoDB";
#endif
void setupSignals();
void closeAllSockets();
void startReplSets();
void startReplication();
void pairWith(const char *remoteEnd, const char *arb);
void setRecCacheSize(unsigned MB);
void exitCleanly( ExitCode code );
const char *ourgetns() {
Client *c = currentClient.get();
if ( ! c )
return "";
Client::Context* cc = c->getContext();
return cc ? cc->ns() : "";
}
struct MyStartupTests {
MyStartupTests() {
assert( sizeof(OID) == 12 );
}
} mystartupdbcpp;
QueryResult* emptyMoreResult(long long);
MessagingPort *connGrab = 0;
void connThread();
class OurListener : public Listener {
public:
OurListener(const string &ip, int p) : Listener(ip, p) { }
virtual void accepted(MessagingPort *mp) {
assert( connGrab == 0 );
if ( ! connTicketHolder.tryAcquire() ){
log() << "connection refused because too many open connections" << endl;
// TODO: would be nice if we notified them...
mp->shutdown();
return;
}
connGrab = mp;
try {
boost::thread thr(connThread);
while ( connGrab )
sleepmillis(1);
}
catch ( boost::thread_resource_error& ){
log() << "can't create new thread, closing connection" << endl;
mp->shutdown();
connGrab = 0;
}
catch ( ... ){
log() << "unkonwn exception starting connThread" << endl;
mp->shutdown();
connGrab = 0;
}
}
};
void webServerThread();
void listen(int port) {
//testTheDb();
log() << "waiting for connections on port " << port << endl;
OurListener l(bind_ip, port);
startReplication();
if ( !noHttpInterface )
boost::thread thr(webServerThread);
l.initAndListen();
}
} // namespace mongo
#include "client.h"
namespace mongo {
void sysRuntimeInfo() {
out() << "sysinfo:\n";
#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
}
/* we create one thread for each connection from an app server database.
app server will open a pool of threads.
*/
void connThread()
{
TicketHolderReleaser connTicketReleaser( &connTicketHolder );
Client::initThread("conn");
/* todo: move to Client object */
LastError *le = new LastError();
lastError.reset(le);
auto_ptr<MessagingPort> dbMsgPort( connGrab );
connGrab = 0;
Client& c = cc();
try {
c.getAuthenticationInfo()->isLocalHost = dbMsgPort->farEnd.isLocalHost();
Message m;
while ( 1 ) {
m.reset();
if ( !dbMsgPort->recv(m) ) {
if( !cmdLine.quiet )
log() << "end connection " << dbMsgPort->farEnd.toString() << endl;
dbMsgPort->shutdown();
break;
}
if ( inShutdown() ) {
log() << "got request after shutdown()" << endl;
break;
}
lastError.startRequest( m , le );
DbResponse dbresponse;
if ( !assembleResponse( m, dbresponse, dbMsgPort->farEnd ) ) {
out() << curTimeMillis() % 10000 << " end msg " << dbMsgPort->farEnd.toString() << endl;
/* todo: we may not wish to allow this, even on localhost: very low priv accounts could stop us. */
if ( dbMsgPort->farEnd.isLocalHost() ) {
dbMsgPort->shutdown();
sleepmillis(50);
problem() << "exiting end msg" << endl;
dbexit(EXIT_CLEAN);
}
else {
out() << " (not from localhost, ignoring end msg)" << endl;
}
}
if ( dbresponse.response )
dbMsgPort->reply(m, *dbresponse.response, dbresponse.responseTo);
}
}
catch ( AssertionException& ) {
problem() << "AssertionException in connThread, closing client connection" << endl;
dbMsgPort->shutdown();
}
catch ( SocketException& ) {
problem() << "SocketException in connThread, closing client connection" << endl;
dbMsgPort->shutdown();
}
catch ( const ClockSkewException & ) {
exitCleanly( EXIT_CLOCK_SKEW );
}
catch ( std::exception &e ) {
problem() << "Uncaught std::exception: " << e.what() << ", terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
catch ( ... ) {
problem() << "Uncaught exception, terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
// any thread cleanup can happen here
if ( currentClient.get() )
currentClient->shutdown();
globalScriptEngine->threadDone();
}
void msg(const char *m, const char *address, int port, int extras = 0) {
SockAddr db(address, port);
// SockAddr db("127.0.0.1", DBPort);
// SockAddr db("192.168.37.1", MessagingPort::DBPort);
// SockAddr db("10.0.21.60", MessagingPort::DBPort);
// SockAddr db("172.16.0.179", MessagingPort::DBPort);
MessagingPort p;
if ( !p.connect(db) ){
out() << "msg couldn't connect" << endl;
return;
}
const int Loops = 1;
for ( int q = 0; q < Loops; q++ ) {
Message send;
Message response;
send.setData( dbMsg , m);
int len = send.data->dataLen();
for ( int i = 0; i < extras; i++ )
p.say(/*db, */send);
Timer t;
bool ok = p.call(send, response);
double tm = ((double) t.micros()) + 1;
out() << " ****ok. response.data:" << ok << " time:" << tm / 1000.0 << "ms "
<< "len: " << len << " data: " << response.data->_data << endl;
if ( q+1 < Loops ) {
out() << "\t\tSLEEP 8 then sending again as a test" << endl;
sleepsecs(8);
}
}
sleepsecs(1);
p.shutdown();
}
void msg(const char *m, int extras = 0) {
msg(m, "127.0.0.1", CmdLine::DefaultDBPort, extras);
}
bool shouldRepairDatabases = 0;
bool forceRepair = 0;
bool doDBUpgrade( const string& dbName , string errmsg , DataFileHeader * h ){
static DBDirectClient db;
if ( h->version == 4 && h->versionMinor == 4 ){
assert( VERSION == 4 );
assert( VERSION_MINOR == 5 );
list<string> colls = db.getCollectionNames( dbName );
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 );
if ( ! ok ){
errmsg = "reindex failed";
log() << "\t\t reindex failed: " << out << endl;
return false;
}
}
h->versionMinor = 5;
return true;
}
// do this in the general case
return repairDatabase( dbName.c_str(), errmsg );
}
extern bool checkNsFilesOnLoad;
void repairDatabases() {
LastError * le = lastError.get( true );
Client::GodScope gs;
log(1) << "enter repairDatabases" << endl;
//assert(checkNsFilesOnLoad);
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;
log(1) << "\t" << dbName << endl;
Client::Context ctx( dbName );
MongoDataFile *p = cc().database()->getFile( 0 );
DataFileHeader *h = p->getHeader();
if ( !h->currentVersion() || forceRepair ) {
log() << "****" << endl;
log() << "****" << endl;
log() << "need to upgrade database " << dbName << " with pdfile version " << h->version << "." << h->versionMinor << ", "
<< "new version: " << VERSION << "." << VERSION_MINOR << endl;
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 {
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;
}
} else {
closeDatabase( dbName.c_str() );
}
}
log(1) << "done repairDatabases" << endl;
if ( shouldRepairDatabases ){
log() << "finished checking dbs" << endl;
cc().shutdown();
dbexit( EXIT_CLEAN );
}
checkNsFilesOnLoad = true;
}
void clearTmpFiles() {
boost::filesystem::path path( dbpath );
for ( boost::filesystem::directory_iterator i( path );
i != boost::filesystem::directory_iterator(); ++i ) {
string fileName = boost::filesystem::path(*i).leaf();
if ( boost::filesystem::is_directory( *i ) &&
fileName.length() && fileName[ 0 ] == '$' )
boost::filesystem::remove_all( *i );
}
}
void clearTmpCollections() {
Client::GodScope gs;
vector< string > toDelete;
DBDirectClient cli;
auto_ptr< DBClientCursor > c = cli.query( "local.system.namespaces", Query( fromjson( "{name:/^local.temp./}" ) ) );
while( c->more() ) {
BSONObj o = c->next();
toDelete.push_back( o.getStringField( "name" ) );
}
for( vector< string >::iterator i = toDelete.begin(); i != toDelete.end(); ++i ) {
log() << "Dropping old temporary collection: " << *i << endl;
cli.dropCollection( *i );
}
}
/**
* does background async flushes of mmapped files
*/
class DataFileSync : public BackgroundJob {
public:
void run(){
log(1) << "will flush memory every: " << _sleepsecs << " seconds" << endl;
int time_flushing = 0;
while ( ! inShutdown() ){
if ( _sleepsecs == 0 ){
// in case at some point we add an option to change at runtime
sleepsecs(5);
continue;
}
sleepmillis( (long long) std::max(0.0, (_sleepsecs * 1000) - time_flushing) );
if ( inShutdown() ){
// occasional issue trying to flush during shutdown when sleep interrupted
break;
}
Date_t start = jsTime();
MemoryMappedFile::flushAll( true );
time_flushing = (int) (jsTime() - start);
globalFlushCounters.flushed(time_flushing);
log(1) << "flushing mmap took " << time_flushing << "ms" << endl;
}
}
double _sleepsecs; // default value controlled by program options
} dataFileSync;
void show_32_warning(){
#if BOOST_VERSION < 103500
cout << "\nwarning: built with boost version <= 1.34, limited concurrency" << endl;
#endif
{
const char * foo = strchr( versionString , '.' ) + 1;
int bar = atoi( foo );
if ( ( 2 * ( bar / 2 ) ) != bar ){
log() << "****\n";
log() << "WARNING: This is development a version (" << versionString << ") of MongoDB. Not recommended for production.\n";
log() << "****" << endl;
}
}
if ( sizeof(int*) != 4 )
return;
cout << endl;
cout << "** NOTE: when using MongoDB 32 bit, you are limited to about 2 gigabytes of data" << endl;
cout << "** see http://blog.mongodb.org/post/137788967/32-bit-limitations for more" << endl;
cout << endl;
}
Timer startupSrandTimer;
void _initAndListen(int listenPort, const char *appserverLoc = NULL) {
#if !defined(_WIN32)
pid_t pid = 0;
pid = getpid();
#else
int pid=0;
#endif
bool is32bit = sizeof(int*) == 4;
{
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 " << endl;
}
DEV log() << "_DEBUG build (which is slower)" << endl;
show_32_warning();
log() << mongodVersion() << endl;
printGitVersion();
printSysInfo();
{
stringstream ss;
ss << "dbpath (" << dbpath << ") does not exist";
massert( 10296 , ss.str().c_str(), boost::filesystem::exists( dbpath ) );
}
{
stringstream ss;
ss << "repairpath (" << repairpath << ") does not exist";
massert( 12590 , ss.str().c_str(), boost::filesystem::exists( repairpath ) );
}
acquirePathLock();
remove_all( dbpath + "/_tmp/" );
theFileAllocator().start();
BOOST_CHECK_EXCEPTION( clearTmpFiles() );
Client::initThread("initandlisten");
_diaglog.init();
clearTmpCollections();
Module::initAll();
#if 0
{
stringstream indexpath;
indexpath << dbpath << "/indexes.dat";
RecCache::tempStore.init(indexpath.str().c_str(), BucketSize);
}
#endif
if ( useJNI ) {
ScriptEngine::setup();
}
repairDatabases();
/* we didn't want to pre-open all fiels for the repair check above. for regular
operation we do for read/write lock concurrency reasons.
*/
Database::_openAllFiles = true;
if ( shouldRepairDatabases )
return;
/* this is for security on certain platforms (nonce generation) */
srand((unsigned) (curTimeMicros() ^ startupSrandTimer.micros()));
snapshotThread.go();
clientCursorMonitor.go();
if( !cmdLine.replSet.empty() ) {
replSet = true;
boost::thread t(startReplSets);
}
listen(listenPort);
// listen() will return when exit code closes its socket.
while( 1 )
sleepsecs( 100 );
}
void initAndListen(int listenPort, const char *appserverLoc = NULL) {
try { _initAndListen(listenPort, appserverLoc); }
catch ( std::exception &e ) {
problem() << "exception in initAndListen std::exception: " << e.what() << ", terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
catch ( int& n ){
problem() << "exception in initAndListen int: " << n << ", terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
catch(...) {
log() << "exception in initAndListen, terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
}
#if defined(_WIN32)
bool initService() {
ServiceController::reportStatus( SERVICE_RUNNING );
initAndListen( cmdLine.port, appsrvPath );
return true;
}
#endif
} // namespace mongo
using namespace mongo;
#include <boost/program_options.hpp>
namespace po = boost::program_options;
void show_help_text(po::options_description options) {
show_32_warning();
cout << options << endl;
};
/* Return error string or "" if no errors. */
string arg_error_check(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
string s = argv[i];
/* check for inclusion of old-style arbiter setting. */
if (s == "--pairwith") {
if (argc > i + 2) {
string old_arbiter = argv[i + 2];
if (old_arbiter == "-" || old_arbiter.substr(0, 1) != "-") {
return "Specifying arbiter using --pairwith is no longer supported, please use --arbiter";
}
}
}
}
return "";
}
int main(int argc, char* argv[], char *envp[] )
{
static StaticObserver staticObserver;
getcurns = ourgetns;
po::options_description general_options("General options");
po::options_description replication_options("Replication 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()
("bind_ip", po::value<string>(&bind_ip),
"comma separated list of ip addresses to listen on - all local ips by default")
("dbpath", po::value<string>()->default_value("/data/db/"), "directory for datafiles")
#if !defined(_WIN32) && !defined(__sunos__)
("lockfilepath", po::value<string>(&lockfilepath), "directory for lockfile (if not set, dbpath is used)")
#endif
("directoryperdb", "each database will be stored in a separate directory")
("repairpath", po::value<string>() , "root directory for repair files - defaults to dbpath" )
("cpu", "periodically show cpu and iowait utilization")
("noauth", "run without security")
("auth", "run with security")
("objcheck", "inspect client data for validity on receipt")
("quota", "enable db quota management")
("quotaFiles", po::value<int>(), "number of files allower per db, requires --quota")
("appsrvpath", po::value<string>(), "root directory for the babble app server")
("nocursors", "diagnostic/debugging option")
("nohints", "ignore query hints")
("nohttpinterface", "disable http interface")
("rest","turn on simple rest api")
("noscripting", "disable scripting engine")
("noprealloc", "disable data file preallocation")
("smallfiles", "use a smaller default file size")
("nssize", po::value<int>()->default_value(16), ".ns file size (in MB) for new databases")
("diaglog", po::value<int>(), "0=off 1=W 2=R 3=both 7=W+some reads")
("sysinfo", "print some diagnostic system information")
("upgrade", "upgrade db if needed")
("repair", "run repair on all dbs")
("notablescan", "do not allow table scans")
("syncdelay",po::value<double>(&dataFileSync._sleepsecs)->default_value(60), "seconds between disk syncs (0 for never)")
("profile",po::value<int>(), "0=off 1=slow, 2=all")
("slowms",po::value<int>(&cmdLine.slowMS)->default_value(100), "value of slow for profile and console log" )
("maxConns",po::value<int>(), "max number of simultaneous connections")
#if defined(_WIN32)
("install", "install mongodb service")
("remove", "remove mongodb service")
("service", "start mongodb service")
("serviceName", po::value<string>(), "windows service name")
#else
("nounixsocket", "disable listening on unix sockets")
#endif
("ipv6", "enable IPv6 support (disabled by default)")
;
replication_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")
("pairwith", po::value<string>(), "address of server to pair with")
("arbiter", po::value<string>(), "address of arbiter server")
("slavedelay", po::value<int>(), "specify delay (in seconds) to be used when applying master ops to slave")
("fastsync", "indicate that this instance is starting from a dbpath snapshot of the repl peer")
("autoresync", "automatically resync if slave data is stale")
("oplogSize", po::value<int>(), "size limit (in MB) for op log")
("opIdMem", po::value<long>(), "size limit (in bytes) for in memory storage of op ids")
;
sharding_options.add_options()
("configsvr", "declare this is a config db of a cluster")
("shardsvr", "declare this is a shard db of a cluster")
;
hidden_options.add_options()
("replSet", po::value<string>(), "specify repl set seed hostnames")
("command", po::value< vector<string> >(), "command")
("cacheSize", po::value<long>(), "cache size (in MB) for rec store")
;
positional_options.add("command", 3);
visible_options.add(general_options);
visible_options.add(replication_options);
visible_options.add(sharding_options);
Module::addOptions( visible_options );
setupSignals();
dbExecCommand = argv[0];
srand(curTimeMicros());
boost::filesystem::path::default_name_check( boost::filesystem::no_check );
{
unsigned x = 0x12345678;
unsigned char& b = (unsigned char&) x;
if ( b != 0x78 ) {
out() << "big endian cpus not yet supported" << endl;
return 33;
}
}
UnitTest::runTests();
if( argc == 1 )
cout << dbExecCommand << " --help for help and startup options" << endl;
{
bool installService = false;
bool removeService = false;
bool startService = false;
po::variables_map params;
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;
if (params.count("help")) {
show_help_text(visible_options);
return 0;
}
if (params.count("version")) {
cout << mongodVersion() << endl;
printGitVersion();
return 0;
}
dbpath = params["dbpath"].as<string>();
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;
}
if (params.count("objcheck")) {
objcheck = true;
}
if (params.count("appsrvpath")) {
/* casting away the const-ness here */
appsrvPath = (char*)(params["appsrvpath"].as<string>().c_str());
}
if (params.count("repairpath")) {
repairpath = params["repairpath"].as<string>();
uassert( 12589, "repairpath has to be non-zero", repairpath.size() );
} else {
repairpath = dbpath;
}
if (params.count("nocursors")) {
useCursors = false;
}
if (params.count("nohints")) {
useHints = false;
}
if (params.count("nohttpinterface")) {
noHttpInterface = true;
}
if (params.count("rest")) {
cmdLine.rest = true;
}
if (params.count("noscripting")) {
useJNI = false;
}
if (params.count("noprealloc")) {
cmdLine.prealloc = false;
}
if (params.count("smallfiles")) {
cmdLine.smallfiles = true;
}
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.level = x;
}
if (params.count("sysinfo")) {
sysRuntimeInfo();
return 0;
}
if (params.count("repair")) {
shouldRepairDatabases = 1;
forceRepair = 1;
}
if (params.count("upgrade")) {
shouldRepairDatabases = 1;
}
if (params.count("notablescan")) {
cmdLine.notablescan = true;
}
if (params.count("install")) {
installService = true;
}
if (params.count("remove")) {
removeService = true;
}
if (params.count("service")) {
startService = 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("source")) {
/* specifies what the source in local.sources should be */
cmdLine.source = params["source"].as<string>().c_str();
}
if (params.count("replSet")) {
/* seed list of hosts for the repl set */
cmdLine.replSet = params["replSet"].as<string>().c_str();
}
if (params.count("only")) {
cmdLine.only = params["only"].as<string>().c_str();
}
if (params.count("pairwith")) {
string paired = params["pairwith"].as<string>();
if (params.count("arbiter")) {
string arbiter = params["arbiter"].as<string>();
pairWith(paired.c_str(), arbiter.c_str());
} else {
pairWith(paired.c_str(), "-");
}
} else if (params.count("arbiter")) {
uasserted(10999,"specifying --arbiter without --pairwith");
}
if( params.count("nssize") ) {
int x = params["nssize"].as<int>();
uassert( 10034 , "bad --nssize arg", x > 0 && x <= (0x7fffffff/1024/1024));
lenForNewNsFiles = x * 1024 * 1024;
assert(lenForNewNsFiles > 0);
}
if (params.count("oplogSize")) {
long x = params["oplogSize"].as<int>();
uassert( 10035 , "bad --oplogSize arg", x > 0);
cmdLine.oplogSize = x * 1024 * 1024;
assert(cmdLine.oplogSize > 0);
}
if (params.count("opIdMem")) {
long x = params["opIdMem"].as<long>();
uassert( 10036 , "bad --opIdMem arg", x > 0);
replSettings.opIdMem = x;
assert(replSettings.opIdMem > 0);
}
if (params.count("cacheSize")) {
long x = params["cacheSize"].as<long>();
uassert( 10037 , "bad --cacheSize arg", x > 0);
setRecCacheSize(x);
}
if (params.count("port") == 0 ) {
if( params.count("configsvr") ) {
cmdLine.port = CmdLine::ConfigServerPort;
}
if( params.count("shardsvr") )
cmdLine.port = CmdLine::ShardServerPort;
}
if ( params.count("configsvr" ) && params.count( "diaglog" ) == 0 ){
_diaglog.level = 1;
}
if ( params.count( "profile" ) ){
cmdLine.defaultProfile = params["profile"].as<int>();
}
if ( params.count( "maxConns" ) ){
int newSize = params["maxConns"].as<int>();
uassert( 12507 , "maxConns has to be at least 5" , newSize >= 5 );
uassert( 12508 , "maxConns can't be greater than 10000000" , newSize < 10000000 );
connTicketHolder.resize( newSize );
}
if (params.count("nounixsocket")){
noUnixSocket = true;
}
if (params.count("ipv6")){
enableIPv6();
}
#if defined(_WIN32)
if (params.count("serviceName")){
string x = params["serviceName"].as<string>();
windowsServiceName = wstring(x.size(),L' ');
for ( size_t i=0; i<x.size(); i++)
windowsServiceName[i] = x[i];
}
#endif
Module::configAll( params );
dataFileSync.go();
if (params.count("command")) {
vector<string> command = params["command"].as< vector<string> >();
if (command[0].compare("msg") == 0) {
const char *m;
if (command.size() < 3) {
cout << "Too few parameters to 'msg' command" << endl;
cout << visible_options << endl;
return 0;
}
m = command[1].c_str();
msg(m, "127.0.0.1", atoi(command[2].c_str()));
return 0;
}
if (command[0].compare("run") == 0) {
if (command.size() > 1) {
cout << "Too many parameters to 'run' command" << endl;
cout << visible_options << endl;
return 0;
}
initAndListen(cmdLine.port);
return 0;
}
if (command[0].compare("dbpath") == 0) {
cout << dbpath << endl;
return 0;
}
cout << "Invalid command: " << command[0] << endl;
cout << visible_options << endl;
return 0;
}
#if defined(_WIN32)
if ( installService ) {
if ( !ServiceController::installService( windowsServiceName , L"Mongo DB", L"Mongo DB Server", argc, argv ) )
dbexit( EXIT_NTSERVICE_ERROR );
dbexit( EXIT_CLEAN );
}
else if ( removeService ) {
if ( !ServiceController::removeService( windowsServiceName ) )
dbexit( EXIT_NTSERVICE_ERROR );
dbexit( EXIT_CLEAN );
}
else if ( startService ) {
if ( !ServiceController::startService( windowsServiceName , mongo::initService ) )
dbexit( EXIT_NTSERVICE_ERROR );
dbexit( EXIT_CLEAN );
}
#endif
}
initAndListen(cmdLine.port, appsrvPath);
dbexit(EXIT_CLEAN);
return 0;
}
namespace mongo {
/* we do not use log() below as it uses a mutex and that could cause deadlocks.
*/
string getDbContext();
#undef out
void exitCleanly( ExitCode code ) {
goingAway = true;
killCurrentOp.killAll();
{
dblock lk;
log() << "now exiting" << endl;
dbexit( code );
}
}
#if !defined(_WIN32)
} // namespace mongo
#include <signal.h>
#include <string.h>
namespace mongo {
void pipeSigHandler( int signal ) {
#ifdef psignal
psignal( signal, "Signal Received : ");
#else
cout << "got pipe signal:" << signal << endl;
#endif
}
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() );
dbexit( EXIT_ABRUBT );
}
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 );
log() << "got kill or ctrl c signal " << x << " (" << strsignal( x ) << "), will terminate after current cmd ends" << endl;
Client::initThread( "interruptThread" );
exitCleanly( EXIT_KILL );
}
// this will be called in certain c++ error cases, for example if there are two active
// exceptions
void myterminate() {
rawOut( "terminate() called, printing stack:\n" );
printStackTrace();
abort();
}
void setupSignals() {
assert( signal(SIGSEGV, abruptQuit) != SIG_ERR );
assert( signal(SIGFPE, abruptQuit) != SIG_ERR );
assert( signal(SIGABRT, abruptQuit) != SIG_ERR );
assert( signal(SIGBUS, abruptQuit) != SIG_ERR );
assert( signal(SIGQUIT, abruptQuit) != SIG_ERR );
assert( signal(SIGPIPE, pipeSigHandler) != SIG_ERR );
setupSIGTRAPforGDB();
sigemptyset( &asyncSignals );
sigaddset( &asyncSignals, SIGINT );
sigaddset( &asyncSignals, SIGTERM );
assert( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 );
boost::thread it( interruptThread );
set_terminate( myterminate );
}
#else
void ctrlCTerminate() {
log() << "got kill or ctrl-c signal, will terminate after current cmd ends" << endl;
Client::initThread( "ctrlCTerminate" );
exitCleanly( EXIT_KILL );
}
BOOL CtrlHandler( DWORD fdwCtrlType )
{
switch( fdwCtrlType )
{
case CTRL_C_EVENT:
rawOut("Ctrl-C signal\n");
ctrlCTerminate();
return( TRUE );
case CTRL_CLOSE_EVENT:
rawOut("CTRL_CLOSE_EVENT signal\n");
ctrlCTerminate();
return( TRUE );
case CTRL_BREAK_EVENT:
rawOut("CTRL_BREAK_EVENT signal\n");
ctrlCTerminate();
return TRUE;
case CTRL_LOGOFF_EVENT:
rawOut("CTRL_LOGOFF_EVENT signal (ignored)\n");
return FALSE;
case CTRL_SHUTDOWN_EVENT:
rawOut("CTRL_SHUTDOWN_EVENT signal (ignored)\n");
return FALSE;
default:
return FALSE;
}
}
void myPurecallHandler() {
rawOut( "pure virtual method called, printing stack:\n" );
printStackTrace();
abort();
}
void setupSignals() {
if( SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) )
;
else
massert( 10297 , "Couldn't register Windows Ctrl-C handler", false);
_set_purecall_handler( myPurecallHandler );
}
#endif
} // namespace mongo
#include "recstore.h"
#include "reccache.h"