summaryrefslogtreecommitdiff
path: root/src/mongo/util/assert_util.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/assert_util.h')
-rw-r--r--src/mongo/util/assert_util.h618
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; \
}
/**