diff options
Diffstat (limited to 'db/stats')
-rw-r--r-- | db/stats/counters.cpp | 110 | ||||
-rw-r--r-- | db/stats/counters.h | 77 | ||||
-rw-r--r-- | db/stats/fine_clock.h | 13 | ||||
-rw-r--r-- | db/stats/service_stats.cpp | 6 | ||||
-rw-r--r-- | db/stats/snapshots.cpp | 121 | ||||
-rw-r--r-- | db/stats/snapshots.h | 20 | ||||
-rw-r--r-- | db/stats/top.cpp | 115 | ||||
-rw-r--r-- | db/stats/top.h | 57 |
8 files changed, 302 insertions, 217 deletions
diff --git a/db/stats/counters.cpp b/db/stats/counters.cpp index a2d4cfb..889e8a8 100644 --- a/db/stats/counters.cpp +++ b/db/stats/counters.cpp @@ -22,7 +22,7 @@ namespace mongo { - OpCounters::OpCounters(){ + OpCounters::OpCounters() { int zero = 0; BSONObjBuilder b; @@ -42,16 +42,16 @@ namespace mongo { _command = (AtomicUInt*)_obj["command"].value(); } - void OpCounters::gotOp( int op , bool isCommand ){ - switch ( op ){ + void OpCounters::gotOp( int op , bool isCommand ) { + switch ( op ) { case dbInsert: /*gotInsert();*/ break; // need to handle multi-insert - case dbQuery: + case dbQuery: if ( isCommand ) gotCommand(); - else - gotQuery(); + else + gotQuery(); break; - + case dbUpdate: gotUpdate(); break; case dbDelete: gotDelete(); break; case dbGetMore: gotGetMore(); break; @@ -62,24 +62,48 @@ namespace mongo { default: log() << "OpCounters::gotOp unknown op: " << op << endl; } } - - IndexCounters::IndexCounters(){ + + BSONObj& OpCounters::getObj() { + const unsigned MAX = 1 << 30; + RARELY { + bool wrap = + _insert->get() > MAX || + _query->get() > MAX || + _update->get() > MAX || + _delete->get() > MAX || + _getmore->get() > MAX || + _command->get() > MAX; + + if ( wrap ) { + _insert->zero(); + _query->zero(); + _update->zero(); + _delete->zero(); + _getmore->zero(); + _command->zero(); + } + + } + return _obj; + } + + IndexCounters::IndexCounters() { _memSupported = _pi.blockCheckSupported(); - + _btreeMemHits = 0; _btreeMemMisses = 0; _btreeAccesses = 0; - - + + _maxAllowed = ( numeric_limits< long long >::max() ) / 2; _resets = 0; _sampling = 0; _samplingrate = 100; } - - void IndexCounters::append( BSONObjBuilder& b ){ - if ( ! _memSupported ){ + + void IndexCounters::append( BSONObjBuilder& b ) { + if ( ! _memSupported ) { b.append( "note" , "not supported on this platform" ); return; } @@ -90,33 +114,33 @@ namespace mongo { bb.appendNumber( "misses" , _btreeMemMisses ); bb.append( "resets" , _resets ); - + bb.append( "missRatio" , (_btreeAccesses ? (_btreeMemMisses / (double)_btreeAccesses) : 0) ); - + bb.done(); - - if ( _btreeAccesses > _maxAllowed ){ + + if ( _btreeAccesses > _maxAllowed ) { _btreeAccesses = 0; _btreeMemMisses = 0; _btreeMemHits = 0; _resets++; } } - + FlushCounters::FlushCounters() : _total_time(0) , _flushes(0) , _last() {} - void FlushCounters::flushed(int ms){ + void FlushCounters::flushed(int ms) { _flushes++; _total_time += ms; _last_time = ms; _last = jsTime(); } - void FlushCounters::append( BSONObjBuilder& b ){ + void FlushCounters::append( BSONObjBuilder& b ) { b.appendNumber( "flushes" , _flushes ); b.appendNumber( "total_ms" , _total_time ); b.appendNumber( "average_ms" , (_flushes ? (_total_time / double(_flushes)) : 0.0) ); @@ -125,25 +149,59 @@ namespace mongo { } - void GenericCounter::hit( const string& name , int count ){ + void GenericCounter::hit( const string& name , int count ) { scoped_lock lk( _mutex ); _counts[name]++; } - + BSONObj GenericCounter::getObj() { BSONObjBuilder b(128); { mongo::mutex::scoped_lock lk( _mutex ); - for ( map<string,long long>::iterator i=_counts.begin(); i!=_counts.end(); i++ ){ + for ( map<string,long long>::iterator i=_counts.begin(); i!=_counts.end(); i++ ) { b.appendNumber( i->first , i->second ); } } return b.obj(); } - + + void NetworkCounter::hit( long long bytesIn , long long bytesOut ) { + const long long MAX = 1ULL << 60; + + // don't care about the race as its just a counter + bool overflow = _bytesIn > MAX || _bytesOut > MAX; + + if ( overflow ) { + _lock.lock(); + _overflows++; + _bytesIn = bytesIn; + _bytesOut = bytesOut; + _requests = 1; + _lock.unlock(); + } + else { + _lock.lock(); + _bytesIn += bytesIn; + _bytesOut += bytesOut; + _requests++; + _lock.unlock(); + } + } + + void NetworkCounter::append( BSONObjBuilder& b ) { + _lock.lock(); + b.appendNumber( "bytesIn" , _bytesIn ); + b.appendNumber( "bytesOut" , _bytesOut ); + b.appendNumber( "numRequests" , _requests ); + _lock.unlock(); + } + OpCounters globalOpCounters; + OpCounters replOpCounters; IndexCounters globalIndexCounters; FlushCounters globalFlushCounters; + NetworkCounter networkCounter; + } diff --git a/db/stats/counters.h b/db/stats/counters.h index 2704464..b5cad85 100644 --- a/db/stats/counters.h +++ b/db/stats/counters.h @@ -21,6 +21,7 @@ #include "../jsobj.h" #include "../../util/message.h" #include "../../util/processinfo.h" +#include "../../util/concurrency/spin_lock.h" namespace mongo { @@ -30,28 +31,33 @@ namespace mongo { */ class OpCounters { public: - + OpCounters(); - AtomicUInt * getInsert(){ return _insert; } - AtomicUInt * getQuery(){ return _query; } - AtomicUInt * getUpdate(){ return _update; } - AtomicUInt * getDelete(){ return _delete; } - AtomicUInt * getGetMore(){ return _getmore; } - AtomicUInt * getCommand(){ return _command; } - - void gotInsert(){ _insert[0]++; } - void gotQuery(){ _query[0]++; } - void gotUpdate(){ _update[0]++; } - void gotDelete(){ _delete[0]++; } - void gotGetMore(){ _getmore[0]++; } - void gotCommand(){ _command[0]++; } + AtomicUInt * getInsert() { return _insert; } + AtomicUInt * getQuery() { return _query; } + AtomicUInt * getUpdate() { return _update; } + AtomicUInt * getDelete() { return _delete; } + AtomicUInt * getGetMore() { return _getmore; } + AtomicUInt * getCommand() { return _command; } + + void incInsertInWriteLock(int n) { _insert->x += n; } + void gotInsert() { _insert[0]++; } + void gotQuery() { _query[0]++; } + void gotUpdate() { _update[0]++; } + void gotDelete() { _delete[0]++; } + void gotGetMore() { _getmore[0]++; } + void gotCommand() { _command[0]++; } void gotOp( int op , bool isCommand ); - BSONObj& getObj(){ return _obj; } + BSONObj& getObj(); + private: BSONObj _obj; + + // todo: there will be a lot of cache line contention on these. need to do something + // else eventually. AtomicUInt * _insert; AtomicUInt * _query; AtomicUInt * _update; @@ -59,14 +65,16 @@ namespace mongo { AtomicUInt * _getmore; AtomicUInt * _command; }; - + extern OpCounters globalOpCounters; + extern OpCounters replOpCounters; + class IndexCounters { public: IndexCounters(); - - void btree( char * node ){ + + void btree( char * node ) { if ( ! _memSupported ) return; if ( _sampling++ % _samplingrate ) @@ -74,28 +82,28 @@ namespace mongo { btree( _pi.blockInMemory( node ) ); } - void btree( bool memHit ){ + void btree( bool memHit ) { if ( memHit ) _btreeMemHits++; else _btreeMemMisses++; _btreeAccesses++; } - void btreeHit(){ _btreeMemHits++; _btreeAccesses++; } - void btreeMiss(){ _btreeMemMisses++; _btreeAccesses++; } - + void btreeHit() { _btreeMemHits++; _btreeAccesses++; } + void btreeMiss() { _btreeMemMisses++; _btreeAccesses++; } + void append( BSONObjBuilder& b ); - + private: ProcessInfo _pi; bool _memSupported; int _sampling; int _samplingrate; - + int _resets; long long _maxAllowed; - + long long _btreeMemMisses; long long _btreeMemHits; long long _btreeAccesses; @@ -108,7 +116,7 @@ namespace mongo { FlushCounters(); void flushed(int ms); - + void append( BSONObjBuilder& b ); private: @@ -130,4 +138,21 @@ namespace mongo { map<string,long long> _counts; // TODO: replace with thread safe map mongo::mutex _mutex; }; + + class NetworkCounter { + public: + NetworkCounter() : _bytesIn(0), _bytesOut(0), _requests(0), _overflows(0) {} + void hit( long long bytesIn , long long bytesOut ); + void append( BSONObjBuilder& b ); + private: + long long _bytesIn; + long long _bytesOut; + long long _requests; + + long long _overflows; + + SpinLock _lock; + }; + + extern NetworkCounter networkCounter; } diff --git a/db/stats/fine_clock.h b/db/stats/fine_clock.h index 1f23175..02600e7 100644 --- a/db/stats/fine_clock.h +++ b/db/stats/fine_clock.h @@ -36,29 +36,30 @@ namespace mongo { * Really, you shouldn't be using this class in hot code paths for * platforms you're not sure whether the overhead is low. */ - class FineClock{ + class FineClock { public: typedef timespec WallTime; - static WallTime now(){ + static WallTime now() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts; } - static uint64_t diffInNanos( WallTime end, WallTime start ){ + static uint64_t diffInNanos( WallTime end, WallTime start ) { uint64_t diff; - if ( end.tv_nsec < start.tv_nsec ){ + if ( end.tv_nsec < start.tv_nsec ) { diff = 1000000000 * ( end.tv_sec - start.tv_sec - 1); diff += 1000000000 + end.tv_nsec - start.tv_nsec; - } else { + } + else { diff = 1000000000 * ( end.tv_sec - start.tv_sec ); diff += end.tv_nsec - start.tv_nsec; } return diff; } - + }; } diff --git a/db/stats/service_stats.cpp b/db/stats/service_stats.cpp index 5574ecb..d69147f 100644 --- a/db/stats/service_stats.cpp +++ b/db/stats/service_stats.cpp @@ -25,7 +25,7 @@ namespace mongo { using std::ostringstream; - ServiceStats::ServiceStats(){ + ServiceStats::ServiceStats() { // Time histogram covers up to 128msec in exponential intervals // starting at 125usec. Histogram::Options timeOpts; @@ -43,12 +43,12 @@ namespace mongo { _spaceHistogram = new Histogram( spaceOpts ); } - ServiceStats::~ServiceStats(){ + ServiceStats::~ServiceStats() { delete _timeHistogram; delete _spaceHistogram; } - void ServiceStats::logResponse( uint64_t duration, uint64_t bytes ){ + void ServiceStats::logResponse( uint64_t duration, uint64_t bytes ) { _spinLock.lock(); _timeHistogram->insert( duration / 1000 /* in usecs */ ); _spaceHistogram->insert( bytes ); diff --git a/db/stats/snapshots.cpp b/db/stats/snapshots.cpp index 3ce80ca..a81568d 100644 --- a/db/stats/snapshots.cpp +++ b/db/stats/snapshots.cpp @@ -27,28 +27,27 @@ handles snapshotting performance metrics and other such things */ namespace mongo { - void SnapshotData::takeSnapshot(){ - _created = curTimeMicros64(); - _globalUsage = Top::global.getGlobalData(); + void SnapshotData::takeSnapshot() { + _created = curTimeMicros64(); + _globalUsage = Top::global.getGlobalData(); _totalWriteLockedTime = dbMutex.info().getTimeLocked(); Top::global.cloneMap(_usage); } SnapshotDelta::SnapshotDelta( const SnapshotData& older , const SnapshotData& newer ) - : _older( older ) , _newer( newer ) - { + : _older( older ) , _newer( newer ) { assert( _newer._created > _older._created ); _elapsed = _newer._created - _older._created; - + } - - Top::CollectionData SnapshotDelta::globalUsageDiff(){ + + Top::CollectionData SnapshotDelta::globalUsageDiff() { return Top::CollectionData( _older._globalUsage , _newer._globalUsage ); } - Top::UsageMap SnapshotDelta::collectionUsageDiff(){ + Top::UsageMap SnapshotDelta::collectionUsageDiff() { Top::UsageMap u; - - for ( Top::UsageMap::const_iterator i=_newer._usage.begin(); i != _newer._usage.end(); i++ ){ + + for ( Top::UsageMap::const_iterator i=_newer._usage.begin(); i != _newer._usage.end(); i++ ) { Top::UsageMap::const_iterator j = _older._usage.find(i->first); if (j != _older._usage.end()) u[i->first] = Top::CollectionData( j->second , i->second ); @@ -62,8 +61,8 @@ namespace mongo { , _loc(0) , _stored(0) {} - - const SnapshotData* Snapshots::takeSnapshot(){ + + const SnapshotData* Snapshots::takeSnapshot() { scoped_lock lk(_lock); _loc = ( _loc + 1 ) % _n; _snapshots[_loc].takeSnapshot(); @@ -72,7 +71,7 @@ namespace mongo { return &_snapshots[_loc]; } - auto_ptr<SnapshotDelta> Snapshots::computeDelta( int numBack ){ + auto_ptr<SnapshotDelta> Snapshots::computeDelta( int numBack ) { scoped_lock lk(_lock); auto_ptr<SnapshotDelta> p; if ( numBack < numDeltas() ) @@ -80,43 +79,43 @@ namespace mongo { return p; } - const SnapshotData& Snapshots::getPrev( int numBack ){ + const SnapshotData& Snapshots::getPrev( int numBack ) { int x = _loc - numBack; if ( x < 0 ) x += _n; return _snapshots[x]; } - void Snapshots::outputLockInfoHTML( stringstream& ss ){ + void Snapshots::outputLockInfoHTML( stringstream& ss ) { scoped_lock lk(_lock); ss << "\n<div>"; - for ( int i=0; i<numDeltas(); i++ ){ + for ( int i=0; i<numDeltas(); i++ ) { SnapshotDelta d( getPrev(i+1) , getPrev(i) ); unsigned e = (unsigned) d.elapsed() / 1000; ss << (unsigned)(100*d.percentWriteLocked()); - if( e < 3900 || e > 4100 ) + if( e < 3900 || e > 4100 ) ss << '(' << e / 1000.0 << "s)"; ss << ' '; } ss << "</div>\n"; } - void SnapshotThread::run(){ + void SnapshotThread::run() { Client::initThread("snapshotthread"); Client& client = cc(); long long numLoops = 0; - + const SnapshotData* prev = 0; - while ( ! inShutdown() ){ + while ( ! inShutdown() ) { try { const SnapshotData* s = statsSnapshots.takeSnapshot(); - - if ( prev ){ + + if ( prev ) { unsigned long long elapsed = s->_created - prev->_created; - if ( cmdLine.cpu ){ + if ( cmdLine.cpu ) { SnapshotDelta d( *prev , *s ); log() << "cpu: elapsed:" << (elapsed/1000) <<" writelock: " << (int)(100*d.percentWriteLocked()) << "%" << endl; } @@ -125,14 +124,14 @@ namespace mongo { prev = s; } - catch ( std::exception& e ){ + catch ( std::exception& e ) { log() << "ERROR in SnapshotThread: " << e.what() << endl; } - + numLoops++; sleepsecs(4); } - + client.shutdown(); } @@ -140,15 +139,15 @@ namespace mongo { class WriteLockStatus : public WebStatusPlugin { public: - WriteLockStatus() : WebStatusPlugin( "write lock" , 51 , "% time in write lock, by 4 sec periods" ){} - virtual void init(){} + WriteLockStatus() : WebStatusPlugin( "write lock" , 51 , "% time in write lock, by 4 sec periods" ) {} + virtual void init() {} - virtual void run( stringstream& ss ){ + virtual void run( stringstream& ss ) { statsSnapshots.outputLockInfoHTML( ss ); ss << "<a " - "href=\"http://www.mongodb.org/pages/viewpage.action?pageId=7209296\" " - "title=\"snapshot: was the db in the write lock when this page was generated?\">"; + "href=\"http://www.mongodb.org/pages/viewpage.action?pageId=7209296\" " + "title=\"snapshot: was the db in the write lock when this page was generated?\">"; ss << "write locked now:</a> " << (dbMutex.info().isLocked() ? "true" : "false") << "\n"; } @@ -156,22 +155,26 @@ namespace mongo { class DBTopStatus : public WebStatusPlugin { public: - DBTopStatus() : WebStatusPlugin( "dbtop" , 50 , "(occurences|percent of elapsed)" ){} + DBTopStatus() : WebStatusPlugin( "dbtop" , 50 , "(occurences|percent of elapsed)" ) {} - void display( stringstream& ss , double elapsed , const Top::UsageData& usage ){ + void display( stringstream& ss , double elapsed , const Top::UsageData& usage ) { ss << "<td>"; ss << usage.count; ss << "</td><td>"; double per = 100 * ((double)usage.time)/elapsed; - ss << setprecision(1) << fixed << per << "%"; + if( per == (int) per ) + ss << (int) per; + else + ss << setprecision(1) << fixed << per; + ss << '%'; ss << "</td>"; } - void display( stringstream& ss , double elapsed , const string& ns , const Top::CollectionData& data ){ - if ( ns != "GLOBAL" && data.total.count == 0 ) + void display( stringstream& ss , double elapsed , const string& ns , const Top::CollectionData& data ) { + if ( ns != "TOTAL" && data.total.count == 0 ) return; ss << "<tr><th>" << ns << "</th>"; - + display( ss , elapsed , data.total ); display( ss , elapsed , data.readLock ); @@ -182,43 +185,43 @@ namespace mongo { display( ss , elapsed , data.insert ); display( ss , elapsed , data.update ); display( ss , elapsed , data.remove ); - + ss << "</tr>\n"; } - void run( stringstream& ss ){ + void run( stringstream& ss ) { auto_ptr<SnapshotDelta> delta = statsSnapshots.computeDelta(); if ( ! delta.get() ) return; - + ss << "<table border=1 cellpadding=2 cellspacing=0>"; ss << "<tr align='left'><th>"; - ss << a("http://www.mongodb.org/display/DOCS/Developer+FAQ#DeveloperFAQ-What%27sa%22namespace%22%3F", "namespace") << - "NS</a></th>" - "<th colspan=2>total</th>" - "<th colspan=2>Reads</th>" - "<th colspan=2>Writes</th>" - "<th colspan=2>Queries</th>" - "<th colspan=2>GetMores</th>" - "<th colspan=2>Inserts</th>" - "<th colspan=2>Updates</th>" - "<th colspan=2>Removes</th>"; + ss << a("http://www.mongodb.org/display/DOCS/Developer+FAQ#DeveloperFAQ-What%27sa%22namespace%22%3F", "namespace") << + "NS</a></th>" + "<th colspan=2>total</th>" + "<th colspan=2>Reads</th>" + "<th colspan=2>Writes</th>" + "<th colspan=2>Queries</th>" + "<th colspan=2>GetMores</th>" + "<th colspan=2>Inserts</th>" + "<th colspan=2>Updates</th>" + "<th colspan=2>Removes</th>"; ss << "</tr>\n"; - - display( ss , (double) delta->elapsed() , "GLOBAL" , delta->globalUsageDiff() ); - + + display( ss , (double) delta->elapsed() , "TOTAL" , delta->globalUsageDiff() ); + Top::UsageMap usage = delta->collectionUsageDiff(); - for ( Top::UsageMap::iterator i=usage.begin(); i != usage.end(); i++ ){ + for ( Top::UsageMap::iterator i=usage.begin(); i != usage.end(); i++ ) { display( ss , (double) delta->elapsed() , i->first , i->second ); } - + ss << "</table>"; - + } - virtual void init(){} + virtual void init() {} } dbtopStatus; Snapshots statsSnapshots; - SnapshotThread snapshotThread; + SnapshotThread snapshotThread; } diff --git a/db/stats/snapshots.h b/db/stats/snapshots.h index 6d8e23d..d9b8e5e 100644 --- a/db/stats/snapshots.h +++ b/db/stats/snapshots.h @@ -28,7 +28,7 @@ namespace mongo { class SnapshotThread; - + /** * stores a point in time snapshot * i.e. all counters at a given time @@ -45,14 +45,14 @@ namespace mongo { friend class SnapshotDelta; friend class Snapshots; }; - + /** * contains performance information for a time period */ class SnapshotDelta { public: SnapshotDelta( const SnapshotData& older , const SnapshotData& newer ); - + unsigned long long start() const { return _older._created; } @@ -60,7 +60,7 @@ namespace mongo { unsigned long long elapsed() const { return _elapsed; } - + unsigned long long timeInWriteLock() const { return _newer._totalWriteLockedTime - _older._totalWriteLockedTime; } @@ -83,15 +83,15 @@ namespace mongo { class Snapshots { public: Snapshots(int n=100); - + const SnapshotData* takeSnapshot(); - + int numDeltas() const { return _stored-1; } const SnapshotData& getPrev( int numBack = 0 ); auto_ptr<SnapshotDelta> computeDelta( int numBack = 0 ); - - + + void outputLockInfoHTML( stringstream& ss ); private: mongo::mutex _lock; @@ -103,10 +103,10 @@ namespace mongo { class SnapshotThread : public BackgroundJob { public: - string name() { return "snapshot"; } + virtual string name() const { return "snapshot"; } void run(); }; - + extern Snapshots statsSnapshots; extern SnapshotThread snapshotThread; diff --git a/db/stats/top.cpp b/db/stats/top.cpp index 3e65261..77aef0d 100644 --- a/db/stats/top.cpp +++ b/db/stats/top.cpp @@ -22,16 +22,16 @@ #include "../commands.h" namespace mongo { - - Top::UsageData::UsageData( const UsageData& older , const UsageData& newer ) - : time(newer.time-older.time) , - count(newer.count-older.count) - { - + + Top::UsageData::UsageData( const UsageData& older , const UsageData& newer ) { + // this won't be 100% accurate on rollovers and drop(), but at least it won't be negative + time = (newer.time > older.time) ? (newer.time - older.time) : newer.time; + count = (newer.count > older.count) ? (newer.count - older.count) : newer.count; + } Top::CollectionData::CollectionData( const CollectionData& older , const CollectionData& newer ) - : total( older.total , newer.total ) , + : total( older.total , newer.total ) , readLock( older.readLock , newer.readLock ) , writeLock( older.writeLock , newer.writeLock ) , queries( older.queries , newer.queries ) , @@ -39,17 +39,18 @@ namespace mongo { insert( older.insert , newer.insert ) , update( older.update , newer.update ) , remove( older.remove , newer.remove ), - commands( older.commands , newer.commands ) - { - + commands( older.commands , newer.commands ) { + } - - void Top::record( const string& ns , int op , int lockType , long long micros , bool command ){ + void Top::record( const string& ns , int op , int lockType , long long micros , bool command ) { + if ( ns[0] == '?' ) + return; + //cout << "record: " << ns << "\t" << op << "\t" << command << endl; scoped_lock lk(_lock); - - if ( ( command || op == dbQuery ) && ns == _lastDropped ){ + + if ( ( command || op == dbQuery ) && ns == _lastDropped ) { _lastDropped = ""; return; } @@ -59,22 +60,15 @@ namespace mongo { _record( _global , op , lockType , micros , command ); } - void Top::collectionDropped( const string& ns ){ - //cout << "collectionDropped: " << ns << endl; - scoped_lock lk(_lock); - _usage.erase(ns); - _lastDropped = ns; - } - - void Top::_record( CollectionData& c , int op , int lockType , long long micros , bool command ){ + void Top::_record( CollectionData& c , int op , int lockType , long long micros , bool command ) { c.total.inc( micros ); - + if ( lockType > 0 ) c.writeLock.inc( micros ); else if ( lockType < 0 ) c.readLock.inc( micros ); - - switch ( op ){ + + switch ( op ) { case 0: // use 0 for unknown, non-specific break; @@ -98,7 +92,7 @@ namespace mongo { break; case dbKillCursors: break; - case opReply: + case opReply: case dbMsg: log() << "unexpected op in Top::record: " << op << endl; break; @@ -108,55 +102,62 @@ namespace mongo { } - void Top::cloneMap(Top::UsageMap& out){ + void Top::collectionDropped( const string& ns ) { + //cout << "collectionDropped: " << ns << endl; + scoped_lock lk(_lock); + _usage.erase(ns); + _lastDropped = ns; + } + + void Top::cloneMap(Top::UsageMap& out) const { scoped_lock lk(_lock); out = _usage; } - void Top::append( BSONObjBuilder& b ){ + void Top::append( BSONObjBuilder& b ) { scoped_lock lk( _lock ); - append( b , _usage ); + _appendToUsageMap( b , _usage ); } - void Top::append( BSONObjBuilder& b , const char * name , const UsageData& map ){ - BSONObjBuilder bb( b.subobjStart( name ) ); - bb.appendNumber( "time" , map.time ); - bb.appendNumber( "count" , map.count ); - bb.done(); - } + void Top::_appendToUsageMap( BSONObjBuilder& b , const UsageMap& map ) const { + for ( UsageMap::const_iterator i=map.begin(); i!=map.end(); i++ ) { + BSONObjBuilder bb( b.subobjStart( i->first ) ); - void Top::append( BSONObjBuilder& b , const UsageMap& map ){ - for ( UsageMap::const_iterator i=map.begin(); i!=map.end(); i++ ){ - BSONObjBuilder bb( b.subobjStart( i->first.c_str() ) ); - const CollectionData& coll = i->second; - - append( b , "total" , coll.total ); - - append( b , "readLock" , coll.readLock ); - append( b , "writeLock" , coll.writeLock ); - - append( b , "queries" , coll.queries ); - append( b , "getmore" , coll.getmore ); - append( b , "insert" , coll.insert ); - append( b , "update" , coll.update ); - append( b , "remove" , coll.remove ); - append( b , "commands" , coll.commands ); - + + _appendStatsEntry( b , "total" , coll.total ); + + _appendStatsEntry( b , "readLock" , coll.readLock ); + _appendStatsEntry( b , "writeLock" , coll.writeLock ); + + _appendStatsEntry( b , "queries" , coll.queries ); + _appendStatsEntry( b , "getmore" , coll.getmore ); + _appendStatsEntry( b , "insert" , coll.insert ); + _appendStatsEntry( b , "update" , coll.update ); + _appendStatsEntry( b , "remove" , coll.remove ); + _appendStatsEntry( b , "commands" , coll.commands ); + bb.done(); } } + void Top::_appendStatsEntry( BSONObjBuilder& b , const char * statsName , const UsageData& map ) const { + BSONObjBuilder bb( b.subobjStart( statsName ) ); + bb.appendNumber( "time" , map.time ); + bb.appendNumber( "count" , map.count ); + bb.done(); + } + class TopCmd : public Command { public: - TopCmd() : Command( "top", true ){} + TopCmd() : Command( "top", true ) {} virtual bool slaveOk() const { return true; } virtual bool adminOnly() const { return true; } - virtual LockType locktype() const { return READ; } + virtual LockType locktype() const { return READ; } virtual void help( stringstream& help ) const { help << "usage by collection"; } - virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl){ + virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { { BSONObjBuilder b( result.subobjStart( "totals" ) ); Top::global.append( b ); @@ -164,11 +165,11 @@ namespace mongo { } return true; } - + } topCmd; Top Top::global; - + TopOld::T TopOld::_snapshotStart = TopOld::currentTime(); TopOld::D TopOld::_snapshotDuration; TopOld::UsageMap TopOld::_totalUsage; diff --git a/db/stats/top.h b/db/stats/top.h index 135e8f8..9645ed1 100644 --- a/db/stats/top.h +++ b/db/stats/top.h @@ -31,29 +31,27 @@ namespace mongo { public: Top() : _lock("Top") { } - class UsageData { - public: - UsageData() : time(0) , count(0){} + struct UsageData { + UsageData() : time(0) , count(0) {} UsageData( const UsageData& older , const UsageData& newer ); long long time; long long count; - void inc( long long micros ){ + void inc( long long micros ) { count++; time += micros; } }; - class CollectionData { - public: + struct CollectionData { /** * constructs a diff */ - CollectionData(){} + CollectionData() {} CollectionData( const CollectionData& older , const CollectionData& newer ); - + UsageData total; - + UsageData readLock; UsageData writeLock; @@ -66,25 +64,23 @@ namespace mongo { }; typedef map<string,CollectionData> UsageMap; - + public: void record( const string& ns , int op , int lockType , long long micros , bool command ); void append( BSONObjBuilder& b ); - void cloneMap(UsageMap& out); - CollectionData getGlobalData(){ return _global; } + void cloneMap(UsageMap& out) const; + CollectionData getGlobalData() const { return _global; } void collectionDropped( const string& ns ); public: // static stuff static Top global; - - void append( BSONObjBuilder& b , const char * name , const UsageData& map ); - void append( BSONObjBuilder& b , const UsageMap& map ); - + private: - + void _appendToUsageMap( BSONObjBuilder& b , const UsageMap& map ) const; + void _appendStatsEntry( BSONObjBuilder& b , const char * statsName , const UsageData& map ) const; void _record( CollectionData& c , int op , int lockType , long long micros , bool command ); - mongo::mutex _lock; + mutable mongo::mutex _lock; CollectionData _global; UsageMap _usage; string _lastDropped; @@ -99,9 +95,9 @@ namespace mongo { typedef boost::tuple< D, int, int, int > UsageData; public: TopOld() : _read(false), _write(false) { } - + /* these are used to record activity: */ - + void clientStart( const char *client ) { clientStop(); _currentStart = currentTime(); @@ -130,11 +126,11 @@ namespace mongo { /* these are used to fetch the stats: */ - struct Usage { - string ns; - D time; - double pct; - int reads, writes, calls; + struct Usage { + string ns; + D time; + double pct; + int reads, writes, calls; }; static void usage( vector< Usage > &res ) { @@ -145,7 +141,7 @@ namespace mongo { UsageMap totalUsage; fillParentNamespaces( snapshot, _snapshot ); fillParentNamespaces( totalUsage, _totalUsage ); - + multimap< D, string, more > sorted; for( UsageMap::iterator i = snapshot.begin(); i != snapshot.end(); ++i ) sorted.insert( make_pair( i->second.get<0>(), i->first ) ); @@ -181,7 +177,8 @@ namespace mongo { if ( &_snapshot == &_snapshotA ) { _snapshot = _snapshotB; _nextSnapshot = _snapshotA; - } else { + } + else { _snapshot = _snapshotA; _nextSnapshot = _snapshotB; } @@ -211,7 +208,7 @@ namespace mongo { g.get< 1 >()++; else if ( !_read && _write ) g.get< 2 >()++; - g.get< 3 >()++; + g.get< 3 >()++; } static void fillParentNamespaces( UsageMap &to, const UsageMap &from ) { for( UsageMap::const_iterator i = from.begin(); i != from.end(); ++i ) { @@ -224,8 +221,8 @@ namespace mongo { current = current.substr( 0, dot ); inc( to[ current ], i->second ); dot = current.rfind( "." ); - } - } + } + } } static void inc( UsageData &to, const UsageData &from ) { to.get<0>() += from.get<0>(); |