Files
mongo/db/db.cpp

594 lines
14 KiB
C++
Raw Normal View History

2008-06-06 09:43:15 -04:00
// db.cpp : Defines the entry point for the console application.
//
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2008-12-03 10:12:27 -05:00
#include "stdafx.h"
2008-06-06 09:43:15 -04:00
#include "db.h"
#include "javajs.h"
#include "query.h"
#include "introspect.h"
2008-07-28 17:52:44 -04:00
#include "repl.h"
#include "../util/unittest.h"
2008-09-29 18:00:53 -04:00
#include "dbmessage.h"
2008-12-02 09:54:32 -08:00
#include "instance.h"
2008-06-06 09:43:15 -04:00
2008-07-11 12:27:23 -04:00
bool useJNI = true;
2008-06-06 09:43:15 -04:00
2008-07-11 12:27:23 -04:00
/* only off if --nocursors which is for debugging. */
2008-12-02 09:54:32 -08:00
extern bool useCursors;
extern int port;
extern int curOp;
extern string dashDashSource;
extern int opLogging;
extern OpLog _oplog;
2008-07-09 12:32:11 -04:00
2008-12-02 09:54:32 -08:00
extern int ctr;
extern int callDepth;
2008-06-06 09:43:15 -04:00
2008-07-01 20:01:28 -04:00
void closeAllSockets();
void startReplication();
2008-09-11 15:13:47 -04:00
void pairWith(const char *remoteEnd, const char *arb);
2008-07-01 20:01:28 -04:00
2008-06-06 09:43:15 -04:00
struct MyStartupTests {
MyStartupTests() {
assert( sizeof(OID) == 12 );
}
} mystartupdbcpp;
void quicktest() {
cout << "quicktest()\n";
MemoryMappedFile mmf;
char *m = (char *) mmf.map("/tmp/quicktest", 16384);
// cout << "mmf reads: " << m << endl;
strcpy_s(m, 1000, "hello worldz");
2008-04-25 17:24:27 -04:00
}
2008-06-06 09:43:15 -04:00
2008-06-17 16:57:12 -04:00
QueryResult* emptyMoreResult(long long);
2008-06-06 09:43:15 -04:00
void testTheDb() {
stringstream ss;
setClient("sys.unittest.pdfile");
/* 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-10-21 16:13:48 -04:00
BSONObj j1((const char *) &js1);
2008-06-06 09:43:15 -04:00
deleteObjects("sys.unittest.delete", j1, false);
theDataFileMgr.insert("sys.unittest.delete", &js1, sizeof(js1));
deleteObjects("sys.unittest.delete", j1, false);
updateObjects("sys.unittest.delete", j1, j1, true,ss);
updateObjects("sys.unittest.delete", j1, j1, false,ss);
auto_ptr<Cursor> c = theDataFileMgr.findAll("sys.unittest.pdfile");
while( c->ok() ) {
Record* r = c->_current();
c->advance();
}
cout << endl;
database = 0;
2008-06-06 09:43:15 -04:00
}
MessagingPort *grab = 0;
void connThread();
class OurListener : public Listener {
public:
OurListener(int p) : Listener(p) { }
virtual void accepted(MessagingPort *mp) {
assert( grab == 0 );
grab = mp;
boost::thread thr(connThread);
while( grab )
sleepmillis(1);
}
};
2008-11-29 20:01:58 -05:00
void webServerThread();
2008-12-02 09:54:32 -08:00
void pdfileInit();
2008-11-29 20:01:58 -05:00
2008-06-11 16:58:34 -04:00
/* versions
114 bad memory bug fixed
2008-06-18 17:34:14 -04:00
115 replay, opLogging
2008-06-11 16:58:34 -04:00
*/
2008-06-06 09:43:15 -04:00
void listen(int port) {
2008-09-04 18:24:03 -04:00
const char *Version = "db version: 122";
2008-06-06 09:43:15 -04:00
problem() << Version << endl;
pdfileInit();
//testTheDb();
2008-08-19 14:39:44 -04:00
log() << "waiting for connections on port " << port << "..." << endl;
2008-06-06 09:43:15 -04:00
OurListener l(port);
startReplication();
2008-11-29 20:01:58 -05:00
boost::thread thr(webServerThread);
2008-06-06 09:43:15 -04:00
l.listen();
}
class JniMessagingPort : public AbstractMessagingPort {
public:
JniMessagingPort(Message& _container) : container(_container) { }
2008-06-11 16:58:34 -04:00
void reply(Message& received, Message& response, MSGID) {
container = response;
}
2008-06-06 09:43:15 -04:00
void reply(Message& received, Message& response) {
container = response;
}
Message & container;
};
/* we create one thread for each connection from an app server database.
2008-07-16 17:38:46 -04:00
app server will open a pool of threads.
*/
2008-06-06 09:43:15 -04:00
void connThread()
{
try {
MessagingPort& dbMsgPort = *grab;
grab = 0;
Message m;
while( 1 ) {
m.reset();
stringstream ss;
if( !dbMsgPort.recv(m) ) {
2008-07-29 17:54:54 -04:00
log() << "end connection " << dbMsgPort.farEnd.toString() << endl;
2008-06-06 09:43:15 -04:00
dbMsgPort.shutdown();
break;
}
char buf[64];
time_t_to_String(time(0), buf);
buf[20] = 0; // don't want the year
ss << buf;
// ss << curTimeMillis() % 10000 << ' ';
DbResponse dbresponse;
2008-06-06 09:43:15 -04:00
{
dblock lk;
2008-06-06 09:43:15 -04:00
Timer t;
database = 0;
2008-06-06 09:43:15 -04:00
curOp = 0;
int ms;
2008-06-06 09:43:15 -04:00
bool log = false;
curOp = m.data->operation();
2008-06-29 22:33:59 -04:00
#if 0
/* use this if you only want to process operations for a particular namespace.
maybe add to cmd line parms or something fancier.
*/
DbMessage ddd(m);
if( strncmp(ddd.getns(), "clusterstock", 12) != 0 ) {
static int q;
if( ++q < 20 )
cout << "TEMP skip " << ddd.getns() << endl;
goto skip;
}
#endif
2008-06-29 22:33:59 -04:00
if( m.data->operation() == dbMsg ) {
2008-06-06 09:43:15 -04:00
ss << "msg ";
char *p = m.data->_data;
int len = strlen(p);
if( len > 400 )
cout << curTimeMillis() % 10000 <<
" long msg received, len:" << len <<
" ends with: " << p + len - 10 << endl;
bool end = strcmp("end", p) == 0;
Message *resp = new Message();
resp->setData(opReply, "i am fine");
dbresponse.response = resp;
dbresponse.responseTo = m.data->id;
//dbMsgPort.reply(m, resp);
2008-06-06 09:43:15 -04:00
if( end ) {
cout << curTimeMillis() % 10000 << " end msg " << dbMsgPort.farEnd.toString() << endl;
if( dbMsgPort.farEnd.isLocalHost() ) {
dbMsgPort.shutdown();
sleepmillis(50);
problem() << "exiting end msg" << endl;
exit(EXIT_SUCCESS);
}
else {
cout << " (not from localhost, ignoring end msg)" << endl;
}
2008-06-06 09:43:15 -04:00
}
}
else if( m.data->operation() == dbQuery ) {
receivedQuery(dbresponse, m, ss, true);
2008-06-06 09:43:15 -04:00
}
else if( m.data->operation() == dbInsert ) {
2008-06-18 17:34:14 -04:00
OPWRITE;
2008-06-06 09:43:15 -04:00
try {
ss << "insert ";
receivedInsert(m, ss);
}
2008-09-11 15:13:47 -04:00
catch( AssertionException& e ) {
problem() << " Caught Assertion insert, continuing\n";
ss << " exception " + e.toString();
2008-06-06 09:43:15 -04:00
}
}
else if( m.data->operation() == dbUpdate ) {
2008-06-18 17:34:14 -04:00
OPWRITE;
2008-06-06 09:43:15 -04:00
try {
ss << "update ";
receivedUpdate(m, ss);
}
2008-09-11 15:13:47 -04:00
catch( AssertionException& e ) {
2008-06-06 09:43:15 -04:00
problem() << " Caught Assertion update, continuing" << endl;
2008-09-11 15:13:47 -04:00
ss << " exception " + e.toString();
2008-06-06 09:43:15 -04:00
}
}
else if( m.data->operation() == dbDelete ) {
2008-06-18 17:34:14 -04:00
OPWRITE;
2008-06-06 09:43:15 -04:00
try {
ss << "remove ";
receivedDelete(m);
}
2008-09-11 15:13:47 -04:00
catch( AssertionException& e ) {
problem() << " Caught Assertion receivedDelete, continuing" << endl;
2008-09-11 15:13:47 -04:00
ss << " exception " + e.toString();
2008-06-06 09:43:15 -04:00
}
}
else if( m.data->operation() == dbGetMore ) {
2008-06-18 17:34:14 -04:00
OPREAD;
2008-06-25 10:46:33 -04:00
DEV log = true;
2008-06-06 09:43:15 -04:00
ss << "getmore ";
receivedGetMore(dbresponse, m, ss);
2008-06-06 09:43:15 -04:00
}
else if( m.data->operation() == dbKillCursors ) {
2008-06-18 17:34:14 -04:00
OPREAD;
2008-06-06 09:43:15 -04:00
try {
log = true;
ss << "killcursors ";
receivedKillCursors(m);
}
2008-09-11 15:13:47 -04:00
catch( AssertionException& e ) {
2008-06-06 09:43:15 -04:00
problem() << " Caught Assertion in kill cursors, continuing" << endl;
2008-09-11 15:13:47 -04:00
ss << " exception " + e.toString();
2008-06-06 09:43:15 -04:00
}
}
else {
cout << " operation isn't supported: " << m.data->operation() << endl;
2008-06-06 09:43:15 -04:00
assert(false);
}
ms = t.millis();
2008-06-24 17:31:51 -04:00
log = log || ctr++ % 512 == 0;
2008-06-10 17:20:15 -04:00
DEV log = true;
2008-06-06 09:43:15 -04:00
if( log || ms > 100 ) {
ss << ' ' << t.millis() << "ms";
cout << ss.str().c_str() << endl;
}
2008-08-11 14:53:08 -04:00
//skip:
if( database && database->profile >= 1 ) {
if( database->profile >= 2 || ms >= 100 ) {
2008-06-06 09:43:15 -04:00
// profile it
profile(ss.str().c_str()+20/*skip ts*/, ms);
}
}
} /* end lock */
if( dbresponse.response )
dbMsgPort.reply(m, *dbresponse.response, dbresponse.responseTo);
2008-06-06 09:43:15 -04:00
}
}
2008-09-11 15:13:47 -04:00
catch( AssertionException& ) {
problem() << "Uncaught AssertionException, terminating" << endl;
exit(15);
2008-06-06 09:43:15 -04:00
}
}
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) )
return;
const int Loops = 1;
for( int q = 0; q < Loops; q++ ) {
2008-06-06 09:43:15 -04:00
Message send;
Message response;
send.setData( dbMsg , m);
int len = send.data->dataLen();
for( int i = 0; i < extras; i++ )
2008-07-27 18:36:47 -04:00
p.say(/*db, */send);
2008-06-06 09:43:15 -04:00
Timer t;
2008-07-27 18:36:47 -04:00
bool ok = p.call(send, response);
2008-06-06 09:43:15 -04:00
double tm = t.micros() + 1;
cout << " ****ok. response.data:" << ok << " time:" << tm / 1000.0 << "ms " <<
((double) len) * 8 / 1000000 / (tm/1000000) << "Mbps" << endl;
if( q+1 < Loops ) {
cout << "\t\tSLEEP 8 then sending again as a test" << endl;
2008-06-06 09:43:15 -04:00
sleepsecs(8);
}
}
sleepsecs(1);
2008-06-06 09:43:15 -04:00
p.shutdown();
}
void msg(const char *m, int extras = 0) {
msg(m, "127.0.0.1", DBPort, extras);
}
#if !defined(_WIN32)
#include <signal.h>
void pipeSigHandler( int signal ) {
psignal( signal, "Signal Received : ");
}
int segvs = 0;
2008-06-06 10:17:58 -04:00
void segvhandler(int x) {
if( ++segvs > 1 ) {
signal(x, SIG_DFL);
if( segvs == 2 ) {
cout << "\n\n\n got 2nd SIGSEGV" << endl;
sayDbContext();
}
return;
}
2008-06-06 09:43:15 -04:00
problem() << "got SIGSEGV " << x << ", terminating :-(" << endl;
sayDbContext();
// closeAllSockets();
// MemoryMappedFile::closeAllFiles();
// flushOpLog();
dbexit(14);
2008-06-06 09:43:15 -04:00
}
void mysighandler(int x) {
2008-06-06 10:17:58 -04:00
signal(x, SIG_IGN);
log() << "got kill or ctrl c signal " << x << ", will terminate after current cmd ends" << endl;
2008-06-06 10:17:58 -04:00
{
dblock lk;
problem() << " now exiting" << endl;
2008-06-06 10:17:58 -04:00
exit(12);
}
2008-06-06 09:43:15 -04:00
}
void setupSignals() {
2008-06-06 10:17:58 -04:00
assert( signal(SIGINT, mysighandler) != SIG_ERR );
2008-04-25 17:24:27 -04:00
assert( signal(SIGTERM, mysighandler) != SIG_ERR );
2008-06-06 09:43:15 -04:00
}
#else
void setupSignals() {}
#endif
void initAndListen(int listenPort, const char *dbPath, const char *appserverLoc = null) {
2008-07-11 12:27:23 -04:00
if( opLogging )
2008-09-08 20:37:59 -04:00
log() << "opLogging = " << opLogging << endl;
_oplog.init();
2008-06-07 09:19:49 -04:00
#if !defined(_WIN32)
2008-09-08 20:37:59 -04:00
assert( signal(SIGSEGV, segvhandler) != SIG_ERR );
2008-06-07 09:19:49 -04:00
#endif
2008-06-06 09:43:15 -04:00
2008-09-08 20:37:59 -04:00
/*
* ensure that the dbpath ends with a path delim if not supplied
* @TODO - the following is embarassing - not sure of there's a clean way to
* find the platform delim
*/
char endchar = '/';
const char *endstr = "/";
#if defined(_WIN32)
2008-09-08 20:37:59 -04:00
endchar = '\\';
endstr = "\\";
#endif
2008-06-06 09:43:15 -04:00
if (dbPath && dbPath[strlen(dbPath)-1] != endchar) {
char *t = (char *) malloc(strlen(dbPath) + 2);
strcpy(t, dbPath);
strcat(t, endstr);
dbPath = t;
2008-06-06 09:43:15 -04:00
}
dbpath = dbPath;
#if !defined(_WIN32)
pid_t pid = 0;
pid = getpid();
#else
int pid=0;
#endif
log() << "Mongo DB : starting : pid = " << pid << " port = " << port << " dbpath = " << dbpath
<< " master = " << master << " slave = " << slave << endl;
2008-06-06 09:43:15 -04:00
2008-07-11 12:27:23 -04:00
if( useJNI ) {
JavaJS = new JavaJSImpl(appserverLoc);
javajstest();
}
2008-06-06 09:43:15 -04:00
2008-06-06 10:17:58 -04:00
setupSignals();
2008-06-06 09:43:15 -04:00
listen(listenPort);
}
2008-06-06 10:47:39 -04:00
//ofstream problems("dbproblems.log", ios_base::app | ios_base::out);
2008-06-26 09:09:19 -04:00
int test2();
2008-07-27 18:36:47 -04:00
void testClient();
2008-06-06 09:43:15 -04:00
int main(int argc, char* argv[], char *envp[] )
{
DEV cout << "warning: DEV mode enabled\n";
2008-06-06 09:43:15 -04:00
#if !defined(_WIN32)
signal(SIGPIPE, pipeSigHandler);
#endif
srand(curTimeMillis());
UnitTest::runTests();
2008-06-06 09:43:15 -04:00
if( argc >= 2 ) {
2008-06-26 09:09:19 -04:00
if( strcmp(argv[1], "quicktest") == 0 ) {
quicktest();
return 0;
}
2008-09-14 12:38:48 -04:00
if( strcmp(argv[1], "javatest") == 0 ) {
JavaJS = new JavaJSImpl();
javajstest();
return 0;
}
2008-06-26 09:09:19 -04:00
if( strcmp(argv[1], "test2") == 0 ) {
return test2();
}
2008-06-06 09:43:15 -04:00
if( strcmp(argv[1], "msg") == 0 ) {
// msg(argc >= 3 ? argv[2] : "ping");
const char *m = "ping";
int thePort = DBPort;
if (argc >= 3) {
m = argv[2];
if (argc > 3) {
thePort = atoi(argv[3]);
}
}
msg(m, "127.0.0.1", thePort);
return 0;
}
if( strcmp(argv[1], "msglots") == 0 ) {
msg(argc >= 3 ? argv[2] : "ping", 1000);
return 0;
}
2008-07-27 18:36:47 -04:00
if( strcmp( argv[1], "testclient") == 0 ) {
testClient();
2008-08-19 16:12:13 -04:00
return 0;
2008-07-27 18:36:47 -04:00
}
2008-06-24 17:31:51 -04:00
if( strcmp(argv[1], "zzz") == 0 ) {
msg(argc >= 3 ? argv[2] : "ping", 1000);
return 0;
}
2008-06-06 09:43:15 -04:00
if( strcmp(argv[1], "run") == 0 ) {
initAndListen(port, dbpath);
2008-06-06 09:43:15 -04:00
return 0;
}
if( strcmp(argv[1], "longmsg") == 0 ) {
char buf[800000];
memset(buf, 'a', 799999);
buf[799999] = 0;
buf[799998] = 'b';
buf[0] = 'c';
msg(buf);
return 0;
}
/*
* *** POST STANDARD SWITCH METHOD - if we don't satisfy, we switch to a
* slightly different mode where "run" is assumed and we can set values
*/
char *appsrvPath = null;
for (int i = 1; i < argc; i++) {
2008-07-11 12:27:23 -04:00
if( argv[i] == 0 ) continue;
string s = argv[i];
if( s == "--port" )
2008-06-06 09:43:15 -04:00
port = atoi(argv[++i]);
2008-07-11 12:27:23 -04:00
else if( s == "--nojni" )
useJNI = false;
2008-07-28 17:52:44 -04:00
else if( s == "--master" )
master = true;
else if( s == "--slave" )
slave = true;
2008-11-10 11:20:30 -05:00
else if( s == "--source" ) {
/* specifies what the source in local.sources should be */
dashDashSource = argv[++i];
}
else if( s == "--pairwith" ) {
2008-09-11 15:13:47 -04:00
pairWith( argv[i+1], argv[i+2] );
i += 2;
}
2008-07-11 12:27:23 -04:00
else if( s == "--dbpath" )
2008-06-06 09:43:15 -04:00
dbpath = argv[++i];
2008-07-11 12:27:23 -04:00
else if( s == "--appsrvpath" )
2008-06-06 09:43:15 -04:00
appsrvPath = argv[++i];
2008-07-11 12:27:23 -04:00
else if( s == "--nocursors" )
2008-07-09 12:32:11 -04:00
useCursors = false;
2008-07-11 12:27:23 -04:00
else if( strncmp(s.c_str(), "--oplog", 7) == 0 ) {
2008-07-10 09:35:30 -04:00
int x = s[7] - '0';
if( x < 0 || x > 7 ) {
cout << "can't interpret --oplog setting" << endl;
exit(13);
}
opLogging = x;
}
2008-06-06 09:43:15 -04:00
}
initAndListen(port, dbpath, appsrvPath);
2008-06-23 16:28:25 -04:00
exit(0);
2008-06-06 09:43:15 -04:00
}
cout << "Mongo db usage:\n";
2008-06-06 09:43:15 -04:00
cout << " run run db" << endl;
2008-06-26 15:05:14 -04:00
cout << " msg end [port] shut down db server listening on port (or default)" << endl;
cout << " msg [msg] [port] send a request to the db server listening on port (or default)" << endl;
2008-06-06 09:43:15 -04:00
cout << " msglots send a bunch of test messages, and then wait for answer on the last one" << endl;
2008-06-26 15:05:14 -04:00
cout << " longmsg send a long test message to the db server" << endl;
cout << " quicktest just check basic assertions and exit" << endl;
cout << " test2 run test2() - see code" << endl;
2008-11-10 11:20:30 -05:00
cout << "\nOptions:" << endl;
2008-07-09 12:32:11 -04:00
cout << " --port <portno> --dbpath <root> --appsrvpath <root of appsrv>" << endl;
2008-07-11 12:27:23 -04:00
cout << " --nocursors --nojni" << endl;
2008-07-10 09:35:30 -04:00
cout << " --oplog<n> 0=off 1=W 2=R 3=both 7=W+some reads" << endl;
2008-11-10 11:20:30 -05:00
cout << "\nReplication:" << endl;
cout << " --master\n";
cout << " --slave" << endl;
cout << " --source <server:port>" << endl;
2008-09-11 15:13:47 -04:00
cout << " --pairwith <server:port> <arbiter>" << endl;
2008-07-10 09:35:30 -04:00
cout << endl;
2008-06-06 09:43:15 -04:00
return 0;
}
2008-09-14 22:49:30 -04:00
void foo() {
boost::mutex z;
boost::detail::thread::lock_ops<boost::mutex>::lock(z);
cout << "inside lock" << endl;
boost::detail::thread::lock_ops<boost::mutex>::unlock(z);
}