void run() { IndexDescriptor* id = addIndexWithInfo(); // Create a SortPhaseOne. SortPhaseOne phaseOne; phaseOne.sorter.reset( new BSONObjExternalSorter(_aFirstSort)); // Add index keys to the phaseOne. int32_t nKeys = 130; for( int32_t i = 0; i < nKeys; ++i ) { phaseOne.sorter->add( BSON( "a" << i ), /* dummy disk loc */ DiskLoc(), false ); } phaseOne.nkeys = phaseOne.n = nKeys; phaseOne.sorter->sort( false ); // Set up remaining arguments. set<DiskLoc> dups; CurOp* op = cc().curop(); ProgressMeterHolder pm (op->setMessage("BuildBottomUp", "BuildBottomUp Progress", nKeys, nKeys)); pm.finished(); Timer timer; // The index's root has not yet been set. ASSERT( id->getHead().isNull() ); // Finish building the index. buildBottomUpPhases2And3<V1>( true, id, *phaseOne.sorter, false, dups, op, &phaseOne, pm, timer, true ); // The index's root is set after the build is complete. ASSERT( !id->getHead().isNull() ); // Create a cursor over the index. scoped_ptr<BtreeCursor> cursor( BtreeCursor::make( nsdetails( _ns ), id->getOnDisk(), BSON( "" << -1 ), // startKey below minimum key. BSON( "" << nKeys ), // endKey above maximum key. true, // endKeyInclusive true. 1 // direction forward. ) ); // Check that the keys in the index are the expected ones. int32_t expectedKey = 0; for( ; cursor->ok(); cursor->advance(), ++expectedKey ) { ASSERT_EQUALS( expectedKey, cursor->currKey().firstElement().number() ); } ASSERT_EQUALS( nKeys, expectedKey ); }
void profile(OperationContext* txn, const Client& c, int op, CurOp& currentOp) { // initialize with 1kb to start, to avoid realloc later // doing this outside the dblock to improve performance BufBuilder profileBufBuilder(1024); bool tryAgain = false; while ( 1 ) { try { // NOTE: It's kind of weird that we lock the op's namespace, but have to for now // since we're sometimes inside the lock already const string dbname(nsToDatabase(currentOp.getNS())); scoped_ptr<Lock::DBLock> lk; // todo: this can be slow, perhaps can re-work if ( !txn->lockState()->isDbLockedForMode( dbname, MODE_IX ) ) { lk.reset( new Lock::DBLock( txn->lockState(), dbname, tryAgain ? MODE_X : MODE_IX) ); } Database* db = dbHolder().get(txn, dbname); if (db != NULL) { // We want the profiling to happen in a different WUOW from the actual op. Lock::CollectionLock clk(txn->lockState(), db->getProfilingNS(), MODE_X); WriteUnitOfWork wunit(txn); Client::Context cx(txn, currentOp.getNS(), false); if ( !_profile(txn, c, cx.db(), currentOp, profileBufBuilder ) && lk.get() ) { if ( tryAgain ) { // we couldn't profile, but that's ok, we should have logged already break; } // we took an IX lock, so now we try again with an X lock tryAgain = true; continue; } wunit.commit(); } else { mongo::log() << "note: not profiling because db went away - " << "probably a close on: " << currentOp.getNS(); } return; } catch (const AssertionException& assertionEx) { warning() << "Caught Assertion while trying to profile " << opToString(op) << " against " << currentOp.getNS() << ": " << assertionEx.toString() << endl; return; } } }
bool receivedGetMore(DbResponse& dbresponse, Message& m, CurOp& curop ) { bool ok = true; DbMessage d(m); const char *ns = d.getns(); int ntoreturn = d.pullInt(); long long cursorid = d.pullInt64(); curop.debug().ns = ns; curop.debug().ntoreturn = ntoreturn; curop.debug().cursorid = cursorid; time_t start = 0; int pass = 0; bool exhaust = false; QueryResult* msgdata; while( 1 ) { try { readlock lk; Client::Context ctx(ns); msgdata = processGetMore(ns, ntoreturn, cursorid, curop, pass, exhaust); } catch ( AssertionException& e ) { exhaust = false; curop.debug().exceptionInfo = e.getInfo(); msgdata = emptyMoreResult(cursorid); ok = false; } if (msgdata == 0) { exhaust = false; massert(13073, "shutting down", !inShutdown() ); if( pass == 0 ) { start = time(0); } else { if( time(0) - start >= 4 ) { // after about 4 seconds, return. this is a sanity check. pass stops at 1000 normally // for DEV this helps and also if sleep is highly inaccurate on a platform. we want to // return occasionally so slave can checkpoint. pass = 10000; } } pass++; DEV sleepmillis(20); else sleepmillis(2); continue; }
std::vector<BSONObj> IndexBuilder::killMatchingIndexBuilds(const BSONObj& criteria) { verify(Lock::somethingWriteLocked()); std::vector<BSONObj> indexes; CurOp* op = NULL; while ((op = CurOp::getOp(criteria)) != NULL) { BSONObj index = op->query(); killCurrentOp.kill(op->opNum()); indexes.push_back(index); } if (indexes.size() > 0) { log() << "halted " << indexes.size() << " index build(s)" << endl; } return indexes; }
void ClientCursor::staticYield(int micros, const StringData& ns) { bool haveReadLock = Lock::isReadLocked(); killCurrentOp.checkForInterrupt(); { dbtempreleasecond unlock; if ( unlock.unlocked() ) { if ( haveReadLock ) { // This sleep helps reader threads yield to writer threads. // Without this, the underlying reader/writer lock implementations // are not sufficiently writer-greedy. #ifdef _WIN32 SwitchToThread(); #else if ( micros == 0 ) { yieldOrSleepFor1Microsecond(); } else { sleepmicros(1); } #endif } else { if ( micros == -1 ) { sleepmicros(Client::recommendedYieldMicros()); } else if ( micros == 0 ) { yieldOrSleepFor1Microsecond(); } else if ( micros > 0 ) { sleepmicros( micros ); } } } else if ( Listener::getTimeTracker() == 0 ) { // we aren't running a server, so likely a repair, so don't complain } else { CurOp * c = cc().curop(); while ( c->parent() ) c = c->parent(); warning() << "ClientCursor::staticYield can't unlock b/c of recursive lock" << " ns: " << ns << " top: " << c->info() << endl; } } }
void MoveTimingHelper::done(int step) { invariant(step == ++_nextStep); invariant(step <= _totalNumSteps); const std::string s = str::stream() << "step " << step << " of " << _totalNumSteps; CurOp* op = CurOp::get(_txn); { stdx::lock_guard<Client> lk(*_txn->getClient()); op->setMessage_inlock(s.c_str()); } _b.appendNumber(s, _t.millis()); _t.reset(); }
void profile( const Client& c , CurOp& currentOp ) { assertInWriteLock(); Database *db = c.database(); DEV assert( db ); const char *ns = db->profileName.c_str(); // build object profileBufBuilder.reset(); BSONObjBuilder b(profileBufBuilder); b.appendDate("ts", jsTime()); currentOp.debug().append( b ); b.append("client", c.clientAddress() ); if ( c.getAuthenticationInfo() ) b.append( "user" , c.getAuthenticationInfo()->getUser( nsToDatabase( ns ) ) ); BSONObj p = b.done(); // write: not replicated NamespaceDetails *d = db->namespaceIndex.details(ns); if( d ) { int len = p.objsize(); Record *r = theDataFileMgr.fast_oplog_insert(d, ns, len); memcpy(getDur().writingPtr(r->data, len), p.objdata(), len); } else { static time_t last; if( time(0) > last+10 ) { log() << "profile: warning ns " << ns << " does not exist" << endl; last = time(0); } } }
void receivedUpdate(Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); op.debug().ns = ns; int flags = d.pullInt(); BSONObj query = d.nextJsObj(); verify( d.moreJSObjs() ); verify( query.objsize() < m.header()->dataLen() ); BSONObj toupdate = d.nextJsObj(); uassert( 10055 , "update object too large", toupdate.objsize() <= BSONObjMaxUserSize); verify( toupdate.objsize() < m.header()->dataLen() ); verify( query.objsize() + toupdate.objsize() < m.header()->dataLen() ); bool upsert = flags & UpdateOption_Upsert; bool multi = flags & UpdateOption_Multi; bool broadcast = flags & UpdateOption_Broadcast; Status status = cc().getAuthorizationManager()->checkAuthForUpdate(ns, upsert); uassert(16538, status.reason(), status.isOK()); op.debug().query = query; op.setQuery(query); PageFaultRetryableSection s; while ( 1 ) { try { Lock::DBWrite lk(ns); // void ReplSetImpl::relinquish() uses big write lock so // this is thus synchronized given our lock above. uassert( 10054 , "not master", isMasterNs( ns ) ); // if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) ) return; Client::Context ctx( ns ); UpdateResult res = updateObjects(ns, toupdate, query, upsert, multi, true, op.debug() ); lastError.getSafe()->recordUpdate( res.existing , res.num , res.upserted ); // for getlasterror break; } catch ( PageFaultException& e ) { e.touch(); } } }
void inProgCmd( Message &m, DbResponse &dbresponse ) { BSONObjBuilder b; if (!cc().getAuthorizationManager()->checkAuthorization( AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::inprog)) { b.append("err", "unauthorized"); } else { DbMessage d(m); QueryMessage q(d); bool all = q.query["$all"].trueValue(); bool allMatching = q.query["$allMatching"].trueValue(); vector<BSONObj> vals; BSONObjBuilder qb; for (BSONObjIterator it(q.query); it.more(); ) { BSONElement e = it.next(); StringData fn(e.fieldName()); if (fn != "$all" && fn != "$allMatching") { qb.append(e); } } { Client& me = cc(); scoped_lock bl(Client::clientsMutex); scoped_ptr<Matcher> m(new Matcher(qb.done())); for( set<Client*>::iterator i = Client::clients.begin(); i != Client::clients.end(); i++ ) { Client *c = *i; verify( c ); CurOp* co = c->curop(); if ( c == &me && !co ) { continue; } verify( co ); if( all || allMatching || co->displayInCurop() ) { BSONObj info = co->info(); if ( all || m->matches( info )) { vals.push_back( info ); } } } } b.append("inprog", vals); } replyToQuery(0, m, dbresponse, b.obj()); }
bool GlobalEnvironmentMongoD::killOperation(AtomicUInt opId) { scoped_lock clientLock(Client::clientsMutex); bool found = false; // XXX clean up { for( set< Client* >::const_iterator j = Client::clients.begin(); !found && j != Client::clients.end(); ++j ) { for( CurOp *k = ( *j )->curop(); !found && k; k = k->parent() ) { if ( k->opNum() != opId ) continue; k->kill(); for( CurOp *l = ( *j )->curop(); l; l = l->parent() ) { l->kill(); } found = true; } } } if ( found ) { interruptJs( &opId ); } return found; }
void receivedUpdate(Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); op.debug().ns = ns; int flags = d.pullInt(); BSONObj query = d.nextJsObj(); verify(d.moreJSObjs()); verify(query.objsize() < m.header()->dataLen()); const BSONObj updateobj = d.nextJsObj(); uassert(10055, "update object too large", updateobj.objsize() <= BSONObjMaxUserSize); verify(updateobj.objsize() < m.header()->dataLen()); verify(query.objsize() + updateobj.objsize() < m.header()->dataLen()); op.debug().query = query; op.debug().updateobj = updateobj; op.setQuery(query); const bool upsert = flags & UpdateOption_Upsert; const bool multi = flags & UpdateOption_Multi; const bool broadcast = flags & UpdateOption_Broadcast; Status status = cc().getAuthorizationManager()->checkAuthForUpdate(ns, upsert); uassert(16538, status.reason(), status.isOK()); OpSettings settings; settings.setQueryCursorMode(WRITE_LOCK_CURSOR); settings.setJustOne(!multi); cc().setOpSettings(settings); Client::ShardedOperationScope sc; if (!broadcast && sc.handlePossibleShardedMessage(m, 0)) { return; } LOCK_REASON(lockReason, "update"); try { Lock::DBRead lk(ns, lockReason); lockedReceivedUpdate(ns, m, op, updateobj, query, upsert, multi); } catch (RetryWithWriteLock &e) { Lock::DBWrite lk(ns, lockReason); lockedReceivedUpdate(ns, m, op, updateobj, query, upsert, multi); } }
bool KillCurrentOp::_killImpl_inclientlock(AtomicUInt i, bool* pNotifyFlag /* = NULL */) { bool found = false; { for( set< Client* >::const_iterator j = Client::clients.begin(); !found && j != Client::clients.end(); ++j ) { for( CurOp *k = ( *j )->curop(); !found && k; k = k->parent() ) { if ( k->opNum() != i ) continue; k->kill(pNotifyFlag); for( CurOp *l = ( *j )->curop(); l; l = l->parent() ) { l->kill(); } found = true; } } } if ( found ) { interruptJs( &i ); } return found; }
Status OperationContextImpl::checkForInterruptNoAssert() const { if (getGlobalServiceContext()->getKillAllOperations()) { return Status(ErrorCodes::InterruptedAtShutdown, "interrupted at shutdown"); } CurOp* curOp = CurOp::get(this); if (curOp->maxTimeHasExpired()) { curOp->kill(); return Status(ErrorCodes::ExceededTimeLimit, "operation exceeded time limit"); } MONGO_FAIL_POINT_BLOCK(checkForInterruptFail, scopedFailPoint) { if (opShouldFail(this, scopedFailPoint.getData())) { log() << "set pending kill on " << (curOp->parent() ? "nested" : "top-level") << " op " << curOp->opNum() << ", for checkForInterruptFail"; curOp->kill(); } } if (curOp->killPending()) { return Status(ErrorCodes::Interrupted, "operation was interrupted"); } return Status::OK(); }
void receivedDelete(Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); Status status = cc().getAuthorizationManager()->checkAuthForDelete(ns); uassert(16542, status.reason(), status.isOK()); op.debug().ns = ns; int flags = d.pullInt(); verify(d.moreJSObjs()); BSONObj pattern = d.nextJsObj(); op.debug().query = pattern; op.setQuery(pattern); const bool justOne = flags & RemoveOption_JustOne; const bool broadcast = flags & RemoveOption_Broadcast; OpSettings settings; settings.setQueryCursorMode(WRITE_LOCK_CURSOR); settings.setJustOne(justOne); cc().setOpSettings(settings); Client::ShardedOperationScope sc; if (!broadcast && sc.handlePossibleShardedMessage(m, 0)) { return; } LOCK_REASON(lockReason, "delete"); Lock::DBRead lk(ns, lockReason); // writelock is used to synchronize stepdowns w/ writes uassert(10056, "not master", isMasterNs(ns)); Client::Context ctx(ns); long long n; scoped_ptr<Client::AlternateTransactionStack> altStack(opNeedsAltTxn(ns) ? new Client::AlternateTransactionStack : NULL); Client::Transaction transaction(DB_SERIALIZABLE); n = deleteObjects(ns, pattern, justOne, true); transaction.commit(); lastError.getSafe()->recordDelete( n ); op.debug().ndeleted = n; }
void ClientCursor::staticYield( int micros , const StringData& ns , Record * rec ) { bool haveReadLock = Lock::isReadLocked(); killCurrentOp.checkForInterrupt( false ); { auto_ptr<LockMongoFilesShared> lk; if ( rec ) { // need to lock this else rec->touch won't be safe file could disappear lk.reset( new LockMongoFilesShared() ); } dbtempreleasecond unlock; if ( unlock.unlocked() ) { if ( haveReadLock ) { // don't sleep with a read lock } else { if ( micros == -1 ) micros = Client::recommendedYieldMicros(); if ( micros > 0 ) sleepmicros( micros ); } } else if ( Listener::getTimeTracker() == 0 ) { // we aren't running a server, so likely a repair, so don't complain } else { CurOp * c = cc().curop(); while ( c->parent() ) c = c->parent(); warning() << "ClientCursor::yield can't unlock b/c of recursive lock" << " ns: " << ns << " top: " << c->info() << endl; } if ( rec ) rec->touch(); lk.reset(0); // need to release this before dbtempreleasecond } }
void receivedDelete(Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); Status status = cc().getAuthorizationManager()->checkAuthForDelete(ns); uassert(16542, status.reason(), status.isOK()); op.debug().ns = ns; int flags = d.pullInt(); bool justOne = flags & RemoveOption_JustOne; bool broadcast = flags & RemoveOption_Broadcast; verify( d.moreJSObjs() ); BSONObj pattern = d.nextJsObj(); op.debug().query = pattern; op.setQuery(pattern); PageFaultRetryableSection s; while ( 1 ) { try { Lock::DBWrite lk(ns); // writelock is used to synchronize stepdowns w/ writes uassert( 10056 , "not master", isMasterNs( ns ) ); // if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) ) return; Client::Context ctx(ns); long long n = deleteObjects(ns, pattern, justOne, true); lastError.getSafe()->recordDelete( n ); op.debug().ndeleted = n; break; } catch ( PageFaultException& e ) { LOG(2) << "recordDelete got a PageFaultException" << endl; e.touch(); } } }
/** * @return if collection existed or was created */ static bool _profile(OperationContext* txn, const Client& c, Database* db, CurOp& currentOp, BufBuilder& profileBufBuilder) { dassert( db ); // build object BSONObjBuilder b(profileBufBuilder); const bool isQueryObjTooBig = !currentOp.debug().append(currentOp, b, MAX_PROFILE_DOC_SIZE_BYTES); b.appendDate("ts", jsTime()); b.append("client", c.clientAddress()); AuthorizationSession * authSession = c.getAuthorizationSession(); _appendUserInfo(currentOp, b, authSession); BSONObj p = b.done(); if (static_cast<size_t>(p.objsize()) > MAX_PROFILE_DOC_SIZE_BYTES || isQueryObjTooBig) { string small = p.toString(/*isArray*/false, /*full*/false); warning() << "can't add full line to system.profile: " << small << endl; // rebuild with limited info BSONObjBuilder b(profileBufBuilder); b.appendDate("ts", jsTime()); b.append("client", c.clientAddress() ); _appendUserInfo(currentOp, b, authSession); b.append("err", "profile line too large (max is 100KB)"); // should be much smaller but if not don't break anything if (small.size() < MAX_PROFILE_DOC_SIZE_BYTES){ b.append("abbreviated", small); } p = b.done(); } WriteUnitOfWork wunit(txn); // write: not replicated // get or create the profiling collection Collection* profileCollection = getOrCreateProfileCollection(txn, db); if ( !profileCollection ) { return false; } profileCollection->insertDocument( txn, p, false ); wunit.commit(); return true; }
void receivedInsert(Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); op.debug().ns = ns; StringData coll = nsToCollectionSubstring(ns); // Auth checking for index writes happens later. if (coll != "system.indexes") { Status status = cc().getAuthorizationManager()->checkAuthForInsert(ns); uassert(16544, status.reason(), status.isOK()); } if (!d.moreJSObjs()) { // strange. should we complain? return; } vector<BSONObj> objs; while (d.moreJSObjs()) { objs.push_back(d.nextJsObj()); } const bool keepGoing = d.reservedField() & InsertOption_ContinueOnError; OpSettings settings; settings.setQueryCursorMode(WRITE_LOCK_CURSOR); cc().setOpSettings(settings); if (coll == "system.indexes" && // Can only build non-unique indexes in the background, because the // hot indexer does not know how to perform unique checks. objs[0]["background"].trueValue() && !objs[0]["unique"].trueValue()) { _buildHotIndex(ns, m, objs); return; } scoped_ptr<Client::ShardedOperationScope> scp; if (coll != "system.indexes") { scp.reset(new Client::ShardedOperationScope); if (scp->handlePossibleShardedMessage(m, 0)) { return; } } LOCK_REASON(lockReason, "insert"); try { Lock::DBRead lk(ns, lockReason); lockedReceivedInsert(ns, m, objs, op, keepGoing); } catch (RetryWithWriteLock &e) { Lock::DBWrite lk(ns, lockReason); lockedReceivedInsert(ns, m, objs, op, keepGoing); } }
void profile( const Client& c , CurOp& currentOp ) { verify( Lock::somethingWriteLocked() ); Database *db = c.database(); DEV verify( db ); const char *ns = db->profileName.c_str(); // build object profileBufBuilder.reset(); BSONObjBuilder b(profileBufBuilder); const bool isQueryObjTooBig = !currentOp.debug().append(currentOp, b, MAX_PROFILE_DOC_SIZE_BYTES); b.appendDate("ts", jsTime()); b.append("client", c.clientAddress()); if (c.getAuthenticationInfo()) { b.append("user", c.getAuthenticationInfo()->getUser(nsToDatabase(ns))); } BSONObj p = b.done(); if (static_cast<size_t>(p.objsize()) > MAX_PROFILE_DOC_SIZE_BYTES || isQueryObjTooBig) { string small = p.toString(/*isArray*/false, /*full*/false); warning() << "can't add full line to system.profile: " << small << endl; // rebuild with limited info BSONObjBuilder b(profileBufBuilder); b.appendDate("ts", jsTime()); b.append("client", c.clientAddress() ); if ( c.getAuthenticationInfo() ) b.append( "user" , c.getAuthenticationInfo()->getUser( nsToDatabase( ns ) ) ); b.append("err", "profile line too large (max is 100KB)"); // should be much smaller but if not don't break anything if (small.size() < MAX_PROFILE_DOC_SIZE_BYTES){ b.append("abbreviated", small); } p = b.done(); } // write: not replicated // get or create the profiling collection NamespaceDetails *details = getOrCreateProfileCollection(db); if (details) { int len = p.objsize(); Record *r = theDataFileMgr.fast_oplog_insert(details, ns, len); memcpy(getDur().writingPtr(r->data(), len), p.objdata(), len); } }
void inProgCmd( Message &m, DbResponse &dbresponse ) { BSONObjBuilder b; if (!cc().getAuthorizationManager()->checkAuthorization( AuthorizationManager::SERVER_RESOURCE_NAME, ActionType::inprog)) { b.append("err", "unauthorized"); } else { DbMessage d(m); QueryMessage q(d); bool all = q.query["$all"].trueValue(); vector<BSONObj> vals; { Client& me = cc(); scoped_lock bl(Client::clientsMutex); scoped_ptr<Matcher> m(new Matcher(q.query)); for( set<Client*>::iterator i = Client::clients.begin(); i != Client::clients.end(); i++ ) { Client *c = *i; verify( c ); CurOp* co = c->curop(); if ( c == &me && !co ) { continue; } verify( co ); if( all || co->displayInCurop() ) { BSONObj info = co->info(); if ( all || m->matches( info )) { vals.push_back( info ); } } } } b.append("inprog", vals); if( lockedForWriting() ) { b.append("fsyncLock", true); b.append("info", "use db.fsyncUnlock() to terminate the fsync write/snapshot lock"); } } replyToQuery(0, m, dbresponse, b.obj()); }
void receivedUpdate(Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); assert(*ns); op.debug().str << ns << ' '; int flags = d.pullInt(); BSONObj query = d.nextJsObj(); assert( d.moreJSObjs() ); assert( query.objsize() < m.header()->dataLen() ); BSONObj toupdate = d.nextJsObj(); uassert( 10055 , "update object too large", toupdate.objsize() <= BSONObjMaxUserSize); assert( toupdate.objsize() < m.header()->dataLen() ); assert( query.objsize() + toupdate.objsize() < m.header()->dataLen() ); bool upsert = flags & UpdateOption_Upsert; bool multi = flags & UpdateOption_Multi; bool broadcast = flags & UpdateOption_Broadcast; { string s = query.toString(); /* todo: we shouldn't do all this ss stuff when we don't need it, it will slow us down. instead, let's just story the query BSON in the debug object, and it can toString() lazily */ op.debug().str << " query: " << s; op.setQuery(query); } writelock lk; // writelock is used to synchronize stepdowns w/ writes uassert( 10054 , "not master", isMasterNs( ns ) ); // if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) ) return; Client::Context ctx( ns ); UpdateResult res = updateObjects(ns, toupdate, query, upsert, multi, true, op.debug() ); lastError.getSafe()->recordUpdate( res.existing , res.num , res.upserted ); // for getlasterror }
void inProgCmd( Message &m, DbResponse &dbresponse ) { BSONObjBuilder b; if( ! cc().isAdmin() ) { b.append("err", "unauthorized"); } else { DbMessage d(m); QueryMessage q(d); bool all = q.query["$all"].trueValue(); vector<BSONObj> vals; { Client& me = cc(); scoped_lock bl(Client::clientsMutex); auto_ptr<Matcher> m(new Matcher(q.query)); for( set<Client*>::iterator i = Client::clients.begin(); i != Client::clients.end(); i++ ) { Client *c = *i; assert( c ); CurOp* co = c->curop(); if ( c == &me && !co ) { continue; } assert( co ); if( all || co->active() ) { BSONObj info = co->infoNoauth(); if ( all || m->matches( info )) { vals.push_back( info ); } } } } b.append("inprog", vals); unsigned x = lockedForWriting; if( x ) { b.append("fsyncLock", x); b.append("info", "use db.fsyncUnlock() to terminate the fsync write/snapshot lock"); } } replyToQuery(0, m, dbresponse, b.obj()); }
void ClientCursor::staticYield( int micros , const StringData& ns ) { killCurrentOp.checkForInterrupt( false ); { dbtempreleasecond unlock; if ( unlock.unlocked() ) { if ( micros == -1 ) micros = Client::recommendedYieldMicros(); if ( micros > 0 ) sleepmicros( micros ); } else { CurOp * c = cc().curop(); while ( c->parent() ) c = c->parent(); warning() << "ClientCursor::yield can't unlock b/c of recursive lock" << " ns: " << ns << " top: " << c->info() << endl; } } }
void OpDebug::append( const CurOp& curop, BSONObjBuilder& b ) const { b.append( "op" , iscommand ? "command" : opToString( op ) ); b.append( "ns" , ns.toString() ); if ( ! query.isEmpty() ) b.append( iscommand ? "command" : "query" , query ); else if ( ! iscommand && curop.haveQuery() ) curop.appendQuery( b , "query" ); if ( ! updateobj.isEmpty() ) b.append( "updateobj" , updateobj ); const bool moved = (nmoved >= 1); OPDEBUG_APPEND_NUMBER( cursorid ); OPDEBUG_APPEND_NUMBER( ntoreturn ); OPDEBUG_APPEND_NUMBER( ntoskip ); OPDEBUG_APPEND_BOOL( exhaust ); OPDEBUG_APPEND_NUMBER( nscanned ); OPDEBUG_APPEND_BOOL( idhack ); OPDEBUG_APPEND_BOOL( scanAndOrder ); OPDEBUG_APPEND_BOOL( moved ); OPDEBUG_APPEND_NUMBER( nmoved ); OPDEBUG_APPEND_NUMBER( nupdated ); OPDEBUG_APPEND_BOOL( fastmod ); OPDEBUG_APPEND_BOOL( fastmodinsert ); OPDEBUG_APPEND_BOOL( upsert ); OPDEBUG_APPEND_NUMBER( keyUpdates ); b.appendNumber( "numYield" , curop.numYields() ); b.append( "lockStats" , curop.lockStat().report() ); if ( ! exceptionInfo.empty() ) exceptionInfo.append( b , "exception" , "exceptionCode" ); OPDEBUG_APPEND_NUMBER( nreturned ); OPDEBUG_APPEND_NUMBER( responseLength ); b.append( "millis" , executionTime ); }
static void lockedReceivedInsert(const char *ns, Message &m, const vector<BSONObj> &objs, CurOp &op, const bool keepGoing) { // writelock is used to synchronize stepdowns w/ writes uassert(10058, "not master", isMasterNs(ns)); Client::Context ctx(ns); scoped_ptr<Client::AlternateTransactionStack> altStack(opNeedsAltTxn(ns) ? new Client::AlternateTransactionStack : NULL); Client::Transaction transaction(DB_SERIALIZABLE); insertObjects(ns, objs, keepGoing, 0, true); transaction.commit(); size_t n = objs.size(); globalOpCounters.gotInsert(n); op.debug().ninserted = n; }
void profile(const Client& c, int op, CurOp& currentOp) { // initialize with 1kb to start, to avoid realloc later // doing this outside the dblock to improve performance BufBuilder profileBufBuilder(1024); try { Lock::DBWrite lk( currentOp.getNS() ); if ( dbHolder()._isLoaded( nsToDatabase( currentOp.getNS() ) , dbpath ) ) { Client::Context cx(currentOp.getNS(), dbpath); _profile(c, currentOp, profileBufBuilder); } else { mongo::log() << "note: not profiling because db went away - probably a close on: " << currentOp.getNS() << endl; } } catch (const AssertionException& assertionEx) { warning() << "Caught Assertion while trying to profile " << opToString(op) << " against " << currentOp.getNS() << ": " << assertionEx.toString() << endl; } }
void ClientCursor::updateSlaveLocation(OperationContext* txn, CurOp& curop) { if (_slaveReadTill.isNull()) return; verify(str::startsWith(_ns.c_str(), "local.oplog.")); Client* c = curop.getClient(); verify(c); OID rid = c->getRemoteID(); if (!rid.isSet()) return; repl::getGlobalReplicationCoordinator()->setLastOptimeForSlave(rid, _slaveReadTill); }
CurOp* CurOp::getOp(const BSONObj& criteria) { // Regarding Matcher: This is not quite the right hammer to use here. // Future: use an actual property of CurOp to flag index builds // and use that to filter. // This will probably need refactoring once we change index builds // to be a real command instead of an insert into system.indexes Matcher matcher(criteria); Client& me = cc(); scoped_lock client_lock(Client::clientsMutex); for (std::set<Client*>::iterator it = Client::clients.begin(); it != Client::clients.end(); it++) { Client *client = *it; verify(client); CurOp* curop = client->curop(); if (client == &me || curop == NULL) { continue; } if ( !curop->active() ) continue; if ( curop->killPendingStrict() ) continue; BSONObj info = curop->description(); if (matcher.matches(info)) { return curop; } } return NULL; }
bool _tryQueryByPKHack(const char *ns, const BSONObj &query, const ParsedQuery &pq, CurOp &curop, Message &result) { BSONObj resObject; bool found = false; Collection *cl = getCollection(ns); if (cl == NULL) { return false; // ns doesn't exist, fall through to optimizer for legacy reasons } const BSONObj &pk = cl->getSimplePKFromQuery(query); if (pk.isEmpty()) { return false; // unable to query by PK - resort to using the optimizer } found = queryByPKHack(cl, pk, query, resObject); if ( shardingState.needShardChunkManager( ns ) ) { ShardChunkManagerPtr m = shardingState.getShardChunkManager( ns ); if ( m && ! m->belongsToMe( resObject ) ) { // I have something for this _id // but it doesn't belong to me // so return nothing resObject = BSONObj(); found = false; } } BufBuilder bb(sizeof(QueryResult)+resObject.objsize()+32); bb.skip(sizeof(QueryResult)); if ( found ) { fillQueryResultFromObj( bb , pq.getFields() , resObject ); } auto_ptr< QueryResult > qr( (QueryResult *) bb.buf() ); bb.decouple(); qr->setResultFlagsToOk(); qr->len = bb.len(); curop.debug().responseLength = bb.len(); qr->setOperation(opReply); qr->cursorId = 0; qr->startingFrom = 0; qr->nReturned = found ? 1 : 0; result.setData( qr.release(), true ); return true; }
void receivedInsert(Message& m, CurOp& op) { DbMessage d(m); const char *ns = d.getns(); op.debug().ns = ns; if( !d.moreJSObjs() ) { // strange. should we complain? return; } BSONObj first = d.nextJsObj(); vector<BSONObj> multi; while (d.moreJSObjs()){ if (multi.empty()) // first pass multi.push_back(first); multi.push_back( d.nextJsObj() ); } PageFaultRetryableSection s; while ( true ) { try { Lock::DBWrite lk(ns); // CONCURRENCY TODO: is being read locked in big log sufficient here? // writelock is used to synchronize stepdowns w/ writes uassert( 10058 , "not master", isMasterNs(ns) ); if ( handlePossibleShardedMessage( m , 0 ) ) return; Client::Context ctx(ns); if( !multi.empty() ) { const bool keepGoing = d.reservedField() & InsertOption_ContinueOnError; insertMulti(keepGoing, ns, multi); return; } checkAndInsert(ns, first); globalOpCounters.incInsertInWriteLock(1); return; } catch ( PageFaultException& e ) { e.touch(); } } }