MongoDB  1.8.5
assert_util.h
00001 // assert_util.h
00002 
00003 /*    Copyright 2009 10gen Inc.
00004  *
00005  *    Licensed under the Apache License, Version 2.0 (the "License");
00006  *    you may not use this file except in compliance with the License.
00007  *    You may obtain a copy of the License at
00008  *
00009  *    http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  *    Unless required by applicable law or agreed to in writing, software
00012  *    distributed under the License is distributed on an "AS IS" BASIS,
00013  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  *    See the License for the specific language governing permissions and
00015  *    limitations under the License.
00016  */
00017 
00018 
00019 #pragma once
00020 
00021 #include "../db/lasterror.h"
00022 
00023 namespace mongo {
00024 
00025     enum CommonErrorCodes {
00026         DatabaseDifferCaseCode = 13297 ,
00027         StaleConfigInContextCode = 13388
00028     };
00029 
00030     class AssertionCount {
00031     public:
00032         AssertionCount();
00033         void rollover();
00034         void condrollover( int newValue );
00035 
00036         int regular;
00037         int warning;
00038         int msg;
00039         int user;
00040         int rollovers;
00041     };
00042 
00043     extern AssertionCount assertionCount;
00044 
00045     struct ExceptionInfo {
00046         ExceptionInfo() : msg(""),code(-1) {}
00047         ExceptionInfo( const char * m , int c )
00048             : msg( m ) , code( c ) {
00049         }
00050         ExceptionInfo( const string& m , int c )
00051             : msg( m ) , code( c ) {
00052         }
00053         void append( BSONObjBuilder& b , const char * m = "$err" , const char * c = "code" ) const ;
00054         string toString() const { stringstream ss; ss << "exception: " << code << " " << msg; return ss.str(); }
00055         bool empty() const { return msg.empty(); }
00056 
00057         string msg;
00058         int code;
00059     };
00060 
00061     class DBException : public std::exception {
00062     public:
00063         DBException( const ExceptionInfo& ei ) : _ei(ei) {}
00064         DBException( const char * msg , int code ) : _ei(msg,code) {}
00065         DBException( const string& msg , int code ) : _ei(msg,code) {}
00066         virtual ~DBException() throw() { }
00067 
00068         virtual const char* what() const throw() { return _ei.msg.c_str(); }
00069         virtual int getCode() const { return _ei.code; }
00070 
00071         virtual void appendPrefix( stringstream& ss ) const { }
00072 
00073         virtual string toString() const {
00074             stringstream ss; ss << getCode() << " " << what(); return ss.str();
00075             return ss.str();
00076         }
00077 
00078         const ExceptionInfo& getInfo() const { return _ei; }
00079 
00080     protected:
00081         ExceptionInfo _ei;
00082     };
00083 
00084     class AssertionException : public DBException {
00085     public:
00086 
00087         AssertionException( const ExceptionInfo& ei ) : DBException(ei) {}
00088         AssertionException( const char * msg , int code ) : DBException(msg,code) {}
00089         AssertionException( const string& msg , int code ) : DBException(msg,code) {}
00090 
00091         virtual ~AssertionException() throw() { }
00092 
00093         virtual bool severe() { return true; }
00094         virtual bool isUserAssertion() { return false; }
00095 
00096         /* true if an interrupted exception - see KillCurrentOp */
00097         bool interrupted() {
00098             return _ei.code == 11600 || _ei.code == 11601;
00099         }
00100     };
00101 
00102     /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */
00103     class UserException : public AssertionException {
00104     public:
00105         UserException(int c , const string& m) : AssertionException( m , c ) {}
00106 
00107         virtual bool severe() { return false; }
00108         virtual bool isUserAssertion() { return true; }
00109         virtual void appendPrefix( stringstream& ss ) const { ss << "userassert:"; }
00110     };
00111 
00112     class MsgAssertionException : public AssertionException {
00113     public:
00114         MsgAssertionException( const ExceptionInfo& ei ) : AssertionException( ei ) {}
00115         MsgAssertionException(int c, const string& m) : AssertionException( m , c ) {}
00116         virtual bool severe() { return false; }
00117         virtual void appendPrefix( stringstream& ss ) const { ss << "massert:"; }
00118     };
00119 
00120 
00121     void asserted(const char *msg, const char *file, unsigned line);
00122     void wasserted(const char *msg, const char *file, unsigned line);
00123 
00127     void uasserted(int msgid, const char *msg);
00128     inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_str()); }
00129 
00131     void uassert_nothrow(const char *msg);
00132 
00136     void msgassertedNoTrace(int msgid, const char *msg);
00137     inline void msgassertedNoTrace(int msgid, const string& msg) { msgassertedNoTrace( msgid , msg.c_str() ); }
00138     void msgasserted(int msgid, const char *msg);
00139     inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg.c_str()); }
00140 
00141 #ifdef assert
00142 #undef assert
00143 #endif
00144 
00145 #define MONGO_assert(_Expression) (void)( (!!(_Expression)) || (mongo::asserted(#_Expression, __FILE__, __LINE__), 0) )
00146 #define assert MONGO_assert
00147 
00148     /* "user assert".  if asserts, user did something wrong, not our code */
00149 #define MONGO_uassert(msgid, msg, expr) (void)( (!!(expr)) || (mongo::uasserted(msgid, msg), 0) )
00150 #define uassert MONGO_uassert
00151 
00152     /* warning only - keeps going */
00153 #define MONGO_wassert(_Expression) (void)( (!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) )
00154 #define wassert MONGO_wassert
00155 
00156     /* display a message, no context, and throw assertionexception
00157 
00158        easy way to throw an exception and log something without our stack trace
00159        display happening.
00160     */
00161 #define MONGO_massert(msgid, msg, expr) (void)( (!!(expr)) || (mongo::msgasserted(msgid, msg), 0) )
00162 #define massert MONGO_massert
00163 
00164     /* dassert is 'debug assert' -- might want to turn off for production as these
00165        could be slow.
00166     */
00167 #if defined(_DEBUG)
00168 # define MONGO_dassert assert
00169 #else
00170 # define MONGO_dassert(x)
00171 #endif
00172 #define dassert MONGO_dassert
00173 
00174     // some special ids that we want to duplicate
00175 
00176     // > 10000 asserts
00177     // < 10000 UserException
00178 
00179     enum { ASSERT_ID_DUPKEY = 11000 };
00180 
00181     /* throws a uassertion with an appropriate msg */
00182     void streamNotGood( int code , string msg , std::ios& myios );
00183 
00184     inline void assertStreamGood(unsigned msgid, string msg, std::ios& myios) {
00185         if( !myios.good() ) streamNotGood(msgid, msg, myios);
00186     }
00187 
00188     string demangleName( const type_info& typeinfo );
00189 
00190 } // namespace mongo
00191 
00192 #define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION
00193 #define MONGO_BOOST_CHECK_EXCEPTION( expression ) \
00194     try { \
00195         expression; \
00196     } catch ( const std::exception &e ) { \
00197         stringstream ss; \
00198         ss << "caught boost exception: " << e.what();   \
00199         msgasserted( 13294 , ss.str() );        \
00200     } catch ( ... ) { \
00201         massert( 10437 ,  "unknown boost failed" , false );   \
00202     }
00203 
00204 #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
00205 #define MONGO_DESTRUCTOR_GUARD( expression ) \
00206     try { \
00207         expression; \
00208     } catch ( const std::exception &e ) { \
00209         problem() << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" << endl; \
00210     } catch ( ... ) { \
00211         problem() << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << endl; \
00212     }