// ns is either a full namespace or "dbname." when invalidating for a whole db void ClientCursor::invalidate(const char *ns) { Lock::assertWriteLocked(ns); int len = strlen(ns); const char* dot = strchr(ns, '.'); verify( len > 0 && dot); bool isDB = (dot == &ns[len-1]); // first (and only) dot is the last char { //cout << "\nTEMP invalidate " << ns << endl; Database *db = cc().database(); verify(db); verify( str::startsWith(ns, db->name) ); for( LockedIterator i; i.ok(); ) { ClientCursor *cc = i.current(); bool shouldDelete = false; if ( cc->_db == db ) { if (isDB) { // already checked that db matched above dassert( str::startsWith(cc->_ns.c_str(), ns) ); shouldDelete = true; } else { if ( str::equals(cc->_ns.c_str(), ns) ) shouldDelete = true; } } if ( shouldDelete ) { i.deleteAndAdvance(); } else { i.advance(); } } /* note : we can't iterate byloc because clientcursors may exist with a loc of null in which case they are not in the map. perhaps they should not exist though in the future? something to change??? CCByLoc& bl = db->ccByLoc; for ( CCByLoc::iterator i = bl.begin(); i != bl.end(); ++i ) { ClientCursor *cc = i->second; if ( strncmp(ns, cc->ns.c_str(), len) == 0 ) { verify( cc->_db == db ); toDelete.push_back(i->second); } }*/ /*cout << "TEMP after invalidate " << endl; for( auto i = clientCursorsById.begin(); i != clientCursorsById.end(); ++i ) { cout << " " << i->second->ns << endl; } cout << "TEMP after invalidate done" << endl;*/ } }
/* called every 4 seconds. millis is amount of idle time passed since the last call -- could be zero */ void ClientCursor::idleTimeReport(unsigned millis) { LockedIterator i; unsigned sz = clientCursorsById.size(); if (sz >= 100000) { RATELIMITED(300000) log() << "warning number of open cursors is very large: " << sz << endl; } while (i.ok()) { ClientCursor *cc = i.current(); if (cc->shouldTimeout(millis)) { LOG(1) << "killing old cursor " << cc->_cursorid << ' ' << cc->_ns << " idle:" << cc->idleTime() << "ms" << endl; i.deleteAndAdvance(); } else { i.advance(); } } }
/* called every 4 seconds. millis is amount of idle time passed since the last call -- could be zero */ void ClientCursor::idleTimeReport(unsigned millis) { bool foundSomeToTimeout = false; // two passes so that we don't need to readlock unless we really do some timeouts // we assume here that incrementing _idleAgeMillis outside readlock is ok. { recursive_scoped_lock lock(ccmutex); { unsigned sz = clientCursorsById.size(); static time_t last; if( sz >= 100000 ) { if( time(0) - last > 300 ) { last = time(0); log() << "warning number of open cursors is very large: " << sz << endl; } } } for ( CCById::iterator i = clientCursorsById.begin(); i != clientCursorsById.end(); ) { CCById::iterator j = i; i++; if( j->second->shouldTimeout( millis ) ) { foundSomeToTimeout = true; } } } if( foundSomeToTimeout ) { // todo: ideally all readlocks automatically note what we are locking for so this // can be reported in currentop command. e.g. something like: // readlock lk("", "timeout cursors"); readlock lk(""); for( LockedIterator i; i.ok(); ) { ClientCursor *cc = i.current(); if( cc->shouldTimeout(0) ) { numberTimedOut++; LOG(1) << "killing old cursor " << cc->_cursorid << ' ' << cc->_ns << " idle:" << cc->idleTime() << "ms\n"; i.deleteAndAdvance(); } else { i.advance(); } } } }
// ns is either a full namespace or "dbname." when invalidating for a whole db void ClientCursor::invalidate(const StringData &ns) { Lock::assertWriteLocked(ns); size_t dotpos = ns.find('.'); verify(dotpos != string::npos); bool isDB = (dotpos + 1) == ns.size(); // first (and only) dot is the last char { //cout << "\nTEMP invalidate " << ns << endl; Database *db = cc().database(); verify(db); verify( ns.startsWith(db->name()) ); for( LockedIterator i; i.ok(); ) { ClientCursor *cc = i.current(); bool shouldDelete = false; if (cc->c()->shouldDestroyOnNSDeletion() && cc->_db == db) { if (isDB) { // already checked that db matched above dassert( StringData(cc->_ns).startsWith(ns) ); shouldDelete = true; } else { if ( ns == cc->_ns ) shouldDelete = true; } } if ( shouldDelete ) { i.deleteAndAdvance(); } else { i.advance(); } } } }