diff options
Diffstat (limited to 'src/mongo/db/stats/top.cpp')
-rw-r--r-- | src/mongo/db/stats/top.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/mongo/db/stats/top.cpp b/src/mongo/db/stats/top.cpp new file mode 100644 index 00000000000..f5b6ee42f1c --- /dev/null +++ b/src/mongo/db/stats/top.cpp @@ -0,0 +1,183 @@ +// top.cpp +/* + * Copyright (C) 2010 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "pch.h" +#include "top.h" +#include "../../util/net/message.h" +#include "../commands.h" + +namespace mongo { + + 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 ) , + readLock( older.readLock , newer.readLock ) , + writeLock( older.writeLock , newer.writeLock ) , + queries( older.queries , newer.queries ) , + getmore( older.getmore , newer.getmore ) , + insert( older.insert , newer.insert ) , + update( older.update , newer.update ) , + remove( older.remove , newer.remove ), + commands( older.commands , newer.commands ) { + + } + + 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 ) { + _lastDropped = ""; + return; + } + + CollectionData& coll = _usage[ns]; + _record( coll , op , lockType , micros , command ); + _record( _global , op , lockType , micros , 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 ) { + case 0: + // use 0 for unknown, non-specific + break; + case dbUpdate: + c.update.inc( micros ); + break; + case dbInsert: + c.insert.inc( micros ); + break; + case dbQuery: + if ( command ) + c.commands.inc( micros ); + else + c.queries.inc( micros ); + break; + case dbGetMore: + c.getmore.inc( micros ); + break; + case dbDelete: + c.remove.inc( micros ); + break; + case dbKillCursors: + break; + case opReply: + case dbMsg: + log() << "unexpected op in Top::record: " << op << endl; + break; + default: + log() << "unknown op in Top::record: " << op << endl; + } + + } + + 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 ) { + scoped_lock lk( _lock ); + _appendToUsageMap( b , _usage ); + } + + 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 ) ); + + const CollectionData& coll = i->second; + + _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 ) {} + + virtual bool slaveOk() const { return true; } + virtual bool adminOnly() const { return true; } + virtual LockType locktype() const { return READ; } + virtual void help( stringstream& help ) const { help << "usage by collection, in micros "; } + + virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + { + BSONObjBuilder b( result.subobjStart( "totals" ) ); + b.append( "note" , "all times in microseconds" ); + Top::global.append( b ); + b.done(); + } + return true; + } + + } topCmd; + + Top Top::global; + + TopOld::T TopOld::_snapshotStart = TopOld::currentTime(); + TopOld::D TopOld::_snapshotDuration; + TopOld::UsageMap TopOld::_totalUsage; + TopOld::UsageMap TopOld::_snapshotA; + TopOld::UsageMap TopOld::_snapshotB; + TopOld::UsageMap &TopOld::_snapshot = TopOld::_snapshotA; + TopOld::UsageMap &TopOld::_nextSnapshot = TopOld::_snapshotB; + mongo::mutex TopOld::topMutex("topMutex"); + + +} |