MongoDB  2.6.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/client/export_macros.h"
27 #include "mongo/platform/compiler.h"
28 
29 namespace mongo {
30 
31  enum CommonErrorCodes {
32  OkCode = 0,
33  DatabaseDifferCaseCode = 13297 , // uassert( 13297 )
34  SendStaleConfigCode = 13388 , // uassert( 13388 )
35  RecvStaleConfigCode = 9996, // uassert( 9996 )
36  PrepareConfigsFailedCode = 13104, // uassert( 13104 )
37  NotMasterOrSecondaryCode = 13436, // uassert( 13436 )
38  NotMasterNoSlaveOkCode = 13435, // uassert( 13435 )
39  NotMaster = 10107, // uassert( 10107 )
40  IndexOptionsDiffer = 17427 // uassert( 17427 )
41  };
42 
43  class MONGO_CLIENT_API AssertionCount {
44  public:
46  void rollover();
47  void condrollover( int newValue );
48 
49  int regular;
50  int warning;
51  int msg;
52  int user;
53  int rollovers;
54  };
55 
56  extern AssertionCount assertionCount;
57 
58  class BSONObjBuilder;
59 
60  struct MONGO_CLIENT_API ExceptionInfo {
61  ExceptionInfo() : msg(""),code(-1) {}
62  ExceptionInfo( const char * m , int c )
63  : msg( m ) , code( c ) {
64  }
65  ExceptionInfo( const std::string& m , int c )
66  : msg( m ) , code( c ) {
67  }
68  void append( BSONObjBuilder& b , const char * m = "$err" , const char * c = "code" ) const ;
69  std::string toString() const;
70  bool empty() const { return msg.empty(); }
71  void reset(){ msg = ""; code=-1; }
72  std::string msg;
73  int code;
74  };
75 
82  class MONGO_CLIENT_API ErrorMsg {
83  public:
84  ErrorMsg(const char *msg, char ch);
85  ErrorMsg(const char *msg, unsigned val);
86  operator std::string() const { return buf; }
87  private:
88  char buf[256];
89  };
90 
91  class DBException;
92  MONGO_CLIENT_API std::string causedBy( const DBException& e );
93  MONGO_CLIENT_API std::string causedBy( const std::string& e );
94  MONGO_CLIENT_API bool inShutdown();
95 
97  class MONGO_CLIENT_API DBException : public std::exception {
98  public:
99  DBException( const ExceptionInfo& ei ) : _ei(ei) { traceIfNeeded(*this); }
100  DBException( const char * msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); }
101  DBException( const std::string& msg , int code ) : _ei(msg,code) { traceIfNeeded(*this); }
102  virtual ~DBException() throw() { }
103 
104  virtual const char* what() const throw() { return _ei.msg.c_str(); }
105  virtual int getCode() const { return _ei.code; }
106  virtual void appendPrefix( std::stringstream& ss ) const { }
107  virtual void addContext( const std::string& str ) {
108  _ei.msg = str + causedBy( _ei.msg );
109  }
110 
111  // Utilities for the migration to Status objects
112  static ErrorCodes::Error convertExceptionCode(int exCode);
113 
114  Status toStatus(const std::string& context) const {
115  return Status(convertExceptionCode(getCode()), context + causedBy(*this));
116  }
117  Status toStatus() const {
118  return Status(convertExceptionCode(getCode()), this->what());
119  }
120 
121  // context when applicable. otherwise ""
122  std::string _shard;
123 
124  virtual std::string toString() const;
125 
126  const ExceptionInfo& getInfo() const { return _ei; }
127  private:
128  static void traceIfNeeded( const DBException& e );
129  public:
130  static bool traceExceptions;
131 
132  protected:
133  ExceptionInfo _ei;
134  };
135 
136  class MONGO_CLIENT_API AssertionException : public DBException {
137  public:
138 
139  AssertionException( const ExceptionInfo& ei ) : DBException(ei) {}
140  AssertionException( const char * msg , int code ) : DBException(msg,code) {}
141  AssertionException( const std::string& msg , int code ) : DBException(msg,code) {}
142 
143  virtual ~AssertionException() throw() { }
144 
145  virtual bool severe() const { return true; }
146  virtual bool isUserAssertion() const { return false; }
147  };
148 
149  /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */
150  class MONGO_CLIENT_API UserException : public AssertionException {
151  public:
152  UserException(int c , const std::string& m) : AssertionException( m , c ) {}
153  virtual bool severe() const { return false; }
154  virtual bool isUserAssertion() const { return true; }
155  virtual void appendPrefix( std::stringstream& ss ) const;
156  };
157 
158  class MONGO_CLIENT_API MsgAssertionException : public AssertionException {
159  public:
161  MsgAssertionException(int c, const std::string& m) : AssertionException( m , c ) {}
162  virtual bool severe() const { return false; }
163  virtual void appendPrefix( std::stringstream& ss ) const;
164  };
165 
166  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void verifyFailed(const char *msg, const char *file, unsigned line);
167  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void invariantFailed(const char *msg, const char *file, unsigned line);
168  MONGO_CLIENT_API void wasserted(const char *msg, const char *file, unsigned line);
169  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void fassertFailed( int msgid );
170  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void fassertFailedNoTrace( int msgid );
171  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void fassertFailedWithStatus(
172  int msgid, const Status& status);
173 
177  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void uasserted(int msgid, const char *msg);
178  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void uasserted(int msgid , const std::string &msg);
179 
183  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void msgassertedNoTrace(int msgid, const char *msg);
184  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg);
185  MONGO_CLIENT_API MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string &msg);
186 
187  /* convert various types of exceptions to strings */
188  MONGO_CLIENT_API std::string causedBy( const char* e );
189  MONGO_CLIENT_API std::string causedBy( const DBException& e );
190  MONGO_CLIENT_API std::string causedBy( const std::exception& e );
191  MONGO_CLIENT_API std::string causedBy( const std::string& e );
192  MONGO_CLIENT_API std::string causedBy( const std::string* e );
193  MONGO_CLIENT_API std::string causedBy( const Status& e );
194 
196  MONGO_CLIENT_API inline void fassert(int msgid, bool testOK) {
197  if (MONGO_unlikely(!testOK)) fassertFailed(msgid);
198  }
199 
200  MONGO_CLIENT_API inline void fassert(int msgid, const Status& status) {
201  if (MONGO_unlikely(!status.isOK())) {
202  fassertFailedWithStatus(msgid, status);
203  }
204  }
205 
206 
207  /* "user assert". if asserts, user did something wrong, not our code */
208 #define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (::mongo::uasserted(msgid, msg), 0) )
209 
210  MONGO_CLIENT_API inline void uassertStatusOK(const Status& status) {
211  if (MONGO_unlikely(!status.isOK())) {
212  uasserted((status.location() != 0 ? status.location() : status.code()),
213  status.reason());
214  }
215  }
216 
217  /* warning only - keeps going */
218 #define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) || (::mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) )
219 
220  /* display a message, no context, and throw assertionexception
221 
222  easy way to throw an exception and log something without our stack trace
223  display happening.
224  */
225 #define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (::mongo::msgasserted(msgid, msg), 0) )
226  /* same as massert except no msgid */
227 #define MONGO_verify(_Expression) (void)( MONGO_likely(!!(_Expression)) || (::mongo::verifyFailed(#_Expression, __FILE__, __LINE__), 0) )
228 
229 #define MONGO_invariant(_Expression) (void)( MONGO_likely(!!(_Expression)) || (::mongo::invariantFailed(#_Expression, __FILE__, __LINE__), 0) )
230 
231  /* dassert is 'debug assert' -- might want to turn off for production as these
232  could be slow.
233  */
234 #if defined(_DEBUG)
235 # define MONGO_dassert(x) fassert(16199, (x))
236 #else
237 # define MONGO_dassert(x)
238 #endif
239 
240 #ifdef MONGO_EXPOSE_MACROS
241 # define dassert MONGO_dassert
242 # define verify MONGO_verify
243 # define invariant MONGO_invariant
244 # define uassert MONGO_uassert
245 # define wassert MONGO_wassert
246 # define massert MONGO_massert
247 #endif
248 
249  // some special ids that we want to duplicate
250 
251  // > 10000 asserts
252  // < 10000 UserException
253 
254  enum { ASSERT_ID_DUPKEY = 11000 };
255 
256  /* throws a uassertion with an appropriate msg */
257  MONGO_COMPILER_NORETURN void streamNotGood( int code, const std::string& msg, std::ios& myios );
258 
259  inline void assertStreamGood(unsigned msgid, const std::string& msg, std::ios& myios) {
260  if( !myios.good() ) streamNotGood(msgid, msg, myios);
261  }
262 
263  std::string demangleName( const std::type_info& typeinfo );
264 
265 } // namespace mongo
266 
267 #define MONGO_ASSERT_ON_EXCEPTION( expression ) \
268  try { \
269  expression; \
270  } catch ( const std::exception &e ) { \
271  stringstream ss; \
272  ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \
273  msgasserted( 13294 , ss.str() ); \
274  } catch ( ... ) { \
275  massert( 10437 , "unknown exception" , false ); \
276  }
277 
278 #define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG( expression, msg ) \
279  try { \
280  expression; \
281  } catch ( const std::exception &e ) { \
282  stringstream ss; \
283  ss << msg << " caught exception exception: " << e.what(); \
284  msgasserted( 14043 , ss.str() ); \
285  } catch ( ... ) { \
286  msgasserted( 14044 , std::string("unknown exception") + msg ); \
287  }
288 
289 #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
290 #define MONGO_DESTRUCTOR_GUARD( expression ) \
291  try { \
292  expression; \
293  } catch ( const std::exception &e ) { \
294  problem() << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ \
295  << ")" << std::endl; \
296  } catch ( ... ) { \
297  problem() << "caught unknown exception in destructor (" << __FUNCTION__ << ")" \
298  << std::endl; \
299  }
300 
Utility for creating a BSONObj.
Definition: bsonobjbuilder.h:52
Most mongo exceptions inherit from this; this is commonly caught in most threads. ...
Definition: assert_util.h:97
Definition: assert_util.h:150
Definition: assert_util.h:43
Definition: assert_util.h:136
LogstreamBuilder warning()
Returns a LogstreamBuilder for logging a message with LogSeverity::Warning().
Definition: log.h:60
Definition: assert_util.h:60
NOINLINE_DECL void msgassertedNoTrace(int msgid, const char *msg)
msgassert and massert are for errors that are internal but have a well defined error text std::string...
Definition: assert_util.cpp:186
MONGO_CLIENT_API void fassert(int msgid, bool testOK)
aborts on condition failure
Definition: assert_util.h:196
helper class that builds error strings.
Definition: assert_util.h:82
Definition: assert_util.h:158
LogstreamBuilder severe()
Returns a LogstreamBuilder for logging a message with LogSeverity::Severe().
Definition: log.h:42