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