void ClientCursorMonitor::run(){ Client::initThread("clientcursormon"); Client& client = cc(); unsigned old = curTimeMillis(); while ( ! inShutdown() ){ unsigned now = curTimeMillis(); ClientCursor::idleTimeReport( now - old ); old = now; sleepsecs(4); } client.shutdown(); }
/** thread for timing out old cursors */ void ClientCursorMonitor::run() { Client::initThread("clientcursormon"); Client& client = cc(); unsigned old = curTimeMillis(); const int Secs = 4; unsigned n = 0; while ( ! inShutdown() ) { unsigned now = curTimeMillis(); ClientCursor::idleTimeReport( now - old ); old = now; sleepsecs(Secs); if( ++n % (60/4) == 0 /*once a minute*/ ) { sayMemoryStatus(); } } client.shutdown(); }
long long ClientCursor::allocCursorId_inlock() { long long x; int ctm = (int) curTimeMillis(); while ( 1 ) { x = (((long long)rand()) << 32); x = x | ctm | 0x80000000; // OR to make sure not zero if ( ctm != ctmLast || ClientCursor::find_inlock(x, false) == 0 ) break; } ctmLast = ctm; //DEV tlog() << " alloccursorid " << x << endl; return x; }
// Returns false when request includes 'end' bool assembleResponse( Message &m, DbResponse &dbresponse, const sockaddr_in &client ) { // before we lock... if ( m.data->operation() == dbQuery ) { const char *ns = m.data->_data + 4; 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; } } } if ( handlePossibleShardedMessage( m , dbresponse ) ){ /* important to do this before we lock so if a message has to be forwarded, doesn't block for that */ return true; } dblock lk; stringstream ss; char buf[64]; time_t now = time(0); CurOp& currentOp = *cc().curop(); currentOp.reset(now, client); time_t_to_String(now, buf); buf[20] = 0; // don't want the year ss << buf; Timer t; Client& c = cc(); c.clearns(); int logThreshold = 100; int ms; bool log = logLevel >= 1; c.curop()->op = m.data->operation(); #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 if ( m.data->operation() == dbQuery ) { // receivedQuery() does its own authorization processing. receivedQuery(dbresponse, m, ss, true); } else if ( m.data->operation() == dbGetMore ) { // receivedQuery() does its own authorization processing. OPREAD; DEV log = true; ss << "getmore "; receivedGetMore(dbresponse, m, ss); } else if ( m.data->operation() == dbMsg ) { /* 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; } 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; if( !ai->isAuthorized(cl) ) { uassert_nothrow("unauthorized"); } else if ( m.data->operation() == dbInsert ) { OPWRITE; try { ss << "insert "; receivedInsert(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion insert, continuing\n"; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbUpdate ) { OPWRITE; try { ss << "update "; receivedUpdate(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion update, continuing" << endl; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbDelete ) { OPWRITE; try { ss << "remove "; receivedDelete(m, ss); } catch ( AssertionException& e ) { LOGSOME problem() << " Caught Assertion receivedDelete, continuing" << endl; ss << " exception " + e.toString(); } } else if ( m.data->operation() == dbKillCursors ) { OPREAD; try { logThreshold = 10; ss << "killcursors "; receivedKillCursors(m); } catch ( AssertionException& e ) { problem() << " Caught Assertion in kill cursors, continuing" << endl; ss << " exception " + e.toString(); } } else { out() << " operation isn't supported: " << m.data->operation() << endl; currentOp.active = false; assert(false); } } ms = t.millis(); log = log || (logLevel >= 2 && ++ctr % 512 == 0); DEV log = true; 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 ) { // profile it profile(ss.str().c_str()+20/*skip ts*/, ms); } } currentOp.active = false; return true; }
// Returns false when request includes 'end' bool assembleResponse( Message &m, DbResponse &dbresponse, const SockAddr &client ) { // before we lock... int op = m.operation(); bool isCommand = false; const char *ns = m.singleData()->_data + 4; if ( op == dbQuery ) { if( strstr(ns, ".$cmd") ) { isCommand = true; opwrite(m); 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; } if( strstr(ns, "$cmd.sys.unlock") ) { unlockFsync(ns, m, dbresponse); return true; } } } else { opread(m); } } else if( op == dbGetMore ) { opread(m); } else { opwrite(m); } globalOpCounters.gotOp( op , isCommand ); Client& c = cc(); auto_ptr<CurOp> nestedOp; CurOp* currentOpP = c.curop(); if ( currentOpP->active() ){ nestedOp.reset( new CurOp( &c , currentOpP ) ); currentOpP = nestedOp.get(); } CurOp& currentOp = *currentOpP; currentOp.reset(client,op); OpDebug& debug = currentOp.debug(); StringBuilder& ss = debug.str; ss << opToString( op ) << " "; int logThreshold = cmdLine.slowMS; bool log = logLevel >= 1; if ( op == dbQuery ) { if ( handlePossibleShardedMessage( m , &dbresponse ) ) return true; receivedQuery(c , dbresponse, m ); } else if ( op == dbGetMore ) { if ( ! receivedGetMore(dbresponse, m, currentOp) ) log = true; } else if ( op == dbMsg ) { // deprecated - replaced by commands char *p = m.singleData()->_data; int len = strlen(p); if ( len > 400 ) out() << curTimeMillis() % 10000 << " long msg received, len:" << len << endl; Message *resp = new Message(); if ( strcmp( "end" , p ) == 0 ) resp->setData( opReply , "dbMsg end no longer supported" ); else resp->setData( opReply , "i am fine - dbMsg deprecated"); dbresponse.response = resp; dbresponse.responseTo = m.header()->id; } else { const char *ns = m.singleData()->_data + 4; char cl[256]; nsToDatabase(ns, cl); if( ! c.getAuthenticationInfo()->isAuthorized(cl) ) { uassert_nothrow("unauthorized"); } else { try { if ( op == dbInsert ) { receivedInsert(m, currentOp); } else if ( op == dbUpdate ) { receivedUpdate(m, currentOp); } else if ( op == dbDelete ) { receivedDelete(m, currentOp); } else if ( op == dbKillCursors ) { currentOp.ensureStarted(); logThreshold = 10; ss << "killcursors "; receivedKillCursors(m); } else { mongo::log() << " operation isn't supported: " << op << endl; currentOp.done(); log = true; } } catch ( UserException& ue ) { tlog(3) << " Caught Assertion in " << opToString(op) << ", continuing " << ue.toString() << endl; ss << " exception " << ue.toString(); } catch ( AssertionException& e ) { tlog(3) << " Caught Assertion in " << opToString(op) << ", continuing " << e.toString() << endl; ss << " exception " << e.toString(); log = true; } } } currentOp.ensureStarted(); currentOp.done(); int ms = currentOp.totalTimeMillis(); //DEV log = true; if ( log || ms > logThreshold ) { if( logLevel < 3 && op == dbGetMore && strstr(ns, ".oplog.") && ms < 3000 && !log ) { /* it's normal for getMore on the oplog to be slow because of use of awaitdata flag. */ } else { ss << ' ' << ms << "ms"; mongo::tlog() << ss.str() << endl; } } if ( currentOp.shouldDBProfile( ms ) ){ // performance profiling is on if ( dbMutex.getState() < 0 ){ mongo::log(1) << "note: not profiling because recursive read lock" << endl; } else { writelock lk; if ( dbHolder.isLoaded( nsToDatabase( currentOp.getNS() ) , dbpath ) ){ Client::Context c( currentOp.getNS() ); profile(ss.str().c_str(), ms); } else { mongo::log() << "note: not profiling because db went away - probably a close on: " << currentOp.getNS() << endl; } } } return true; } /* assembleResponse() */
/* we create one thread for each connection from an app server database. app server will open a pool of threads. todo: one day, asio... */ void connThread( MessagingPort * inPort ) { TicketHolderReleaser connTicketReleaser( &connTicketHolder ); /* todo: move to Client object */ LastError *le = new LastError(); lastError.reset(le); inPort->_logLevel = 1; auto_ptr<MessagingPort> dbMsgPort( inPort ); Client& c = Client::initThread("conn", inPort); try { c.getAuthenticationInfo()->isLocalHost = dbMsgPort->farEnd.isLocalHost(); Message m; while ( 1 ) { if ( !dbMsgPort->recv(m) ) { if( !cmdLine.quiet ) log() << "end connection " << dbMsgPort->farEnd.toString() << endl; dbMsgPort->shutdown(); break; } sendmore: if ( inShutdown() ) { log() << "got request after shutdown()" << endl; break; } lastError.startRequest( m , le ); DbResponse dbresponse; if ( !assembleResponse( m, dbresponse, dbMsgPort->farEnd ) ) { log() << 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 { log() << " (not from localhost, ignoring end msg)" << endl; } } if ( dbresponse.response ) { dbMsgPort->reply(m, *dbresponse.response, dbresponse.responseTo); if( dbresponse.exhaust ) { MsgData *header = dbresponse.response->header(); QueryResult *qr = (QueryResult *) header; long long cursorid = qr->cursorId; if( cursorid ) { assert( dbresponse.exhaust && *dbresponse.exhaust != 0 ); string ns = dbresponse.exhaust; // before reset() free's it... m.reset(); BufBuilder b(512); b.appendNum((int) 0 /*size set later in appendData()*/); b.appendNum(header->id); b.appendNum(header->responseTo); b.appendNum((int) dbGetMore); b.appendNum((int) 0); b.appendStr(ns); b.appendNum((int) 0); // ntoreturn b.appendNum(cursorid); m.appendData(b.buf(), b.len()); b.decouple(); DEV log() << "exhaust=true sending more" << endl; beNice(); goto sendmore; } } } m.reset(); } } catch ( AssertionException& e ) { log() << "AssertionException in connThread, closing client connection" << endl; log() << ' ' << e.what() << 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 ); } // thread ending... { Client * c = currentClient.get(); if( c ) c->shutdown(); } globalScriptEngine->threadDone(); }
/* we create one thread for each connection from an app server database. app server will open a pool of threads. */ void connThread() { AuthenticationInfo *ai = new AuthenticationInfo(); authInfo.reset(ai); LastError *le = new LastError(); lastError.reset(le); MessagingPort& dbMsgPort = *grab; grab = 0; try { ai->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; } lastError.startRequest( m , le ); DbResponse dbresponse; if ( !assembleResponse( m, dbresponse, dbMsgPort.farEnd.sa ) ) { 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 ( 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 globalScriptEngine->threadDone(); }
MsgStart() { NextMsgId = (((unsigned) time(0)) << 16) ^ curTimeMillis(); assert(MsgDataHeaderSize == 16); }