diff options
-rw-r--r-- | src/mongo/platform/source_location.h | 1 | ||||
-rw-r--r-- | src/mongo/util/assert_util.cpp | 7 | ||||
-rw-r--r-- | src/mongo/util/assert_util.h | 36 | ||||
-rw-r--r-- | src/mongo/util/assert_util_test.cpp | 39 | ||||
-rw-r--r-- | src/mongo/util/interruptible.h | 4 |
5 files changed, 85 insertions, 2 deletions
diff --git a/src/mongo/platform/source_location.h b/src/mongo/platform/source_location.h index 3d9830ec97b..1909ab1c436 100644 --- a/src/mongo/platform/source_location.h +++ b/src/mongo/platform/source_location.h @@ -30,6 +30,7 @@ #pragma once #include <cstdint> +#include <ostream> #include <string> #if !defined(_MSC_VER) && !defined(__clang__) // not windows or clang diff --git a/src/mongo/util/assert_util.cpp b/src/mongo/util/assert_util.cpp index cc52a6f1d13..d1e9281f490 100644 --- a/src/mongo/util/assert_util.cpp +++ b/src/mongo/util/assert_util.cpp @@ -269,6 +269,13 @@ MONGO_COMPILER_NOINLINE void msgassertedWithLocation(const Status& status, error_details::throwExceptionForStatus(status); } +void internalAssertWithLocation(SourceLocationHolder loc, const Status& status) { + if (status.isOK()) + return; + LOGV2_DEBUG(4892201, 3, "Internal assertion", "error"_attr = status, "location"_attr = loc); + error_details::throwExceptionForStatus(status); +} + std::string causedBy(StringData e) { constexpr auto prefix = " :: caused by :: "_sd; std::string out; diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h index 44ac167c33f..f1e54d2a7ce 100644 --- a/src/mongo/util/assert_util.h +++ b/src/mongo/util/assert_util.h @@ -36,6 +36,7 @@ #include "mongo/base/status.h" // NOTE: This is safe as utils depend on base #include "mongo/base/status_with.h" #include "mongo/platform/compiler.h" +#include "mongo/platform/source_location.h" #include "mongo/util/concurrency/thread_name.h" #include "mongo/util/debug_util.h" @@ -436,6 +437,41 @@ inline void massertStatusOKWithLocation(const Status& status, const char* file, } /** + * `internalAssert` is provided as an alternative for `uassert` variants (e.g., `uassertStatusOK`) + * to support cases where we expect a failure, the failure is recoverable, or accounting for the + * failure, updating assertion counters, isn't desired. `internalAssert` logs at D3 instead of D1, + * which helps with reducing the noise of assertions in production. The goal is to keep one + * interface (i.e., `internalAssert(...)`) for all possible assertion variants, and use function + * overloading to expand type support as needed. + */ +#define internalAssert(...) \ + ::mongo::internalAssertWithLocation(MONGO_SOURCE_LOCATION(), __VA_ARGS__) + +void internalAssertWithLocation(SourceLocationHolder loc, const Status& status); + +inline void internalAssertWithLocation(SourceLocationHolder loc, Status&& status) { + internalAssertWithLocation(std::move(loc), status); +} + +inline void internalAssertWithLocation(SourceLocationHolder loc, + int msgid, + const std::string& msg, + bool expr) { + if (MONGO_unlikely(!expr)) + internalAssertWithLocation(std::move(loc), Status(ErrorCodes::Error(msgid), msg)); +} + +template <typename T> +inline void internalAssertWithLocation(SourceLocationHolder loc, const StatusWith<T>& sw) { + internalAssertWithLocation(std::move(loc), sw.getStatus()); +} + +template <typename T> +inline void internalAssertWithLocation(SourceLocationHolder loc, StatusWith<T>&& sw) { + internalAssertWithLocation(std::move(loc), sw); +} + +/** * verify is deprecated. It is like invariant() in debug builds and massert() in release builds. */ #define verify(expression) MONGO_verify(expression) diff --git a/src/mongo/util/assert_util_test.cpp b/src/mongo/util/assert_util_test.cpp index 07367a80a7a..4275d8a907e 100644 --- a/src/mongo/util/assert_util_test.cpp +++ b/src/mongo/util/assert_util_test.cpp @@ -212,6 +212,45 @@ TEST(AssertUtils, UassertTypedExtraInfoWorks) { } } +TEST(AssertUtils, UassertIncrementsUserAssertionCounter) { + auto userAssertions = assertionCount.user.load(); + auto asserted = false; + try { + Status status = {ErrorCodes::BadValue, "Test"}; + uassertStatusOK(status); + } catch (const DBException&) { + asserted = true; + } + ASSERT(asserted); + ASSERT_EQ(userAssertions + 1, assertionCount.user.load()); +} + +TEST(AssertUtils, InternalAssertWithStatus) { + auto userAssertions = assertionCount.user.load(); + try { + Status status = {ErrorCodes::BadValue, "Test"}; + internalAssert(status); + } catch (const DBException& ex) { + ASSERT_EQ(ex.code(), ErrorCodes::BadValue); + ASSERT_EQ(ex.reason(), "Test"); + } + ASSERT_EQ(userAssertions, assertionCount.user.load()); +} + +TEST(AssertUtils, InternalAssertWithExpression) { + auto userAssertions = assertionCount.user.load(); + try { + internalAssert(48922, "Test", false); + } catch (const DBException& ex) { + ASSERT_EQ(ex.code(), 48922); + ASSERT_EQ(ex.reason(), "Test"); + } + + internalAssert(48922, "Another test", true); + + ASSERT_EQ(userAssertions, assertionCount.user.load()); +} + TEST(AssertUtils, MassertTypedExtraInfoWorks) { try { msgasserted(ErrorExtraInfoExample(123), ""); diff --git a/src/mongo/util/interruptible.h b/src/mongo/util/interruptible.h index 364a3927f0d..5b14c29bcc1 100644 --- a/src/mongo/util/interruptible.h +++ b/src/mongo/util/interruptible.h @@ -317,7 +317,7 @@ public: * Raises a AssertionException if this operation is in a killed state. */ void checkForInterrupt() { - uassertStatusOK(checkForInterruptNoAssert()); + internalAssert(checkForInterruptNoAssert()); } /** @@ -395,7 +395,7 @@ public: if (!swResult.isOK()) { _onWake(latchName, WakeReason::kInterrupt, speed); - uassertStatusOK(std::move(swResult)); + internalAssert(std::move(swResult)); } if (pred()) { |