diff options
Diffstat (limited to 'src/mongo/util/assert_util.h')
-rw-r--r-- | src/mongo/util/assert_util.h | 618 |
1 files changed, 324 insertions, 294 deletions
diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h index b45585abd8d..c6075e9cf5d 100644 --- a/src/mongo/util/assert_util.h +++ b/src/mongo/util/assert_util.h @@ -32,7 +32,7 @@ #include <typeinfo> #include <string> -#include "mongo/base/status.h" // NOTE: This is safe as utils depend on base +#include "mongo/base/status.h" // NOTE: This is safe as utils depend on base #include "mongo/platform/compiler.h" #include "mongo/logger/log_severity.h" #include "mongo/logger/logger.h" @@ -46,262 +46,293 @@ namespace mongo { - enum CommonErrorCodes { - OkCode = 0, - SendStaleConfigCode = 13388 , // uassert( 13388 ) - RecvStaleConfigCode = 9996, // uassert( 9996 ) - PrepareConfigsFailedCode = 13104, // uassert( 13104 ) - NotMasterOrSecondaryCode = 13436, // uassert( 13436 ) - NotMasterNoSlaveOkCode = 13435, // uassert( 13435 ) - NotMaster = 10107, // uassert( 10107 ) - }; - - class AssertionCount { - public: - AssertionCount(); - void rollover(); - void condrollover( int newValue ); - - int regular; - int warning; - int msg; - int user; - int rollovers; - }; - - extern AssertionCount assertionCount; - - class BSONObjBuilder; - - struct ExceptionInfo { - ExceptionInfo() : msg(""),code(-1) {} - ExceptionInfo( const char * m , int c ) - : msg( m ) , code( c ) { - } - ExceptionInfo( const std::string& m , int c ) - : msg( m ) , code( c ) { - } - void append( BSONObjBuilder& b , const char * m = "$err" , const char * c = "code" ) const ; - std::string toString() const; - bool empty() const { return msg.empty(); } - void reset(){ msg = ""; code=-1; } - std::string msg; - int code; - }; - - /** helper class that builds error strings. lighter weight than a StringBuilder, albeit less flexible. - NOINLINE_DECL used in the constructor implementations as we are assuming this is a cold code path when used. - - example: - throw UserException(123, ErrorMsg("blah", num_val)); - */ - class ErrorMsg { - public: - ErrorMsg(const char *msg, char ch); - ErrorMsg(const char *msg, unsigned val); - operator std::string() const { return buf; } - private: - char buf[256]; - }; - - class DBException; - std::string causedBy( const DBException& e ); - std::string causedBy( const std::string& e ); - - /** Most mongo exceptions inherit from this; this is commonly caught in most threads */ - class DBException : public std::exception { - public: - DBException( const ExceptionInfo& ei ) : _ei(ei) { traceIfNeeded(*this); } - DBException( const char * msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); } - DBException( const std::string& msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); } - virtual ~DBException() throw() { } - - virtual const char* what() const throw() { return _ei.msg.c_str(); } - virtual int getCode() const { return _ei.code; } - virtual void appendPrefix( std::stringstream& ss ) const { } - virtual void addContext( const std::string& str ) { - _ei.msg = str + causedBy( _ei.msg ); - } - - // Utilities for the migration to Status objects - static ErrorCodes::Error convertExceptionCode(int exCode); - - Status toStatus(const std::string& context) const { - return Status(convertExceptionCode(getCode()), context + causedBy(*this)); - } - Status toStatus() const { - return Status(convertExceptionCode(getCode()), this->what()); - } - - // context when applicable. otherwise "" - std::string _shard; - - virtual std::string toString() const; - - const ExceptionInfo& getInfo() const { return _ei; } - private: - static void traceIfNeeded( const DBException& e ); - public: - static bool traceExceptions; - - protected: - ExceptionInfo _ei; - }; - - class AssertionException : public DBException { - public: - - AssertionException( const ExceptionInfo& ei ) : DBException(ei) {} - AssertionException( const char * msg , int code ) : DBException(msg,code) {} - AssertionException( const std::string& msg , int code ) : DBException(msg,code) {} - - virtual ~AssertionException() throw() { } - - virtual bool severe() const { return true; } - virtual bool isUserAssertion() const { return false; } - }; - - /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */ - class UserException : public AssertionException { - public: - UserException(int c , const std::string& m) : AssertionException( m , c ) {} - virtual bool severe() const { return false; } - virtual bool isUserAssertion() const { return true; } - virtual void appendPrefix( std::stringstream& ss ) const; - }; - - class MsgAssertionException : public AssertionException { - public: - MsgAssertionException( const ExceptionInfo& ei ) : AssertionException( ei ) {} - MsgAssertionException(int c, const std::string& m) : AssertionException( m , c ) {} - virtual bool severe() const { return false; } - virtual void appendPrefix( std::stringstream& ss ) const; - }; - - MONGO_COMPILER_NORETURN void verifyFailed(const char* expr, const char* file, unsigned line); - MONGO_COMPILER_NORETURN void invariantOKFailed(const char* expr, const Status& status, const char *file, unsigned line); - void wasserted(const char* expr, const char* file, unsigned line); - MONGO_COMPILER_NORETURN void fassertFailed( int msgid ); - MONGO_COMPILER_NORETURN void fassertFailedNoTrace( int msgid ); - MONGO_COMPILER_NORETURN void fassertFailedWithStatus( - int msgid, const Status& status); - MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace( - int msgid, const Status& status); - - /** a "user assertion". throws UserAssertion. logs. typically used for errors that a user - could cause, such as duplicate key, disk full, etc. - */ - MONGO_COMPILER_NORETURN void uasserted(int msgid, const char *msg); - MONGO_COMPILER_NORETURN void uasserted(int msgid , const std::string &msg); - - /** msgassert and massert are for errors that are internal but have a well defined error text - std::string. a stack trace is logged. - */ - MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char *msg); - MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const std::string &msg); - MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg); - MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string &msg); - - /* convert various types of exceptions to strings */ - std::string causedBy( const char* e ); - std::string causedBy( const DBException& e ); - std::string causedBy( const std::exception& e ); - std::string causedBy( const std::string& e ); - std::string causedBy( const std::string* e ); - std::string causedBy( const Status& e ); - - /** aborts on condition failure */ - inline void fassert(int msgid, bool testOK) { - if (MONGO_unlikely(!testOK)) fassertFailed(msgid); +enum CommonErrorCodes { + OkCode = 0, + SendStaleConfigCode = 13388, // uassert( 13388 ) + RecvStaleConfigCode = 9996, // uassert( 9996 ) + PrepareConfigsFailedCode = 13104, // uassert( 13104 ) + NotMasterOrSecondaryCode = 13436, // uassert( 13436 ) + NotMasterNoSlaveOkCode = 13435, // uassert( 13435 ) + NotMaster = 10107, // uassert( 10107 ) +}; + +class AssertionCount { +public: + AssertionCount(); + void rollover(); + void condrollover(int newValue); + + int regular; + int warning; + int msg; + int user; + int rollovers; +}; + +extern AssertionCount assertionCount; + +class BSONObjBuilder; + +struct ExceptionInfo { + ExceptionInfo() : msg(""), code(-1) {} + ExceptionInfo(const char* m, int c) : msg(m), code(c) {} + ExceptionInfo(const std::string& m, int c) : msg(m), code(c) {} + void append(BSONObjBuilder& b, const char* m = "$err", const char* c = "code") const; + std::string toString() const; + bool empty() const { + return msg.empty(); } + void reset() { + msg = ""; + code = -1; + } + std::string msg; + int code; +}; + +/** helper class that builds error strings. lighter weight than a StringBuilder, albeit less flexible. + NOINLINE_DECL used in the constructor implementations as we are assuming this is a cold code path when used. + + example: + throw UserException(123, ErrorMsg("blah", num_val)); +*/ +class ErrorMsg { +public: + ErrorMsg(const char* msg, char ch); + ErrorMsg(const char* msg, unsigned val); + operator std::string() const { + return buf; + } + +private: + char buf[256]; +}; - inline void fassert(int msgid, const Status& status) { - if (MONGO_unlikely(!status.isOK())) { - fassertFailedWithStatus(msgid, status); - } +class DBException; +std::string causedBy(const DBException& e); +std::string causedBy(const std::string& e); + +/** Most mongo exceptions inherit from this; this is commonly caught in most threads */ +class DBException : public std::exception { +public: + DBException(const ExceptionInfo& ei) : _ei(ei) { + traceIfNeeded(*this); + } + DBException(const char* msg, int code) : _ei(msg, code) { + traceIfNeeded(*this); + } + DBException(const std::string& msg, int code) : _ei(msg, code) { + traceIfNeeded(*this); } + virtual ~DBException() throw() {} - inline void fassertNoTrace(int msgid, const Status& status) { - if (MONGO_unlikely(!status.isOK())) { - fassertFailedWithStatusNoTrace(msgid, status); - } + virtual const char* what() const throw() { + return _ei.msg.c_str(); + } + virtual int getCode() const { + return _ei.code; + } + virtual void appendPrefix(std::stringstream& ss) const {} + virtual void addContext(const std::string& str) { + _ei.msg = str + causedBy(_ei.msg); } + // Utilities for the migration to Status objects + static ErrorCodes::Error convertExceptionCode(int exCode); - /* "user assert". if asserts, user did something wrong, not our code */ -#define MONGO_uassert(msgid, msg, expr) do { \ - if (MONGO_unlikely(!(expr))) { \ - ::mongo::uasserted(msgid, msg); \ - } \ - } while (false) + Status toStatus(const std::string& context) const { + return Status(convertExceptionCode(getCode()), context + causedBy(*this)); + } + Status toStatus() const { + return Status(convertExceptionCode(getCode()), this->what()); + } - inline void uassertStatusOK(const Status& status) { - if (MONGO_unlikely(!status.isOK())) { - uasserted((status.location() != 0 ? status.location() : status.code()), - status.reason()); - } + // context when applicable. otherwise "" + std::string _shard; + + virtual std::string toString() const; + + const ExceptionInfo& getInfo() const { + return _ei; } - template<typename T> - inline T uassertStatusOK(StatusWith<T> sw) { - if (MONGO_unlikely(!sw.isOK())) { - const auto& status = sw.getStatus(); - uasserted((status.location() != 0 ? status.location() : status.code()), - status.reason()); - } - return std::move(sw.getValue()); +private: + static void traceIfNeeded(const DBException& e); + +public: + static bool traceExceptions; + +protected: + ExceptionInfo _ei; +}; + +class AssertionException : public DBException { +public: + AssertionException(const ExceptionInfo& ei) : DBException(ei) {} + AssertionException(const char* msg, int code) : DBException(msg, code) {} + AssertionException(const std::string& msg, int code) : DBException(msg, code) {} + + virtual ~AssertionException() throw() {} + + virtual bool severe() const { + return true; + } + virtual bool isUserAssertion() const { + return false; + } +}; + +/* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */ +class UserException : public AssertionException { +public: + UserException(int c, const std::string& m) : AssertionException(m, c) {} + virtual bool severe() const { + return false; + } + virtual bool isUserAssertion() const { + return true; + } + virtual void appendPrefix(std::stringstream& ss) const; +}; + +class MsgAssertionException : public AssertionException { +public: + MsgAssertionException(const ExceptionInfo& ei) : AssertionException(ei) {} + MsgAssertionException(int c, const std::string& m) : AssertionException(m, c) {} + virtual bool severe() const { + return false; } + virtual void appendPrefix(std::stringstream& ss) const; +}; + +MONGO_COMPILER_NORETURN void verifyFailed(const char* expr, const char* file, unsigned line); +MONGO_COMPILER_NORETURN void invariantOKFailed(const char* expr, + const Status& status, + const char* file, + unsigned line); +void wasserted(const char* expr, const char* file, unsigned line); +MONGO_COMPILER_NORETURN void fassertFailed(int msgid); +MONGO_COMPILER_NORETURN void fassertFailedNoTrace(int msgid); +MONGO_COMPILER_NORETURN void fassertFailedWithStatus(int msgid, const Status& status); +MONGO_COMPILER_NORETURN void fassertFailedWithStatusNoTrace(int msgid, const Status& status); + +/** a "user assertion". throws UserAssertion. logs. typically used for errors that a user + could cause, such as duplicate key, disk full, etc. +*/ +MONGO_COMPILER_NORETURN void uasserted(int msgid, const char* msg); +MONGO_COMPILER_NORETURN void uasserted(int msgid, const std::string& msg); + +/** msgassert and massert are for errors that are internal but have a well defined error text + std::string. a stack trace is logged. +*/ +MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char* msg); +MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const std::string& msg); +MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char* msg); +MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string& msg); + +/* convert various types of exceptions to strings */ +std::string causedBy(const char* e); +std::string causedBy(const DBException& e); +std::string causedBy(const std::exception& e); +std::string causedBy(const std::string& e); +std::string causedBy(const std::string* e); +std::string causedBy(const Status& e); + +/** aborts on condition failure */ +inline void fassert(int msgid, bool testOK) { + if (MONGO_unlikely(!testOK)) + fassertFailed(msgid); +} + +inline void fassert(int msgid, const Status& status) { + if (MONGO_unlikely(!status.isOK())) { + fassertFailedWithStatus(msgid, status); + } +} - template<typename T> - inline T fassertStatusOK(int msgid, StatusWith<T> sw) { - if (MONGO_unlikely(!sw.isOK())) { - fassertFailedWithStatus(msgid, sw.getStatus()); - } - return std::move(sw.getValue()); +inline void fassertNoTrace(int msgid, const Status& status) { + if (MONGO_unlikely(!status.isOK())) { + fassertFailedWithStatusNoTrace(msgid, status); } +} + - /* warning only - keeps going */ -#define MONGO_wassert(_Expression) do { \ - if (MONGO_unlikely(!(_Expression))) { \ - ::mongo::wasserted(#_Expression, __FILE__, __LINE__); \ - } \ +/* "user assert". if asserts, user did something wrong, not our code */ +#define MONGO_uassert(msgid, msg, expr) \ + do { \ + if (MONGO_unlikely(!(expr))) { \ + ::mongo::uasserted(msgid, msg); \ + } \ } while (false) - /* display a message, no context, and throw assertionexception +inline void uassertStatusOK(const Status& status) { + if (MONGO_unlikely(!status.isOK())) { + uasserted((status.location() != 0 ? status.location() : status.code()), status.reason()); + } +} - easy way to throw an exception and log something without our stack trace - display happening. - */ -#define MONGO_massert(msgid, msg, expr) do { \ - if (MONGO_unlikely(!(expr))) { \ - ::mongo::msgasserted(msgid, msg); \ - } \ - } while (false) +template <typename T> +inline T uassertStatusOK(StatusWith<T> sw) { + if (MONGO_unlikely(!sw.isOK())) { + const auto& status = sw.getStatus(); + uasserted((status.location() != 0 ? status.location() : status.code()), status.reason()); + } + return std::move(sw.getValue()); +} - inline void massertStatusOK(const Status& status) { - if (MONGO_unlikely(!status.isOK())) { - msgasserted((status.location() != 0 ? status.location() : status.code()), - status.reason()); - } +template <typename T> +inline T fassertStatusOK(int msgid, StatusWith<T> sw) { + if (MONGO_unlikely(!sw.isOK())) { + fassertFailedWithStatus(msgid, sw.getStatus()); } + return std::move(sw.getValue()); +} + +/* warning only - keeps going */ +#define MONGO_wassert(_Expression) \ + do { \ + if (MONGO_unlikely(!(_Expression))) { \ + ::mongo::wasserted(#_Expression, __FILE__, __LINE__); \ + } \ + } while (false) - inline void massertNoTraceStatusOK(const Status& status) { - if (MONGO_unlikely(!status.isOK())) { - msgassertedNoTrace((status.location() != 0 ? status.location() : status.code()), - status.reason()); - } +/* display a message, no context, and throw assertionexception + + easy way to throw an exception and log something without our stack trace + display happening. +*/ +#define MONGO_massert(msgid, msg, expr) \ + do { \ + if (MONGO_unlikely(!(expr))) { \ + ::mongo::msgasserted(msgid, msg); \ + } \ + } while (false) + +inline void massertStatusOK(const Status& status) { + if (MONGO_unlikely(!status.isOK())) { + msgasserted((status.location() != 0 ? status.location() : status.code()), status.reason()); } +} - /* same as massert except no msgid */ -#define MONGO_verify(_Expression) do { \ - if (MONGO_unlikely(!(_Expression))) { \ - ::mongo::verifyFailed(#_Expression, __FILE__, __LINE__); \ - } \ +inline void massertNoTraceStatusOK(const Status& status) { + if (MONGO_unlikely(!status.isOK())) { + msgassertedNoTrace((status.location() != 0 ? status.location() : status.code()), + status.reason()); + } +} + +/* same as massert except no msgid */ +#define MONGO_verify(_Expression) \ + do { \ + if (MONGO_unlikely(!(_Expression))) { \ + ::mongo::verifyFailed(#_Expression, __FILE__, __LINE__); \ + } \ } while (false) -#define MONGO_invariantOK(expression) do { \ - const ::mongo::Status _invariantOK_status = expression; \ +#define MONGO_invariantOK(expression) \ + do { \ + const ::mongo::Status _invariantOK_status = expression; \ if (MONGO_unlikely(!_invariantOK_status.isOK())) { \ ::mongo::invariantOKFailed(#expression, _invariantOK_status, __FILE__, __LINE__); \ } \ @@ -313,75 +344,74 @@ namespace mongo { #define wassert MONGO_wassert #define massert MONGO_massert - // some special ids that we want to duplicate - - // > 10000 asserts - // < 10000 UserException - - enum { ASSERT_ID_DUPKEY = 11000 }; - - std::string demangleName( const std::type_info& typeinfo ); - - /** - * A utility function that converts an exception to a Status. - * Only call this function when there is an active exception - * (e.g. in a catch block). - * - * Note: this technique was created by Lisa Lippincott. - * - * Example usage: - * - * Status myFunc() { - * try { - * funcThatThrows(); - * return Status::OK(); - * } catch (...) { - * return exceptionToStatus(); - * } - * } - */ - Status exceptionToStatus(); - -} // namespace mongo - -#define MONGO_ASSERT_ON_EXCEPTION( expression ) \ - try { \ - expression; \ - } catch ( const std::exception &e ) { \ - std::stringstream ss; \ +// some special ids that we want to duplicate + +// > 10000 asserts +// < 10000 UserException + +enum { ASSERT_ID_DUPKEY = 11000 }; + +std::string demangleName(const std::type_info& typeinfo); + +/** + * A utility function that converts an exception to a Status. + * Only call this function when there is an active exception + * (e.g. in a catch block). + * + * Note: this technique was created by Lisa Lippincott. + * + * Example usage: + * + * Status myFunc() { + * try { + * funcThatThrows(); + * return Status::OK(); + * } catch (...) { + * return exceptionToStatus(); + * } + * } + */ +Status exceptionToStatus(); + +} // namespace mongo + +#define MONGO_ASSERT_ON_EXCEPTION(expression) \ + try { \ + expression; \ + } catch (const std::exception& e) { \ + std::stringstream ss; \ ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \ - msgasserted( 13294 , ss.str() ); \ - } catch ( ... ) { \ - massert( 10437 , "unknown exception" , false ); \ + msgasserted(13294, ss.str()); \ + } catch (...) { \ + massert(10437, "unknown exception", false); \ } -#define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG( expression, msg ) \ - try { \ - expression; \ - } catch ( const std::exception &e ) { \ - std::stringstream ss; \ +#define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG(expression, msg) \ + try { \ + expression; \ + } catch (const std::exception& e) { \ + std::stringstream ss; \ ss << msg << " caught exception exception: " << e.what(); \ - msgasserted( 14043 , ss.str() ); \ - } catch ( ... ) { \ - msgasserted( 14044 , std::string("unknown exception") + msg ); \ + msgasserted(14043, ss.str()); \ + } catch (...) { \ + msgasserted(14044, std::string("unknown exception") + msg); \ } #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD -#define MONGO_DESTRUCTOR_GUARD( expression ) \ - try { \ - expression; \ - } catch ( const std::exception &e ) { \ - ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ - ::mongo::getThreadName(), \ - ::mongo::logger::LogSeverity::Log()) \ - << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ \ - << ")" << std::endl; \ - } catch ( ... ) { \ - ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ - ::mongo::getThreadName(), \ - ::mongo::logger::LogSeverity::Log()) \ - << "caught unknown exception in destructor (" << __FUNCTION__ << ")" \ - << std::endl; \ +#define MONGO_DESTRUCTOR_GUARD(expression) \ + try { \ + expression; \ + } catch (const std::exception& e) { \ + ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ + ::mongo::getThreadName(), \ + ::mongo::logger::LogSeverity::Log()) \ + << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" \ + << std::endl; \ + } catch (...) { \ + ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \ + ::mongo::getThreadName(), \ + ::mongo::logger::LogSeverity::Log()) \ + << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << std::endl; \ } /** |