diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2015-06-20 00:22:50 -0400 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2015-06-20 10:56:02 -0400 |
commit | 9c2ed42daa8fbbef4a919c21ec564e2db55e8d60 (patch) | |
tree | 3814f79c10d7b490948d8cb7b112ac1dd41ceff1 /src/mongo/db/curop.h | |
parent | 01965cf52bce6976637ecb8f4a622aeb05ab256a (diff) | |
download | mongo-9c2ed42daa8fbbef4a919c21ec564e2db55e8d60.tar.gz |
SERVER-18579: Clang-Format - reformat code, no comment reflow
Diffstat (limited to 'src/mongo/db/curop.h')
-rw-r--r-- | src/mongo/db/curop.h | 789 |
1 files changed, 422 insertions, 367 deletions
diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h index e8467f507b8..e223d888386 100644 --- a/src/mongo/db/curop.h +++ b/src/mongo/db/curop.h @@ -42,417 +42,472 @@ namespace mongo { - class Client; - class Command; - class CurOp; - class OperationContext; +class Client; +class Command; +class CurOp; +class OperationContext; + +/** + * stores a copy of a bson obj in a fixed size buffer + * if its too big for the buffer, says "too big" + * useful for keeping a copy around indefinitely without wasting a lot of space or doing malloc + */ +class CachedBSONObjBase { +public: + static BSONObj _tooBig; // { $msg : "query not recording (too large)" } +}; + +template <size_t BUFFER_SIZE> +class CachedBSONObj : public CachedBSONObjBase { +public: + enum { TOO_BIG_SENTINEL = 1 }; + + CachedBSONObj() { + _size = (int*)_buf; + reset(); + } + + void reset(int sz = 0) { + _lock.lock(); + _reset(sz); + _lock.unlock(); + } + + void set(const BSONObj& o) { + scoped_spinlock lk(_lock); + size_t sz = o.objsize(); + if (sz > sizeof(_buf)) { + _reset(TOO_BIG_SENTINEL); + } else { + memcpy(_buf, o.objdata(), sz); + } + } + + int size() const { + return *_size; + } + bool have() const { + return size() > 0; + } + bool tooBig() const { + return size() == TOO_BIG_SENTINEL; + } + + BSONObj get() const { + scoped_spinlock lk(_lock); + return _get(); + } + + void append(BSONObjBuilder& b, StringData name) const { + scoped_spinlock lk(_lock); + BSONObj temp = _get(); + b.append(name, temp); + } + +private: + /** you have to be locked when you call this */ + BSONObj _get() const { + int sz = size(); + if (sz == 0) + return BSONObj(); + if (sz == TOO_BIG_SENTINEL) + return _tooBig; + return BSONObj(_buf).copy(); + } + + /** you have to be locked when you call this */ + void _reset(int sz) { + _size[0] = sz; + } + + mutable SpinLock _lock; + int* _size; + char _buf[BUFFER_SIZE]; +}; + +/* lifespan is different than CurOp because of recursives with DBDirectClient */ +class OpDebug { +public: + OpDebug() : planSummary(2048) { + reset(); + } + + void reset(); + + std::string report(const CurOp& curop, const SingleThreadedLockStats& lockStats) const; /** - * stores a copy of a bson obj in a fixed size buffer - * if its too big for the buffer, says "too big" - * useful for keeping a copy around indefinitely without wasting a lot of space or doing malloc + * Appends information about the current operation to "builder" + * + * @param curop reference to the CurOp that owns this OpDebug + * @param lockStats lockStats object containing locking information about the operation */ - class CachedBSONObjBase { - public: - static BSONObj _tooBig; // { $msg : "query not recording (too large)" } - }; - - template <size_t BUFFER_SIZE> - class CachedBSONObj : public CachedBSONObjBase { - public: - enum { TOO_BIG_SENTINEL = 1 } ; - - CachedBSONObj() { - _size = (int*)_buf; - reset(); - } - - void reset( int sz = 0 ) { - _lock.lock(); - _reset( sz ); - _lock.unlock(); - } - - void set( const BSONObj& o ) { - scoped_spinlock lk(_lock); - size_t sz = o.objsize(); - if ( sz > sizeof(_buf) ) { - _reset(TOO_BIG_SENTINEL); - } - else { - memcpy(_buf, o.objdata(), sz ); - } - } + void append(const CurOp& curop, + const SingleThreadedLockStats& lockStats, + BSONObjBuilder& builder) const; + + // ------------------- + + StringBuilder extra; // weird things we need to fix later + + // basic options + int op; + bool iscommand; + std::string ns; + BSONObj query; + BSONObj updateobj; + + // detailed options + long long cursorid; + int ntoreturn; + int ntoskip; + bool exhaust; + + // debugging/profile info + long long nscanned; + long long nscannedObjects; + bool idhack; // indicates short circuited code path on an update to make the update faster + bool scanAndOrder; // scanandorder query plan aspect was used + long long nMatched; // number of records that match the query + long long nModified; // number of records written (no no-ops) + long long nmoved; // updates resulted in a move (moves are expensive) + long long ninserted; + long long ndeleted; + bool fastmod; + bool fastmodinsert; // upsert of an $operation. builds a default object + bool upsert; // true if the update actually did an insert + bool cursorExhausted; // true if the cursor has been closed at end a find/getMore operation + int keyUpdates; + long long writeConflicts; + ThreadSafeString planSummary; // a brief std::string describing the query solution + + // New Query Framework debugging/profiling info + // TODO: should this really be an opaque BSONObj? Not sure. + CachedBSONObj<4096> execStats; + + // error handling + ExceptionInfo exceptionInfo; + + // response info + int executionTime; + int nreturned; + int responseLength; +}; + +/** + * Container for data used to report information about an OperationContext. + * + * Every OperationContext in a server with CurOp support has a stack of CurOp + * objects. The entry at the top of the stack is used to record timing and + * resource statistics for the executing operation or suboperation. + * + * All of the accessor methods on CurOp may be called by the thread executing + * the associated OperationContext at any time, or by other threads that have + * locked the context's owning Client object. + * + * The mutator methods on CurOp whose names end _inlock may only be called by the thread + * executing the associated OperationContext and Client, and only when that thread has also + * locked the Client object. All other mutators may only be called by the thread executing + * CurOp, but do not require holding the Client lock. The exception to this is the kill() + * method, which is self-synchronizing. + * + * The OpDebug member of a CurOp, accessed via the debug() accessor should *only* be accessed + * from the thread executing an operation, and as a result its fields may be accessed without + * any synchronization. + */ +class CurOp { + MONGO_DISALLOW_COPYING(CurOp); - int size() const { return *_size; } - bool have() const { return size() > 0; } - bool tooBig() const { return size() == TOO_BIG_SENTINEL; } +public: + static CurOp* get(const OperationContext* opCtx); + static CurOp* get(const OperationContext& opCtx); - BSONObj get() const { - scoped_spinlock lk(_lock); - return _get(); - } + /** + * Constructs a nested CurOp at the top of the given "opCtx"'s CurOp stack. + */ + explicit CurOp(OperationContext* opCtx); + ~CurOp(); - void append( BSONObjBuilder& b , StringData name ) const { - scoped_spinlock lk(_lock); - BSONObj temp = _get(); - b.append( name , temp ); - } + bool haveQuery() const { + return _query.have(); + } + BSONObj query() const { + return _query.get(); + } + void appendQuery(BSONObjBuilder& b, StringData name) const { + _query.append(b, name); + } - private: - /** you have to be locked when you call this */ - BSONObj _get() const { - int sz = size(); - if ( sz == 0 ) - return BSONObj(); - if ( sz == TOO_BIG_SENTINEL ) - return _tooBig; - return BSONObj( _buf ).copy(); - } + void enter_inlock(const char* ns, int dbProfileLevel); - /** you have to be locked when you call this */ - void _reset( int sz ) { _size[0] = sz; } + /** + * Sets the type of the current operation to "op". + */ + void setOp_inlock(int op); - mutable SpinLock _lock; - int * _size; - char _buf[BUFFER_SIZE]; - }; + /** + * Marks the current operation as being a command. + */ + void markCommand_inlock() { + _isCommand = true; + } - /* lifespan is different than CurOp because of recursives with DBDirectClient */ - class OpDebug { - public: - OpDebug() : planSummary(2048) { reset(); } + /** + * Returns a structure containing data used for profiling, accessed only by a thread + * currently executing the operation context associated with this CurOp. + */ + OpDebug& debug() { + return _debug; + } - void reset(); + /** + * Gets the name of the namespace on which the current operation operates. + */ + std::string getNS() const { + return _ns; + } - std::string report(const CurOp& curop, const SingleThreadedLockStats& lockStats) const; + bool shouldDBProfile(int ms) const { + if (_dbprofile <= 0) + return false; - /** - * Appends information about the current operation to "builder" - * - * @param curop reference to the CurOp that owns this OpDebug - * @param lockStats lockStats object containing locking information about the operation - */ - void append(const CurOp& curop, - const SingleThreadedLockStats& lockStats, - BSONObjBuilder& builder) const; - - // ------------------- - - StringBuilder extra; // weird things we need to fix later - - // basic options - int op; - bool iscommand; - std::string ns; - BSONObj query; - BSONObj updateobj; - - // detailed options - long long cursorid; - int ntoreturn; - int ntoskip; - bool exhaust; - - // debugging/profile info - long long nscanned; - long long nscannedObjects; - bool idhack; // indicates short circuited code path on an update to make the update faster - bool scanAndOrder; // scanandorder query plan aspect was used - long long nMatched; // number of records that match the query - long long nModified; // number of records written (no no-ops) - long long nmoved; // updates resulted in a move (moves are expensive) - long long ninserted; - long long ndeleted; - bool fastmod; - bool fastmodinsert; // upsert of an $operation. builds a default object - bool upsert; // true if the update actually did an insert - bool cursorExhausted; // true if the cursor has been closed at end a find/getMore operation - int keyUpdates; - long long writeConflicts; - ThreadSafeString planSummary; // a brief std::string describing the query solution - - // New Query Framework debugging/profiling info - // TODO: should this really be an opaque BSONObj? Not sure. - CachedBSONObj<4096> execStats; - - // error handling - ExceptionInfo exceptionInfo; - - // response info - int executionTime; - int nreturned; - int responseLength; - }; + return _dbprofile >= 2 || ms >= serverGlobalParams.slowMS; + } /** - * Container for data used to report information about an OperationContext. - * - * Every OperationContext in a server with CurOp support has a stack of CurOp - * objects. The entry at the top of the stack is used to record timing and - * resource statistics for the executing operation or suboperation. + * Raises the profiling level for this operation to "dbProfileLevel" if it was previously + * less than "dbProfileLevel". * - * All of the accessor methods on CurOp may be called by the thread executing - * the associated OperationContext at any time, or by other threads that have - * locked the context's owning Client object. - * - * The mutator methods on CurOp whose names end _inlock may only be called by the thread - * executing the associated OperationContext and Client, and only when that thread has also - * locked the Client object. All other mutators may only be called by the thread executing - * CurOp, but do not require holding the Client lock. The exception to this is the kill() - * method, which is self-synchronizing. - * - * The OpDebug member of a CurOp, accessed via the debug() accessor should *only* be accessed - * from the thread executing an operation, and as a result its fields may be accessed without - * any synchronization. + * This belongs on OpDebug, and so does not have the _inlock suffix. */ - class CurOp { - MONGO_DISALLOW_COPYING(CurOp); - public: - static CurOp* get(const OperationContext* opCtx); - static CurOp* get(const OperationContext& opCtx); - - /** - * Constructs a nested CurOp at the top of the given "opCtx"'s CurOp stack. - */ - explicit CurOp(OperationContext* opCtx); - ~CurOp(); - - bool haveQuery() const { return _query.have(); } - BSONObj query() const { return _query.get(); } - void appendQuery( BSONObjBuilder& b , StringData name ) const { _query.append( b , name ); } + void raiseDbProfileLevel(int dbProfileLevel); - void enter_inlock(const char* ns, int dbProfileLevel); - - /** - * Sets the type of the current operation to "op". - */ - void setOp_inlock(int op); - - /** - * Marks the current operation as being a command. - */ - void markCommand_inlock() { _isCommand = true; } + /** + * Gets the type of the current operation. + */ + int getOp() const { + return _op; + } - /** - * Returns a structure containing data used for profiling, accessed only by a thread - * currently executing the operation context associated with this CurOp. - */ - OpDebug& debug() { return _debug; } + /** + * Returns true if the current operation is known to be a command. + */ + bool isCommand() const { + return _isCommand; + } - /** - * Gets the name of the namespace on which the current operation operates. - */ - std::string getNS() const { return _ns; } + // + // Methods for controlling CurOp "max time". + // - bool shouldDBProfile( int ms ) const { - if ( _dbprofile <= 0 ) - return false; + /** + * Sets the amount of time operation this should be allowed to run, units of microseconds. + * The special value 0 is "allow to run indefinitely". + */ + void setMaxTimeMicros(uint64_t maxTimeMicros); - return _dbprofile >= 2 || ms >= serverGlobalParams.slowMS; - } + /** + * Returns true if a time limit has been set on this operation, and false otherwise. + */ + bool isMaxTimeSet() const; - /** - * Raises the profiling level for this operation to "dbProfileLevel" if it was previously - * less than "dbProfileLevel". - * - * This belongs on OpDebug, and so does not have the _inlock suffix. - */ - void raiseDbProfileLevel(int dbProfileLevel); + /** + * Checks whether this operation has been running longer than its time limit. Returns + * false if not, or if the operation has no time limit. + */ + bool maxTimeHasExpired(); - /** - * Gets the type of the current operation. - */ - int getOp() const { return _op; } + /** + * Returns the number of microseconds remaining for this operation's time limit, or the + * special value 0 if the operation has no time limit. + * + * Calling this method is more expensive than calling its sibling "maxTimeHasExpired()", + * since an accurate measure of remaining time needs to be calculated. + */ + uint64_t getRemainingMaxTimeMicros() const; + + // + // Methods for getting/setting elapsed time. + // + + void ensureStarted(); + bool isStarted() const { + return _start > 0; + } + long long startTime() { // micros + ensureStarted(); + return _start; + } + void done() { + _end = curTimeMicros64(); + } + + long long totalTimeMicros() { + massert(12601, "CurOp not marked done yet", _end); + return _end - startTime(); + } + int totalTimeMillis() { + return (int)(totalTimeMicros() / 1000); + } + long long elapsedMicros() { + return curTimeMicros64() - startTime(); + } + int elapsedMillis() { + return (int)(elapsedMicros() / 1000); + } + int elapsedSeconds() { + return elapsedMillis() / 1000; + } + + void setQuery_inlock(const BSONObj& query) { + _query.set(query); + } + + Command* getCommand() const { + return _command; + } + void setCommand_inlock(Command* command) { + _command = command; + } - /** - * Returns true if the current operation is known to be a command. - */ - bool isCommand() const { return _isCommand; } + /** + * Appends information about this CurOp to "builder". + * + * If called from a thread other than the one executing the operation associated with this + * CurOp, it is necessary to lock the associated Client object before executing this method. + */ + void reportState(BSONObjBuilder* builder); - // - // Methods for controlling CurOp "max time". - // + /** + * Sets the message and the progress meter for this CurOp. + * + * While it is necessary to hold the lock while this method executes, the + * "hit" and "finished" methods of ProgressMeter may be called safely from + * the thread executing the operation without locking the Client. + */ + ProgressMeter& setMessage_inlock(const char* msg, + std::string name = "Progress", + unsigned long long progressMeterTotal = 0, + int secondsBetween = 3); - /** - * Sets the amount of time operation this should be allowed to run, units of microseconds. - * The special value 0 is "allow to run indefinitely". - */ - void setMaxTimeMicros(uint64_t maxTimeMicros); + /** + * Gets the message for this CurOp. + */ + const std::string& getMessage() const { + return _message; + } + const ProgressMeter& getProgressMeter() { + return _progressMeter; + } + CurOp* parent() const { + return _parent; + } + void yielded() { + _numYields++; + } // Should be _inlock()? - /** - * Returns true if a time limit has been set on this operation, and false otherwise. - */ - bool isMaxTimeSet() const; + /** + * Returns the number of times yielded() was called. Callers on threads other + * than the one executing the operation must lock the client. + */ + int numYields() const { + return _numYields; + } - /** - * Checks whether this operation has been running longer than its time limit. Returns - * false if not, or if the operation has no time limit. - */ - bool maxTimeHasExpired(); + long long getExpectedLatencyMs() const { + return _expectedLatencyMs; + } + void setExpectedLatencyMs(long long latency) { + _expectedLatencyMs = latency; + } - /** - * Returns the number of microseconds remaining for this operation's time limit, or the - * special value 0 if the operation has no time limit. - * - * Calling this method is more expensive than calling its sibling "maxTimeHasExpired()", - * since an accurate measure of remaining time needs to be calculated. - */ - uint64_t getRemainingMaxTimeMicros() const; + /** + * this should be used very sparingly + * generally the Context should set this up + * but sometimes you want to do it ahead of time + */ + void setNS_inlock(StringData ns); + +private: + class CurOpStack; + + static const OperationContext::Decoration<CurOpStack> _curopStack; + + CurOp(OperationContext*, CurOpStack*); + + CurOpStack* _stack; + CurOp* _parent = nullptr; + Command* _command; + long long _start; + long long _end; + int _op; + bool _isCommand; + int _dbprofile; // 0=off, 1=slow, 2=all + std::string _ns; + CachedBSONObj<512> _query; // CachedBSONObj is thread safe + OpDebug _debug; + std::string _message; + ProgressMeter _progressMeter; + int _numYields; + + // this is how much "extra" time a query might take + // a writebacklisten for example will block for 30s + // so this should be 30000 in that case + long long _expectedLatencyMs; + + // Time limit for this operation. 0 if the operation has no time limit. + uint64_t _maxTimeMicros; + + /** Nested class that implements tracking of a time limit for a CurOp object. */ + class MaxTimeTracker { + MONGO_DISALLOW_COPYING(MaxTimeTracker); - // - // Methods for getting/setting elapsed time. - // + public: + /** Newly-constructed MaxTimeTracker objects have the time limit disabled. */ + MaxTimeTracker(); - void ensureStarted(); - bool isStarted() const { return _start > 0; } - long long startTime() { // micros - ensureStarted(); - return _start; - } - void done() { - _end = curTimeMicros64(); - } + /** Disables the time tracker. */ + void reset(); - long long totalTimeMicros() { - massert( 12601 , "CurOp not marked done yet" , _end ); - return _end - startTime(); + /** Returns whether or not time tracking is enabled. */ + bool isEnabled() const { + return _enabled; } - int totalTimeMillis() { return (int) (totalTimeMicros() / 1000); } - long long elapsedMicros() { - return curTimeMicros64() - startTime(); - } - int elapsedMillis() { - return (int) (elapsedMicros() / 1000); - } - int elapsedSeconds() { return elapsedMillis() / 1000; } - - void setQuery_inlock(const BSONObj& query) { _query.set( query ); } - - Command * getCommand() const { return _command; } - void setCommand_inlock(Command* command) { _command = command; } - - /** - * Appends information about this CurOp to "builder". - * - * If called from a thread other than the one executing the operation associated with this - * CurOp, it is necessary to lock the associated Client object before executing this method. - */ - void reportState(BSONObjBuilder* builder); /** - * Sets the message and the progress meter for this CurOp. + * Enables time tracking. The time limit is set to be "durationMicros" microseconds + * from "startEpochMicros" (units of microseconds since the epoch). * - * While it is necessary to hold the lock while this method executes, the - * "hit" and "finished" methods of ProgressMeter may be called safely from - * the thread executing the operation without locking the Client. + * "durationMicros" must be nonzero. */ - ProgressMeter& setMessage_inlock(const char * msg, - std::string name = "Progress", - unsigned long long progressMeterTotal = 0, - int secondsBetween = 3); + void setTimeLimit(uint64_t startEpochMicros, uint64_t durationMicros); /** - * Gets the message for this CurOp. + * Checks whether the time limit has been hit. Returns false if not, or if time + * tracking is disabled. */ - const std::string& getMessage() const { return _message; } - const ProgressMeter& getProgressMeter() { return _progressMeter; } - CurOp *parent() const { return _parent; } - void yielded() { _numYields++; } // Should be _inlock()? + bool checkTimeLimit(); /** - * Returns the number of times yielded() was called. Callers on threads other - * than the one executing the operation must lock the client. - */ - int numYields() const { return _numYields; } - - long long getExpectedLatencyMs() const { return _expectedLatencyMs; } - void setExpectedLatencyMs( long long latency ) { _expectedLatencyMs = latency; } - - /** - * this should be used very sparingly - * generally the Context should set this up - * but sometimes you want to do it ahead of time + * Returns the number of microseconds remaining for the time limit, or the special + * value 0 if time tracking is disabled. + * + * Calling this method is more expensive than calling its sibling "checkInterval()", + * since an accurate measure of remaining time needs to be calculated. */ - void setNS_inlock( StringData ns ); + uint64_t getRemainingMicros() const; private: - class CurOpStack; - - static const OperationContext::Decoration<CurOpStack> _curopStack; - - CurOp(OperationContext*, CurOpStack*); - - CurOpStack* _stack; - CurOp* _parent = nullptr; - Command * _command; - long long _start; - long long _end; - int _op; - bool _isCommand; - int _dbprofile; // 0=off, 1=slow, 2=all - std::string _ns; - CachedBSONObj<512> _query; // CachedBSONObj is thread safe - OpDebug _debug; - std::string _message; - ProgressMeter _progressMeter; - int _numYields; - - // this is how much "extra" time a query might take - // a writebacklisten for example will block for 30s - // so this should be 30000 in that case - long long _expectedLatencyMs; - - // Time limit for this operation. 0 if the operation has no time limit. - uint64_t _maxTimeMicros; - - /** Nested class that implements tracking of a time limit for a CurOp object. */ - class MaxTimeTracker { - MONGO_DISALLOW_COPYING(MaxTimeTracker); - public: - /** Newly-constructed MaxTimeTracker objects have the time limit disabled. */ - MaxTimeTracker(); - - /** Disables the time tracker. */ - void reset(); - - /** Returns whether or not time tracking is enabled. */ - bool isEnabled() const { return _enabled; } - - /** - * Enables time tracking. The time limit is set to be "durationMicros" microseconds - * from "startEpochMicros" (units of microseconds since the epoch). - * - * "durationMicros" must be nonzero. - */ - void setTimeLimit(uint64_t startEpochMicros, uint64_t durationMicros); - - /** - * Checks whether the time limit has been hit. Returns false if not, or if time - * tracking is disabled. - */ - bool checkTimeLimit(); - - /** - * Returns the number of microseconds remaining for the time limit, or the special - * value 0 if time tracking is disabled. - * - * Calling this method is more expensive than calling its sibling "checkInterval()", - * since an accurate measure of remaining time needs to be calculated. - */ - uint64_t getRemainingMicros() const; - private: - // Whether or not time tracking is enabled for this operation. - bool _enabled; - - // Point in time at which the time limit is hit. Units of microseconds since the - // epoch. - uint64_t _targetEpochMicros; - - // Approximate point in time at which the time limit is hit. Units of milliseconds - // since the server process was started. - int64_t _approxTargetServerMillis; - } _maxTimeTracker; - - }; + // Whether or not time tracking is enabled for this operation. + bool _enabled; + + // Point in time at which the time limit is hit. Units of microseconds since the + // epoch. + uint64_t _targetEpochMicros; + + // Approximate point in time at which the time limit is hit. Units of milliseconds + // since the server process was started. + int64_t _approxTargetServerMillis; + } _maxTimeTracker; +}; } |