0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00
mongodb/db/db.cpp

1089 lines
35 KiB
C++
Raw Normal View History

2008-06-06 15:43:15 +02:00
// db.cpp : Defines the entry point for the console application.
//
/**
2009-01-29 22:06:22 +01:00
* Copyright (C) 2008 10gen Inc.info
2008-12-29 02:28:49 +01: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-29 02:28:49 +01: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-29 02:28:49 +01: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/>.
*/
2008-12-03 16:12:27 +01:00
#include "stdafx.h"
2008-06-06 15:43:15 +02:00
#include "db.h"
#include "query.h"
#include "introspect.h"
2008-07-28 23:52:44 +02:00
#include "repl.h"
#include "../util/unittest.h"
#include "../util/file_allocator.h"
#include "../util/background.h"
2008-09-30 00:00:53 +02:00
#include "dbmessage.h"
2008-12-02 18:54:32 +01:00
#include "instance.h"
#include "clientcursor.h"
#include "pdfile.h"
2009-03-10 20:32:59 +01:00
#if !defined(_WIN32)
#include <sys/file.h>
#endif
2008-06-06 15:43:15 +02:00
#if defined(_WIN32)
#include "../util/ntservice.h"
#endif
#include "../scripting/engine.h"
2009-11-18 18:53:56 +01:00
#include "module.h"
2009-08-25 16:24:44 +02:00
#include "cmdline.h"
2009-01-14 23:09:51 +01:00
namespace mongo {
bool useJNI = true;
/* only off if --nocursors which is for debugging. */
extern bool useCursors;
2009-03-10 15:54:00 +01:00
/* only off if --nohints */
extern bool useHints;
2009-04-02 23:58:09 +02:00
bool noHttpInterface = false;
2009-07-08 20:15:14 +02:00
extern string bind_ip;
2009-07-08 20:15:14 +02:00
extern char *appsrvPath;
2009-02-02 17:15:24 +01:00
extern bool autoresync;
2009-11-11 19:54:05 +01:00
extern int diagLogging;
2009-09-18 20:32:25 +02:00
extern int lenForNewNsFiles;
2009-04-01 19:48:02 +02:00
extern int lockFile;
2009-07-08 20:15:14 +02:00
void setupSignals();
void closeAllSockets();
void startReplication();
void pairWith(const char *remoteEnd, const char *arb);
void setRecCacheSize(unsigned MB);
2009-10-13 22:01:02 +02:00
const char *ourgetns() {
Client *c = currentClient.get();
return c ? c->ns() : "";
}
struct MyStartupTests {
MyStartupTests() {
assert( sizeof(OID) == 12 );
}
} mystartupdbcpp;
2008-06-06 15:43:15 +02:00
QueryResult* emptyMoreResult(long long);
2008-06-06 15:43:15 +02:00
void testTheDb() {
2009-12-30 05:30:29 +01:00
OpDebug debug;
setClient("sys.unittest.pdfile");
2008-06-06 15:43:15 +02:00
/* this is not validly formatted, if you query this namespace bad things will happen */
theDataFileMgr.insert("sys.unittest.pdfile", (void *) "hello worldx", 13);
theDataFileMgr.insert("sys.unittest.pdfile", (void *) "hello worldx", 13);
2008-06-06 15:43:15 +02:00
BSONObj j1((const char *) &js1);
deleteObjects("sys.unittest.delete", j1, false);
theDataFileMgr.insert("sys.unittest.delete", &js1, sizeof(js1));
deleteObjects("sys.unittest.delete", j1, false);
2009-12-30 05:30:29 +01:00
updateObjects("sys.unittest.delete", j1, j1, true,false,true,debug);
updateObjects("sys.unittest.delete", j1, j1, false,false,true,debug);
2008-06-06 15:43:15 +02:00
auto_ptr<Cursor> c = theDataFileMgr.findAll("sys.unittest.pdfile");
while ( c->ok() ) {
c->_current();
c->advance();
}
out() << endl;
2008-06-06 15:43:15 +02:00
cc().clearns();
2008-12-29 02:28:49 +01:00
}
2008-06-06 15:43:15 +02:00
MessagingPort *grab = 0;
void connThread();
class OurListener : public Listener {
public:
OurListener(const string &ip, int p) : Listener(ip, p) { }
virtual void accepted(MessagingPort *mp) {
assert( grab == 0 );
if ( ! connTicketHolder.tryAcquire() ){
log() << "connection refused because too many open connections" << endl;
// TODO: would be nice if we notified them...
mp->shutdown();
return;
}
grab = mp;
boost::thread thr(connThread);
while ( grab )
sleepmillis(1);
}
};
void webServerThread();
void pdfileInit();
void listen(int port) {
log() << mongodVersion() << endl;
2009-03-17 15:22:26 +01:00
printGitVersion();
2009-03-18 19:15:52 +01:00
printSysInfo();
pdfileInit();
//testTheDb();
log() << "waiting for connections on port " << port << endl;
OurListener l(bind_ip, port);
startReplication();
2009-04-02 23:58:09 +02:00
if ( !noHttpInterface )
boost::thread thr(webServerThread);
2009-04-01 18:26:31 +02:00
if ( l.init() ) {
registerListenerSocket( l.socket() );
l.listen();
}
2008-12-29 02:28:49 +01:00
}
2009-01-14 23:09:51 +01:00
} // namespace mongo
#include "client.h"
2009-01-05 21:30:07 +01:00
2009-01-14 23:09:51 +01:00
namespace mongo {
2009-07-08 20:15:14 +02:00
void sysRuntimeInfo() {
2009-01-29 22:06:22 +01:00
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);
2008-12-29 02:28:49 +01:00
MessagingPort& dbMsgPort = *grab;
grab = 0;
2009-12-31 22:22:28 +01:00
Client& c = cc();
try {
2009-01-05 21:30:07 +01:00
2009-12-31 22:22:28 +01:00
c.ai->isLocalHost = dbMsgPort.farEnd.isLocalHost();
Message m;
while ( 1 ) {
m.reset();
if ( !dbMsgPort.recv(m) ) {
2009-08-25 20:35:22 +02:00
if( !cmdLine.quiet )
2009-12-31 22:22:28 +01:00
log() << "end connection " << dbMsgPort.farEnd.toString() << endl;
2008-12-29 02:28:49 +01:00
dbMsgPort.shutdown();
break;
2008-12-29 02:28:49 +01:00
}
lastError.startRequest( m , le );
2009-09-18 20:32:25 +02:00
DbResponse dbresponse;
if ( !assembleResponse( m, dbresponse, dbMsgPort.farEnd.sa ) ) {
out() << curTimeMillis() % 10000 << " end msg " << dbMsgPort.farEnd.toString() << endl;
2009-01-19 02:31:33 +01:00
/* 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;
2009-08-07 21:37:50 +02:00
dbexit(EXIT_CLEAN);
}
else {
out() << " (not from localhost, ignoring end msg)" << endl;
}
2008-12-29 02:28:49 +01:00
}
if ( dbresponse.response )
dbMsgPort.reply(m, *dbresponse.response, dbresponse.responseTo);
2008-12-29 02:28:49 +01:00
}
}
catch ( AssertionException& ) {
problem() << "AssertionException in connThread, closing client connection" << endl;
dbMsgPort.shutdown();
}
2009-02-06 18:44:50 +01:00
catch ( SocketException& ) {
problem() << "SocketException in connThread, closing client connection" << endl;
dbMsgPort.shutdown();
}
catch ( std::exception &e ) {
problem() << "Uncaught std::exception: " << e.what() << ", terminating" << endl;
2009-08-07 21:37:50 +02:00
dbexit( EXIT_UNCAUGHT );
}
catch ( ... ) {
problem() << "Uncaught exception, terminating" << endl;
2009-08-07 21:37:50 +02:00
dbexit( EXIT_UNCAUGHT );
}
2009-08-12 16:51:31 +02:00
// any thread cleanup can happen here
2009-09-18 20:32:25 +02:00
2009-10-14 21:15:38 +02:00
if ( currentClient.get() )
currentClient->shutdown();
2009-08-12 16:51:31 +02:00
globalScriptEngine->threadDone();
}
2008-06-06 15:43:15 +02:00
void msg(const char *m, const char *address, int port, int extras = 0) {
2008-06-06 15:43:15 +02:00
SockAddr db(address, port);
2008-06-06 15:43:15 +02:00
2009-07-08 20:15:14 +02:00
// 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);
2008-06-06 15:43:15 +02:00
MessagingPort p;
if ( !p.connect(db) )
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);
2009-09-21 15:05:27 +02:00
double tm = ((double) t.micros()) + 1;
out() << " ****ok. response.data:" << ok << " time:" << tm / 1000.0 << "ms " <<
((double) len) * 8 / 1000000 / (tm/1000000) << "Mbps" << endl;
if ( q+1 < Loops ) {
out() << "\t\tSLEEP 8 then sending again as a test" << endl;
sleepsecs(8);
}
2008-12-29 02:28:49 +01:00
}
sleepsecs(1);
2008-12-29 02:28:49 +01:00
p.shutdown();
}
2008-06-06 15:43:15 +02:00
void msg(const char *m, int extras = 0) {
2009-08-25 16:24:44 +02:00
msg(m, "127.0.0.1", CmdLine::DefaultDBPort, extras);
}
2008-06-06 15:43:15 +02:00
bool shouldRepairDatabases = 0;
2009-10-10 03:01:32 +02:00
bool forceRepair = 0;
bool doDBUpgrade( const string& dbName , string errmsg , MDFHeader * 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 );
}
void repairDatabases() {
2009-11-03 19:01:07 +01:00
log(1) << "enter repairDatabases" << endl;
dblock lk;
vector< string > dbNames;
getDatabaseNames( dbNames );
for ( vector< string >::iterator i = dbNames.begin(); i != dbNames.end(); ++i ) {
string dbName = *i;
2009-11-03 19:01:07 +01:00
log(1) << "\t" << dbName << endl;
2009-10-13 22:01:02 +02:00
assert( !setClient( dbName.c_str() ) );
MongoDataFile *p = cc().database()->getFile( 0 );
MDFHeader *h = p->getHeader();
2009-10-09 21:32:05 +02:00
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() );
}
2008-12-29 02:28:49 +01:00
}
2009-11-03 19:01:07 +01:00
log(1) << "done repairDatabases" << endl;
if ( shouldRepairDatabases ){
log() << "finished checking dbs" << endl;
dbexit( EXIT_CLEAN );
}
2008-12-29 02:28:49 +01:00
}
void clearTmpFiles() {
boost::filesystem::path path( dbpath );
for ( boost::filesystem::directory_iterator i( path );
i != boost::filesystem::directory_iterator(); ++i ) {
2009-11-16 17:33:57 +01:00
string fileName = boost::filesystem::path(*i).leaf();
if ( boost::filesystem::is_directory( *i ) &&
fileName.length() > 2 && fileName.substr( 0, 3 ) == "tmp" )
boost::filesystem::remove_all( *i );
}
2009-01-14 23:17:24 +01:00
}
2009-07-08 20:15:14 +02:00
2009-03-06 19:13:07 +01:00
void clearTmpCollections() {
vector< string > toDelete;
DBDirectClient cli;
auto_ptr< DBClientCursor > c = cli.query( "local.system.namespaces", Query( fromjson( "{name:/^local.temp./}" ) ) );
2009-12-11 18:41:26 +01:00
while( c->more() ) {
BSONObj o = c->next();
toDelete.push_back( o.getStringField( "name" ) );
}
2009-03-06 19:13:07 +01:00
for( vector< string >::iterator i = toDelete.begin(); i != toDelete.end(); ++i ) {
log() << "Dropping old temporary collection: " << *i << endl;
cli.dropCollection( *i );
}
}
2008-12-29 20:22:36 +01:00
2009-11-28 04:28:56 +01:00
/**
* does background async flushes of mmapped files
*/
class DataFileSync : public BackgroundJob {
public:
void run(){
2009-11-28 16:41:14 +01:00
log(1) << "will flush memory every: " << _sleepsecs << " seconds" << endl;
while ( ! inShutdown() ){
if ( _sleepsecs == 0 ){
// in case at some point we add an option to change at runtime
sleepsecs(5);
continue;
}
2009-11-28 17:50:46 +01:00
sleepmillis( (int)(_sleepsecs * 1000) );
MemoryMappedFile::flushAll( false );
log(1) << "flushing mmmap" << endl;
}
}
2009-11-28 16:41:14 +01:00
double _sleepsecs; // default value controlled by program options
} dataFileSync;
2009-08-11 17:27:02 +02:00
void show_32_warning(){
2009-11-28 19:57:30 +01:00
#if BOOST_VERSION < 103500
2009-12-30 21:58:16 +01:00
cout << "\nwarning: built with boost version <= 1.34, limited concurrency" << endl;
2009-11-28 19:57:30 +01:00
#endif
2009-08-11 17:27:02 +02:00
if ( sizeof(int*) != 4 )
return;
2009-08-11 17:32:03 +02:00
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;
2009-08-11 17:27:02 +02:00
}
Timer startupSrandTimer;
2009-01-07 19:31:16 +01:00
void _initAndListen(int listenPort, const char *appserverLoc = null) {
#if !defined(_WIN32)
pid_t pid = 0;
pid = getpid();
#else
int pid=0;
#endif
2009-08-11 16:28:32 +02:00
bool is32bit = sizeof(int*) == 4;
2009-08-25 16:24:44 +02:00
log() << "Mongo DB : starting : pid = " << pid << " port = " << cmdLine.port << " dbpath = " << dbpath
<< " master = " << master << " slave = " << (int) slave << " " << ( is32bit ? "32" : "64" ) << "-bit " << endl;
2009-08-11 17:27:02 +02:00
show_32_warning();
2009-07-08 20:15:14 +02:00
stringstream ss;
ss << "dbpath (" << dbpath << ") does not exist";
massert( 10296 , ss.str().c_str(), boost::filesystem::exists( dbpath ) );
2009-07-08 20:15:14 +02:00
acquirePathLock();
remove_all( dbpath + "/_tmp/" );
2009-07-08 20:15:14 +02:00
theFileAllocator().start();
2009-07-08 20:15:14 +02:00
BOOST_CHECK_EXCEPTION( clearTmpFiles() );
2009-07-08 20:15:14 +02:00
Client::initThread("initandlisten");
2009-03-06 19:13:07 +01:00
clearTmpCollections();
2009-07-08 20:15:14 +02:00
_diaglog.init();
2009-07-08 20:15:14 +02:00
2009-11-18 18:53:56 +01:00
Module::initAll();
2009-07-17 21:49:24 +02:00
#if 0
{
stringstream indexpath;
indexpath << dbpath << "/indexes.dat";
RecCache::tempStore.init(indexpath.str().c_str(), BucketSize);
}
#endif
2009-02-03 00:18:22 +01:00
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;
2009-09-21 15:05:27 +02:00
/* this is for security on certain platforms (nonce generation) */
srand((unsigned) (curTimeMicros() ^ startupSrandTimer.micros()));
2009-07-08 20:15:14 +02:00
listen(listenPort);
2009-07-08 20:15:14 +02:00
// 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); }
2009-10-09 17:55:56 +02:00
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 );
}
2009-07-08 20:15:14 +02:00
catch(...) {
log() << " exception in initAndListen, terminating" << endl;
dbexit( EXIT_UNCAUGHT );
}
}
2008-06-06 15:43:15 +02:00
2009-07-08 20:15:14 +02:00
#if defined(_WIN32)
bool initService() {
2009-07-08 20:15:14 +02:00
ServiceController::reportStatus( SERVICE_RUNNING );
2009-08-25 16:24:44 +02:00
initAndListen( cmdLine.port, appsrvPath );
2009-07-08 20:15:14 +02:00
return true;
}
#endif
2009-01-14 23:09:51 +01:00
} // namespace mongo
2009-01-14 23:09:51 +01:00
using namespace mongo;
#include <boost/program_options.hpp>
namespace po = boost::program_options;
2009-08-11 17:27:02 +02:00
void show_help_text(po::options_description options) {
2009-08-11 17:27:02 +02:00
show_32_warning();
2009-08-11 17:32:03 +02:00
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 "";
}
2008-06-06 15:43:15 +02:00
int main(int argc, char* argv[], char *envp[] )
{
2009-10-13 22:01:02 +02:00
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::options_description cmdline_options("Command line options");
po::positional_options_description positional_options;
general_options.add_options()
("help,h", "show this usage information")
2009-09-22 16:05:53 +02:00
("version", "show version information")
("config,f", po::value<string>(), "configuration file specifying additional options")
("port", po::value<int>(&cmdLine.port)/*->default_value(CmdLine::DefaultDBPort)*/, "specify port number")
("bind_ip", po::value<string>(&bind_ip),
"local ip address to bind listener - all local ips bound by default")
("verbose,v", "be more verbose (include multiple times for more verbosity e.g. -vvvvv)")
("dbpath", po::value<string>()->default_value("/data/db/"), "directory for datafiles")
("quiet", "quieter output")
2009-08-31 17:22:40 +02:00
("logpath", po::value<string>() , "file to send all output to instead of stdout" )
("logappend" , "appnd to logpath instead of over-writing" )
#ifndef _WIN32
2009-08-31 21:38:43 +02:00
("fork" , "fork server process" )
2009-08-31 17:22:40 +02:00
#endif
("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")
2009-10-20 19:29:05 +02:00
("quotaFiles", po::value<int>(), "number of files allower per db, requires --quota")
2009-09-16 02:17:54 +02:00
("appsrvpath", po::value<string>(), "root directory for the babble app server")
("nocursors", "diagnostic/debugging option")
("nohints", "ignore query hints")
("nohttpinterface", "disable http interface")
("noscripting", "disable scripting engine")
("noprealloc", "disable data file preallocation")
2009-10-08 22:29:04 +02:00
("smallfiles", "use a smaller default file size")
2009-08-20 21:00:25 +02:00
("nssize", po::value<int>()->default_value(16), ".ns file size (in MB) for new databases")
2009-11-11 19:54:05 +01:00
("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")
2009-10-09 21:32:05 +02:00
("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")
2009-11-06 22:27:49 +01:00
#endif
;
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")
2009-07-09 20:59:23 +02:00
("autoresync", "automatically resync if slave data is stale")
("oplogSize", po::value<long>(), "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()
("command", po::value< vector<string> >(), "command")
2009-07-09 20:59:23 +02:00
("cacheSize", po::value<long>(), "cache size (in MB) for rec store")
;
/* support for -vv -vvvv etc. */
for (string s = "vv"; s.length() <= 10; s.append("v")) {
hidden_options.add_options()(s.c_str(), "verbose");
}
positional_options.add("command", 3);
visible_options.add(general_options);
visible_options.add(replication_options);
visible_options.add(sharding_options);
2009-11-18 18:53:56 +01:00
Module::addOptions( visible_options );
cmdline_options.add(visible_options);
cmdline_options.add(hidden_options);
setupSignals();
2009-07-08 20:15:14 +02:00
dbExecCommand = argv[0];
2009-07-08 20:15:14 +02:00
2009-01-18 18:19:26 +01:00
srand(curTimeMicros());
2008-12-29 23:59:44 +01:00
boost::filesystem::path::default_name_check( boost::filesystem::no_check );
2009-01-14 23:17:24 +01:00
{
unsigned x = 0x12345678;
unsigned char& b = (unsigned char&) x;
2008-12-29 02:28:49 +01:00
if ( b != 0x78 ) {
out() << "big endian cpus not yet supported" << endl;
return 33;
}
}
2009-10-13 18:55:23 +02:00
DEV out() << "DEV is defined (using _DEBUG), which is slower...\n";
2009-09-18 20:32:25 +02:00
2008-12-29 02:28:49 +01:00
UnitTest::runTests();
2009-09-18 20:32:25 +02:00
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;
2008-12-29 02:28:49 +01:00
string error_message = arg_error_check(argc, argv);
if (error_message != "") {
cout << error_message << endl << endl;
show_help_text(visible_options);
return 0;
}
/* don't allow guessing - creates ambiguities when some options are
* prefixes of others. allow long disguises and don't allow guessing
* to get away with our vvvvvvv trick. */
int command_line_style = (((po::command_line_style::unix_style ^
po::command_line_style::allow_guessing) |
po::command_line_style::allow_long_disguise) ^
po::command_line_style::allow_sticky);
2008-12-29 02:28:49 +01:00
try {
po::store(po::command_line_parser(argc, argv).options(cmdline_options).
positional(positional_options).
style(command_line_style).run(), params);
if (params.count("config")) {
ifstream config_file (params["config"].as<string>().c_str());
if (config_file.is_open()) {
po::store(po::parse_config_file(config_file, cmdline_options), params);
config_file.close();
} else {
cout << "ERROR: could not read from config file" << endl << endl;
cout << visible_options << endl;
return 0;
}
}
po::notify(params);
} catch (po::error &e) {
cout << "ERROR: " << e.what() << endl << endl;
cout << visible_options << endl;
return 0;
}
2009-07-21 22:53:35 +02:00
if (params.count("help")) {
show_help_text(visible_options);
2008-12-29 02:28:49 +01:00
return 0;
}
2009-09-22 16:05:53 +02:00
if (params.count("version")) {
cout << mongodVersion() << endl;
printGitVersion();
return 0;
}
2009-08-11 20:29:03 +02:00
dbpath = params["dbpath"].as<string>();
if (params.count("quiet")) {
2009-08-25 20:35:22 +02:00
cmdLine.quiet = true;
}
if (params.count("verbose")) {
logLevel = 1;
}
for (string s = "vv"; s.length() <= 10; s.append("v")) {
if (params.count(s)) {
logLevel = s.length();
}
}
if (params.count("cpu")) {
2009-10-16 17:36:38 +02:00
cmdLine.cpu = true;
}
if (params.count("noauth")) {
noauth = true;
}
if (params.count("auth")) {
noauth = false;
}
if (params.count("quota")) {
2009-10-16 17:36:38 +02:00
cmdLine.quota = true;
}
2009-10-20 19:29:05 +02:00
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());
}
2009-08-31 17:22:40 +02:00
#ifndef _WIN32
2009-08-31 21:38:43 +02:00
if (params.count("fork")) {
if ( ! params.count( "logpath" ) ){
cout << "--fork has to be used with --logpath" << endl;
2009-08-31 21:38:43 +02:00
return -1;
}
pid_t c = fork();
if ( c ){
cout << "forked process: " << c << endl;
2009-08-31 21:38:43 +02:00
::exit(0);
}
setsid();
setupSignals();
}
#endif
2009-08-31 17:22:40 +02:00
if (params.count("logpath")) {
string lp = params["logpath"].as<string>();
uassert( 10033 , "logpath has to be non-zero" , lp.size() );
initLogging( lp , params.count( "logappend" ) );
2009-08-31 17:22:40 +02:00
}
if (params.count("nocursors")) {
useCursors = false;
}
if (params.count("nohints")) {
useHints = false;
}
if (params.count("nohttpinterface")) {
noHttpInterface = true;
}
if (params.count("noscripting")) {
useJNI = false;
}
if (params.count("noprealloc")) {
2009-10-08 22:29:04 +02:00
cmdLine.prealloc = false;
}
if (params.count("smallfiles")) {
cmdLine.smallfiles = true;
}
2009-11-11 19:54:05 +01:00
if (params.count("diaglog")) {
int x = params["diaglog"].as<int>();
if ( x < 0 || x > 7 ) {
2009-11-11 19:54:05 +01:00
out() << "can't interpret --diaglog setting" << endl;
dbexit( EXIT_BADOPTIONS );
}
_diaglog.level = x;
}
if (params.count("sysinfo")) {
sysRuntimeInfo();
2008-12-29 02:28:49 +01:00
return 0;
}
2009-10-09 21:32:05 +02:00
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")) {
master = true;
}
if (params.count("slave")) {
2009-09-18 20:32:25 +02:00
slave = SimpleSlave;
}
if (params.count("source")) {
/* specifies what the source in local.sources should be */
2009-08-25 20:35:22 +02:00
cmdLine.source = params["source"].as<string>().c_str();
}
if (params.count("only")) {
2009-08-25 20:35:22 +02:00
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("autoresync")) {
autoresync = true;
}
2009-09-18 20:32:25 +02:00
if( params.count("nssize") ) {
2009-08-20 21:00:25 +02:00
int x = params["nssize"].as<int>();
uassert( 10034 , "bad --nssize arg", x > 0 && x <= (0x7fffffff/1024/1024));
2009-09-18 20:32:25 +02:00
lenForNewNsFiles = x * 1024 * 1024;
2009-08-20 21:00:25 +02:00
assert(lenForNewNsFiles > 0);
2009-09-18 20:32:25 +02:00
}
if (params.count("oplogSize")) {
long x = params["oplogSize"].as<long>();
uassert( 10035 , "bad --oplogSize arg", x > 0);
2009-10-17 05:32:34 +02:00
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);
opIdMem = x;
assert(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;
}
2009-11-11 22:04:52 +01:00
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 );
}
2009-11-18 18:53:56 +01:00
Module::configAll( params );
dataFileSync.go();
2009-07-17 21:49:24 +02:00
if (params.count("command")) {
vector<string> command = params["command"].as< vector<string> >();
2008-12-29 02:28:49 +01:00
if (command[0].compare("msg") == 0) {
2009-07-08 23:14:51 +02:00
const char *m;
2009-07-08 23:14:51 +02:00
if (command.size() < 3) {
cout << "Too few parameters to 'msg' command" << endl;
cout << visible_options << endl;
return 0;
}
m = command[1].c_str();
2009-07-08 23:14:51 +02:00
msg(m, "127.0.0.1", atoi(command[2].c_str()));
2009-02-02 17:15:24 +01:00
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;
2008-12-29 02:28:49 +01:00
}
2009-08-25 16:24:44 +02:00
initAndListen(cmdLine.port);
return 0;
2008-12-29 02:28:49 +01:00
}
2009-10-27 21:37:14 +01: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 15:43:15 +02:00
}
2009-07-21 22:53:35 +02:00
2009-08-11 20:29:03 +02:00
#if defined(_WIN32)
if ( installService ) {
2009-07-08 20:15:14 +02:00
if ( !ServiceController::installService( L"MongoDB", L"Mongo DB", L"Mongo DB Server", argc, argv ) )
dbexit( EXIT_NTSERVICE_ERROR );
dbexit( EXIT_CLEAN );
2009-07-08 20:15:14 +02:00
}
else if ( removeService ) {
if ( !ServiceController::removeService( L"MongoDB" ) )
dbexit( EXIT_NTSERVICE_ERROR );
dbexit( EXIT_CLEAN );
2009-07-08 20:15:14 +02:00
}
else if ( startService ) {
if ( !ServiceController::startService( L"MongoDB", mongo::initService ) )
dbexit( EXIT_NTSERVICE_ERROR );
dbexit( EXIT_CLEAN );
2009-07-08 20:15:14 +02:00
}
2009-08-11 20:29:03 +02:00
#endif
2009-09-18 20:32:25 +02:00
}
2008-06-06 15:43:15 +02:00
2009-08-25 16:24:44 +02:00
initAndListen(cmdLine.port, appsrvPath);
dbexit(EXIT_CLEAN);
2008-12-27 04:06:48 +01:00
return 0;
2008-06-06 15:43:15 +02:00
}
2009-01-14 23:09:51 +01:00
namespace mongo {
/* we do not use log() below as it uses a mutex and that could cause deadlocks.
*/
string getDbContext();
2009-01-18 17:53:33 +01:00
#undef out
2009-10-05 18:59:51 +02:00
void exitCleanly() {
goingAway = true;
2009-12-22 21:22:37 +01:00
killCurrentOp.killAll();
2009-10-05 18:59:51 +02:00
{
dblock lk;
log() << "now exiting" << endl;
dbexit( EXIT_KILL );
}
}
#if !defined(_WIN32)
2009-01-14 23:09:51 +01:00
} // namespace mongo
#include <signal.h>
2009-03-12 22:36:46 +01:00
#include <string.h>
2009-01-14 23:09:51 +01: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 22:36:46 +01:00
ostringstream ossSig;
ossSig << "Got signal: " << x << " (" << strsignal( x ) << ")." << endl;
rawOut( ossSig.str() );
/*
2009-03-03 22:10:42 +01:00
ostringstream ossOp;
ossOp << "Last op: " << currentOp.infoNoauth() << endl;
rawOut( ossOp.str() );
*/
2009-03-12 22:36:46 +01:00
ostringstream oss;
2009-03-12 22:36:46 +01:00
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 );
2009-03-12 22:36:46 +01:00
log() << "got kill or ctrl c signal " << x << " (" << strsignal( x ) << "), will terminate after current cmd ends" << endl;
2009-10-05 18:59:51 +02:00
exitCleanly();
}
2009-07-08 20:15:14 +02:00
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(SIGPIPE, pipeSigHandler) != SIG_ERR );
assert( signal(SIGUSR1 , rotateLogs ) != SIG_ERR );
2009-11-03 21:05:31 +01:00
setupSIGTRAPforGDB();
sigemptyset( &asyncSignals );
sigaddset( &asyncSignals, SIGINT );
sigaddset( &asyncSignals, SIGTERM );
assert( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 );
boost::thread it( interruptThread );
}
#else
void ctrlCTerminate() {
log() << "got kill or ctrl c signal, will terminate after current cmd ends" << endl;
2009-10-05 18:59:51 +02:00
exitCleanly();
}
2009-09-18 20:32:25 +02:00
BOOL CtrlHandler( DWORD fdwCtrlType )
{
switch( fdwCtrlType )
{
case CTRL_C_EVENT:
2009-09-03 19:11:30 +02:00
rawOut("Ctrl-C signal\n");
ctrlCTerminate();
return( TRUE );
2009-09-18 20:32:25 +02:00
case CTRL_CLOSE_EVENT:
2009-09-03 19:11:30 +02:00
rawOut("CTRL_CLOSE_EVENT signal\n");
ctrlCTerminate();
2009-09-18 20:32:25 +02:00
return( TRUE );
case CTRL_BREAK_EVENT:
2009-09-03 19:11:30 +02:00
rawOut("CTRL_BREAK_EVENT signal\n");
ctrlCTerminate();
return TRUE;
2009-09-18 20:32:25 +02:00
case CTRL_LOGOFF_EVENT:
2009-09-03 19:11:30 +02:00
rawOut("CTRL_LOGOFF_EVENT signal (ignored)\n");
2009-09-18 20:32:25 +02:00
return FALSE;
case CTRL_SHUTDOWN_EVENT:
2009-09-03 19:11:30 +02:00
rawOut("CTRL_SHUTDOWN_EVENT signal (ignored)\n");
2009-09-18 20:32:25 +02:00
return FALSE;
default:
return FALSE;
}
}
void setupSignals() {
2009-09-18 20:32:25 +02:00
if( SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) )
2009-09-03 19:11:30 +02:00
;
else
massert( 10297 , "Couldn't register Windows Ctrl-C handler", false);
2009-09-18 20:32:25 +02:00
}
#endif
2009-01-14 23:09:51 +01:00
2009-11-28 17:50:46 +01:00
void temptestfoo() {
MongoMutex m;
m.lock();
// m.lock_upgrade();
m.lock_shared();
}
2009-01-14 23:09:51 +01:00
} // namespace mongo
2009-02-03 00:18:22 +01:00
#include "recstore.h"
#include "reccache.h"
2009-11-28 17:50:46 +01:00