summaryrefslogtreecommitdiff
path: root/src/mongo/db/stats/snapshots.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/stats/snapshots.cpp')
-rw-r--r--src/mongo/db/stats/snapshots.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/mongo/db/stats/snapshots.cpp b/src/mongo/db/stats/snapshots.cpp
new file mode 100644
index 00000000000..900cc4ff1ad
--- /dev/null
+++ b/src/mongo/db/stats/snapshots.cpp
@@ -0,0 +1,227 @@
+// snapshots.cpp
+
+/**
+* Copyright (C) 2008 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 "snapshots.h"
+#include "../client.h"
+#include "../clientcursor.h"
+#include "../dbwebserver.h"
+#include "../../util/mongoutils/html.h"
+
+/**
+ handles snapshotting performance metrics and other such things
+ */
+namespace mongo {
+
+ void SnapshotData::takeSnapshot() {
+ _created = curTimeMicros64();
+ _globalUsage = Top::global.getGlobalData();
+// _totalWriteLockedTime = d.dbMutex.info().getTimeLocked();
+ Top::global.cloneMap(_usage);
+ }
+
+ SnapshotDelta::SnapshotDelta( const SnapshotData& older , const SnapshotData& newer )
+ : _older( older ) , _newer( newer ) {
+ assert( _newer._created > _older._created );
+ _elapsed = _newer._created - _older._created;
+ }
+
+ Top::CollectionData SnapshotDelta::globalUsageDiff() {
+ return Top::CollectionData( _older._globalUsage , _newer._globalUsage );
+ }
+ Top::UsageMap SnapshotDelta::collectionUsageDiff() {
+ assert( _newer._created > _older._created );
+ Top::UsageMap u;
+
+ 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 );
+ else
+ u[i->first] = i->second;
+ }
+ return u;
+ }
+
+ Snapshots::Snapshots(int n)
+ : _lock("Snapshots"), _n(n)
+ , _snapshots(new SnapshotData[n])
+ , _loc(0)
+ , _stored(0)
+ {}
+
+ const SnapshotData* Snapshots::takeSnapshot() {
+ scoped_lock lk(_lock);
+ _loc = ( _loc + 1 ) % _n;
+ _snapshots[_loc].takeSnapshot();
+ if ( _stored < _n )
+ _stored++;
+ return &_snapshots[_loc];
+ }
+
+ auto_ptr<SnapshotDelta> Snapshots::computeDelta( int numBack ) {
+ scoped_lock lk(_lock);
+ auto_ptr<SnapshotDelta> p;
+ if ( numBack < numDeltas() )
+ p.reset( new SnapshotDelta( getPrev(numBack+1) , getPrev(numBack) ) );
+ return p;
+ }
+
+ const SnapshotData& Snapshots::getPrev( int numBack ) {
+ int x = _loc - numBack;
+ if ( x < 0 )
+ x += _n;
+ return _snapshots[x];
+ }
+
+ void Snapshots::outputLockInfoHTML( stringstream& ss ) {
+ scoped_lock lk(_lock);
+ ss << "\n<div>";
+ 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 )
+ ss << '(' << e / 1000.0 << "s)";
+ ss << ' ';
+ }
+ ss << "</div>\n";
+ }
+
+ void SnapshotThread::run() {
+ Client::initThread("snapshotthread");
+ Client& client = cc();
+
+ long long numLoops = 0;
+
+ const SnapshotData* prev = 0;
+
+ while ( ! inShutdown() ) {
+ try {
+ const SnapshotData* s = statsSnapshots.takeSnapshot();
+
+ if ( prev && cmdLine.cpu ) {
+ unsigned long long elapsed = s->_created - prev->_created;
+ SnapshotDelta d( *prev , *s );
+ log() << "cpu: elapsed:" << (elapsed/1000) <<" writelock: " << (int)(100*d.percentWriteLocked()) << "%" << endl;
+ }
+
+ prev = s;
+ }
+ catch ( std::exception& e ) {
+ log() << "ERROR in SnapshotThread: " << e.what() << endl;
+ }
+
+ numLoops++;
+ sleepsecs(4);
+ }
+
+ client.shutdown();
+ }
+
+ using namespace mongoutils::html;
+
+ class WriteLockStatus : public WebStatusPlugin {
+ public:
+ WriteLockStatus() : WebStatusPlugin( "write lock" , 51 , "% time in write lock, by 4 sec periods" ) {}
+ virtual void init() {}
+
+ 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?\">";
+ ss << "write locked now:</a> " << (d.dbMutex.info().isLocked() ? "true" : "false") << "\n";
+ }
+
+ } writeLockStatus;
+
+ class DBTopStatus : public WebStatusPlugin {
+ public:
+ DBTopStatus() : WebStatusPlugin( "dbtop" , 50 , "(occurrences|percent of elapsed)" ) {}
+
+ 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;
+ 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 != "TOTAL" && data.total.count == 0 )
+ return;
+ ss << "<tr><th>" << ns << "</th>";
+
+ display( ss , elapsed , data.total );
+
+ display( ss , elapsed , data.readLock );
+ display( ss , elapsed , data.writeLock );
+
+ display( ss , elapsed , data.queries );
+ display( ss , elapsed , data.getmore );
+ display( ss , elapsed , data.insert );
+ display( ss , elapsed , data.update );
+ display( ss , elapsed , data.remove );
+
+ ss << "</tr>\n";
+ }
+
+ 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 << "</tr>\n";
+
+ display( ss , (double) delta->elapsed() , "TOTAL" , delta->globalUsageDiff() );
+
+ Top::UsageMap usage = delta->collectionUsageDiff();
+ 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() {}
+ } dbtopStatus;
+
+ Snapshots statsSnapshots;
+ SnapshotThread snapshotThread;
+
+}