MongoDB C++ Driver  legacy-1.1.2
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 <typeinfo>
21 #include <string>
22 
23 #include "mongo/base/status.h" // NOTE: This is safe as utils depend on base
24 #include "mongo/client/export_macros.h"
25 #include "mongo/platform/compiler.h"
26 #include "mongo/logger/log_severity.h"
27 #include "mongo/logger/logger.h"
28 #include "mongo/logger/logstream_builder.h"
29 
30 namespace mongo {
31 
32 enum CommonErrorCodes {
33  OkCode = 0,
34  DatabaseDifferCaseCode = 13297, // uassert( 13297 )
35  SendStaleConfigCode = 13388, // uassert( 13388 )
36  RecvStaleConfigCode = 9996, // uassert( 9996 )
37  PrepareConfigsFailedCode = 13104, // uassert( 13104 )
38  NotMasterOrSecondaryCode = 13436, // uassert( 13436 )
39  NotMasterNoSlaveOkCode = 13435, // uassert( 13435 )
40  NotMaster = 10107, // uassert( 10107 )
41 };
42 
43 class BSONObjBuilder;
44 
45 struct MONGO_CLIENT_API ExceptionInfo {
46  ExceptionInfo() : msg(""), code(-1) {}
47  ExceptionInfo(const char* m, int c) : msg(m), code(c) {}
48  ExceptionInfo(const std::string& m, int c) : msg(m), code(c) {}
49  void append(BSONObjBuilder& b, const char* m = "$err", const char* c = "code") const;
50  std::string toString() const;
51  bool empty() const {
52  return msg.empty();
53  }
54  void reset() {
55  msg = "";
56  code = -1;
57  }
58  std::string msg;
59  int code;
60 };
61 
70 class MONGO_CLIENT_API ErrorMsg {
71 public:
72  ErrorMsg(const char* msg, char ch);
73  ErrorMsg(const char* msg, unsigned val);
74  operator std::string() const {
75  return buf;
76  }
77 
78 private:
79  char buf[256];
80 };
81 
82 class DBException;
83 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const DBException& e);
84 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::string& e);
85 
87 class MONGO_CLIENT_API DBException : public std::exception {
88 public:
89  DBException(const ExceptionInfo& ei) : _ei(ei) {}
90  DBException(const char* msg, int code) : _ei(msg, code) {}
91  DBException(const std::string& msg, int code) : _ei(msg, code) {}
92  virtual ~DBException() throw() {}
93 
94  virtual const char* what() const throw() {
95  return _ei.msg.c_str();
96  }
97  virtual int getCode() const {
98  return _ei.code;
99  }
100  virtual void appendPrefix(std::stringstream& ss) const {}
101  virtual void addContext(const std::string& str) {
102  _ei.msg = str + causedBy(_ei.msg);
103  }
104 
105  // Utilities for the migration to Status objects
106  static ErrorCodes::Error MONGO_CLIENT_FUNC convertExceptionCode(int exCode);
107 
108  Status toStatus(const std::string& context) const {
109  return Status(convertExceptionCode(getCode()), context + causedBy(*this));
110  }
111  Status toStatus() const {
112  return Status(convertExceptionCode(getCode()), this->what());
113  }
114 
115  // context when applicable. otherwise ""
116  std::string _shard;
117 
118  virtual std::string toString() const;
119 
120  const ExceptionInfo& getInfo() const {
121  return _ei;
122  }
123 
124 protected:
125  ExceptionInfo _ei;
126 };
127 
128 class MONGO_CLIENT_API AssertionException : public DBException {
129 public:
130  AssertionException(const ExceptionInfo& ei) : DBException(ei) {}
131  AssertionException(const char* msg, int code) : DBException(msg, code) {}
132  AssertionException(const std::string& msg, int code) : DBException(msg, code) {}
133 
134  virtual ~AssertionException() throw() {}
135 
136  virtual bool severe() const {
137  return true;
138  }
139  virtual bool isUserAssertion() const {
140  return false;
141  }
142 };
143 
144 /* UserExceptions are valid errors that a user can cause, like out of disk space or duplicate key */
145 class MONGO_CLIENT_API UserException : public AssertionException {
146 public:
147  UserException(int c, const std::string& m) : AssertionException(m, c) {}
148  virtual bool severe() const {
149  return false;
150  }
151  virtual bool isUserAssertion() const {
152  return true;
153  }
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 {
162  return false;
163  }
164  virtual void appendPrefix(std::stringstream& ss) const;
165 };
166 
167 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
168 verifyFailed(const char* expr, const char* file, unsigned line);
169 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
170 invariantFailed(const char* expr, const char* file, unsigned line);
171 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
172 invariantOKFailed(const char* expr, const Status& status, const char* file, unsigned line);
173 MONGO_CLIENT_API void MONGO_CLIENT_FUNC
174 wasserted(const char* expr, const char* file, unsigned line);
175 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC fassertFailed(int msgid);
176 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
177 fassertFailedWithStatus(int msgid, const Status& status);
178 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
179 fassertFailedWithStatusNoTrace(int msgid, const Status& status);
180 
184 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
185 uasserted(int msgid, const char* msg);
186 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
187 uasserted(int msgid, const std::string& msg);
188 
192 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
193 msgassertedNoTrace(int msgid, const char* msg);
194 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
195 msgassertedNoTrace(int msgid, const std::string& msg);
196 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
197 msgasserted(int msgid, const char* msg);
198 MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC
199 msgasserted(int msgid, const std::string& msg);
200 
201 /* convert various types of exceptions to strings */
202 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const char* e);
203 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const DBException& e);
204 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::exception& e);
205 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::string& e);
206 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const std::string* e);
207 MONGO_CLIENT_API std::string MONGO_CLIENT_FUNC causedBy(const Status& e);
208 
210 MONGO_CLIENT_API inline void MONGO_CLIENT_FUNC fassert(int msgid, bool testOK) {
211  if (MONGO_unlikely(!testOK))
212  fassertFailed(msgid);
213 }
214 
215 MONGO_CLIENT_API inline void MONGO_CLIENT_FUNC fassert(int msgid, const Status& status) {
216  if (MONGO_unlikely(!status.isOK())) {
217  fassertFailedWithStatus(msgid, status);
218  }
219 }
220 
221 MONGO_CLIENT_API inline void fassertNoTrace(int msgid, const Status& status) {
222  if (MONGO_unlikely(!status.isOK())) {
223  fassertFailedWithStatusNoTrace(msgid, status);
224  }
225 }
226 
227 
228 /* "user assert". if asserts, user did something wrong, not our code */
229 #define MONGO_uassert(msgid, msg, expr) \
230  do { \
231  if (MONGO_unlikely(!(expr))) { \
232  ::mongo::uasserted(msgid, msg); \
233  } \
234  } while (false)
235 
236 MONGO_CLIENT_API inline void MONGO_CLIENT_FUNC uassertStatusOK(const Status& status) {
237  if (MONGO_unlikely(!status.isOK())) {
238  uasserted((status.location() != 0 ? status.location() : status.code()), status.reason());
239  }
240 }
241 
242 /* warning only - keeps going */
243 #define MONGO_wassert(_Expression) \
244  do { \
245  if (MONGO_unlikely(!(_Expression))) { \
246  ::mongo::wasserted(#_Expression, __FILE__, __LINE__); \
247  } \
248  } while (false)
249 
250 /* display a message, no context, and throw assertionexception
251 
252  easy way to throw an exception and log something without our stack trace
253  display happening.
254 */
255 #define MONGO_massert(msgid, msg, expr) \
256  do { \
257  if (MONGO_unlikely(!(expr))) { \
258  ::mongo::msgasserted(msgid, msg); \
259  } \
260  } while (false)
261 
262 MONGO_CLIENT_API inline void massertStatusOK(const Status& status) {
263  if (MONGO_unlikely(!status.isOK())) {
264  msgasserted((status.location() != 0 ? status.location() : status.code()), status.reason());
265  }
266 }
267 
268 MONGO_CLIENT_API inline void massertNoTraceStatusOK(const Status& status) {
269  if (MONGO_unlikely(!status.isOK())) {
270  msgassertedNoTrace((status.location() != 0 ? status.location() : status.code()),
271  status.reason());
272  }
273 }
274 
275 /* same as massert except no msgid */
276 #define MONGO_verify(_Expression) \
277  do { \
278  if (MONGO_unlikely(!(_Expression))) { \
279  ::mongo::verifyFailed(#_Expression, __FILE__, __LINE__); \
280  } \
281  } while (false)
282 
283 #define MONGO_invariant(_Expression) \
284  do { \
285  if (MONGO_unlikely(!(_Expression))) { \
286  ::mongo::invariantFailed(#_Expression, __FILE__, __LINE__); \
287  } \
288  } while (false)
289 
290 #define MONGO_invariantOK(expression) \
291  do { \
292  const ::mongo::Status _invariantOK_status = expression; \
293  if (MONGO_unlikely(!_invariantOK_status.isOK())) { \
294  ::mongo::invariantOKFailed(#expression, _invariantOK_status, __FILE__, __LINE__); \
295  } \
296  } while (false)
297 
298 #ifdef MONGO_EXPOSE_MACROS
299 #define verify(expression) MONGO_verify(expression)
300 #define invariant MONGO_invariant
301 #define invariantOK MONGO_invariantOK
302 #define uassert MONGO_uassert
303 #define wassert MONGO_wassert
304 #define massert MONGO_massert
305 #endif
306 
307 // some special ids that we want to duplicate
308 
309 // > 10000 asserts
310 // < 10000 UserException
311 
312 enum { ASSERT_ID_DUPKEY = 11000 };
313 
314 std::string demangleName(const std::type_info& typeinfo);
315 
316 } // namespace mongo
317 
318 #define MONGO_ASSERT_ON_EXCEPTION(expression) \
319  try { \
320  expression; \
321  } catch (const std::exception& e) { \
322  std::stringstream ss; \
323  ss << "caught exception: " << e.what() << ' ' << __FILE__ << ' ' << __LINE__; \
324  msgasserted(13294, ss.str()); \
325  } catch (...) { \
326  massert(10437, "unknown exception", false); \
327  }
328 
329 #define MONGO_ASSERT_ON_EXCEPTION_WITH_MSG(expression, msg) \
330  try { \
331  expression; \
332  } catch (const std::exception& e) { \
333  std::stringstream ss; \
334  ss << msg << " caught exception exception: " << e.what(); \
335  msgasserted(14043, ss.str()); \
336  } catch (...) { \
337  msgasserted(14044, std::string("unknown exception") + msg); \
338  }
339 
340 #define DESTRUCTOR_GUARD MONGO_DESTRUCTOR_GUARD
341 #define MONGO_DESTRUCTOR_GUARD(expression) \
342  try { \
343  expression; \
344  } catch (const std::exception& e) { \
345  ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
346  std::string(), \
347  ::mongo::logger::LogSeverity::Log()) \
348  << "caught exception (" << e.what() << ") in destructor (" << __FUNCTION__ << ")" \
349  << std::endl; \
350  } catch (...) { \
351  ::mongo::logger::LogstreamBuilder(::mongo::logger::globalLogDomain(), \
352  std::string(), \
353  ::mongo::logger::LogSeverity::Log()) \
354  << "caught unknown exception in destructor (" << __FUNCTION__ << ")" << std::endl; \
355  }
356 
369 #define MONGO_UNREACHABLE ::mongo::invariantFailed("Hit a MONGO_UNREACHABLE!", __FILE__, __LINE__);
Status represents an error state or the absence thereof.
Definition: status.h:50
Utility functions for parsing numbers from strings.
Definition: compare_numbers.h:20
Definition: assert_util.h:45
helper class that builds error strings.
Definition: assert_util.h:70
MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC uasserted(int msgid, const char *msg)
a "user assertion".
Utility for creating a BSONObj.
Definition: bsonobjbuilder.h:53
MONGO_CLIENT_API MONGO_COMPILER_NORETURN void MONGO_CLIENT_FUNC 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.h:128
MONGO_CLIENT_API void MONGO_CLIENT_FUNC fassert(int msgid, bool testOK)
aborts on condition failure
Definition: assert_util.h:210
Definition: assert_util.h:145
Most mongo exceptions inherit from this; this is commonly caught in most threads. ...
Definition: assert_util.h:87
MONGO_CLIENT_API Status(MONGO_CLIENT_FUNC *saslClientAuthenticate)(DBClientWithCommands *client
Attempts to authenticate "client" using the SASL protocol.
Definition: assert_util.h:157