From fb26a7fb81b1c6986ebfebbdd9289297fbfd16aa Mon Sep 17 00:00:00 2001 From: Ian Whalen Date: Wed, 12 Feb 2020 12:21:17 -0500 Subject: SERVER-37414 Move branch-specific docs from GitHub Wiki into repo --- docs/exception_architecture.md | 77 ++++++++++++++++++++++++++++++++++++++++++ docs/memory_management.md | 6 ++++ docs/parsing_stack_traces.md | 63 ++++++++++++++++++++++++++++++++++ docs/string_manipulation.md | 31 +++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 docs/exception_architecture.md create mode 100644 docs/memory_management.md create mode 100644 docs/parsing_stack_traces.md create mode 100644 docs/string_manipulation.md (limited to 'docs') diff --git a/docs/exception_architecture.md b/docs/exception_architecture.md new file mode 100644 index 00000000000..230a26e75c1 --- /dev/null +++ b/docs/exception_architecture.md @@ -0,0 +1,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 diff --git a/docs/memory_management.md b/docs/memory_management.md new file mode 100644 index 00000000000..5363f7aff25 --- /dev/null +++ b/docs/memory_management.md @@ -0,0 +1,6 @@ +# Memory Management + +- Avoid using bare pointers for dynamically allocated objects. Prefer `std::unique_ptr`, + `std::shared_ptr`, or another RAII class such as `BSONObj`. +- If you assign the output of `new/malloc()` directly to a bare pointer you should document where + it gets deleted/freed, who owns it along the way, and how exception safety is ensured. diff --git a/docs/parsing_stack_traces.md b/docs/parsing_stack_traces.md new file mode 100644 index 00000000000..84dd8b3cd34 --- /dev/null +++ b/docs/parsing_stack_traces.md @@ -0,0 +1,63 @@ +# Parsing Stack Traces + +## `addr2line` + +[`addr2line`][1] is a utility to translate addresses into filenames and line numbers. + +``` +addr2line -e mongod -ifC +``` + + +## `c++filt` + +Use [`c++filt`][2] to demangle function names by pasting the whole stack trace to stdin. + + +## Finding the Right Binary + +To find the correct binary for a specific log you need to: + +1. Get the commit from the header of the logs. +2. Use git to locate that commit and check for the surrounding "version bump" commit. +3. Download and open the binary: + +``` +curl -O http://s3.amazonaws.com/downloads.mongodb.org/linux/mongodb-linux-x86_64-debugsymbols-1.x.x.tgz +``` + +You can also get the debugsymbols archive for official builds through [the Downloads page][3]. In the +Archived Releases section, click on the appropriate platform link to view the available archives. +Select the appropriate debug symbols archive. + +### Example: Reading the Log + +Note that the log has lines like this: + +``` +/home/abc/mongod(_ZN5mongo15printStackTraceERSo+0x27) [0x689280] +``` + +You want to use the address in between the brackets `0x689280`. Note that you will get more than one +stack frame for the address if the code is inlined. + +### Example: Using `addr2line` + +Actual example from a v1.8.1 64-bit Linux build: + +``` +$ curl http://downloads.mongodb.org/linux/mongodb-linux-x86_64-debugsymbols-1.8.1.tgz > out.tgz +$ tar -xzf out.tgz +$ cd mongodb-linux-x86_64-debugsymbols-1.8.1/ +$ cd bin +$ addr2line --help +$ addr2line -i -e mongod 0x6d6a74 +/mnt/home/buildbot/slave/Linux_64bit_V1.8/mongo/db/repl/health.cpp:394 +$ addr2line -i -e mongod 0x6d0694 +/mnt/home/buildbot/slave/Linux_64bit_V1.8/mongo/db/repl/rs.h:385 +/mnt/home/buildbot/slave/Linux_64bit_V1.8/mongo/db/repl/replset_commands.cpp:111 +``` + +[1]: https://sourceware.org/binutils/docs/binutils/addr2line.html +[2]: https://sourceware.org/binutils/docs-2.17/binutils/c_002b_002bfilt.html +[3]: https://www.mongodb.com/download-center diff --git a/docs/string_manipulation.md b/docs/string_manipulation.md new file mode 100644 index 00000000000..ed881784b06 --- /dev/null +++ b/docs/string_manipulation.md @@ -0,0 +1,31 @@ +# String Manipulation + +For string manipulation, use the util/mongoutils/str.h library. + +## `str.h` + +`util/mongoutils/str.h` provides string helper functions for each manipulation. + +`str::stream()` is quite useful for assembling strings inline: +``` +uassert(12345, str::stream() << "bad ns:" << ns, isOk); +``` + +## `StringData` + +``` +/** A StringData object wraps a 'const std::string&' or a 'const char*' without + * copying its contents. The most common usage is as a function argument that + * takes any of the two forms of strings above. Fundamentally, this class tries + * to work around the fact that string literals in C++ are char[N]'s. + * + * Important: the object StringData wraps must remain alive while the StringData + * is. +*/ +class StringData { +``` + +See also [`bson/string_data.h`][1]. + + +[1]: ../src/mongo/base/string_data.h -- cgit v1.2.1