summaryrefslogtreecommitdiff
path: root/db/stats
diff options
context:
space:
mode:
Diffstat (limited to 'db/stats')
-rw-r--r--db/stats/counters.cpp110
-rw-r--r--db/stats/counters.h77
-rw-r--r--db/stats/fine_clock.h13
-rw-r--r--db/stats/service_stats.cpp6
-rw-r--r--db/stats/snapshots.cpp121
-rw-r--r--db/stats/snapshots.h20
-rw-r--r--db/stats/top.cpp115
-rw-r--r--db/stats/top.h57
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>();