Files
mongo/db/instance.cpp

814 lines
27 KiB
C++
Raw Normal View History

// instance.cpp : Global state variables and functions.
//
/**
* 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/>.
*/
2008-12-03 10:12:27 -05:00
#include "stdafx.h"
#include "db.h"
#include "query.h"
#include "introspect.h"
#include "repl.h"
#include "dbmessage.h"
#include "instance.h"
2009-01-05 15:30:07 -05:00
#include "lasterror.h"
2009-01-18 20:31:33 -05:00
#include "security.h"
2009-01-28 18:08:02 -05:00
#include "json.h"
2009-02-02 18:18:22 -05:00
#include "reccache.h"
2009-03-30 14:07:04 -04:00
#include "replset.h"
2009-03-19 10:33:35 -04:00
#include "../s/d_logic.h"
#include "../util/file_allocator.h"
2009-08-25 10:24:44 -04:00
#include "cmdline.h"
2009-04-01 14:10:21 -04:00
#if !defined(_WIN32)
#include <sys/file.h>
#endif
2009-01-14 17:09:51 -05:00
namespace mongo {
void receivedKillCursors(Message& m);
void receivedUpdate(Message& m, stringstream& ss);
void receivedDelete(Message& m, stringstream& ss);
void receivedInsert(Message& m, stringstream& ss);
bool receivedGetMore(DbResponse& dbresponse, Message& m, stringstream& ss);
bool Database::_openAllFiles = false;
2009-08-25 10:24:44 -04:00
CmdLine cmdLine;
int nloggedsome = 0;
2008-12-28 20:28:49 -05:00
#define LOGSOME if( ++nloggedsome < 1000 || nloggedsome % 100 == 0 )
2008-12-27 12:07:20 -05:00
SlaveTypes slave = NotSlave;
bool master = false; // true means keep an op log
2009-02-02 11:15:24 -05:00
bool autoresync = false;
2009-08-25 16:14:55 -04:00
/* we use new here so we don't have to worry about destructor orders at program shutdown */
2009-11-28 11:50:46 -05:00
MongoMutex &dbMutex( *(new MongoMutex) );
MutexInfo dbMutexInfo;
2009-12-03 13:48:45 -05:00
string dbExecCommand;
string bind_ip = "";
char *appsrvPath = null;
2009-02-02 18:18:22 -05:00
DiagLog _diaglog;
int opIdMem = 100000000;
bool useCursors = true;
2009-03-10 10:54:00 -04:00
bool useHints = true;
void closeAllSockets();
void flushOpLog( stringstream &ss ) {
if( _diaglog.f && _diaglog.f->is_open() ) {
ss << "flushing op log and files\n";
_diaglog.flush();
2009-02-02 18:18:22 -05:00
}
}
int ctr = 0;
2009-01-28 18:08:02 -05:00
/* 0 = ok
1 = kill current operation and reset this to 0
future: maybe use this as a "going away" thing on process termination with a higher flag value
*/
int killCurrentOp = 0;
2009-04-01 13:48:02 -04:00
int lockFile = 0;
2009-01-28 18:08:02 -05:00
void inProgCmd( Message &m, DbResponse &dbresponse ) {
BSONObjBuilder b;
AuthenticationInfo *ai = cc().ai;
if( !ai->isAuthorized("admin") ) {
BSONObjBuilder b;
b.append("err", "unauthorized");
}
else {
vector<BSONObj> vals;
{
boostlock bl(Client::clientsMutex);
for( set<Client*>::iterator i = Client::clients.begin(); i != Client::clients.end(); i++ ) {
Client *c = *i;
CurOp& co = *(c->curop());
if( co.active )
vals.push_back( co.infoNoauth() );
}
}
b.append("inprog", vals);
}
2009-10-07 11:51:13 -04:00
replyToQuery(0, m, dbresponse, b.obj());
2009-01-28 18:08:02 -05:00
}
2009-03-17 17:25:10 -04:00
2009-01-28 18:08:02 -05:00
void killOp( Message &m, DbResponse &dbresponse ) {
BSONObj obj;
AuthenticationInfo *ai = currentClient.get()->ai;
if( !ai->isAuthorized("admin") ) {
2009-01-29 09:27:45 -05:00
obj = fromjson("{\"err\":\"unauthorized\"}");
}
else if( !dbMutexInfo.isLocked() )
2009-01-28 18:08:02 -05:00
obj = fromjson("{\"info\":\"no op in progress/not locked\"}");
else {
killCurrentOp = 1;
obj = fromjson("{\"info\":\"attempting to kill op\"}");
}
replyToQuery(0, m, dbresponse, obj);
}
2009-03-17 17:25:10 -04:00
bool receivedQuery(DbResponse& dbresponse, Message& m,
stringstream& ss, bool logit,
mongolock& lock
) {
bool ok = true;
MSGID responseTo = m.data->id;
DbMessage d(m);
QueryMessage q(d);
QueryResult* msgdata;
try {
if (q.fields.get() && q.fields->errmsg)
uassert(q.fields->errmsg, false);
/* note these are logged BEFORE authentication -- which is sort of ok */
if ( _diaglog.level && logit ) {
if ( strstr(q.ns, ".$cmd") ) {
/* $cmd queries are "commands" and usually best treated as write operations */
OPWRITE;
}
else {
OPREAD;
}
}
setClient( q.ns, dbpath, &lock );
Client& client = cc();
client.top.setRead();
strncpy(client.curop()->ns, q.ns, Namespace::MaxNsLen);
msgdata = runQuery(m, ss ).release();
}
catch ( AssertionException& e ) {
ok = false;
ss << " exception ";
LOGSOME problem() << " Caught Assertion in runQuery ns:" << q.ns << ' ' << e.toString() << '\n';
log() << " ntoskip:" << q.ntoskip << " ntoreturn:" << q.ntoreturn << '\n';
if ( q.query.valid() )
log() << " query:" << q.query.toString() << endl;
else
log() << " query object is not valid!" << endl;
BSONObjBuilder err;
err.append("$err", e.msg.empty() ? "assertion during query" : e.msg);
BSONObj errObj = err.done();
BufBuilder b;
b.skip(sizeof(QueryResult));
b.append((void*) errObj.objdata(), errObj.objsize());
// todo: call replyToQuery() from here instead of this!!! see dbmessage.h
msgdata = (QueryResult *) b.buf();
b.decouple();
QueryResult *qr = msgdata;
qr->resultFlags() = QueryResult::ResultFlag_ErrSet;
qr->len = b.len();
qr->setOperation(opReply);
qr->cursorId = 0;
qr->startingFrom = 0;
qr->nReturned = 1;
}
Message *resp = new Message();
resp->setData(msgdata, true); // transport will free
dbresponse.response = resp;
dbresponse.responseTo = responseTo;
Database *database = cc().database();
if ( database ) {
if ( database->profile )
ss << " bytes:" << resp->data->dataLen();
}
else {
if ( strstr(q.ns, "$cmd") == 0 ) // (this condition is normal for $cmd dropDatabase)
log() << "ERROR: receiveQuery: database is null; ns=" << q.ns << endl;
}
return ok;
}
2009-12-03 11:50:09 -05:00
bool commandIsReadOnly(BSONObj& _cmdobj);
2009-01-28 18:08:02 -05:00
// Returns false when request includes 'end'
bool assembleResponse( Message &m, DbResponse &dbresponse, const sockaddr_in &client ) {
2009-11-28 13:57:30 -05:00
bool writeLock = true;
2009-01-28 18:08:02 -05:00
// before we lock...
2009-11-28 13:57:30 -05:00
int op = m.data->operation();
const char *ns = m.data->_data + 4;
2009-11-28 13:57:30 -05:00
if ( op == dbQuery ) {
2009-12-03 11:50:09 -05:00
if( strstr(ns, ".$cmd") ) {
if( strstr(ns, ".$cmd.sys.") ) {
if( strstr(ns, "$cmd.sys.inprog") ) {
inProgCmd(m, dbresponse);
return true;
}
if( strstr(ns, "$cmd.sys.killop") ) {
killOp(m, dbresponse);
return true;
}
2009-01-28 18:08:02 -05:00
}
2009-12-03 11:50:09 -05:00
DbMessage d( m );
QueryMessage q( d );
writeLock = !commandIsReadOnly(q.query);
2009-01-28 18:08:02 -05:00
}
else
writeLock = false;
2009-01-28 18:08:02 -05:00
}
2009-11-28 13:57:30 -05:00
else if( op == dbGetMore ) {
writeLock = false;
}
2009-03-17 17:25:10 -04:00
2009-03-23 11:32:30 -04:00
if ( handlePossibleShardedMessage( m , dbresponse ) ){
/* important to do this before we lock
so if a message has to be forwarded, doesn't block for that
*/
2009-03-17 17:25:10 -04:00
return true;
2009-03-23 11:32:30 -04:00
}
2009-01-28 18:08:02 -05:00
2009-11-28 13:57:30 -05:00
mongolock lk(writeLock);
stringstream ss;
char buf[64];
2009-01-28 18:08:02 -05:00
time_t now = time(0);
CurOp& currentOp = *cc().curop();
currentOp.reset(now, client);
2009-01-28 18:08:02 -05:00
time_t_to_String(now, buf);
buf[20] = 0; // don't want the year
ss << buf;
2008-12-28 20:28:49 -05:00
Timer t;
Client& c = cc();
c.clearns();
2008-12-28 20:28:49 -05:00
2009-10-04 21:49:36 -04:00
int logThreshold = 100;
int ms;
2009-06-20 20:19:34 -04:00
bool log = logLevel >= 1;
2009-11-28 13:57:30 -05:00
c.curop()->op = op;
2008-12-28 20:28:49 -05: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 )
out() << "TEMP skip " << ddd.getns() << endl;
goto skip;
}
#endif
2008-12-28 20:28:49 -05:00
2009-11-28 13:57:30 -05:00
if ( op == dbQuery ) {
2009-01-28 18:08:02 -05:00
// receivedQuery() does its own authorization processing.
if ( ! receivedQuery(dbresponse, m, ss, true, lk) )
2009-12-02 15:14:37 -05:00
log = true;
2009-01-28 18:08:02 -05:00
}
2009-11-28 13:57:30 -05:00
else if ( op == dbGetMore ) {
// does its own authorization processing.
2009-09-03 12:52:08 -04:00
OPREAD;
DEV log = true;
ss << "getmore ";
2009-12-02 15:14:37 -05:00
if ( ! receivedGetMore(dbresponse, m, ss) )
log = true;
2009-09-03 12:52:08 -04:00
}
2009-11-28 13:57:30 -05:00
else if ( op == dbMsg ) {
2009-09-03 12:52:08 -04:00
/* deprecated / rarely used. intended for connection diagnostics. */
ss << "msg ";
char *p = m.data->_data;
int len = strlen(p);
if ( len > 400 )
out() << curTimeMillis() % 10000 <<
" long msg received, len:" << len <<
" ends with: " << p + len - 10 << endl;
bool end = false; //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);
if ( end )
return false;
2008-12-28 20:28:49 -05:00
}
2009-01-18 20:31:33 -05:00
else {
const char *ns = m.data->_data + 4;
char cl[256];
nsToClient(ns, cl);
strncpy(currentOp.ns, ns, Namespace::MaxNsLen);
AuthenticationInfo *ai = currentClient.get()->ai;
2009-01-18 20:31:33 -05:00
if( !ai->isAuthorized(cl) ) {
uassert_nothrow("unauthorized");
}
2009-11-28 13:57:30 -05:00
else if ( op == dbInsert ) {
2009-01-18 20:31:33 -05:00
OPWRITE;
try {
ss << "insert ";
receivedInsert(m, ss);
}
catch ( AssertionException& e ) {
LOGSOME problem() << " Caught Assertion insert, continuing\n";
ss << " exception " + e.toString();
2009-12-02 15:14:37 -05:00
log = true;
2009-01-18 20:31:33 -05:00
}
}
2009-11-28 13:57:30 -05:00
else if ( op == dbUpdate ) {
2009-01-18 20:31:33 -05:00
OPWRITE;
try {
ss << "update ";
receivedUpdate(m, ss);
}
catch ( AssertionException& e ) {
LOGSOME problem() << " Caught Assertion update, continuing" << endl;
ss << " exception " + e.toString();
2009-12-02 15:14:37 -05:00
log = true;
2009-01-18 20:31:33 -05:00
}
}
2009-11-28 13:57:30 -05:00
else if ( op == dbDelete ) {
2009-01-18 20:31:33 -05:00
OPWRITE;
try {
ss << "remove ";
2009-05-04 15:46:23 -04:00
receivedDelete(m, ss);
2009-01-18 20:31:33 -05:00
}
catch ( AssertionException& e ) {
LOGSOME problem() << " Caught Assertion receivedDelete, continuing" << endl;
ss << " exception " + e.toString();
2009-12-02 15:14:37 -05:00
log = true;
2009-01-18 20:31:33 -05:00
}
}
2009-11-28 13:57:30 -05:00
else if ( op == dbKillCursors ) {
2009-01-18 20:31:33 -05:00
OPREAD;
try {
2009-10-04 21:49:36 -04:00
logThreshold = 10;
2009-01-18 20:31:33 -05:00
ss << "killcursors ";
receivedKillCursors(m);
}
catch ( AssertionException& e ) {
problem() << " Caught Assertion in kill cursors, continuing" << endl;
ss << " exception " + e.toString();
2009-12-02 15:14:37 -05:00
log = true;
2009-01-18 20:31:33 -05:00
}
}
else {
2009-11-28 13:57:30 -05:00
out() << " operation isn't supported: " << op << endl;
currentOp.active = false;
2009-01-18 20:31:33 -05:00
assert(false);
}
2008-12-28 20:28:49 -05:00
}
ms = t.millis();
2009-09-27 14:46:51 -04:00
log = log || (logLevel >= 2 && ++ctr % 512 == 0);
DEV log = true;
2009-10-04 21:49:36 -04:00
if ( log || ms > logThreshold ) {
ss << ' ' << t.millis() << "ms";
out() << ss.str().c_str() << endl;
}
Database *database = cc().database();
if ( database && database->profile >= 1 ) {
if ( database->profile >= 2 || ms >= 100 ) {
2009-11-28 13:57:30 -05:00
// performance profiling is on
if ( dbMutex.getState() > 1 || dbMutex.getState() < -1 ){
out() << "warning: not profiling because recursive lock" << endl;
}
else {
string old_ns = cc().ns();
lk.releaseAndWriteLock();
resetClient(old_ns.c_str());
profile(ss.str().c_str()+20/*skip ts*/, ms);
}
}
2008-12-28 20:28:49 -05:00
}
currentOp.active = false;
return true;
}
2008-12-28 20:28:49 -05:00
void killCursors(int n, long long *ids);
void receivedKillCursors(Message& m) {
int *x = (int *) m.data->_data;
x++; // reserved
int n = *x++;
assert( n >= 1 );
if ( n > 2000 ) {
problem() << "Assertion failure, receivedKillCursors, n=" << n << endl;
assert( n < 30000 );
2008-12-28 20:28:49 -05:00
}
killCursors(n, (long long *) x);
2008-12-28 20:28:49 -05:00
}
/* cl - database name
path - db directory
*/
void closeDatabase( const char *cl, const string& path ) {
Database *database = cc().database();
2009-05-08 16:57:56 -07:00
assert( database );
assert( database->name == cl );
if ( string("local") != cl ) {
DBInfo i(cl);
i.dbDropped();
}
2008-12-28 20:28:49 -05:00
/* important: kill all open cursors on the database */
string prefix(cl);
prefix += '.';
ClientCursor::invalidate(prefix.c_str());
2008-12-28 20:28:49 -05:00
NamespaceDetailsTransient::clearForPrefix( prefix.c_str() );
2009-03-03 15:32:51 -05:00
eraseDatabase( cl, path );
delete database; // closes files
cc().clearns();
2008-12-28 20:28:49 -05:00
}
void receivedUpdate(Message& m, stringstream& ss) {
DbMessage d(m);
const char *ns = d.getns();
assert(*ns);
uassert( "not master", isMasterNs( ns ) );
setClient(ns);
Client& client = cc();
client.top.setWrite();
ss << ns << ' ';
int flags = d.pullInt();
BSONObj query = d.nextJsObj();
assert( d.moreJSObjs() );
assert( query.objsize() < m.data->dataLen() );
BSONObj toupdate = d.nextJsObj();
uassert("update object too large", toupdate.objsize() <= MaxBSONObjectSize);
assert( toupdate.objsize() < m.data->dataLen() );
assert( query.objsize() + toupdate.objsize() < m.data->dataLen() );
bool upsert = flags & Option_Upsert;
bool multi = flags & Option_Multi;
{
string s = query.toString();
2009-10-01 10:01:02 -04:00
/* todo: we shouldn't do all this ss stuff when we don't need it, it will slow us down. */
2009-05-04 15:46:23 -04:00
ss << " query: " << s;
CurOp& currentOp = *client.curop();
strncpy(currentOp.query, s.c_str(), sizeof(currentOp.query)-2);
}
UpdateResult res = updateObjects(ns, toupdate, query, upsert, multi, ss, true);
2009-11-28 13:57:30 -05:00
/* TODO FIX: recordUpdate should take a long int for parm #2 */
recordUpdate( res.existing , (int) res.num ); // for getlasterror
2008-12-28 20:28:49 -05:00
}
2009-05-04 15:46:23 -04:00
void receivedDelete(Message& m, stringstream &ss) {
DbMessage d(m);
2008-12-28 20:28:49 -05:00
const char *ns = d.getns();
assert(*ns);
uassert( "not master", isMasterNs( ns ) );
2008-12-28 20:28:49 -05:00
setClient(ns);
Client& client = cc();
client.top.setWrite();
int flags = d.pullInt();
bool justOne = flags & 1;
assert( d.moreJSObjs() );
BSONObj pattern = d.nextJsObj();
{
string s = pattern.toString();
2009-05-04 15:46:23 -04:00
ss << " query: " << s;
CurOp& currentOp = *client.curop();
strncpy(currentOp.query, s.c_str(), sizeof(currentOp.query)-2);
}
int n = deleteObjects(ns, pattern, justOne, true);
recordDelete( n );
}
2009-12-02 15:14:37 -05:00
/**
* @return if this was successful
*/
bool receivedQuery(DbResponse& dbresponse, /*AbstractMessagingPort& dbMsgPort, */Message& m, stringstream& ss, bool logit) {
bool ok = true;
MSGID responseTo = m.data->id;
DbMessage d(m);
QueryMessage q(d);
2009-01-18 20:31:33 -05:00
QueryResult* msgdata;
2009-12-02 15:14:37 -05:00
2009-01-18 20:31:33 -05:00
try {
if (q.fields.get() && q.fields->errmsg)
uassert(q.fields->errmsg, false);
2009-01-18 20:31:33 -05:00
/* note these are logged BEFORE authentication -- which is sort of ok */
if ( _diaglog.level && logit ) {
2009-01-18 20:31:33 -05:00
if ( strstr(q.ns, ".$cmd") ) {
/* $cmd queries are "commands" and usually best treated as write operations */
OPWRITE;
}
else {
OPREAD;
}
}
2008-12-08 11:21:00 -05:00
2009-02-06 12:45:05 -05:00
setClient( q.ns );
Client& client = cc();
client.top.setRead();
strncpy(client.curop()->ns, q.ns, Namespace::MaxNsLen);
msgdata = runQuery(m, ss ).release();
}
catch ( AssertionException& e ) {
2009-12-02 15:14:37 -05:00
ok = false;
ss << " exception ";
LOGSOME problem() << " Caught Assertion in runQuery ns:" << q.ns << ' ' << e.toString() << '\n';
log() << " ntoskip:" << q.ntoskip << " ntoreturn:" << q.ntoreturn << '\n';
if ( q.query.valid() )
log() << " query:" << q.query.toString() << endl;
else
log() << " query object is not valid!" << endl;
BSONObjBuilder err;
err.append("$err", e.msg.empty() ? "assertion during query" : e.msg);
BSONObj errObj = err.done();
BufBuilder b;
b.skip(sizeof(QueryResult));
b.append((void*) errObj.objdata(), errObj.objsize());
2009-01-28 18:08:02 -05:00
// todo: call replyToQuery() from here instead of this!!! see dbmessage.h
msgdata = (QueryResult *) b.buf();
b.decouple();
QueryResult *qr = msgdata;
qr->resultFlags() = QueryResult::ResultFlag_ErrSet;
qr->len = b.len();
qr->setOperation(opReply);
qr->cursorId = 0;
qr->startingFrom = 0;
qr->nReturned = 1;
}
Message *resp = new Message();
resp->setData(msgdata, true); // transport will free
dbresponse.response = resp;
dbresponse.responseTo = responseTo;
Database *database = cc().database();
if ( database ) {
if ( database->profile )
ss << " bytes:" << resp->data->dataLen();
}
else {
if ( strstr(q.ns, "$cmd") == 0 ) // (this condition is normal for $cmd dropDatabase)
log() << "ERROR: receiveQuery: database is null; ns=" << q.ns << endl;
}
2009-12-02 15:14:37 -05:00
return ok;
2008-12-28 20:28:49 -05:00
}
2009-12-02 15:14:37 -05:00
QueryResult* emptyMoreResult(long long);
2009-12-02 15:14:37 -05:00
bool receivedGetMore(DbResponse& dbresponse, /*AbstractMessagingPort& dbMsgPort, */Message& m, stringstream& ss) {
bool ok = true;
DbMessage d(m);
const char *ns = d.getns();
ss << ns;
setClient(ns);
2009-10-14 15:48:13 -04:00
cc().top.setRead();
int ntoreturn = d.pullInt();
long long cursorid = d.pullInt64();
ss << " cid:" << cursorid;
ss << " ntoreturn:" << ntoreturn;
QueryResult* msgdata;
try {
AuthenticationInfo *ai = currentClient.get()->ai;
uassert("unauthorized", ai->isAuthorized(cc().database()->name.c_str()));
msgdata = getMore(ns, ntoreturn, cursorid, ss);
}
catch ( AssertionException& e ) {
ss << " exception " + e.toString();
msgdata = emptyMoreResult(cursorid);
2009-12-02 15:14:37 -05:00
ok = false;
}
Message *resp = new Message();
resp->setData(msgdata, true);
ss << " bytes:" << resp->data->dataLen();
ss << " nreturned:" << msgdata->nReturned;
dbresponse.response = resp;
dbresponse.responseTo = m.data->id;
//dbMsgPort.reply(m, resp);
2009-12-02 15:14:37 -05:00
return ok;
2008-12-28 20:28:49 -05:00
}
void receivedInsert(Message& m, stringstream& ss) {
DbMessage d(m);
const char *ns = d.getns();
assert(*ns);
uassert( "not master", isMasterNs( ns ) );
setClient(ns);
2009-10-14 15:48:13 -04:00
cc().top.setWrite();
ss << ns;
while ( d.moreJSObjs() ) {
BSONObj js = d.nextJsObj();
uassert("object to insert too large", js.objsize() <= MaxBSONObjectSize);
theDataFileMgr.insert(ns, js, false);
logOp("i", ns, js);
}
2008-12-28 20:28:49 -05:00
}
class JniMessagingPort : public AbstractMessagingPort {
public:
JniMessagingPort(Message& _container) : container(_container) { }
void reply(Message& received, Message& response, MSGID) {
container = response;
}
void reply(Message& received, Message& response) {
container = response;
}
unsigned remotePort(){
return 1;
}
Message & container;
};
void getDatabaseNames( vector< string > &names ) {
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 ( fileName.length() > 3 && fileName.substr( fileName.length() - 3, 3 ) == ".ns" )
names.push_back( fileName.substr( 0, fileName.length() - 3 ) );
}
}
2008-12-28 20:28:49 -05:00
bool DBDirectClient::call( Message &toSend, Message &response, bool assertOk ) {
SavedContext c;
DbResponse dbResponse;
assembleResponse( toSend, dbResponse );
assert( dbResponse.response );
response = *dbResponse.response;
return true;
2008-12-28 20:28:49 -05:00
}
void DBDirectClient::say( Message &toSend ) {
SavedContext c;
DbResponse dbResponse;
assembleResponse( toSend, dbResponse );
2008-12-29 14:07:21 -05:00
}
auto_ptr<DBClientCursor> DBDirectClient::query(const string &ns, Query query, int nToReturn , int nToSkip ,
const BSONObj *fieldsToReturn , int queryOptions ){
//if ( ! query.obj.isEmpty() || nToReturn != 0 || nToSkip != 0 || fieldsToReturn || queryOptions )
return DBClientBase::query( ns , query , nToReturn , nToSkip , fieldsToReturn , queryOptions );
//
//assert( query.obj.isEmpty() );
//throw UserException( (string)"yay:" + ns );
}
DBDirectClient::AlwaysAuthorized DBDirectClient::SavedContext::always;
2009-02-02 18:18:22 -05:00
2009-05-01 14:35:42 -04:00
DBClientBase * createDirectClient(){
return new DBDirectClient();
}
2009-02-02 18:18:22 -05:00
void recCacheCloseAll();
2009-04-01 12:26:31 -04:00
boost::mutex &listenerSocketMutex( *( new boost::mutex ) );
vector< int > listenerSockets;
void registerListenerSocket( int socket ) {
boostlock lk( listenerSocketMutex );
listenerSockets.push_back( socket );
}
boost::mutex &exitMutex( *( new boost::mutex ) );
2009-12-14 09:50:49 -05:00
int numExitCalls = 0;
void shutdown();
bool inShutdown(){
2009-12-14 11:06:06 -05:00
return numExitCalls > 0;
2009-12-14 09:50:49 -05:00
}
void tryToOutputFatal( const string& s ){
try {
rawOut( s );
return;
}
catch ( ... ){}
try {
cerr << s << endl;
return;
}
catch ( ... ){}
// uh - oh, not sure there is anything else we can do...
}
/* not using log() herein in case we are already locked */
void dbexit( ExitCode rc, const char *why) {
{
boostlock lk( exitMutex );
2009-12-14 09:50:49 -05:00
if ( numExitCalls++ > 0 ) {
if ( numExitCalls > 5 ){
// this means something horrible has happened
::_exit( rc );
}
stringstream ss;
ss << "dbexit: " << why << "; exiting immediately" << endl;
2009-12-14 09:50:49 -05:00
tryToOutputFatal( ss.str() );
::exit( rc );
}
}
2009-12-14 09:50:49 -05:00
stringstream ss;
ss << "dbexit: " << why << endl;
2009-12-14 09:50:49 -05:00
tryToOutputFatal( ss.str() );
try {
shutdown(); // gracefully shutdown instance
}
catch ( ... ){
tryToOutputFatal( "shutdown failed with exception" );
}
tryToOutputFatal( "dbexit: really exiting now\n" );
::exit(rc);
}
void shutdown() {
2009-04-06 17:34:29 -04:00
#ifndef _WIN32
2009-04-01 12:26:31 -04:00
{
// close listener sockets
// We would only hang here if a synchronous signal is received
// during a registerListenerSocket() call, which we don't expect.
boostlock lk( listenerSocketMutex );
for( vector< int >::iterator i = listenerSockets.begin(); i != listenerSockets.end(); ++i )
close( *i );
}
2009-04-06 17:34:29 -04:00
#endif
log() << "\t shutdown: going to flush oplog..." << endl;
stringstream ss2;
flushOpLog( ss2 );
rawOut( ss2.str() );
/* must do this before unmapping mem or you may get a seg fault */
log() << "\t shutdown: going to close sockets..." << endl;
closeAllSockets();
// wait until file preallocation finishes
// we would only hang here if the file_allocator code generates a
// synchronous signal, which we don't expect
log() << "\t shutdown: waiting for fs..." << endl;
theFileAllocator().waitUntilFinished();
log() << "\t shutdown: closing all files..." << endl;
stringstream ss3;
MemoryMappedFile::closeAllFiles( ss3 );
rawOut( ss3.str() );
2009-02-04 13:53:08 -05:00
// should we be locked here? we aren't. might be ok as-is.
2009-02-02 18:18:22 -05:00
recCacheCloseAll();
2009-04-01 13:48:02 -04:00
#if !defined(_WIN32) && !defined(__sunos__)
if ( lockFile ){
log() << "\t shutdown: removing fs lock..." << endl;
2009-10-06 16:17:11 -04:00
if( ftruncate( lockFile , 0 ) )
log() << "\t couldn't remove fs lock errno=" << errno << endl;
flock( lockFile, LOCK_UN );
}
2009-04-01 14:13:08 -04:00
#endif
}
void acquirePathLock() {
#if !defined(_WIN32) && !defined(__sunos__)
string name = ( boost::filesystem::path( dbpath ) / "mongod.lock" ).native_file_string();
2009-07-28 10:46:56 -04:00
lockFile = open( name.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO );
massert( "Unable to create / open lock file for dbpath: " + name, lockFile > 0 );
massert( "Unable to acquire lock for dbpath: " + name, flock( lockFile, LOCK_EX | LOCK_NB ) == 0 );
2009-07-28 10:46:56 -04:00
stringstream ss;
ss << getpid() << endl;
string s = ss.str();
const char * data = s.c_str();
assert( write( lockFile , data , strlen( data ) ) );
fsync( lockFile );
#endif
}
2009-07-28 10:46:56 -04:00
2009-01-14 17:09:51 -05:00
} // namespace mongo