1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
# Exception Architecture
MongoDB code uses the following types of assertions that are available for use:
- `uassert`
- Checks for per-operation user errors. Operation-fatal.
- `massert`
- Checks per-operation invariants. Operation-fatal.
- `fassert`
- Checks fatal process invariants. Process-fatal. Use to detect unexpected situations (such
as a system function returning an unexpected error status).
- `invariant`
- Checks process invariant. Process-fatal. Use to detect code logic errors ("pointer should
never be null", "we should always be locked").
__Note__: Calling C function `assert` is not allowed. Use one of the above instead.
The following types of assertions are deprecated:
- `verify`
- Checks per-operation invariants. A synonym for massert but doesn't require an error code.
Do not use for new code; use invariant or fassert instead.
- `dassert`
- Calls `verify` but only in debug mode. Do not use!
## Considerations
When per-operation invariant checks fail, the current operation fails, but the process and
connection persist. This means that `massert`, `uassert` and `verify` only terminate the current
operation, not the whole process. Be careful not to corrupt process state by mistakenly using these
assertions midway through mutating process state. Examples of this include `uassert` and `massert`
inside of constructors and destructors.
`fassert` failures will terminate the entire process; this is used for low-level checks where
continuing might lead to corrupt data or loss of data on disk.
Both `massert` and uassert take error codes, so that all errors have codes associated with them.
These error codes are assigned incrementally; the numbers have no meaning other than a way to
associate a log message with a line of code. SCons checks for duplicates, but if you want the next
available code you can run:
```
python buildscripts/errorcodes.py
```
## Exception
A failed operation-fatal assertion throws an `AssertionException` or a child of that.
The inheritance hierarchy resembles:
- `std::exception`
- `mongo::DBException`
- `mongo::AssertionException`
- `mongo::UserException`
- `mongo::MsgAssertionException`
See util/assert_util.h.
Generally, code in the server should be prepared to catch a `DBException`. The code should also
expect `UserException`. We use [Resource Acquisition Is Initialization][1] heavily.
## Gotchas
Gotchas to watch out for:
- Generally, do not throw an `AssertionException` directly. Functions like `uasserted()` do work
beyond just that. In particular, it makes sure that the `getLastError` structures are set up
properly.
- Think about the location of your asserts in constructors, as the destructor would not be
called. But at a minimum, use `wassert` a lot therein, we want to know if something is wrong.
- Do __not__ throw in destructors or allow exceptions to leak out (if you call a function that
may throw).
[1]: https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
|