MongoDB  2.0.3
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 // MONGO_NORETURN undefed at end of file
00024 #ifdef __GNUC__
00025 # define MONGO_NORETURN __attribute__((__noreturn__))
00026 #else
00027 # define MONGO_NORETURN 
00028 #endif
00029 
00030 namespace mongo {
00031 
00032     enum CommonErrorCodes {
00033         DatabaseDifferCaseCode = 13297 ,
00034         StaleConfigInContextCode = 13388
00035     };
00036 
00037     class AssertionCount {
00038     public:
00039         AssertionCount();
00040         void rollover();
00041         void condrollover( int newValue );
00042 
00043         int regular;
00044         int warning;
00045         int msg;
00046         int user;
00047         int rollovers;
00048     };
00049 
00050     extern AssertionCount assertionCount;
00051 
00052     struct ExceptionInfo {
00053         ExceptionInfo() : msg(""),code(-1) {}
00054         ExceptionInfo( const char * m , int c )
00055             : msg( m ) , code( c ) {
00056         }
00057         ExceptionInfo( const string& m , int c )
00058             : msg( m ) , code( c ) {
00059         }
00060         void append( BSONObjBuilder& b , const char * m = "$err" , const char * c = "code" ) const ;
00061         string toString() const { stringstream ss; ss << "exception: " << code << " " << msg; return ss.str(); }
00062         bool empty() const { return msg.empty(); }
00063         
00064         void reset(){ msg = ""; code=-1; }
00065 
00066         string msg;
00067         int code;
00068     };
00069 
00076     class ErrorMsg { 
00077     public:
00078         ErrorMsg(const char *msg, char ch);
00079         ErrorMsg(const char *msg, unsigned val);
00080         operator string() const { return buf; }
00081     private:
00082         char buf[256];
00083     };
00084 
00085     class DBException : public std::exception {
00086     public:
00087         DBException( const ExceptionInfo& ei ) : _ei(ei) {}
00088         DBException( const char * msg , int code ) : _ei(msg,code) {}
00089         DBException( const string& msg , int code ) : _ei(msg,code) {}
00090         virtual ~DBException() throw() { }
00091 
00092         virtual const char* what() const throw() { return _ei.msg.c_str(); }
00093         virtual int getCode() const { return _ei.code; }
00094 
00095         virtual void appendPrefix( stringstream& ss ) const { }
00096 
00097         virtual string toString() const {
00098             stringstream ss; ss << getCode() << " " << what(); return ss.str();
00099             return ss.str();
00100         }
00101 
00102         const ExceptionInfo& getInfo() const { return _ei; }
00103 
00104     protected:
00105         ExceptionInfo _ei;
00106     };
00107 
00108     class AssertionException : public DBException {
00109     public:
00110 
00111         AssertionException( const ExceptionInfo& ei ) : DBException(ei) {}
00112         AssertionException( const char * msg , int code ) : DBException(msg,code) {}
00113         AssertionException( const string& msg , int code ) : DBException(msg,code) {}
00114 
00115         virtual ~AssertionException() throw() { }
00116 
00117         virtual bool severe() { return true; }
00118         virtual bool isUserAssertion() { return false; }
00119 
00120         /* true if an interrupted exception - see KillCurrentOp */
00121         bool interrupted() {
00122             return _ei.code == 11600 || _ei.code == 11601;
00123         }
00124     };
00125 
00126     /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */
00127     class UserException : public AssertionException {
00128     public:
00129         UserException(int c , const string& m) : AssertionException( m , c ) {}
00130 
00131         virtual bool severe() { return false; }
00132         virtual bool isUserAssertion() { return true; }
00133         virtual void appendPrefix( stringstream& ss ) const { ss << "userassert:"; }
00134     };
00135 
00136     class MsgAssertionException : public AssertionException {
00137     public:
00138         MsgAssertionException( const ExceptionInfo& ei ) : AssertionException( ei ) {}
00139         MsgAssertionException(int c, const string& m) : AssertionException( m , c ) {}
00140         virtual bool severe() { return false; }
00141         virtual void appendPrefix( stringstream& ss ) const { ss << "massert:"; }
00142     };
00143 
00144     void asserted(const char *msg, const char *file, unsigned line) MONGO_NORETURN;
00145     void wasserted(const char *msg, const char *file, unsigned line);
00146     void verifyFailed( int msgid );
00147     
00151     void uasserted(int msgid, const char *msg) MONGO_NORETURN;
00152     inline void uasserted(int msgid , string msg) { uasserted(msgid, msg.c_str()); }
00153 
00155     void uassert_nothrow(const char *msg);
00156 
00160     void msgassertedNoTrace(int msgid, const char *msg) MONGO_NORETURN;
00161     inline void msgassertedNoTrace(int msgid, const string& msg) { msgassertedNoTrace( msgid , msg.c_str() ); }
00162     void msgasserted(int msgid, const char *msg) MONGO_NORETURN;
00163     inline void msgasserted(int msgid, string msg) { msgasserted(msgid, msg.c_str()); }
00164 
00165     /* convert various types of exceptions to strings */
00166     inline string causedBy( const char* e ){ return (string)" :: caused by :: " + e; }
00167     inline string causedBy( const DBException& e ){ return causedBy( e.toString().c_str() ); }
00168     inline string causedBy( const std::exception& e ){ return causedBy( e.what() ); }
00169     inline string causedBy( const string& e ){ return causedBy( e.c_str() ); }
00170 
00172     inline void verify( int msgid , bool testOK ) { if ( ! testOK ) verifyFailed( msgid ); }
00173 
00174 #ifdef assert
00175 #undef assert
00176 #endif
00177 
00178 #define MONGO_assert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::asserted(#_Expression, __FILE__, __LINE__), 0) )
00179 #define assert MONGO_assert
00180 
00181     /* "user assert".  if asserts, user did something wrong, not our code */
00182 #define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (mongo::uasserted(msgid, msg), 0) )
00183 #define uassert MONGO_uassert
00184 
00185     /* warning only - keeps going */
00186 #define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) )
00187 #define wassert MONGO_wassert
00188 
00189     /* display a message, no context, and throw assertionexception
00190 
00191        easy way to throw an exception and log something without our stack trace
00192        display happening.
00193     */
00194 #define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (mongo::msgasserted(msgid, msg), 0) )
00195 #define massert MONGO_massert
00196 
00197     /* dassert is 'debug assert' -- might want to turn off for production as these
00198        could be slow.
00199     */
00200 #if defined(_DEBUG)
00201 # define MONGO_dassert assert
00202 #else
00203 # define MONGO_dassert(x)
00204 #endif
00205 #define dassert MONGO_dassert
00206 
00207     // some special ids that we want to duplicate
00208 
00209     // > 10000 asserts
00210     // < 10000 UserException
00211 
00212     enum { ASSERT_ID_DUPKEY = 11000 };
00213 
00214     /* throws a uassertion with an appropriate msg */
00215     void streamNotGood( int code , string msg , std::ios& myios ) MONGO_NORETURN;
00216 
00217     inline void assertStreamGood(unsigned msgid, string msg, std::ios& myios) {
00218         if( !myios.good() ) streamNotGood(msgid, msg, myios);
00219     }
00220 
00221     string demangleName( const type_info& typeinfo );
00222 
00223 } // namespace mongo
00224 
00225 #define BOOST_CHECK_EXCEPTION MONGO_BOOST_CHECK_EXCEPTION
00226 #define MONGO_BOOST_CHECK_EXCEPTION( expression ) \
00227     try { \
00228         expression; \
00229     } catch ( const std::exception &e ) { \
00230         stringstream ss; \
00231         ss << "caught boost exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \
00232         msgasserted( 13294 , ss.str() ); \
00233     } catch ( ... ) { \
00234         massert( 10437 ,  "unknown boost failed" , false ); \
00235     }
00236 
00237 #define MONGO_BOOST_CHECK_EXCEPTION_WITH_MSG( expression, msg ) \
00238     try { \
00239         expression; \
00240     } catch ( const std::exception &e ) { \
00241         stringstream ss; \
00242         ss << msg << " caught boost exception: " << e.what();   \
00243         msgasserted( 14043 , ss.str() );        \
00244     } catch ( ... ) { \
00245         msgasserted( 14044 , string("unknown boost failed ") + msg );   \
00246     }
00247 
00248 #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
00249 #define MONGO_DESTRUCTOR_GUARD( expression ) \
00250     try { \
00251         expression; \
00252     } catch ( const std::exception &e ) { \
00253         problem() << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" << endl; \
00254     } catch ( ... ) { \
00255         problem() << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << endl; \
00256     }
00257 
00258 #undef MONGO_NORETURN