summaryrefslogtreecommitdiff
path: root/src/mongo/db/stats/top.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/stats/top.cpp')
-rw-r--r--src/mongo/db/stats/top.cpp183
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");
+
+
+}