diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2019-10-03 19:57:40 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-10-03 19:57:40 +0000 |
commit | 8ccaacce937ae51deef27c41e977aca0511fb338 (patch) | |
tree | 0c29028123f23dc66aef660f05549dd0ebe109b2 /src/mongo/util | |
parent | 4d9a6a2ae4b6ad9b93d3c389e6d92d6acfe86cf3 (diff) | |
download | mongo-8ccaacce937ae51deef27c41e977aca0511fb338.tar.gz |
SERVER-43317 merge failpoint headers. Rewrite docs.
iterate docs
Diffstat (limited to 'src/mongo/util')
-rw-r--r-- | src/mongo/util/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/util/diagnostic_info.h | 2 | ||||
-rw-r--r-- | src/mongo/util/fail_point.cpp | 142 | ||||
-rw-r--r-- | src/mongo/util/fail_point.h | 266 | ||||
-rw-r--r-- | src/mongo/util/fail_point_registry.cpp | 101 | ||||
-rw-r--r-- | src/mongo/util/fail_point_registry.h | 79 | ||||
-rw-r--r-- | src/mongo/util/fail_point_service.cpp | 88 | ||||
-rw-r--r-- | src/mongo/util/fail_point_service.h | 76 | ||||
-rw-r--r-- | src/mongo/util/fail_point_test.cpp | 1 | ||||
-rw-r--r-- | src/mongo/util/net/sock.cpp | 2 | ||||
-rw-r--r-- | src/mongo/util/net/sock_test.cpp | 2 | ||||
-rw-r--r-- | src/mongo/util/net/ssl/detail/io.hpp | 2 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_stream.cpp | 2 |
13 files changed, 335 insertions, 430 deletions
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 4d98e0b3e9d..406b7594a8d 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -146,8 +146,6 @@ env.Library( target="fail_point", source=[ "fail_point.cpp", - "fail_point_registry.cpp", - "fail_point_service.cpp", env.Idlc('fail_point_server_parameter.idl')[0], ], LIBDEPS=[ diff --git a/src/mongo/util/diagnostic_info.h b/src/mongo/util/diagnostic_info.h index 1e578cecd80..4c4eb15c7ea 100644 --- a/src/mongo/util/diagnostic_info.h +++ b/src/mongo/util/diagnostic_info.h @@ -33,7 +33,7 @@ #include "mongo/db/client.h" #include "mongo/platform/condition_variable.h" #include "mongo/platform/mutex.h" -#include "mongo/util/fail_point_service.h" +#include "mongo/util/fail_point.h" #include "mongo/util/time_support.h" namespace mongo { diff --git a/src/mongo/util/fail_point.cpp b/src/mongo/util/fail_point.cpp index 389a809ef23..60050da7055 100644 --- a/src/mongo/util/fail_point.cpp +++ b/src/mongo/util/fail_point.cpp @@ -28,22 +28,36 @@ */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl +#include "mongo/platform/basic.h" #include "mongo/util/fail_point.h" +#include <fmt/format.h> #include <memory> +#include "mongo/base/init.h" +#include "mongo/bson/json.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/platform/random.h" #include "mongo/stdx/thread.h" -#include "mongo/util/fail_point_service.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/fail_point_server_parameter_gen.h" #include "mongo/util/log.h" -#include "mongo/util/str.h" #include "mongo/util/time_support.h" namespace mongo { namespace { +using namespace fmt::literals; + +MONGO_FAIL_POINT_DEFINE(dummy); // used by tests in jstests/fail_point + +MONGO_INITIALIZER_GENERAL(AllFailPointsRegistered, (), ()) +(InitializerContext* context) { + globalFailPointRegistry().freeze(); + return Status::OK(); +} + /** * Type representing the per-thread PRNG used by fail-points. */ @@ -80,7 +94,7 @@ void FailPoint::setThreadPRNGSeed(int32_t seed) { FailPoint::FailPoint() = default; -void FailPoint::shouldFailCloseBlock() { +void FailPoint::_shouldFailCloseBlock() { _fpInfo.subtractAndFetch(1); } @@ -96,7 +110,7 @@ void FailPoint::setMode(Mode mode, ValType val, BSONObj extra) { stdx::lock_guard<Latch> scoped(_modMutex); // Step 1 - disable(); + _disable(); // Step 2 while (_fpInfo.load() != 0) { @@ -109,23 +123,23 @@ void FailPoint::setMode(Mode mode, ValType val, BSONObj extra) { _data = std::move(extra); if (_mode != off) { - enable(); + _enable(); } } -const BSONObj& FailPoint::getData() const { +const BSONObj& FailPoint::_getData() const { return _data; } -void FailPoint::enable() { +void FailPoint::_enable() { _fpInfo.fetchAndBitOr(kActiveBit); } -void FailPoint::disable() { +void FailPoint::_disable() { _fpInfo.fetchAndBitAnd(~kActiveBit); } -FailPoint::RetCode FailPoint::slowShouldFailOpenBlock( +FailPoint::RetCode FailPoint::_slowShouldFailOpenBlock( std::function<bool(const BSONObj&)> cb) noexcept { ValType localFpInfo = _fpInfo.addAndFetch(1); @@ -133,7 +147,7 @@ FailPoint::RetCode FailPoint::slowShouldFailOpenBlock( return slowOff; } - if (cb && !cb(getData())) { + if (cb && !cb(_getData())) { return userIgnored; } @@ -149,7 +163,7 @@ FailPoint::RetCode FailPoint::slowShouldFailOpenBlock( } case nTimes: { if (_timesOrPeriod.subtractAndFetch(1) <= 0) - disable(); + _disable(); return slowOn; } @@ -181,7 +195,7 @@ StatusWith<FailPoint::ModeOptions> FailPoint::parseBSON(const BSONObj& obj) { } else if (modeStr == "alwaysOn") { mode = FailPoint::alwaysOn; } else { - return {ErrorCodes::BadValue, str::stream() << "unknown mode: " << modeStr}; + return {ErrorCodes::BadValue, "unknown mode: {}"_format(modeStr)}; } } else if (modeElem.type() == Object) { const BSONObj modeObj(modeElem.Obj()); @@ -232,14 +246,14 @@ StatusWith<FailPoint::ModeOptions> FailPoint::parseBSON(const BSONObj& obj) { const double activationProbability = modeObj["activationProbability"].numberDouble(); if (activationProbability < 0 || activationProbability > 1) { return {ErrorCodes::BadValue, - str::stream() << "activationProbability must be between 0.0 and 1.0; found " - << activationProbability}; + "activationProbability must be between 0.0 and 1.0; " + "found {}"_format(activationProbability)}; } val = static_cast<int32_t>(std::numeric_limits<int32_t>::max() * activationProbability); } else { - return { - ErrorCodes::BadValue, - "'mode' must be one of 'off', 'alwaysOn', 'times', and 'activationProbability'"}; + return {ErrorCodes::BadValue, + "'mode' must be one of 'off', 'alwaysOn', '{times:n}', '{skip:n}' or " + "'{activationProbability:p}'"}; } } else { return {ErrorCodes::TypeMismatch, "'mode' must be a string or JSON object"}; @@ -265,4 +279,98 @@ BSONObj FailPoint::toBSON() const { return builder.obj(); } + +FailPointRegisterer::FailPointRegisterer(const std::string& name, FailPoint* fp) { + uassertStatusOK(globalFailPointRegistry().add(name, fp)); +} + +FailPointRegistry& globalFailPointRegistry() { + static auto& p = *new FailPointRegistry(); + return p; +} + +void setGlobalFailPoint(const std::string& failPointName, const BSONObj& cmdObj) { + FailPoint* failPoint = globalFailPointRegistry().find(failPointName); + if (failPoint == nullptr) + uasserted(ErrorCodes::FailPointSetFailed, failPointName + " not found"); + failPoint->setMode(uassertStatusOK(FailPoint::parseBSON(cmdObj))); + warning() << "failpoint: " << failPointName << " set to: " << failPoint->toBSON(); +} + +FailPointEnableBlock::FailPointEnableBlock(std::string failPointName) + : FailPointEnableBlock(std::move(failPointName), {}) {} + +FailPointEnableBlock::FailPointEnableBlock(std::string failPointName, BSONObj data) + : _failPointName(std::move(failPointName)) { + _failPoint = globalFailPointRegistry().find(_failPointName); + invariant(_failPoint != nullptr); + _failPoint->setMode(FailPoint::alwaysOn, 0, std::move(data)); + warning() << "failpoint: " << _failPointName << " set to: " << _failPoint->toBSON(); +} + +FailPointEnableBlock::~FailPointEnableBlock() { + _failPoint->setMode(FailPoint::off); + warning() << "failpoint: " << _failPointName << " set to: " << _failPoint->toBSON(); +} + +FailPointRegistry::FailPointRegistry() : _frozen(false) {} + +Status FailPointRegistry::add(const std::string& name, FailPoint* failPoint) { + if (_frozen) { + return {ErrorCodes::CannotMutateObject, "Registry is already frozen"}; + } + auto [pos, ok] = _fpMap.insert({name, failPoint}); + if (!ok) { + return {ErrorCodes::Error(51006), "Fail point already registered: {}"_format(name)}; + } + return Status::OK(); +} + +FailPoint* FailPointRegistry::find(const std::string& name) const { + auto iter = _fpMap.find(name); + return (iter == _fpMap.end()) ? nullptr : iter->second; +} + +void FailPointRegistry::freeze() { + _frozen = true; +} + +void FailPointRegistry::registerAllFailPointsAsServerParameters() { + for (const auto& [name, ptr] : _fpMap) { + // Intentionally leaked. + new FailPointServerParameter(name, ServerParameterType::kStartupOnly); + } +} + +static constexpr auto kFailPointServerParameterPrefix = "failpoint."_sd; + +FailPointServerParameter::FailPointServerParameter(StringData name, ServerParameterType spt) + : ServerParameter("{}{}"_format(kFailPointServerParameterPrefix, name), spt), + _data(globalFailPointRegistry().find(name.toString())) { + invariant(name != "failpoint.*", "Failpoint prototype was auto-registered from IDL"); + invariant(_data != nullptr, "Unknown failpoint: {}"_format(name)); +} + +void FailPointServerParameter::append(OperationContext* opCtx, + BSONObjBuilder& b, + const std::string& name) { + b << name << _data->toBSON(); +} + +Status FailPointServerParameter::setFromString(const std::string& str) { + BSONObj failPointOptions; + try { + failPointOptions = fromjson(str); + } catch (DBException& ex) { + return ex.toStatus(); + } + + auto swParsedOptions = FailPoint::parseBSON(failPointOptions); + if (!swParsedOptions.isOK()) { + return swParsedOptions.getStatus(); + } + _data->setMode(std::move(swParsedOptions.getValue())); + return Status::OK(); +} + } // namespace mongo diff --git a/src/mongo/util/fail_point.h b/src/mongo/util/fail_point.h index daf39bcba49..c5c12e62c23 100644 --- a/src/mongo/util/fail_point.h +++ b/src/mongo/util/fail_point.h @@ -30,48 +30,78 @@ #pragma once #include <functional> +#include <string> +#include "mongo/base/status.h" #include "mongo/base/status_with.h" #include "mongo/db/jsobj.h" #include "mongo/db/operation_context.h" #include "mongo/platform/atomic_word.h" #include "mongo/platform/mutex.h" +#include "mongo/stdx/unordered_map.h" namespace mongo { /** - * A simple thread-safe fail point implementation that can be activated and - * 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, represented by FailPoint::Scoped handles. + * A FailPoint is a hook mechanism allowing testing behavior to occur at prearranged + * execution points in the server code. They can be activated and deactivated, and + * configured to hold data. + * + * A FailPoint is usually defined by the MONGO_FAIL_POINT_DEFINE(name) macro, + * which arranges for it to be added to the global failpoint registry. * * Sample use: - * // Declared somewhere: - * FailPoint makeBadThingsHappen; * - * // Somewhere in the code - * return false || MONGO_unlikely(makeBadThingsHappen.shouldFail()); + * // Defined somewhere: + * MONGO_FAIL_POINT_DEFINE(failPoint); + * + * bool somewhereInTheCode() { + * ... do some stuff ... + * // The failpoint artificially changes the return value of this function when active. + * if (MONGO_unlikely(failPoint.shouldFail())) + * return false; + * return true; + * } * - * or + * - or to implement more complex scenarios, use execute/executeIf - * - * // Somewhere in the code - * makeBadThingsHappen.execute([&](const BSONObj& data) { - * // Do something - * }); + * bool somewhereInTheCode() { + * failPoint.execute([&](const BSONObj& data) { + * // The bad things happen here, and can read the injected 'data'. + * }); + * return true; + * } * - * // 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... + * // scoped() is another way to do it, where lambda isn't suitable, e.g. to cause + * // a return/continue/break to control the enclosing function. + * for (auto& user : users) { + * // The failpoint can be activated and given a user name, to skip that user. + * if (auto sfp = failPoint.scoped(); MONGO_unlikely(sfp.isActive())) { + * if (sfp.getData()["user"] == user.name()) { + * continue; + * } + * } + * processOneUser(user); * } * - * Invariants: + * // Rendered compactly with scopedIf where the data serves as an activation filter. + * for (auto& user : users) { + * if (MONGO_unlikely(failPoint.scopedIf([&](auto&& o) { + * return o["user"] == user.name(); + * }).isActive())) { + * continue; + * } + * processOneUser(user); + * } + * + * The `scopedIf` and `executeIf` members have an advantage over `scoped` and `execute`. They + * only affect the `FailPoint` activation counters (relevant to the `nTimes` and `skip` modes) + * if the predicate is true. + * + * A FailPoint can be configured remotely by a database command. + * See `src/mongo/db/commands/fail_point_cmd.cpp`. * - * 1. Always refer to _fpInfo first to check if failPoint is active or not before - * entering fail point or modifying fail point. - * 2. Client visible fail point states are read-only when active. */ class FailPoint { private: @@ -88,11 +118,18 @@ public: }; /** - * Helper class for making sure that FailPoint#shouldFailCloseBlock is called when - * FailPoint#shouldFailOpenBlock was called. - * + * An object representing an active FailPoint's interaction with the code it is + * instrumenting. It holds reference to its associated FailPoint, ensuring + * that FailPoint's state doesn't change while a Scoped is attached to it. + * If `isActive()`, then `getData()` may be called to retrieve injected data. * Users don't create these. They are only used within the execute and executeIf * functions and returned by the scoped() and scopedIf() functions. + * + * Ex: + * if (auto scoped = failPoint.scoped(); scoped.isActive()) { + * const BSONObj& data = scoped.getData(); + * // failPoint injects some behavior, informed by `data`. + * } */ class Scoped { public: @@ -103,7 +140,7 @@ public: ~Scoped() { if (_holdsRef) { - _failPoint->shouldFailCloseBlock(); + _failPoint->_shouldFailCloseBlock(); } } @@ -125,7 +162,7 @@ public: const BSONObj& getData() const { // Assert when attempting to get data without holding a ref. fassert(16445, _holdsRef); - return _failPoint->getData(); + return _failPoint->_getData(); } private: @@ -141,7 +178,18 @@ public: static void setThreadPRNGSeed(int32_t seed); /** - * Parses the {Mode, ValType, BSONObj} from the BSON. + * Parses the {mode, val, extra} from the BSON. + * obj = { + * mode: modeElem // required + * data: extra // optional payload to inject into the FailPoint intercept site. + * } + * where `modeElem` is one of: + * "off" + * "alwaysOn" + * {"times" : val} // active for the next val calls + * {"skip" : val} // skip calls, activate on and after call number (val+1). + * {"activationProbability" : val} // val is in interval [0.0, 1.0] + * } */ static StatusWith<ModeOptions> parseBSON(const BSONObj& obj); @@ -151,22 +199,25 @@ public: FailPoint& operator=(const FailPoint&) = delete; /** - * Note: This is not side-effect free - it can change the state to OFF after calling. - * Note: see `executeIf` for information on `pred`. + * Returns true if fail point is active. + * + * Calls to `shouldFail` can have side effects. For example they affect the counters + * kept to manage the `skip` or `nTimes` modes (See `setMode`). * - * Calls to shouldFail should be placed inside MONGO_unlikely for performance. + * See `executeIf` for information on `pred`. * - * @return true if fail point is active. + * Calls to `shouldFail` should be placed inside MONGO_unlikely for performance. + * if (MONGO_unlikely(failpoint.shouldFail())) ... */ template <typename Pred> bool shouldFail(Pred&& pred) { - RetCode ret = shouldFailOpenBlock(std::forward<Pred>(pred)); + RetCode ret = _shouldFailOpenBlock(std::forward<Pred>(pred)); if (MONGO_likely(ret == fastOff)) { return false; } - shouldFailCloseBlock(); + _shouldFailCloseBlock(); return ret == slowOn; } @@ -175,22 +226,20 @@ public: } /** - * 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. + * Changes the settings of this fail point. This will turn off the FailPoint and + * wait for all references on this FailPoint to go away before modifying it. * - * @param mode the new mode for this fail point. - * @param val the value that can have different usage depending on the mode: + * @param mode new mode + * @param val unsigned having different interpretations depending on the mode: * * - off, alwaysOn: ignored * - random: static_cast<int32_t>(std::numeric_limits<int32_t>::max() * p), where * where p is the probability that any given evaluation of the failpoint should * activate. * - nTimes: the number of times this fail point will be active when - * #shouldFail or #shouldFailOpenBlock is called. - * - skip: the number of times this failpoint will be inactive when - * #shouldFail or #shouldFailOpenBlock is called. After this number is reached, the - * failpoint will always be active. + * #shouldFail/#execute/#scoped are called. + * - skip: will become active and remain active after + * #shouldFail/#execute/#scoped are called this number of times. * * @param extra arbitrary BSON object that can be stored to this fail point * that can be referenced afterwards with #getData. Defaults to an empty @@ -208,18 +257,24 @@ public: /** * Create a Scoped from this FailPoint. - * Use the Scoped object to access failpoint data. + * The returned Scoped object will be active if the failpoint is active. + * If it's active, the returned object can be used to access FailPoint data. */ Scoped scoped() { return scopedIf(nullptr); } /** - * Create a Scoped from this FailPoint, only active when `pred(payload)` is true. - * See `executeIf`. Use the Scoped object to access failpoint data. + * Create a Scoped from this FailPoint. + * If `pred(payload)` is true, then the returned Scoped object is active and the + * FailPoint's activation count is altered (relevant to e.g. the `nTimes` mode). If the + * predicate is false, an inactive Scoped is returned and this FailPoint's mode is not + * modified at all. + * If it's active, the returned object can be used to access FailPoint data. + * The `pred` should be callable like a `bool pred(const BSONObj&)`. */ template <typename Pred> Scoped scopedIf(Pred&& pred) { - return Scoped(this, shouldFailOpenBlock(std::forward<Pred>(pred))); + return Scoped(this, _shouldFailOpenBlock(std::forward<Pred>(pred))); } template <typename F> @@ -228,9 +283,11 @@ public: } /** - * 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). + * If `pred(payload)` is true, then `f(payload)` is executed and the FailPoint's + * activation count is altered (relevant to e.g. the `nTimes` mode). Otherwise, `f` + * is not executed and this FailPoint's mode is not altered (e.g. `nTimes` isn't + * consumed). + * The `pred` should be callable like a `bool pred(const BSONObj&)`. */ template <typename F, typename Pred> void executeIf(F&& f, Pred&& pred) { @@ -240,12 +297,21 @@ public: } } + /** + * Take 100msec pauses for as long as the FailPoint is active. + * This uses `shouldFail()` and therefore affects FailPoint counters. + */ void pauseWhileSet() { while (MONGO_unlikely(shouldFail())) { sleepmillis(100); } } + /** + * Like `pauseWhileSet`, but interruptible via the `opCtx->sleepFor` mechanism. See + * `mongo::Interruptible::sleepFor` (Interruptible is a base class of + * OperationContext). + */ void pauseWhileSet(OperationContext* opCtx) { while (MONGO_unlikely(shouldFail())) { opCtx->sleepFor(Milliseconds(100)); @@ -253,8 +319,8 @@ public: } private: - void enable(); - void disable(); + void _enable(); + void _disable(); /** * Checks whether fail point is active and increments the reference counter without @@ -269,37 +335,37 @@ private: * fastOff if its disabled and doesn't need to be closed */ template <typename Pred> - RetCode shouldFailOpenBlock(Pred&& pred) { + RetCode _shouldFailOpenBlock(Pred&& pred) { if (MONGO_likely((_fpInfo.loadRelaxed() & kActiveBit) == 0)) { return fastOff; } - return slowShouldFailOpenBlock(std::forward<Pred>(pred)); + return _slowShouldFailOpenBlock(std::forward<Pred>(pred)); } - RetCode shouldFailOpenBlock() { - return shouldFailOpenBlock(nullptr); + RetCode _shouldFailOpenBlock() { + return _shouldFailOpenBlock(nullptr); } /** * Decrements the reference counter. - * @see #shouldFailOpenBlock + * @see #_shouldFailOpenBlock */ - void shouldFailCloseBlock(); + void _shouldFailCloseBlock(); /** - * slow path for #shouldFailOpenBlock + * 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; + RetCode _slowShouldFailOpenBlock(std::function<bool(const BSONObj&)> cb) noexcept; /** * @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; + const BSONObj& _getData() const; static const ValType kActiveBit = 1 << 31; @@ -317,4 +383,82 @@ private: mutable Mutex _modMutex = MONGO_MAKE_LATCH("FailPoint::_modMutex"); }; +class FailPointRegistry { +public: + FailPointRegistry(); + + /** + * Adds a new fail point to this registry. Duplicate names are not allowed. + * + * @return the status code under these circumstances: + * OK - if successful. + * 51006 - if the given name already exists in this registry. + * CannotMutateObject - if this registry is already frozen. + */ + Status add(const std::string& name, FailPoint* failPoint); + + /** + * @return a registered FailPoint, or nullptr if it was not registered. + */ + FailPoint* find(const std::string& name) const; + + /** + * Freezes this registry from being modified. + */ + void freeze(); + + /** + * Creates a new FailPointServerParameter for each failpoint in the registry. This allows the + * failpoint to be set on the command line via --setParameter, but is only allowed when + * running with '--setParameter enableTestCommands=1'. + */ + void registerAllFailPointsAsServerParameters(); + +private: + bool _frozen; + stdx::unordered_map<std::string, FailPoint*> _fpMap; +}; + +/** + * A scope guard that enables a named FailPoint on construction and disables it on destruction. + */ +class FailPointEnableBlock { +public: + explicit FailPointEnableBlock(std::string failPointName); + FailPointEnableBlock(std::string failPointName, BSONObj cmdObj); + ~FailPointEnableBlock(); + +private: + std::string _failPointName; + FailPoint* _failPoint; +}; + +/** + * Set a fail point in the global registry to a given value via BSON + * @throw DBException corresponding to ErrorCodes::FailPointSetFailed if no failpoint + * called failPointName exists. + */ +void setGlobalFailPoint(const std::string& failPointName, const BSONObj& cmdObj); + +/** + * Registration object for FailPoint. Its static-initializer registers FailPoint `fp` + * into the `globalFailPointRegistry()` under the specified `name`. + */ +class FailPointRegisterer { +public: + FailPointRegisterer(const std::string& name, FailPoint* fp); +}; + +FailPointRegistry& globalFailPointRegistry(); + +/** + * Convenience macro for defining a fail point and registering it. + * Must be used at namespace scope, not at local (inside a function) or class scope. + * Never use in header files, only .cpp files. + */ +#define MONGO_FAIL_POINT_DEFINE(fp) \ + ::mongo::FailPoint fp; \ + ::mongo::FailPointRegisterer fp##failPointRegisterer(#fp, &fp); + + } // namespace mongo diff --git a/src/mongo/util/fail_point_registry.cpp b/src/mongo/util/fail_point_registry.cpp deleted file mode 100644 index f4dfb627a36..00000000000 --- a/src/mongo/util/fail_point_registry.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#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" - -namespace mongo { - -using namespace fmt::literals; - -FailPointRegistry::FailPointRegistry() : _frozen(false) {} - -Status FailPointRegistry::add(const std::string& name, FailPoint* failPoint) { - if (_frozen) { - return {ErrorCodes::CannotMutateObject, "Registry is already frozen"}; - } - auto [pos, ok] = _fpMap.insert({name, failPoint}); - if (!ok) { - return {ErrorCodes::Error(51006), "Fail point already registered: {}"_format(name)}; - } - return Status::OK(); -} - -FailPoint* FailPointRegistry::find(const std::string& name) const { - auto iter = _fpMap.find(name); - return (iter == _fpMap.end()) ? nullptr : iter->second; -} - -void FailPointRegistry::freeze() { - _frozen = true; -} - -void FailPointRegistry::registerAllFailPointsAsServerParameters() { - for (const auto& [name, ptr] : _fpMap) { - // Intentionally leaked. - new FailPointServerParameter(name, ServerParameterType::kStartupOnly); - } -} - -static constexpr auto kFailPointServerParameterPrefix = "failpoint."_sd; - -FailPointServerParameter::FailPointServerParameter(StringData name, ServerParameterType spt) - : ServerParameter("{}{}"_format(kFailPointServerParameterPrefix, name), spt), - _data(globalFailPointRegistry().find(name.toString())) { - invariant(name != "failpoint.*", "Failpoint prototype was auto-registered from IDL"); - invariant(_data != nullptr, "Unknown failpoint: {}"_format(name)); -} - -void FailPointServerParameter::append(OperationContext* opCtx, - BSONObjBuilder& b, - const std::string& name) { - b << name << _data->toBSON(); -} - -Status FailPointServerParameter::setFromString(const std::string& str) { - BSONObj failPointOptions; - try { - failPointOptions = fromjson(str); - } catch (DBException& ex) { - return ex.toStatus(); - } - - auto swParsedOptions = FailPoint::parseBSON(failPointOptions); - if (!swParsedOptions.isOK()) { - return swParsedOptions.getStatus(); - } - _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 deleted file mode 100644 index 7a77b47faba..00000000000 --- a/src/mongo/util/fail_point_registry.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -/** - * Should NOT be included by other header files. Include only in source files. - */ - -#pragma once - -#include "mongo/base/status.h" -#include "mongo/stdx/unordered_map.h" -#include "mongo/util/fail_point.h" - -namespace mongo { -/** - * Class for storing FailPoint instances. - */ -class FailPointRegistry { -public: - FailPointRegistry(); - - /** - * Adds a new fail point to this registry. Duplicate names are not allowed. - * - * @return the status code under these circumstances: - * OK - if successful. - * 51006 - if the given name already exists in this registry. - * CannotMutateObject - if this registry is already frozen. - */ - Status add(const std::string& name, FailPoint* failPoint); - - /** - * @return the fail point object registered, or nullptr if it was not registered. - */ - FailPoint* find(const std::string& name) const; - - /** - * Freezes this registry from being modified. - */ - void freeze(); - - /** - * Creates a new FailPointServerParameter for each failpoint in the registry. This allows the - * failpoint to be set on the command line via --setParameter, but is only allowed when - * running with '--setParameter enableTestCommands=1'. - */ - void registerAllFailPointsAsServerParameters(); - -private: - bool _frozen; - stdx::unordered_map<std::string, FailPoint*> _fpMap; -}; -} // namespace mongo diff --git a/src/mongo/util/fail_point_service.cpp b/src/mongo/util/fail_point_service.cpp deleted file mode 100644 index 44d8c69ae65..00000000000 --- a/src/mongo/util/fail_point_service.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand - -#include "mongo/platform/basic.h" - -#include "mongo/util/fail_point_service.h" - -#include "mongo/util/assert_util.h" -#include "mongo/util/log.h" - -namespace mongo { - -MONGO_FAIL_POINT_DEFINE(dummy); // used by tests in jstests/fail_point - -MONGO_INITIALIZER_GROUP(FailPointRegistry, (), ("BeginStartupOptionHandling")); - -MONGO_INITIALIZER_GENERAL(AllFailPointsRegistered, (), ()) -(InitializerContext* context) { - globalFailPointRegistry().freeze(); - return Status::OK(); -} - -FailPointRegistry& globalFailPointRegistry() { - static auto& p = *new FailPointRegistry(); - return p; -} - -void setGlobalFailPoint(const std::string& failPointName, const BSONObj& cmdObj) { - FailPoint* failPoint = globalFailPointRegistry().find(failPointName); - - if (failPoint == nullptr) - uasserted(ErrorCodes::FailPointSetFailed, failPointName + " not found"); - - failPoint->setMode(uassertStatusOK(FailPoint::parseBSON(cmdObj))); - warning() << "failpoint: " << failPointName << " set to: " << failPoint->toBSON(); -} - -FailPointEnableBlock::FailPointEnableBlock(const std::string& failPointName) - : _failPointName(failPointName) { - _failPoint = globalFailPointRegistry().find(failPointName); - invariant(_failPoint != nullptr); - _failPoint->setMode(FailPoint::alwaysOn); - warning() << "failpoint: " << failPointName << " set to: " << _failPoint->toBSON(); -} - -FailPointEnableBlock::FailPointEnableBlock(const std::string& failPointName, const BSONObj& data) - : _failPointName(failPointName) { - _failPoint = globalFailPointRegistry().find(failPointName); - invariant(_failPoint != nullptr); - _failPoint->setMode(FailPoint::alwaysOn, 0, data); - warning() << "failpoint: " << failPointName << " set to: " << _failPoint->toBSON(); -} - - -FailPointEnableBlock::~FailPointEnableBlock() { - _failPoint->setMode(FailPoint::off); - warning() << "failpoint: " << _failPointName << " set to: " << _failPoint->toBSON(); -} - -} // namespace mongo diff --git a/src/mongo/util/fail_point_service.h b/src/mongo/util/fail_point_service.h deleted file mode 100644 index 8f7f3261b13..00000000000 --- a/src/mongo/util/fail_point_service.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#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 { - -FailPointRegistry& globalFailPointRegistry(); - -/** - * Set a fail point in the global registry to a given value via BSON - * @throw DBException If no failpoint called failPointName exists. - */ -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::FailPointRegisterer fp##failPointRegisterer(#fp, &fp); - -/** - * Convenience class for enabling a failpoint and disabling it as this goes out of scope. - */ -class FailPointEnableBlock { -public: - explicit FailPointEnableBlock(const std::string& failPointName); - FailPointEnableBlock(const std::string& failPointName, const BSONObj& cmdObj); - ~FailPointEnableBlock(); - -private: - FailPoint* _failPoint; - const std::string _failPointName; -}; - -} // namespace mongo diff --git a/src/mongo/util/fail_point_test.cpp b/src/mongo/util/fail_point_test.cpp index a99d7132a40..af15040e0b3 100644 --- a/src/mongo/util/fail_point_test.cpp +++ b/src/mongo/util/fail_point_test.cpp @@ -40,7 +40,6 @@ #include "mongo/stdx/thread.h" #include "mongo/unittest/unittest.h" #include "mongo/util/fail_point.h" -#include "mongo/util/fail_point_service.h" #include "mongo/util/log.h" #include "mongo/util/time_support.h" diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp index bd183130d5a..39210d57a40 100644 --- a/src/mongo/util/net/sock.cpp +++ b/src/mongo/util/net/sock.cpp @@ -60,7 +60,7 @@ #include "mongo/util/background.h" #include "mongo/util/concurrency/value.h" #include "mongo/util/debug_util.h" -#include "mongo/util/fail_point_service.h" +#include "mongo/util/fail_point.h" #include "mongo/util/hex.h" #include "mongo/util/log.h" #include "mongo/util/net/private/socket_poll.h" diff --git a/src/mongo/util/net/sock_test.cpp b/src/mongo/util/net/sock_test.cpp index 0d6d4c69017..10cc799d05d 100644 --- a/src/mongo/util/net/sock_test.cpp +++ b/src/mongo/util/net/sock_test.cpp @@ -41,7 +41,7 @@ #include "mongo/stdx/thread.h" #include "mongo/unittest/unittest.h" #include "mongo/util/concurrency/notification.h" -#include "mongo/util/fail_point_service.h" +#include "mongo/util/fail_point.h" #include "mongo/util/net/socket_exception.h" namespace { diff --git a/src/mongo/util/net/ssl/detail/io.hpp b/src/mongo/util/net/ssl/detail/io.hpp index f6ff6edd1d8..90453c3d8e8 100644 --- a/src/mongo/util/net/ssl/detail/io.hpp +++ b/src/mongo/util/net/ssl/detail/io.hpp @@ -18,7 +18,7 @@ #include "asio/detail/config.hpp" #include "asio/write.hpp" -#include "mongo/util/fail_point_service.h" +#include "mongo/util/fail_point.h" #include "mongo/util/net/ssl/detail/engine.hpp" #include "mongo/util/net/ssl/detail/stream_core.hpp" diff --git a/src/mongo/util/net/ssl_stream.cpp b/src/mongo/util/net/ssl_stream.cpp index 1aeb82d2189..df8bf56770f 100644 --- a/src/mongo/util/net/ssl_stream.cpp +++ b/src/mongo/util/net/ssl_stream.cpp @@ -31,7 +31,7 @@ #include "mongo/config.h" -#include "mongo/util/fail_point_service.h" +#include "mongo/util/fail_point.h" #ifdef MONGO_CONFIG_SSL #include "mongo/util/net/ssl/impl/src.hpp" |