diff options
-rw-r--r-- | src/mongo/db/commands.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands.h | 25 | ||||
-rw-r--r-- | src/mongo/db/commands/generic.cpp | 95 | ||||
-rw-r--r-- | src/mongo/db/commands_test.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/logical_time.cpp | 24 | ||||
-rw-r--r-- | src/mongo/db/logical_time.h | 21 | ||||
-rw-r--r-- | src/mongo/db/logical_time_test.cpp | 34 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_mongod.cpp | 2 |
8 files changed, 132 insertions, 83 deletions
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 24d366880d5..c4e1ea6d2c1 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -246,10 +246,6 @@ void Command::appendCommandWCStatus(BSONObjBuilder& result, } } -void Command::appendOperationTime(BSONObjBuilder& result, LogicalTime operationTime) { - result.append("operationTime", operationTime.asTimestamp()); -} - Status BasicCommand::checkAuthForRequest(OperationContext* opCtx, const OpMsgRequest& request) { uassertNoDocumentSequences(request); return checkAuthForOperation(opCtx, request.getDatabase().toString(), request.body); diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 86fbec22161..cc6a9aec3f7 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -40,7 +40,6 @@ #include "mongo/db/client.h" #include "mongo/db/commands/server_status_metric.h" #include "mongo/db/jsobj.h" -#include "mongo/db/logical_time.h" #include "mongo/db/query/explain.h" #include "mongo/db/write_concern.h" #include "mongo/rpc/reply_builder_interface.h" @@ -50,9 +49,6 @@ namespace mongo { -class BSONObj; -class BSONObjBuilder; -class Client; class OperationContext; class Timer; @@ -264,7 +260,7 @@ public: const std::string& dbname, const BSONObj& cmdObj); - typedef StringMap<Command*> CommandMap; + using CommandMap = StringMap<Command*>; /** * Constructs a new command and causes it to be registered with the global commands list. It is @@ -351,13 +347,12 @@ public: _commandsFailed.increment(); } -protected: - static CommandMap* _commands; - static CommandMap* _commandsByBestName; + static const CommandMap& allCommands() { + return *_commands; + } -public: - static const CommandMap* commandsByBestName() { - return _commandsByBestName; + static const CommandMap& allCommandsByBestName() { + return *_commandsByBestName; } // Counter for unknown commands @@ -381,11 +376,6 @@ public: static bool appendCommandStatus(BSONObjBuilder& result, const Status& status); /** - * Appends "operationTime" field to the command result object as a Timestamp type. - */ - static void appendOperationTime(BSONObjBuilder& result, LogicalTime operationTime); - - /** * Helper for setting a writeConcernError field in the command result object if * a writeConcern error occurs. * @@ -519,6 +509,9 @@ public: static BSONObj filterCommandReplyForPassthrough(const BSONObj& reply); private: + static CommandMap* _commands; + static CommandMap* _commandsByBestName; + // Counters for how many times this command has been executed and failed Counter64 _commandsExecuted; Counter64 _commandsFailed; diff --git a/src/mongo/db/commands/generic.cpp b/src/mongo/db/commands/generic.cpp index 35998427356..d2595b1fda9 100644 --- a/src/mongo/db/commands/generic.cpp +++ b/src/mongo/db/commands/generic.cpp @@ -63,8 +63,8 @@ #include "mongo/util/version.h" namespace mongo { +namespace { -using std::endl; using std::string; using std::stringstream; using std::vector; @@ -100,7 +100,6 @@ public: } cmdBuildInfo; - class PingCommand : public BasicCommand { public: PingCommand() : BasicCommand("ping") {} @@ -264,10 +263,10 @@ public: BSONObjBuilder& result) { // sort the commands before building the result BSON std::vector<Command*> commands; - for (CommandMap::const_iterator it = _commands->begin(); it != _commands->end(); ++it) { + for (const auto command : allCommands()) { // don't show oldnames - if (it->first == it->second->getName()) - commands.push_back(it->second); + if (command.first == command.second->getName()) + commands.push_back(command.second); } std::sort(commands.begin(), commands.end(), [](Command* lhs, Command* rhs) { return (lhs->getName()) < (rhs->getName()); @@ -296,49 +295,6 @@ public: } listCommandsCmd; -namespace { -MONGO_FP_DECLARE(crashOnShutdown); - -int* volatile illegalAddress; // NOLINT - used for fail point only -} // namespace - -void CmdShutdown::addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - ActionSet actions; - actions.addAction(ActionType::shutdown); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); -} - -void CmdShutdown::shutdownHelper() { - MONGO_FAIL_POINT_BLOCK(crashOnShutdown, crashBlock) { - const std::string crashHow = crashBlock.getData()["how"].str(); - if (crashHow == "fault") { - ++*illegalAddress; - } - ::abort(); - } - - log() << "terminating, shutdown command received"; - -#if defined(_WIN32) - // Signal the ServiceMain thread to shutdown. - if (ntservice::shouldStartService()) { - shutdownNoTerminate(); - - // Client expects us to abruptly close the socket as part of exiting - // so this function is not allowed to return. - // The ServiceMain thread will quit for us so just sleep until it does. - while (true) - sleepsecs(60); // Loop forever - } else -#endif - { - exitCleanly(EXIT_CLEAN); // this never returns - invariant(false); - } -} - /* for testing purposes only */ class CmdForceError : public BasicCommand { public: @@ -520,4 +476,47 @@ public: } } cmdGetCmdLineOpts; + +MONGO_FP_DECLARE(crashOnShutdown); +int* volatile illegalAddress; // NOLINT - used for fail point only + +} // namespace + +void CmdShutdown::addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + ActionSet actions; + actions.addAction(ActionType::shutdown); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); } + +void CmdShutdown::shutdownHelper() { + MONGO_FAIL_POINT_BLOCK(crashOnShutdown, crashBlock) { + const std::string crashHow = crashBlock.getData()["how"].str(); + if (crashHow == "fault") { + ++*illegalAddress; + } + ::abort(); + } + + log() << "terminating, shutdown command received"; + +#if defined(_WIN32) + // Signal the ServiceMain thread to shutdown. + if (ntservice::shouldStartService()) { + shutdownNoTerminate(); + + // Client expects us to abruptly close the socket as part of exiting + // so this function is not allowed to return. + // The ServiceMain thread will quit for us so just sleep until it does. + while (true) + sleepsecs(60); // Loop forever + } else +#endif + { + exitCleanly(EXIT_CLEAN); // this never returns + invariant(false); + } +} + +} // namespace mongo diff --git a/src/mongo/db/commands_test.cpp b/src/mongo/db/commands_test.cpp index d26eed1ad74..8396602a663 100644 --- a/src/mongo/db/commands_test.cpp +++ b/src/mongo/db/commands_test.cpp @@ -75,14 +75,4 @@ TEST(Commands, appendCommandStatusNoOverwrite) { ASSERT_BSONOBJ_EQ(actualResult.obj(), expectedResult.obj()); } -TEST(Commands, appendOperationTime) { - BSONObjBuilder actualResult; - LogicalTime testTime(Timestamp(1)); - Command::appendOperationTime(actualResult, testTime); - - BSONObjBuilder expectedResult; - expectedResult.append("operationTime", Timestamp(1)); - - ASSERT_BSONOBJ_EQ(actualResult.obj(), expectedResult.obj()); -} } // namespace mongo diff --git a/src/mongo/db/logical_time.cpp b/src/mongo/db/logical_time.cpp index c26d542ec3d..1bb5ce5b62f 100644 --- a/src/mongo/db/logical_time.cpp +++ b/src/mongo/db/logical_time.cpp @@ -26,19 +26,39 @@ * it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/db/logical_time.h" #include "mongo/base/data_type_endian.h" #include "mongo/base/data_view.h" -#include "mongo/platform/basic.h" -#include "mongo/util/mongoutils/str.h" +#include "mongo/bson/bsonobj.h" +#include "mongo/bson/bsonobjbuilder.h" namespace mongo { +namespace { + +constexpr auto kOperationTime = "operationTime"_sd; + +} // namespace const LogicalTime LogicalTime::kUninitialized = LogicalTime(); LogicalTime::LogicalTime(Timestamp ts) : _time(ts.asULL()) {} +LogicalTime LogicalTime::fromOperationTime(const BSONObj& obj) { + const auto opTimeElem(obj[kOperationTime]); + uassert(ErrorCodes::FailedToParse, "No operationTime found", !opTimeElem.eoo()); + uassert(ErrorCodes::BadValue, + "Operation time is of the wrong value", + opTimeElem.type() == bsonTimestamp); + return LogicalTime(opTimeElem.timestamp()); +} + +void LogicalTime::appendAsOperationTime(BSONObjBuilder* builder) const { + builder->append(kOperationTime, asTimestamp()); +} + void LogicalTime::addTicks(uint64_t ticks) { _time += ticks; } diff --git a/src/mongo/db/logical_time.h b/src/mongo/db/logical_time.h index 4b982612183..719673cf231 100644 --- a/src/mongo/db/logical_time.h +++ b/src/mongo/db/logical_time.h @@ -32,6 +32,9 @@ namespace mongo { +class BSONObj; +class BSONObjBuilder; + /** * The LogicalTime class holds the cluster time of the cluster. It provides conversions to * a Timestamp to allow integration with opLog. @@ -39,7 +42,18 @@ namespace mongo { class LogicalTime { public: LogicalTime() = default; - explicit LogicalTime(Timestamp); + explicit LogicalTime(Timestamp ts); + + /** + * Parses the 'operationTime' field of the specified object and extracts a LogicalTime from it. + * If 'operationTime' is missing or of the wrong type, throws. + */ + static LogicalTime fromOperationTime(const BSONObj& obj); + + /** + * Appends "operationTime" field to the specified builder as a Timestamp type. + */ + void appendAsOperationTime(BSONObjBuilder* builder) const; Timestamp asTimestamp() const { return Timestamp(_time); @@ -50,7 +64,6 @@ public: */ void addTicks(uint64_t ticks); - /** * Const version, returns the LogicalTime with increased _time by ticks. */ @@ -97,4 +110,8 @@ inline bool operator>=(const LogicalTime& l, const LogicalTime& r) { return (l > r || l == r); } +inline std::ostream& operator<<(std::ostream& s, const LogicalTime& v) { + return (s << v.toString()); +} + } // namespace mongo diff --git a/src/mongo/db/logical_time_test.cpp b/src/mongo/db/logical_time_test.cpp index ed738cc20d6..bf0b3b567ba 100644 --- a/src/mongo/db/logical_time_test.cpp +++ b/src/mongo/db/logical_time_test.cpp @@ -105,6 +105,40 @@ TEST(LogicalTime, toUnsignedArray) { } } +TEST(LogicalTime, appendAsOperationTime) { + BSONObjBuilder actualResultBuilder; + LogicalTime testTime(Timestamp(1)); + testTime.appendAsOperationTime(&actualResultBuilder); + + const auto actualResult = actualResultBuilder.obj(); + ASSERT_BSONOBJ_EQ(BSON("operationTime" << Timestamp(1)), actualResult); + + // Test round-trip works + ASSERT_EQ(testTime, LogicalTime::fromOperationTime(actualResult)); +} + +TEST(LogicalTime, fromOperationTime) { + const auto actualTime = LogicalTime::fromOperationTime(BSON("someOtherCommandParameter" + << "Value" + << "operationTime" + << Timestamp(1))); + ASSERT_EQ(LogicalTime(Timestamp(1)), actualTime); +} + +TEST(LogicalTime, fromOperationTimeMissingOperationTime) { + ASSERT_THROWS_CODE(LogicalTime::fromOperationTime(BSON("someOtherCommandParameter" + << "Value")), + DBException, + ErrorCodes::FailedToParse); +} + +TEST(LogicalTime, fromOperationTimeBadType) { + ASSERT_THROWS_CODE(LogicalTime::fromOperationTime(BSON("operationTime" + << "BadStringValue")), + DBException, + ErrorCodes::BadValue); +} + TEST(SignedLogicalTime, roundtrip) { Timestamp tX(1); TimeProofService tps; diff --git a/src/mongo/db/service_entry_point_mongod.cpp b/src/mongo/db/service_entry_point_mongod.cpp index 0802fcedc45..d6f458c9a82 100644 --- a/src/mongo/db/service_entry_point_mongod.cpp +++ b/src/mongo/db/service_entry_point_mongod.cpp @@ -504,7 +504,7 @@ bool runCommandImpl(OperationContext* opCtx, if (operationTime != LogicalTime::kUninitialized && serverGlobalParams.featureCompatibility.version.load() == ServerGlobalParams::FeatureCompatibility::Version::k36) { - Command::appendOperationTime(inPlaceReplyBob, operationTime); + operationTime.appendAsOperationTime(&inPlaceReplyBob); } inPlaceReplyBob.doneFast(); |