summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/commands.cpp4
-rw-r--r--src/mongo/db/commands.h25
-rw-r--r--src/mongo/db/commands/generic.cpp95
-rw-r--r--src/mongo/db/commands_test.cpp10
-rw-r--r--src/mongo/db/logical_time.cpp24
-rw-r--r--src/mongo/db/logical_time.h21
-rw-r--r--src/mongo/db/logical_time_test.cpp34
-rw-r--r--src/mongo/db/service_entry_point_mongod.cpp2
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();