00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #pragma once
00019
00020 #include <boost/date_time/posix_time/posix_time.hpp>
00021 #undef assert
00022 #define assert MONGO_assert
00023
00024 namespace mongo {
00025
00029 class Top {
00030
00031 public:
00032 Top() : _lock("Top") { }
00033
00034 struct UsageData {
00035 UsageData() : time(0) , count(0) {}
00036 UsageData( const UsageData& older , const UsageData& newer );
00037 long long time;
00038 long long count;
00039
00040 void inc( long long micros ) {
00041 count++;
00042 time += micros;
00043 }
00044 };
00045
00046 struct CollectionData {
00050 CollectionData() {}
00051 CollectionData( const CollectionData& older , const CollectionData& newer );
00052
00053 UsageData total;
00054
00055 UsageData readLock;
00056 UsageData writeLock;
00057
00058 UsageData queries;
00059 UsageData getmore;
00060 UsageData insert;
00061 UsageData update;
00062 UsageData remove;
00063 UsageData commands;
00064 };
00065
00066 typedef map<string,CollectionData> UsageMap;
00067
00068 public:
00069 void record( const string& ns , int op , int lockType , long long micros , bool command );
00070 void append( BSONObjBuilder& b );
00071 void cloneMap(UsageMap& out) const;
00072 CollectionData getGlobalData() const { return _global; }
00073 void collectionDropped( const string& ns );
00074
00075 public:
00076 static Top global;
00077
00078 private:
00079 void _appendToUsageMap( BSONObjBuilder& b , const UsageMap& map ) const;
00080 void _appendStatsEntry( BSONObjBuilder& b , const char * statsName , const UsageData& map ) const;
00081 void _record( CollectionData& c , int op , int lockType , long long micros , bool command );
00082
00083 mutable mongo::mutex _lock;
00084 CollectionData _global;
00085 UsageMap _usage;
00086 string _lastDropped;
00087 };
00088
00089
00090
00091
00092 class TopOld {
00093 typedef boost::posix_time::ptime T;
00094 typedef boost::posix_time::time_duration D;
00095 typedef boost::tuple< D, int, int, int > UsageData;
00096 public:
00097 TopOld() : _read(false), _write(false) { }
00098
00099
00100
00101 void clientStart( const char *client ) {
00102 clientStop();
00103 _currentStart = currentTime();
00104 _current = client;
00105 }
00106
00107
00108 void setRead() { _read = true; }
00109
00110 void setWrite() { _write = true; }
00111
00112 void clientStop() {
00113 if ( _currentStart == T() )
00114 return;
00115 D d = currentTime() - _currentStart;
00116
00117 {
00118 scoped_lock L(topMutex);
00119 recordUsage( _current, d );
00120 }
00121
00122 _currentStart = T();
00123 _read = false;
00124 _write = false;
00125 }
00126
00127
00128
00129 struct Usage {
00130 string ns;
00131 D time;
00132 double pct;
00133 int reads, writes, calls;
00134 };
00135
00136 static void usage( vector< Usage > &res ) {
00137 scoped_lock L(topMutex);
00138
00139
00140 UsageMap snapshot;
00141 UsageMap totalUsage;
00142 fillParentNamespaces( snapshot, _snapshot );
00143 fillParentNamespaces( totalUsage, _totalUsage );
00144
00145 multimap< D, string, more > sorted;
00146 for( UsageMap::iterator i = snapshot.begin(); i != snapshot.end(); ++i )
00147 sorted.insert( make_pair( i->second.get<0>(), i->first ) );
00148 for( multimap< D, string, more >::iterator i = sorted.begin(); i != sorted.end(); ++i ) {
00149 if ( trivialNs( i->second.c_str() ) )
00150 continue;
00151 Usage u;
00152 u.ns = i->second;
00153 u.time = totalUsage[ u.ns ].get<0>();
00154 u.pct = _snapshotDuration != D() ? 100.0 * i->first.ticks() / _snapshotDuration.ticks() : 0;
00155 u.reads = snapshot[ u.ns ].get<1>();
00156 u.writes = snapshot[ u.ns ].get<2>();
00157 u.calls = snapshot[ u.ns ].get<3>();
00158 res.push_back( u );
00159 }
00160 for( UsageMap::iterator i = totalUsage.begin(); i != totalUsage.end(); ++i ) {
00161 if ( snapshot.count( i->first ) != 0 || trivialNs( i->first.c_str() ) )
00162 continue;
00163 Usage u;
00164 u.ns = i->first;
00165 u.time = i->second.get<0>();
00166 u.pct = 0;
00167 u.reads = 0;
00168 u.writes = 0;
00169 u.calls = 0;
00170 res.push_back( u );
00171 }
00172 }
00173
00174 static void completeSnapshot() {
00175 scoped_lock L(topMutex);
00176
00177 if ( &_snapshot == &_snapshotA ) {
00178 _snapshot = _snapshotB;
00179 _nextSnapshot = _snapshotA;
00180 }
00181 else {
00182 _snapshot = _snapshotA;
00183 _nextSnapshot = _snapshotB;
00184 }
00185 _snapshotDuration = currentTime() - _snapshotStart;
00186 _snapshotStart = currentTime();
00187 _nextSnapshot.clear();
00188 }
00189
00190 private:
00191 static mongo::mutex topMutex;
00192 static bool trivialNs( const char *ns ) {
00193 const char *ret = strrchr( ns, '.' );
00194 return ret && ret[ 1 ] == '\0';
00195 }
00196 typedef map<string,UsageData> UsageMap;
00197 static T currentTime() {
00198 return boost::posix_time::microsec_clock::universal_time();
00199 }
00200 void recordUsage( const string &client, D duration ) {
00201 recordUsageForMap( _totalUsage, client, duration );
00202 recordUsageForMap( _nextSnapshot, client, duration );
00203 }
00204 void recordUsageForMap( UsageMap &map, const string &client, D duration ) {
00205 UsageData& g = map[client];
00206 g.get< 0 >() += duration;
00207 if ( _read && !_write )
00208 g.get< 1 >()++;
00209 else if ( !_read && _write )
00210 g.get< 2 >()++;
00211 g.get< 3 >()++;
00212 }
00213 static void fillParentNamespaces( UsageMap &to, const UsageMap &from ) {
00214 for( UsageMap::const_iterator i = from.begin(); i != from.end(); ++i ) {
00215 string current = i->first;
00216 size_t dot = current.rfind( "." );
00217 if ( dot == string::npos || dot != current.length() - 1 ) {
00218 inc( to[ current ], i->second );
00219 }
00220 while( dot != string::npos ) {
00221 current = current.substr( 0, dot );
00222 inc( to[ current ], i->second );
00223 dot = current.rfind( "." );
00224 }
00225 }
00226 }
00227 static void inc( UsageData &to, const UsageData &from ) {
00228 to.get<0>() += from.get<0>();
00229 to.get<1>() += from.get<1>();
00230 to.get<2>() += from.get<2>();
00231 to.get<3>() += from.get<3>();
00232 }
00233 struct more { bool operator()( const D &a, const D &b ) { return a > b; } };
00234 string _current;
00235 T _currentStart;
00236 static T _snapshotStart;
00237 static D _snapshotDuration;
00238 static UsageMap _totalUsage;
00239 static UsageMap _snapshotA;
00240 static UsageMap _snapshotB;
00241 static UsageMap &_snapshot;
00242 static UsageMap &_nextSnapshot;
00243 bool _read;
00244 bool _write;
00245 };
00246
00247 }