diff options
| author | Antonin Kral <a.kral@bobek.cz> | 2012-08-29 20:54:51 +0200 |
|---|---|---|
| committer | Antonin Kral <a.kral@bobek.cz> | 2012-08-29 20:54:51 +0200 |
| commit | 83957b73f9177f6e38bd5375bd93ca1f6a47188c (patch) | |
| tree | f20b7d6ac9a9c64ff5bb6b5910a24abbb356b1d5 /src/mongo/util/assert_util.h | |
| parent | 5071d203970edd4c995493d810abe20987e76fe9 (diff) | |
Imported Upstream version 2.2.0upstream/2.2.0
Diffstat (limited to 'src/mongo/util/assert_util.h')
| -rw-r--r-- | src/mongo/util/assert_util.h | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h new file mode 100644 index 00000000000..8ae7ad8863f --- /dev/null +++ b/src/mongo/util/assert_util.h @@ -0,0 +1,263 @@ +// assert_util.h + +/* Copyright 2009 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <iostream> +#include <typeinfo> +#include <string> + +#include "mongo/bson/inline_decls.h" +#include "mongo/platform/compiler.h" + +namespace mongo { + + enum CommonErrorCodes { + DatabaseDifferCaseCode = 13297 , + SendStaleConfigCode = 13388 , + RecvStaleConfigCode = 9996 + }; + + 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 ); + bool inShutdown(); + + /** 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 ); + } + + 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() { return true; } + virtual bool isUserAssertion() { return false; } + + /* true if an interrupted exception - see KillCurrentOp */ + bool interrupted() { + return _ei.code == 11600 || _ei.code == 11601; + } + }; + + /* 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() { return false; } + virtual bool isUserAssertion() { 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() { return false; } + virtual void appendPrefix( std::stringstream& ss ) const; + }; + + MONGO_COMPILER_NORETURN void verifyFailed(const char *msg, const char *file, unsigned line); + void wasserted(const char *msg, const char *file, unsigned line); + MONGO_COMPILER_NORETURN void fassertFailed( int msgid ); + + /** 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 inline void msgassertedNoTrace(int msgid, const std::string& msg) { + msgassertedNoTrace( msgid , msg.c_str() ); + } + 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 */ + inline std::string causedBy( const char* e ){ return (std::string)" :: caused by :: " + e; } + inline std::string causedBy( const DBException& e ){ return causedBy( e.toString().c_str() ); } + inline std::string causedBy( const std::exception& e ){ return causedBy( e.what() ); } + inline std::string causedBy( const std::string& e ){ return causedBy( e.c_str() ); } + + /** abends on condition failure */ + inline void fassert( int msgid , bool testOK ) { if ( ! testOK ) fassertFailed( msgid ); } + + + /* "user assert". if asserts, user did something wrong, not our code */ +#define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (mongo::uasserted(msgid, msg), 0) ) + + /* warning only - keeps going */ +#define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) ) + + /* 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) (void)( MONGO_likely(!!(expr)) || (mongo::msgasserted(msgid, msg), 0) ) + /* same as massert except no msgid */ +#define MONGO_verify(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::verifyFailed(#_Expression, __FILE__, __LINE__), 0) ) + + /* dassert is 'debug assert' -- might want to turn off for production as these + could be slow. + */ +#if defined(_DEBUG) +# define MONGO_dassert(x) fassert(16199, (x)) +#else +# define MONGO_dassert(x) +#endif + + +#ifdef MONGO_EXPOSE_MACROS +# define dassert MONGO_dassert +# define verify MONGO_verify +# define uassert MONGO_uassert +# define wassert MONGO_wassert +# define massert MONGO_massert +#endif + + // some special ids that we want to duplicate + + // > 10000 asserts + // < 10000 UserException + + enum { ASSERT_ID_DUPKEY = 11000 }; + + /* throws a uassertion with an appropriate msg */ + MONGO_COMPILER_NORETURN void streamNotGood( int code , std::string msg , std::ios& myios ); + + inline void assertStreamGood(unsigned msgid, std::string msg, std::ios& myios) { + if( !myios.good() ) streamNotGood(msgid, msg, myios); + } + + std::string demangleName( const std::type_info& typeinfo ); + +} // namespace mongo + +#define MONGO_ASSERT_ON_EXCEPTION( expression ) \ + try { \ + expression; \ + } catch ( const std::exception &e ) { \ + stringstream ss; \ + ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \ + 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 ) { \ + stringstream ss; \ + ss << msg << " caught exception exception: " << e.what(); \ + 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 ) { \ + problem() << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" << endl; \ + } catch ( ... ) { \ + problem() << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << endl; \ + } + |
