// 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 . */ #include "stdafx.h" #include "snapshots.h" #include "../client.h" #include "../clientcursor.h" /** handles snapshotting performance metrics and other such things */ namespace mongo { SnapshotData::SnapshotData() : _created ( curTimeMicros64() ) , _globalUsage( Top::global.getGlobalData() ) { _totalWriteLockedTime = dbMutex.info().getTimeLocked(); _usage = Top::global.cloneMap(); } SnapshotDelta::SnapshotDelta( SnapshotData * older , 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(){ Top::UsageMap u; for ( Top::UsageMap::iterator i=_newer->_usage.begin(); i != _newer->_usage.end(); i++ ){ u[i->first] = Top::CollectionData( _older->_usage[i->first] , i->second ); } return u; } Snapshots::Snapshots(){ _n = 100; _snapshots = new SnapshotData*[_n]; for ( int i=0; i<_n; i++ ) _snapshots[i] = 0; _loc = 0; _stored = 0; } void Snapshots::add( SnapshotData * s ){ boostlock lk(_lock); _loc = ( _loc + 1 ) % _n; _snapshots[_loc] = s; if ( _stored < _n ) _stored++; } auto_ptr Snapshots::computeDelta( int numBack ){ boostlock lk(_lock); auto_ptr p; if ( numBack < numDeltas() ) p.reset( new SnapshotDelta( getPrev(numBack+1) , getPrev(numBack) ) ); return p; } SnapshotData* Snapshots::getPrev( int numBack ){ int x = _loc - numBack; if ( x < 0 ) x += _n; return _snapshots[x]; } void Snapshots::outputLockInfoHTML( stringstream& ss ){ boostlock lk(_lock); ss << "\n"; ss << "\n"; for ( int i=0; i" << "" << "" << "" ; } ss << "
elapsed(ms)% write locked
" << ( d.elapsed() / 1000 ) << "" << (unsigned)(100*d.percentWriteLocked()) << "%
\n"; } void SnapshotThread::run(){ Client::initThread("snapshotthread"); Client& client = cc(); long long numLoops = 0; SnapshotData * prev = 0; while ( ! inShutdown() ){ try { SnapshotData * s = new SnapshotData(); statsSnapshots.add( s ); if ( prev ){ unsigned long long elapsed = s->_created - prev->_created; if ( cmdLine.cpu ){ SnapshotDelta d( prev , s ); log() << "cpu: elapsed:" << (elapsed/1000) <<" writelock: " << (int)(100*d.percentWriteLocked()) << "%" << endl; } // TODO: this should really be somewhere else, like in a special ClientCursor thread ClientCursor::idleTimeReport( (unsigned)(elapsed/1000) ); } prev = s; } catch ( std::exception& e ){ log() << "ERROR in SnapshotThread: " << e.what() << endl; } numLoops++; sleepsecs(4); } client.shutdown(); } Snapshots statsSnapshots; SnapshotThread snapshotThread; }