summaryrefslogtreecommitdiff
path: root/src/mongo/db/curop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/curop.cpp')
-rw-r--r--src/mongo/db/curop.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp
new file mode 100644
index 00000000000..4658150dbfa
--- /dev/null
+++ b/src/mongo/db/curop.cpp
@@ -0,0 +1,207 @@
+/**
+* Copyright (C) 2009 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 "curop.h"
+#include "database.h"
+
+namespace mongo {
+
+ // todo : move more here
+
+ CurOp::CurOp( Client * client , CurOp * wrapped ) :
+ _client(client),
+ _wrapped(wrapped)
+ {
+ if ( _wrapped )
+ _client->_curOp = this;
+ _start = 0;
+ _active = false;
+ _reset();
+ _op = 0;
+ // These addresses should never be written to again. The zeroes are
+ // placed here as a precaution because currentOp may be accessed
+ // without the db mutex.
+ memset(_ns, 0, sizeof(_ns));
+ }
+
+ void CurOp::_reset() {
+ _suppressFromCurop = false;
+ _command = false;
+ _dbprofile = 0;
+ _end = 0;
+ _message = "";
+ _progressMeter.finished();
+ _killed = false;
+ _numYields = 0;
+ _expectedLatencyMs = 0;
+ _lockStat.reset();
+ }
+
+ void CurOp::reset() {
+ _reset();
+ _start = 0;
+ _opNum = _nextOpNum++;
+ _ns[0] = 0;
+ _debug.reset();
+ _query.reset();
+ _active = true; // this should be last for ui clarity
+ }
+
+ void CurOp::reset( const HostAndPort& remote, int op ) {
+ reset();
+ if( _remote != remote ) {
+ // todo : _remote is not thread safe yet is used as such!
+ _remote = remote;
+ }
+ _op = op;
+ }
+
+ ProgressMeter& CurOp::setMessage( const char * msg , unsigned long long progressMeterTotal , int secondsBetween ) {
+ if ( progressMeterTotal ) {
+ if ( _progressMeter.isActive() ) {
+ cout << "about to assert, old _message: " << _message << " new message:" << msg << endl;
+ verify( ! _progressMeter.isActive() );
+ }
+ _progressMeter.reset( progressMeterTotal , secondsBetween );
+ }
+ else {
+ _progressMeter.finished();
+ }
+ _message = msg;
+ return _progressMeter;
+ }
+
+
+ BSONObj CurOp::info() {
+ if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) {
+ BSONObjBuilder b;
+ b.append("err", "unauthorized");
+ return b.obj();
+ }
+ return infoNoauth();
+ }
+
+ CurOp::~CurOp() {
+ if ( _wrapped ) {
+ scoped_lock bl(Client::clientsMutex);
+ _client->_curOp = _wrapped;
+ }
+ _client = 0;
+ }
+
+ void CurOp::ensureStarted() {
+ if ( _start == 0 )
+ _start = curTimeMicros64();
+ }
+
+ void CurOp::enter( Client::Context * context ) {
+ ensureStarted();
+
+ strncpy( _ns, context->ns(), Namespace::MaxNsLen);
+ _ns[Namespace::MaxNsLen] = 0;
+
+ _dbprofile = std::max( context->_db ? context->_db->profile : 0 , _dbprofile );
+ }
+
+ void CurOp::leave( Client::Context * context ) {
+ }
+
+ void CurOp::recordGlobalTime( long long micros ) const {
+ if ( _client ) {
+ const LockState& ls = _client->lockState();
+ verify( ls.threadState() );
+ Top::global.record( _ns , _op , ls.hasAnyWriteLock() ? 1 : -1 , micros , _command );
+ }
+ }
+
+ BSONObj CurOp::infoNoauth() {
+ BSONObjBuilder b;
+ b.append("opid", _opNum);
+ bool a = _active && _start;
+ b.append("active", a);
+
+ if( a ) {
+ b.append("secs_running", elapsedSeconds() );
+ }
+
+ b.append( "op" , opToString( _op ) );
+
+ b.append("ns", _ns);
+
+ _query.append( b , "query" );
+
+ if( !_remote.empty() ) {
+ b.append("client", _remote.toString());
+ }
+
+ if ( _client ) {
+ b.append( "desc" , _client->desc() );
+ if ( _client->_threadId.size() )
+ b.append( "threadId" , _client->_threadId );
+ if ( _client->_connectionId )
+ b.appendNumber( "connectionId" , _client->_connectionId );
+ _client->_ls.reportState(b);
+ }
+
+ if ( ! _message.empty() ) {
+ if ( _progressMeter.isActive() ) {
+ StringBuilder buf;
+ buf << _message.toString() << " " << _progressMeter.toString();
+ b.append( "msg" , buf.str() );
+ BSONObjBuilder sub( b.subobjStart( "progress" ) );
+ sub.appendNumber( "done" , (long long)_progressMeter.done() );
+ sub.appendNumber( "total" , (long long)_progressMeter.total() );
+ sub.done();
+ }
+ else {
+ b.append( "msg" , _message.toString() );
+ }
+ }
+
+ if( killed() )
+ b.append("killed", true);
+
+ b.append( "numYields" , _numYields );
+ b.append( "lockStats" , _lockStat.report() );
+
+ return b.obj();
+ }
+
+ void KillCurrentOp::checkForInterrupt( bool heedMutex ) {
+ Client& c = cc();
+ if ( heedMutex && Lock::somethingWriteLocked() && c.hasWrittenThisPass() )
+ return;
+ if( _globalKill )
+ uasserted(11600,"interrupted at shutdown");
+ if( c.curop()->killed() ) {
+ uasserted(11601,"operation was interrupted");
+ }
+ }
+
+ const char * KillCurrentOp::checkForInterruptNoAssert() {
+ Client& c = cc();
+ if( _globalKill )
+ return "interrupted at shutdown";
+ if( c.curop()->killed() )
+ return "interrupted";
+ return "";
+ }
+
+
+ AtomicUInt CurOp::_nextOpNum;
+
+}