MongoDB  2.5.0
assert_util.h
1 // assert_util.h
2 
3 /* Copyright 2009 10gen Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #pragma once
19 
20 #include <iostream>
21 #include <typeinfo>
22 #include <string>
23 
24 #include "mongo/base/status.h" // NOTE: This is safe as utils depend on base
25 #include "mongo/bson/inline_decls.h"
26 #include "mongo/platform/compiler.h"
27 
28 namespace mongo {
29 
30  enum CommonErrorCodes {
31  OkCode = 0,
32  DatabaseDifferCaseCode = 13297 , // uassert( 13297 )
33  SendStaleConfigCode = 13388 , // uassert( 13388 )
34  RecvStaleConfigCode = 9996, // uassert( 9996 )
35  PrepareConfigsFailedCode = 13104 // uassert( 13104 )
36  };
37 
39  public:
41  void rollover();
42  void condrollover( int newValue );
43 
44  int regular;
45  int warning;
46  int msg;
47  int user;
48  int rollovers;
49  };
50 
51  extern AssertionCount assertionCount;
52 
53  class BSONObjBuilder;
54 
55  struct ExceptionInfo {
56  ExceptionInfo() : msg(""),code(-1) {}
57  ExceptionInfo( const char * m , int c )
58  : msg( m ) , code( c ) {
59  }
60  ExceptionInfo( const std::string& m , int c )
61  : msg( m ) , code( c ) {
62  }
63  void append( BSONObjBuilder& b , const char * m = "$err" , const char * c = "code" ) const ;
64  std::string toString() const;
65  bool empty() const { return msg.empty(); }
66  void reset(){ msg = ""; code=-1; }
67  std::string msg;
68  int code;
69  };
70 
77  class ErrorMsg {
78  public:
79  ErrorMsg(const char *msg, char ch);
80  ErrorMsg(const char *msg, unsigned val);
81  operator std::string() const { return buf; }
82  private:
83  char buf[256];
84  };
85 
86  class DBException;
87  std::string causedBy( const DBException& e );
88  std::string causedBy( const std::string& e );
89  bool inShutdown();
90 
92  class DBException : public std::exception {
93  public:
94  DBException( const ExceptionInfo& ei ) : _ei(ei) { traceIfNeeded(*this); }
95  DBException( const char * msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); }
96  DBException( const std::string& msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); }
97  virtual ~DBException() throw() { }
98 
99  virtual const char* what() const throw() { return _ei.msg.c_str(); }
100  virtual int getCode() const { return _ei.code; }
101  virtual void appendPrefix( std::stringstream& ss ) const { }
102  virtual void addContext( const std::string& str ) {
103  _ei.msg = str + causedBy( _ei.msg );
104  }
105 
106  // Utilities for the migration to Status objects
107  static ErrorCodes::Error convertExceptionCode(int exCode);
108 
109  Status toStatus(const std::string& context) const {
110  return Status(convertExceptionCode(getCode()), context + causedBy(*this));
111  }
112  Status toStatus() const {
113  return Status(convertExceptionCode(getCode()), this->toString());
114  }
115 
116  // context when applicable. otherwise ""
117  std::string _shard;
118 
119  virtual std::string toString() const;
120 
121  const ExceptionInfo& getInfo() const { return _ei; }
122  private:
123  static void traceIfNeeded( const DBException& e );
124  public:
125  static bool traceExceptions;
126 
127  protected:
128  ExceptionInfo _ei;
129  };
130 
132  public:
133 
134  AssertionException( const ExceptionInfo& ei ) : DBException(ei) {}
135  AssertionException( const char * msg , int code ) : DBException(msg,code) {}
136  AssertionException( const std::string& msg , int code ) : DBException(msg,code) {}
137 
138  virtual ~AssertionException() throw() { }
139 
140  virtual bool severe() { return true; }
141  virtual bool isUserAssertion() { return false; }
142 
143  /* true if an interrupted exception - see KillCurrentOp */
144  bool interrupted() {
145  return _ei.code == 11600 || _ei.code == 11601;
146  }
147  };
148 
149  /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */
151  public:
152  UserException(int c , const std::string& m) : AssertionException( m , c ) {}
153  virtual bool severe() { return false; }
154  virtual bool isUserAssertion() { return true; }
155  virtual void appendPrefix( std::stringstream& ss ) const;
156  };
157 
159  public:
161  MsgAssertionException(int c, const std::string& m) : AssertionException( m , c ) {}
162  virtual bool severe() { return false; }
163  virtual void appendPrefix( std::stringstream& ss ) const;
164  };
165 
166  MONGO_COMPILER_NORETURN void verifyFailed(const char *msg, const char *file, unsigned line);
167  void wasserted(const char *msg, const char *file, unsigned line);
168  MONGO_COMPILER_NORETURN void fassertFailed( int msgid );
169  MONGO_COMPILER_NORETURN void fassertFailedNoTrace( int msgid );
170 
174  MONGO_COMPILER_NORETURN void uasserted(int msgid, const char *msg);
175  MONGO_COMPILER_NORETURN void uasserted(int msgid , const std::string &msg);
176 
180  MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char *msg);
181  MONGO_COMPILER_NORETURN inline void msgassertedNoTrace(int msgid, const std::string& msg) {
182  msgassertedNoTrace( msgid , msg.c_str() );
183  }
184  MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg);
185  MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string &msg);
186 
187  /* convert various types of exceptions to strings */
188  inline std::string causedBy( const char* e ){ return (std::string)" :: caused by :: " + e; }
189  inline std::string causedBy( const DBException& e ){ return causedBy( e.toString().c_str() ); }
190  inline std::string causedBy( const std::exception& e ){ return causedBy( e.what() ); }
191  inline std::string causedBy( const std::string& e ){ return causedBy( e.c_str() ); }
192  inline std::string causedBy( const std::string* e ){
193  return (e && *e != "") ? causedBy(*e) : "";
194  }
195  inline std::string causedBy( const Status& e ){ return causedBy( e.reason() ); }
196 
198  inline void fassert(int msgid, bool testOK) {if (MONGO_unlikely(!testOK)) fassertFailed(msgid);}
199 
200 
201  /* "user assert". if asserts, user did something wrong, not our code */
202 #define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (mongo::uasserted(msgid, msg), 0) )
203 
204 #define MONGO_uassertStatusOK(expr) do { \
205  Status status = (expr); \
206  if (!status.isOK()) \
207  uasserted(status.location() != 0 ? status.location() : status.code(), \
208  status.reason()); \
209  } while(0)
210 
211  /* warning only - keeps going */
212 #define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) )
213 
214  /* display a message, no context, and throw assertionexception
215 
216  easy way to throw an exception and log something without our stack trace
217  display happening.
218  */
219 #define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (mongo::msgasserted(msgid, msg), 0) )
220  /* same as massert except no msgid */
221 #define MONGO_verify(_Expression) (void)( MONGO_likely(!!(_Expression)) || (mongo::verifyFailed(#_Expression, __FILE__, __LINE__), 0) )
222 
223  /* dassert is 'debug assert' -- might want to turn off for production as these
224  could be slow.
225  */
226 #if defined(_DEBUG)
227 # define MONGO_dassert(x) fassert(16199, (x))
228 #else
229 # define MONGO_dassert(x)
230 #endif
231 
233  inline bool debugCompare(bool inDebug, bool condition) { return inDebug && condition; }
234 
235 #if defined(_DEBUG)
236 # define MONGO_debug_and(x) debugCompare(true, (x))
237 #else
238 # define MONGO_debug_and(x) debugCompare(false, (x))
239 #endif
240 
241 #ifdef MONGO_EXPOSE_MACROS
242 # define dcompare MONGO_debug_and
243 # define dassert MONGO_dassert
244 # define verify MONGO_verify
245 # define uassert MONGO_uassert
246 # define uassertStatusOK MONGO_uassertStatusOK
247 # define wassert MONGO_wassert
248 # define massert MONGO_massert
249 #endif
250 
251  // some special ids that we want to duplicate
252 
253  // > 10000 asserts
254  // < 10000 UserException
255 
256  enum { ASSERT_ID_DUPKEY = 11000 };
257 
258  /* throws a uassertion with an appropriate msg */
259  MONGO_COMPILER_NORETURN void streamNotGood( int code, const std::string& msg, std::ios& myios );
260 
261  inline void assertStreamGood(unsigned msgid, const std::string& msg, std::ios& myios) {
262  if( !myios.good() ) streamNotGood(msgid, msg, myios);
263  }
264 
265  std::string demangleName( const std::type_info& typeinfo );
266 
267 } // namespace mongo
268 
269 #define MONGO_ASSERT_ON_EXCEPTION( expression ) \
270  try { \
271  expression; \
272  } catch ( const std::exception &e ) { \
273  stringstream ss; \
274  ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \
275  msgasserted( 13294 , ss.str() ); \
276  } catch ( ... ) { \
277  massert( 10437 , "unknown exception" , false ); \
278  }
279 
280 #define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG( expression, msg ) \
281  try { \
282  expression; \
283  } catch ( const std::exception &e ) { \
284  stringstream ss; \
285  ss << msg << " caught exception exception: " << e.what(); \
286  msgasserted( 14043 , ss.str() ); \
287  } catch ( ... ) { \
288  msgasserted( 14044 , std::string("unknown exception") + msg ); \
289  }
290 
291 #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
292 #define MONGO_DESTRUCTOR_GUARD( expression ) \
293  try { \
294  expression; \
295  } catch ( const std::exception &e ) { \
296  problem() << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" << endl; \
297  } catch ( ... ) { \
298  problem() << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << endl; \
299  }
300