summaryrefslogtreecommitdiff
path: root/src/mongo/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util')
-rw-r--r--src/mongo/util/diagnostic_info.cpp2
-rw-r--r--src/mongo/util/diagnostic_info.h2
-rw-r--r--src/mongo/util/fail_point.cpp28
-rw-r--r--src/mongo/util/fail_point.h309
-rw-r--r--src/mongo/util/fail_point_registry.cpp43
-rw-r--r--src/mongo/util/fail_point_registry.h6
-rw-r--r--src/mongo/util/fail_point_service.cpp35
-rw-r--r--src/mongo/util/fail_point_service.h28
-rw-r--r--src/mongo/util/fail_point_test.cpp74
-rw-r--r--src/mongo/util/net/sock.cpp6
-rw-r--r--src/mongo/util/net/sock_test.cpp2
-rw-r--r--src/mongo/util/net/ssl/detail/io.hpp4
12 files changed, 254 insertions, 285 deletions
diff --git a/src/mongo/util/diagnostic_info.cpp b/src/mongo/util/diagnostic_info.cpp
index a42cc5275a9..a05dcb8a3f6 100644
--- a/src/mongo/util/diagnostic_info.cpp
+++ b/src/mongo/util/diagnostic_info.cpp
@@ -73,7 +73,7 @@ MONGO_INITIALIZER(LockActions)(InitializerContext* context) {
DiagnosticInfo::Diagnostic::clearDiagnostic();
}
void onFailedLock() override {
- if (!MONGO_FAIL_POINT(keepDiagnosticCaptureOnFailedLock)) {
+ if (!MONGO_unlikely(keepDiagnosticCaptureOnFailedLock.shouldFail())) {
DiagnosticInfo::Diagnostic::clearDiagnostic();
}
}
diff --git a/src/mongo/util/diagnostic_info.h b/src/mongo/util/diagnostic_info.h
index 7f7325c9b23..0a4958f35de 100644
--- a/src/mongo/util/diagnostic_info.h
+++ b/src/mongo/util/diagnostic_info.h
@@ -36,7 +36,7 @@
#include "mongo/util/time_support.h"
namespace mongo {
-MONGO_FAIL_POINT_DECLARE(keepDiagnosticCaptureOnFailedLock);
+extern FailPoint keepDiagnosticCaptureOnFailedLock;
/**
* DiagnosticInfo keeps track of diagnostic information such as a developer provided
* name, the time when a lock was first acquired, and a partial caller call stack.
diff --git a/src/mongo/util/fail_point.cpp b/src/mongo/util/fail_point.cpp
index d5af18f318f..c40a4b829d6 100644
--- a/src/mongo/util/fail_point.cpp
+++ b/src/mongo/util/fail_point.cpp
@@ -84,7 +84,7 @@ void FailPoint::shouldFailCloseBlock() {
_fpInfo.subtractAndFetch(1);
}
-void FailPoint::setMode(Mode mode, ValType val, const BSONObj& extra) {
+void FailPoint::setMode(Mode mode, ValType val, BSONObj extra) {
/**
* Outline:
*
@@ -96,20 +96,20 @@ void FailPoint::setMode(Mode mode, ValType val, const BSONObj& extra) {
stdx::lock_guard<stdx::mutex> scoped(_modMutex);
// Step 1
- disableFailPoint();
+ disable();
// Step 2
while (_fpInfo.load() != 0) {
sleepmillis(50);
}
+ // Step 3
_mode = mode;
_timesOrPeriod.store(val);
-
- _data = extra.copy();
+ _data = std::move(extra);
if (_mode != off) {
- enableFailPoint();
+ enable();
}
}
@@ -117,19 +117,19 @@ const BSONObj& FailPoint::getData() const {
return _data;
}
-void FailPoint::enableFailPoint() {
- _fpInfo.fetchAndBitOr(ACTIVE_BIT);
+void FailPoint::enable() {
+ _fpInfo.fetchAndBitOr(kActiveBit);
}
-void FailPoint::disableFailPoint() {
- _fpInfo.fetchAndBitAnd(~ACTIVE_BIT);
+void FailPoint::disable() {
+ _fpInfo.fetchAndBitAnd(~kActiveBit);
}
FailPoint::RetCode FailPoint::slowShouldFailOpenBlock(
std::function<bool(const BSONObj&)> cb) noexcept {
ValType localFpInfo = _fpInfo.addAndFetch(1);
- if ((localFpInfo & ACTIVE_BIT) == 0) {
+ if ((localFpInfo & kActiveBit) == 0) {
return slowOff;
}
@@ -149,7 +149,7 @@ FailPoint::RetCode FailPoint::slowShouldFailOpenBlock(
}
case nTimes: {
if (_timesOrPeriod.subtractAndFetch(1) <= 0)
- disableFailPoint();
+ disable();
return slowOn;
}
@@ -168,8 +168,7 @@ FailPoint::RetCode FailPoint::slowShouldFailOpenBlock(
}
}
-StatusWith<std::tuple<FailPoint::Mode, FailPoint::ValType, BSONObj>> FailPoint::parseBSON(
- const BSONObj& obj) {
+StatusWith<FailPoint::ModeOptions> FailPoint::parseBSON(const BSONObj& obj) {
Mode mode = FailPoint::alwaysOn;
ValType val = 0;
const BSONElement modeElem(obj["mode"]);
@@ -177,7 +176,6 @@ StatusWith<std::tuple<FailPoint::Mode, FailPoint::ValType, BSONObj>> FailPoint::
return {ErrorCodes::IllegalOperation, "When setting a failpoint, you must supply a 'mode'"};
} else if (modeElem.type() == String) {
const std::string modeStr(modeElem.valuestr());
-
if (modeStr == "off") {
mode = FailPoint::off;
} else if (modeStr == "alwaysOn") {
@@ -255,7 +253,7 @@ StatusWith<std::tuple<FailPoint::Mode, FailPoint::ValType, BSONObj>> FailPoint::
data = obj["data"].Obj().getOwned();
}
- return std::make_tuple(mode, val, data);
+ return ModeOptions{mode, val, data};
}
BSONObj FailPoint::toBSON() const {
diff --git a/src/mongo/util/fail_point.h b/src/mongo/util/fail_point.h
index f82d85785a5..57ee76bca9d 100644
--- a/src/mongo/util/fail_point.h
+++ b/src/mongo/util/fail_point.h
@@ -44,22 +44,27 @@ namespace mongo {
* deactivated, as well as embed temporary data into it.
*
* The fail point has a static instance, which is represented by a FailPoint
- * object, and dynamic instance, which are all the threads in between
- * shouldFailOpenBlock and shouldFailCloseBlock.
+ * object, and dynamic instance, represented by FailPoint::Scoped handles.
*
* Sample use:
* // Declared somewhere:
* FailPoint makeBadThingsHappen;
*
* // Somewhere in the code
- * return false || MONGO_FAIL_POINT(makeBadThingsHappen);
+ * return false || MONGO_unlikely(makeBadThingsHappen.shouldFail());
*
* or
*
* // Somewhere in the code
- * MONGO_FAIL_POINT_BLOCK(makeBadThingsHappen, blockMakeBadThingsHappen) {
- * const BSONObj& data = blockMakeBadThingsHappen.getData();
+ * makeBadThingsHappen.execute([&](const BSONObj& data) {
* // Do something
+ * });
+ *
+ * // Another way to do it, where lambda isn't suitable, e.g. to cause an early return
+ * // of the enclosing function.
+ * if (auto sfp = makeBadThingsHappen.scoped(); MONGO_unlikely(sfp.isActive())) {
+ * const BSONObj& data = sfp.getData();
+ * // Do something, including break, continue, return, etc...
* }
*
* Invariants:
@@ -69,13 +74,65 @@ namespace mongo {
* 2. Client visible fail point states are read-only when active.
*/
class FailPoint {
- FailPoint(const FailPoint&) = delete;
- FailPoint& operator=(const FailPoint&) = delete;
+private:
+ enum RetCode { fastOff = 0, slowOff, slowOn, userIgnored };
public:
- typedef unsigned ValType;
+ using ValType = unsigned;
enum Mode { off, alwaysOn, random, nTimes, skip };
- enum RetCode { fastOff = 0, slowOff, slowOn, userIgnored };
+
+ struct ModeOptions {
+ Mode mode;
+ ValType val;
+ BSONObj extra;
+ };
+
+ /**
+ * Helper class for making sure that FailPoint#shouldFailCloseBlock is called when
+ * FailPoint#shouldFailOpenBlock was called.
+ *
+ * Users don't create these. They are only used within the execute and executeIf
+ * functions and returned by the scoped() and scopedIf() functions.
+ */
+ class Scoped {
+ public:
+ Scoped(FailPoint* failPoint, RetCode ret)
+ : _failPoint(failPoint),
+ _active(ret == FailPoint::slowOn),
+ _holdsRef(ret != FailPoint::fastOff) {}
+
+ ~Scoped() {
+ if (_holdsRef) {
+ _failPoint->shouldFailCloseBlock();
+ }
+ }
+
+ Scoped(const Scoped&) = delete;
+ Scoped& operator=(const Scoped&) = delete;
+
+ /**
+ * @return true if fail point is on.
+ * Calls to isActive should be placed inside MONGO_unlikely for performance.
+ */
+ bool isActive() {
+ return _active;
+ }
+
+ /**
+ * @return the data stored in the fail point. #isActive must be true
+ * before you can call this.
+ */
+ const BSONObj& getData() const {
+ // Assert when attempting to get data without holding a ref.
+ fassert(16445, _holdsRef);
+ return _failPoint->getData();
+ }
+
+ private:
+ FailPoint* _failPoint;
+ bool _active;
+ bool _holdsRef;
+ };
/**
* Explicitly resets the seed used for the PRNG in this thread. If not called on a thread,
@@ -84,21 +141,26 @@ public:
static void setThreadPRNGSeed(int32_t seed);
/**
- * Parses the FailPoint::Mode, FailPoint::ValType, and data BSONObj from the BSON.
+ * Parses the {Mode, ValType, BSONObj} from the BSON.
*/
- static StatusWith<std::tuple<Mode, ValType, BSONObj>> parseBSON(const BSONObj& obj);
+ static StatusWith<ModeOptions> parseBSON(const BSONObj& obj);
FailPoint();
+ FailPoint(const FailPoint&) = delete;
+ FailPoint& operator=(const FailPoint&) = delete;
+
/**
* Note: This is not side-effect free - it can change the state to OFF after calling.
- * Note: see MONGO_FAIL_POINT_BLOCK_IF for information on the passed callable
+ * Note: see `executeIf` for information on `pred`.
+ *
+ * Calls to shouldFail should be placed inside MONGO_unlikely for performance.
*
* @return true if fail point is active.
*/
- template <typename Callable = std::nullptr_t>
- inline bool shouldFail(Callable&& cb = nullptr) {
- RetCode ret = shouldFailOpenBlock(std::forward<Callable>(cb));
+ template <typename Pred>
+ bool shouldFail(Pred&& pred) {
+ RetCode ret = shouldFailOpenBlock(std::forward<Pred>(pred));
if (MONGO_likely(ret == fastOff)) {
return false;
@@ -108,34 +170,11 @@ public:
return ret == slowOn;
}
- /**
- * Checks whether fail point is active and increments the reference counter without
- * decrementing it. Must call shouldFailCloseBlock afterwards when the return value
- * is not fastOff. Otherwise, this will remain read-only forever.
- *
- * Note: see MONGO_FAIL_POINT_BLOCK_IF for information on the passed callable
- *
- * @return slowOn if its active and needs to be closed
- * userIgnored if its active and needs to be closed, but shouldn't be acted on
- * slowOff if its disabled and needs to be closed
- * fastOff if its disabled and doesn't need to be closed
- */
- template <typename Callable = std::nullptr_t>
- inline RetCode shouldFailOpenBlock(Callable&& cb = nullptr) {
- if (MONGO_likely((_fpInfo.loadRelaxed() & ACTIVE_BIT) == 0)) {
- return fastOff;
- }
-
- return slowShouldFailOpenBlock(std::forward<Callable>(cb));
+ bool shouldFail() {
+ return shouldFail(nullptr);
}
/**
- * Decrements the reference counter.
- * @see #shouldFailOpenBlock
- */
- void shouldFailCloseBlock();
-
- /**
* Changes the settings of this fail point. This will turn off the fail point
* and waits for all dynamic instances referencing this fail point to go away before
* actually modifying the settings.
@@ -157,143 +196,125 @@ public:
* that can be referenced afterwards with #getData. Defaults to an empty
* document.
*/
- void setMode(Mode mode, ValType val = 0, const BSONObj& extra = BSONObj());
+ void setMode(Mode mode, ValType val = 0, BSONObj extra = {});
+ void setMode(ModeOptions opt) {
+ setMode(std::move(opt.mode), std::move(opt.val), std::move(opt.extra));
+ }
/**
* @returns a BSON object showing the current mode and data stored.
*/
BSONObj toBSON() const;
-private:
- static const ValType ACTIVE_BIT = 1 << 31;
- static const ValType REF_COUNTER_MASK = ~ACTIVE_BIT;
-
- // Bit layout:
- // 31: tells whether this fail point is active.
- // 0~30: unsigned ref counter for active dynamic instances.
- AtomicWord<unsigned> _fpInfo{0};
-
- // Invariant: These should be read only if ACTIVE_BIT of _fpInfo is set.
- Mode _mode{off};
- AtomicWord<int> _timesOrPeriod{0};
- BSONObj _data;
-
- // protects _mode, _timesOrPeriod, _data
- mutable stdx::mutex _modMutex;
-
/**
- * Enables this fail point.
+ * Create a Scoped from this FailPoint.
+ * Use the Scoped object to access failpoint data.
*/
- void enableFailPoint();
-
+ Scoped scoped() {
+ return scopedIf(nullptr);
+ }
/**
- * Disables this fail point.
+ * Create a Scoped from this FailPoint, only active when `pred(payload)` is true.
+ * See `executeIf`. Use the Scoped object to access failpoint data.
*/
- void disableFailPoint();
+ template <typename Pred>
+ Scoped scopedIf(Pred&& pred) {
+ return Scoped(this, shouldFailOpenBlock(std::forward<Pred>(pred)));
+ }
- /**
- * slow path for #shouldFailOpenBlock
- *
- * If a callable is passed, and returns false, this will return userIgnored and avoid altering
- * the mode in any way. The argument is the fail point payload.
- */
- RetCode slowShouldFailOpenBlock(std::function<bool(const BSONObj&)> cb) noexcept;
+ template <typename F>
+ void execute(F&& f) {
+ return executeIf(f, nullptr);
+ }
/**
- * @return the stored BSONObj in this fail point. Note that this cannot be safely
- * read if this fail point is off.
+ * The predicate `pred` should behave like a `bool pred(const BSONObj& payload)`.
+ * If `pred(payload)`, then `f(payload)` is executed. Otherwise, `f` is not
+ * executed and this FailPoint's mode is not altered (e.g. `nTimes` isn't consumed).
*/
- const BSONObj& getData() const;
-
- friend class ScopedFailPoint;
-};
-
-/**
- * Helper class for making sure that FailPoint#shouldFailCloseBlock is called when
- * FailPoint#shouldFailOpenBlock was called. This should only be used within the
- * MONGO_FAIL_POINT_BLOCK macro.
- */
-class ScopedFailPoint {
- ScopedFailPoint(const ScopedFailPoint&) = delete;
- ScopedFailPoint& operator=(const ScopedFailPoint&) = delete;
+ template <typename F, typename Pred>
+ void executeIf(F&& f, Pred&& pred) {
+ auto sfp = scopedIf(std::forward<Pred>(pred));
+ if (MONGO_unlikely(sfp.isActive())) {
+ std::forward<F>(f)(sfp.getData());
+ }
+ }
-public:
- template <typename Callable = std::nullptr_t>
- ScopedFailPoint(FailPoint* failPoint, Callable&& cb = nullptr) : _failPoint(failPoint) {
- FailPoint::RetCode ret = _failPoint->shouldFailOpenBlock(std::forward<Callable>(cb));
- _shouldClose = ret != FailPoint::fastOff;
- _shouldRun = ret == FailPoint::slowOn;
+ void pauseWhileSet() {
+ while (MONGO_unlikely(shouldFail())) {
+ sleepmillis(100);
+ }
}
- ~ScopedFailPoint() {
- if (_shouldClose) {
- _failPoint->shouldFailCloseBlock();
+ void pauseWhileSet(OperationContext* opCtx) {
+ while (MONGO_unlikely(shouldFail())) {
+ opCtx->sleepFor(Milliseconds(100));
}
}
+private:
+ void enable();
+ void disable();
+
/**
- * @return true if fail point is on. This will be true at most once.
+ * Checks whether fail point is active and increments the reference counter without
+ * decrementing it. Must call shouldFailCloseBlock afterwards when the return value
+ * is not fastOff. Otherwise, this will remain read-only forever.
+ *
+ * Note: see `executeIf` for information on `pred`.
+ *
+ * @return slowOn if its active and needs to be closed
+ * userIgnored if its active and needs to be closed, but shouldn't be acted on
+ * slowOff if its disabled and needs to be closed
+ * fastOff if its disabled and doesn't need to be closed
*/
- inline bool isActive() {
- if (!_shouldRun) {
- return false;
+ template <typename Pred>
+ RetCode shouldFailOpenBlock(Pred&& pred) {
+ if (MONGO_likely((_fpInfo.loadRelaxed() & kActiveBit) == 0)) {
+ return fastOff;
}
- // We use this in a for loop to prevent iteration, thus flipping to inactive after the first
- // time.
- _shouldRun = false;
- return true;
+ return slowShouldFailOpenBlock(std::forward<Pred>(pred));
+ }
+
+ RetCode shouldFailOpenBlock() {
+ return shouldFailOpenBlock(nullptr);
}
/**
- * @return the data stored in the fail point. #isActive must be true
- * before you can call this.
+ * Decrements the reference counter.
+ * @see #shouldFailOpenBlock
*/
- const BSONObj& getData() const {
- // Assert when attempting to get data without incrementing ref counter.
- fassert(16445, _shouldClose);
- return _failPoint->getData();
- }
+ void shouldFailCloseBlock();
-private:
- FailPoint* _failPoint;
- bool _shouldRun;
- bool _shouldClose;
-};
+ /**
+ * slow path for #shouldFailOpenBlock
+ *
+ * If a callable is passed, and returns false, this will return userIgnored and avoid altering
+ * the mode in any way. The argument is the fail point payload.
+ */
+ RetCode slowShouldFailOpenBlock(std::function<bool(const BSONObj&)> cb) noexcept;
-#define MONGO_FAIL_POINT(symbol) MONGO_unlikely(symbol.shouldFail())
+ /**
+ * @return the stored BSONObj in this fail point. Note that this cannot be safely
+ * read if this fail point is off.
+ */
+ const BSONObj& getData() const;
-inline void MONGO_FAIL_POINT_PAUSE_WHILE_SET(FailPoint& failPoint) {
- while (MONGO_FAIL_POINT(failPoint)) {
- sleepmillis(100);
- }
-}
+ static const ValType kActiveBit = 1 << 31;
-inline void MONGO_FAIL_POINT_PAUSE_WHILE_SET_OR_INTERRUPTED(OperationContext* opCtx,
- FailPoint& failPoint) {
- while (MONGO_FAIL_POINT(failPoint)) {
- opCtx->sleepFor(Milliseconds(100));
- }
-}
+ // Bit layout:
+ // 31: tells whether this fail point is active.
+ // 0~30: unsigned ref counter for active dynamic instances.
+ AtomicWord<std::uint32_t> _fpInfo{0};
-/**
- * Macro for creating a fail point with block context. Also use this when
- * you want to access the data stored in the fail point.
- */
-#define MONGO_FAIL_POINT_BLOCK(symbol, blockSymbol) \
- for (mongo::ScopedFailPoint blockSymbol(&symbol); MONGO_unlikely(blockSymbol.isActive());)
+ // Invariant: These should be read only if kActiveBit of _fpInfo is set.
+ Mode _mode{off};
+ AtomicWord<int> _timesOrPeriod{0};
+ BSONObj _data;
-/**
- * Macro for creating a fail point with block context and a pre-flight condition. Also use this when
- * you want to access the data stored in the fail point.
- *
- * Your passed in callable should take a const BSONObj& (the fail point payload) and return bool.
- * If it returns true, you'll process the block as normal. If you return false, you'll exit the
- * block without evaluating it and avoid altering the mode in any way (you won't consume nTimes for
- * instance).
- */
-#define MONGO_FAIL_POINT_BLOCK_IF(symbol, blockSymbol, ...) \
- for (mongo::ScopedFailPoint blockSymbol(&symbol, __VA_ARGS__); \
- MONGO_unlikely(blockSymbol.isActive());)
+ // protects _mode, _timesOrPeriod, _data
+ mutable stdx::mutex _modMutex;
+};
} // namespace mongo
diff --git a/src/mongo/util/fail_point_registry.cpp b/src/mongo/util/fail_point_registry.cpp
index 158d6ab8023..f4dfb627a36 100644
--- a/src/mongo/util/fail_point_registry.cpp
+++ b/src/mongo/util/fail_point_registry.cpp
@@ -29,34 +29,32 @@
#include "mongo/util/fail_point_registry.h"
+#include <fmt/format.h>
+
#include "mongo/bson/json.h"
#include "mongo/util/fail_point_server_parameter_gen.h"
#include "mongo/util/fail_point_service.h"
-#include "mongo/util/map_util.h"
-#include "mongo/util/str.h"
namespace mongo {
-constexpr auto kFailPointServerParameterPrefix = "failpoint."_sd;
+using namespace fmt::literals;
FailPointRegistry::FailPointRegistry() : _frozen(false) {}
-Status FailPointRegistry::addFailPoint(const std::string& name, FailPoint* failPoint) {
+Status FailPointRegistry::add(const std::string& name, FailPoint* failPoint) {
if (_frozen) {
return {ErrorCodes::CannotMutateObject, "Registry is already frozen"};
}
-
- if (_fpMap.count(name) > 0) {
- return {ErrorCodes::Error(51006),
- str::stream() << "Fail point already registered: " << name};
+ auto [pos, ok] = _fpMap.insert({name, failPoint});
+ if (!ok) {
+ return {ErrorCodes::Error(51006), "Fail point already registered: {}"_format(name)};
}
-
- _fpMap.insert(make_pair(name, failPoint));
return Status::OK();
}
-FailPoint* FailPointRegistry::getFailPoint(const std::string& name) const {
- return mapFindWithDefault(_fpMap, name, static_cast<FailPoint*>(nullptr));
+FailPoint* FailPointRegistry::find(const std::string& name) const {
+ auto iter = _fpMap.find(name);
+ return (iter == _fpMap.end()) ? nullptr : iter->second;
}
void FailPointRegistry::freeze() {
@@ -64,17 +62,19 @@ void FailPointRegistry::freeze() {
}
void FailPointRegistry::registerAllFailPointsAsServerParameters() {
- for (const auto& it : _fpMap) {
+ for (const auto& [name, ptr] : _fpMap) {
// Intentionally leaked.
- new FailPointServerParameter(it.first, ServerParameterType::kStartupOnly);
+ new FailPointServerParameter(name, ServerParameterType::kStartupOnly);
}
}
+static constexpr auto kFailPointServerParameterPrefix = "failpoint."_sd;
+
FailPointServerParameter::FailPointServerParameter(StringData name, ServerParameterType spt)
- : ServerParameter(kFailPointServerParameterPrefix.toString() + name.toString(), spt),
- _data(getGlobalFailPointRegistry()->getFailPoint(name.toString())) {
+ : ServerParameter("{}{}"_format(kFailPointServerParameterPrefix, name), spt),
+ _data(globalFailPointRegistry().find(name.toString())) {
invariant(name != "failpoint.*", "Failpoint prototype was auto-registered from IDL");
- invariant(_data != nullptr, str::stream() << "Unknown failpoint: " << name);
+ invariant(_data != nullptr, "Unknown failpoint: {}"_format(name));
}
void FailPointServerParameter::append(OperationContext* opCtx,
@@ -95,14 +95,7 @@ Status FailPointServerParameter::setFromString(const std::string& str) {
if (!swParsedOptions.isOK()) {
return swParsedOptions.getStatus();
}
-
- FailPoint::Mode mode;
- FailPoint::ValType val;
- BSONObj data;
- std::tie(mode, val, data) = std::move(swParsedOptions.getValue());
-
- _data->setMode(mode, val, data);
-
+ _data->setMode(std::move(swParsedOptions.getValue()));
return Status::OK();
}
} // namespace mongo
diff --git a/src/mongo/util/fail_point_registry.h b/src/mongo/util/fail_point_registry.h
index 7446db95eb1..7a77b47faba 100644
--- a/src/mongo/util/fail_point_registry.h
+++ b/src/mongo/util/fail_point_registry.h
@@ -53,12 +53,12 @@ public:
* 51006 - if the given name already exists in this registry.
* CannotMutateObject - if this registry is already frozen.
*/
- Status addFailPoint(const std::string& name, FailPoint* failPoint);
+ Status add(const std::string& name, FailPoint* failPoint);
/**
- * @return the fail point object registered. Returns NULL if it was not registered.
+ * @return the fail point object registered, or nullptr if it was not registered.
*/
- FailPoint* getFailPoint(const std::string& name) const;
+ FailPoint* find(const std::string& name) const;
/**
* Freezes this registry from being modified.
diff --git a/src/mongo/util/fail_point_service.cpp b/src/mongo/util/fail_point_service.cpp
index 77068f82100..44d8c69ae65 100644
--- a/src/mongo/util/fail_point_service.cpp
+++ b/src/mongo/util/fail_point_service.cpp
@@ -38,49 +38,34 @@
namespace mongo {
-using std::unique_ptr;
-
MONGO_FAIL_POINT_DEFINE(dummy); // used by tests in jstests/fail_point
-unique_ptr<FailPointRegistry> _fpRegistry(nullptr);
-
-MONGO_INITIALIZER_GENERAL(FailPointRegistry,
- MONGO_NO_PREREQUISITES,
- ("BeginGeneralStartupOptionRegistration"))
-(InitializerContext* context) {
- _fpRegistry.reset(new FailPointRegistry());
- return Status::OK();
-}
+MONGO_INITIALIZER_GROUP(FailPointRegistry, (), ("BeginStartupOptionHandling"));
-MONGO_INITIALIZER_GENERAL(AllFailPointsRegistered, MONGO_NO_PREREQUISITES, MONGO_NO_DEPENDENTS)
+MONGO_INITIALIZER_GENERAL(AllFailPointsRegistered, (), ())
(InitializerContext* context) {
- _fpRegistry->freeze();
+ globalFailPointRegistry().freeze();
return Status::OK();
}
-FailPointRegistry* getGlobalFailPointRegistry() {
- return _fpRegistry.get();
+FailPointRegistry& globalFailPointRegistry() {
+ static auto& p = *new FailPointRegistry();
+ return p;
}
void setGlobalFailPoint(const std::string& failPointName, const BSONObj& cmdObj) {
- FailPointRegistry* registry = getGlobalFailPointRegistry();
- FailPoint* failPoint = registry->getFailPoint(failPointName);
+ FailPoint* failPoint = globalFailPointRegistry().find(failPointName);
if (failPoint == nullptr)
uasserted(ErrorCodes::FailPointSetFailed, failPointName + " not found");
- FailPoint::Mode mode;
- FailPoint::ValType val;
- BSONObj data;
- std::tie(mode, val, data) = uassertStatusOK(FailPoint::parseBSON(cmdObj));
-
- failPoint->setMode(mode, val, data);
+ failPoint->setMode(uassertStatusOK(FailPoint::parseBSON(cmdObj)));
warning() << "failpoint: " << failPointName << " set to: " << failPoint->toBSON();
}
FailPointEnableBlock::FailPointEnableBlock(const std::string& failPointName)
: _failPointName(failPointName) {
- _failPoint = getGlobalFailPointRegistry()->getFailPoint(failPointName);
+ _failPoint = globalFailPointRegistry().find(failPointName);
invariant(_failPoint != nullptr);
_failPoint->setMode(FailPoint::alwaysOn);
warning() << "failpoint: " << failPointName << " set to: " << _failPoint->toBSON();
@@ -88,7 +73,7 @@ FailPointEnableBlock::FailPointEnableBlock(const std::string& failPointName)
FailPointEnableBlock::FailPointEnableBlock(const std::string& failPointName, const BSONObj& data)
: _failPointName(failPointName) {
- _failPoint = getGlobalFailPointRegistry()->getFailPoint(failPointName);
+ _failPoint = globalFailPointRegistry().find(failPointName);
invariant(_failPoint != nullptr);
_failPoint->setMode(FailPoint::alwaysOn, 0, data);
warning() << "failpoint: " << failPointName << " set to: " << _failPoint->toBSON();
diff --git a/src/mongo/util/fail_point_service.h b/src/mongo/util/fail_point_service.h
index 64c511942fc..8f7f3261b13 100644
--- a/src/mongo/util/fail_point_service.h
+++ b/src/mongo/util/fail_point_service.h
@@ -30,15 +30,13 @@
#pragma once
#include "mongo/base/init.h"
+#include "mongo/util/assert_util.h"
#include "mongo/util/fail_point.h"
#include "mongo/util/fail_point_registry.h"
namespace mongo {
-/**
- * @return the global fail point registry.
- */
-FailPointRegistry* getGlobalFailPointRegistry();
+FailPointRegistry& globalFailPointRegistry();
/**
* Set a fail point in the global registry to a given value via BSON
@@ -46,29 +44,27 @@ FailPointRegistry* getGlobalFailPointRegistry();
*/
void setGlobalFailPoint(const std::string& failPointName, const BSONObj& cmdObj);
+struct FailPointRegisterer {
+ FailPointRegisterer(const std::string& name, FailPoint* fp) {
+ uassertStatusOK(globalFailPointRegistry().add(name, fp));
+ }
+};
+
/**
* Convenience macro for defining a fail point. Must be used at namespace scope.
* Note: that means never at local scope (inside functions) or class scope.
* NOTE: Never use in header files, only sources.
*/
-#define MONGO_FAIL_POINT_DEFINE(fp) \
- ::mongo::FailPoint fp; \
- MONGO_INITIALIZER_GENERAL(fp, ("FailPointRegistry"), ("AllFailPointsRegistered")) \
- (::mongo::InitializerContext * context) { \
- return ::mongo::getGlobalFailPointRegistry()->addFailPoint(#fp, &fp); \
- }
-
-/**
- * Convenience macro for declaring a fail point in a header.
- */
-#define MONGO_FAIL_POINT_DECLARE(fp) extern ::mongo::FailPoint fp;
+#define MONGO_FAIL_POINT_DEFINE(fp) \
+ ::mongo::FailPoint fp; \
+ ::mongo::FailPointRegisterer fp##failPointRegisterer(#fp, &fp);
/**
* Convenience class for enabling a failpoint and disabling it as this goes out of scope.
*/
class FailPointEnableBlock {
public:
- FailPointEnableBlock(const std::string& failPointName);
+ explicit FailPointEnableBlock(const std::string& failPointName);
FailPointEnableBlock(const std::string& failPointName, const BSONObj& cmdObj);
~FailPointEnableBlock();
diff --git a/src/mongo/util/fail_point_test.cpp b/src/mongo/util/fail_point_test.cpp
index 0a32ec45777..1880b0d18a1 100644
--- a/src/mongo/util/fail_point_test.cpp
+++ b/src/mongo/util/fail_point_test.cpp
@@ -46,7 +46,6 @@
using mongo::BSONObj;
using mongo::FailPoint;
using mongo::FailPointEnableBlock;
-using mongo::getGlobalFailPointRegistry;
namespace stdx = mongo::stdx;
namespace mongo_test {
@@ -60,7 +59,7 @@ TEST(FailPoint, AlwaysOn) {
failPoint.setMode(FailPoint::alwaysOn);
ASSERT(failPoint.shouldFail());
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
+ if (auto scopedFp = failPoint.scoped(); MONGO_unlikely(scopedFp.isActive())) {
ASSERT(scopedFp.getData().isEmpty());
}
@@ -85,11 +84,7 @@ TEST(FailPoint, NTimes) {
TEST(FailPoint, BlockOff) {
FailPoint failPoint;
bool called = false;
-
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- called = true;
- }
-
+ failPoint.execute([&](const BSONObj&) { called = true; });
ASSERT_FALSE(called);
}
@@ -98,9 +93,7 @@ TEST(FailPoint, BlockAlwaysOn) {
failPoint.setMode(FailPoint::alwaysOn);
bool called = false;
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- called = true;
- }
+ failPoint.execute([&](const BSONObj&) { called = true; });
ASSERT(called);
}
@@ -111,9 +104,7 @@ TEST(FailPoint, BlockNTimes) {
size_t counter = 0;
for (size_t x = 0; x < 10; x++) {
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- counter++;
- }
+ failPoint.execute([&](auto&&...) { counter++; });
}
ASSERT_EQUALS(1U, counter);
@@ -125,9 +116,8 @@ TEST(FailPoint, BlockWithException) {
bool threw = false;
try {
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- throw std::logic_error("BlockWithException threw");
- }
+ failPoint.execute(
+ [&](const BSONObj&) { throw std::logic_error("BlockWithException threw"); });
} catch (const std::logic_error&) {
threw = true;
}
@@ -142,9 +132,7 @@ TEST(FailPoint, SetGetParam) {
FailPoint failPoint;
failPoint.setMode(FailPoint::alwaysOn, 0, BSON("x" << 20));
- MONGO_FAIL_POINT_BLOCK(failPoint, scopedFp) {
- ASSERT_EQUALS(20, scopedFp.getData()["x"].numberInt());
- }
+ failPoint.execute([&](const BSONObj& data) { ASSERT_EQUALS(20, data["x"].numberInt()); });
}
class FailPointStress : public mongo::unittest::Test {
@@ -181,9 +169,7 @@ public:
private:
void blockTask() {
while (true) {
- MONGO_FAIL_POINT_BLOCK(_fp, scopedFp) {
- const mongo::BSONObj& data = scopedFp.getData();
-
+ _fp.execute([](const BSONObj& data) {
// Expanded ASSERT_EQUALS since the error is not being
// printed out properly
if (data["a"].numberInt() != 44) {
@@ -191,7 +177,7 @@ private:
<< " - data: " << data << std::endl;
ASSERT(false);
}
- }
+ });
stdx::lock_guard<stdx::mutex> lk(_mutex);
if (_inShutdown)
@@ -202,9 +188,7 @@ private:
void blockWithExceptionTask() {
while (true) {
try {
- MONGO_FAIL_POINT_BLOCK(_fp, scopedFp) {
- const mongo::BSONObj& data = scopedFp.getData();
-
+ _fp.execute([](const BSONObj& data) {
if (data["a"].numberInt() != 44) {
mongo::error() << "blockWithExceptionTask thread detected anomaly"
<< " - data: " << data << std::endl;
@@ -212,7 +196,7 @@ private:
}
throw std::logic_error("blockWithExceptionTask threw");
- }
+ });
} catch (const std::logic_error&) {
}
@@ -224,7 +208,7 @@ private:
void simpleTask() {
while (true) {
- static_cast<void>(MONGO_FAIL_POINT(_fp));
+ static_cast<void>(MONGO_unlikely(_fp.shouldFail()));
stdx::lock_guard<stdx::mutex> lk(_mutex);
if (_inShutdown)
break;
@@ -403,7 +387,7 @@ TEST(FailPoint, parseBSONValidDataSucceeds) {
}
TEST(FailPoint, FailPointBlockBasicTest) {
- auto failPoint = getGlobalFailPointRegistry()->getFailPoint("dummy");
+ auto failPoint = mongo::globalFailPointRegistry().find("dummy");
ASSERT_FALSE(failPoint->shouldFail());
@@ -418,33 +402,25 @@ TEST(FailPoint, FailPointBlockBasicTest) {
TEST(FailPoint, FailPointBlockIfBasicTest) {
FailPoint failPoint;
failPoint.setMode(FailPoint::nTimes, 1, BSON("skip" << true));
-
{
bool hit = false;
-
- MONGO_FAIL_POINT_BLOCK_IF(failPoint, scopedFp, [&](const BSONObj& obj) {
- hit = obj["skip"].trueValue();
- return false;
- }) {
- ASSERT(!"shouldn't get here");
- }
-
+ failPoint.executeIf([](const BSONObj&) { ASSERT(!"shouldn't get here"); },
+ [&hit](const BSONObj& obj) {
+ hit = obj["skip"].trueValue();
+ return false;
+ });
ASSERT(hit);
}
-
{
bool hit = false;
-
- MONGO_FAIL_POINT_BLOCK_IF(failPoint, scopedFp, [](auto) { return true; }) {
- hit = true;
- ASSERT(!scopedFp.getData().isEmpty());
- }
-
+ failPoint.executeIf(
+ [&hit](const BSONObj& data) {
+ hit = true;
+ ASSERT(!data.isEmpty());
+ },
+ [](const BSONObj&) { return true; });
ASSERT(hit);
}
-
- MONGO_FAIL_POINT_BLOCK_IF(failPoint, scopedFp, [](auto) { return true; }) {
- ASSERT(!"shouldn't get here");
- }
+ failPoint.executeIf([](auto&&) { ASSERT(!"shouldn't get here"); }, [](auto&&) { return true; });
}
} // namespace mongo_test
diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp
index b7cecfb3324..bd183130d5a 100644
--- a/src/mongo/util/net/sock.cpp
+++ b/src/mongo/util/net/sock.cpp
@@ -395,7 +395,7 @@ int Socket::_send(const char* data, int len, const char* context) {
void Socket::send(const char* data, int len, const char* context) {
while (len > 0) {
int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+ if (MONGO_unlikely(throwSockExcep.shouldFail())) {
#if defined(_WIN32)
WSASetLastError(WSAENETUNREACH);
#else
@@ -458,7 +458,7 @@ void Socket::send(const vector<pair<char*, int>>& data, const char* context) {
while (meta.msg_iovlen > 0) {
int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+ if (MONGO_unlikely(throwSockExcep.shouldFail())) {
#if defined(_WIN32)
WSASetLastError(WSAENETUNREACH);
#else
@@ -491,7 +491,7 @@ void Socket::send(const vector<pair<char*, int>>& data, const char* context) {
void Socket::recv(char* buf, int len) {
while (len > 0) {
int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+ if (MONGO_unlikely(throwSockExcep.shouldFail())) {
#if defined(_WIN32)
WSASetLastError(WSAENETUNREACH);
#else
diff --git a/src/mongo/util/net/sock_test.cpp b/src/mongo/util/net/sock_test.cpp
index d9b3ec8ee84..0d6d4c69017 100644
--- a/src/mongo/util/net/sock_test.cpp
+++ b/src/mongo/util/net/sock_test.cpp
@@ -208,7 +208,7 @@ const char kSocketFailPointName[] = "throwSockExcep";
class SocketFailPointTest : public unittest::Test {
public:
SocketFailPointTest()
- : _failPoint(getGlobalFailPointRegistry()->getFailPoint(kSocketFailPointName)),
+ : _failPoint(globalFailPointRegistry().find(kSocketFailPointName)),
_sockets(socketPair(SOCK_STREAM)) {
ASSERT_TRUE(_failPoint != nullptr);
ASSERT_TRUE(_sockets.first);
diff --git a/src/mongo/util/net/ssl/detail/io.hpp b/src/mongo/util/net/ssl/detail/io.hpp
index d6e376b00f0..f6ff6edd1d8 100644
--- a/src/mongo/util/net/ssl/detail/io.hpp
+++ b/src/mongo/util/net/ssl/detail/io.hpp
@@ -29,7 +29,7 @@ namespace ssl {
namespace detail {
// Failpoint to force small reads of data to exercise the SChannel buffering code
-MONGO_FAIL_POINT_DECLARE(smallTLSReads);
+extern ::mongo::FailPoint smallTLSReads;
template <typename Stream, typename Operation>
std::size_t io(Stream& next_layer, stream_core& core, const Operation& op, asio::error_code& ec) {
@@ -42,7 +42,7 @@ std::size_t io(Stream& next_layer, stream_core& core, const Operation& op, asio:
// the underlying transport.
if (core.input_.size() == 0) {
// Read tiny amounts of TLS data to test the SChannel buffering code
- if (MONGO_FAIL_POINT(smallTLSReads)) {
+ if (MONGO_unlikely(smallTLSReads.shouldFail())) {
core.input_ =
asio::buffer(core.input_buffer_,
next_layer.read_some(