summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorWilliam Schultz <william.schultz@mongodb.com>2018-11-14 16:11:03 -0500
committerWilliam Schultz <william.schultz@mongodb.com>2018-11-14 16:17:44 -0500
commita6a0ca1ae81b34aab14a9c9a2a3d4a6ec7be66ba (patch)
tree18ddc6ff8413c2dccb528522cbd828b811994e55 /src/mongo/db
parentc1d4e0b8e1a4c197aac2530259f78eb88fb4acd3 (diff)
downloadmongo-a6a0ca1ae81b34aab14a9c9a2a3d4a6ec7be66ba.tar.gz
SERVER-37560 Add API for allowing commands to support speculative majority reads
This patch lays the groundwork for allowing read queries to take advantage of "speculative" majority reads, which is a mechanism for satisfying majority read guarantees without storage engine support for reading from a historical snapshot. This patch adds a flag on the ReadConcernArgs object to indicate whether a query should use the speculative behavior, and it also adds a method to the CommandInvocation interface that allows commands to optionally support speculative majority reads. The intention is to initially only utilize this behavior for change stream queries i.e. 'aggregate' and 'find' commands, but the feature is, in theory, generic.
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands.h13
-rw-r--r--src/mongo/db/commands/find_cmd.cpp5
-rw-r--r--src/mongo/db/commands/pipeline_command.cpp5
-rw-r--r--src/mongo/db/repl/read_concern_args.cpp10
-rw-r--r--src/mongo/db/repl/read_concern_args.h34
-rw-r--r--src/mongo/db/service_entry_point_common.cpp11
6 files changed, 78 insertions, 0 deletions
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h
index 71e75362643..aed2407f8f8 100644
--- a/src/mongo/db/commands.h
+++ b/src/mongo/db/commands.h
@@ -515,6 +515,19 @@ public:
}
/**
+ * Returns true if this command invocation is allowed to utilize "speculative" majority reads to
+ * service 'majority' read concern requests. This allows a query to satisfy a 'majority' read
+ * without storage engine support for reading from a historical snapshot.
+ *
+ * Note: This feature is currently only limited to a very small subset of commands (related to
+ * change streams), and is not intended to be generally used, which is why it is disabled by
+ * default.
+ */
+ virtual bool allowsSpeculativeMajorityReads() const {
+ return false;
+ }
+
+ /**
* The command definition that this invocation runs.
* Note: nonvirtual.
*/
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 523d1663c5f..9e75b094d25 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -123,6 +123,11 @@ public:
return true;
}
+ bool allowsSpeculativeMajorityReads() const override {
+ // TODO (SERVER-37560): Support this for change stream update lookup queries.
+ return false;
+ }
+
NamespaceString ns() const override {
// TODO get the ns from the parsed QueryRequest.
return NamespaceString(CommandHelpers::parseNsFromCommand(_dbName, _request.body));
diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp
index 90b3a2367e5..8d55c05861c 100644
--- a/src/mongo/db/commands/pipeline_command.cpp
+++ b/src/mongo/db/commands/pipeline_command.cpp
@@ -80,6 +80,11 @@ public:
!AggregationRequest::parseNs(_dbName, _request.body).isCollectionlessAggregateNS();
}
+ bool allowsSpeculativeMajorityReads() const override {
+ // TODO (SERVER-37560): Support this for change stream queries.
+ return false;
+ }
+
void run(OperationContext* opCtx, rpc::ReplyBuilderInterface* reply) override {
const auto aggregationRequest = uassertStatusOK(
AggregationRequest::parseFromBSON(_dbName, _request.body, boost::none));
diff --git a/src/mongo/db/repl/read_concern_args.cpp b/src/mongo/db/repl/read_concern_args.cpp
index a2014bdb1b2..4ae80592c11 100644
--- a/src/mongo/db/repl/read_concern_args.cpp
+++ b/src/mongo/db/repl/read_concern_args.cpp
@@ -262,6 +262,16 @@ Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) {
return Status::OK();
}
+void ReadConcernArgs::setMajorityReadMechanism(MajorityReadMechanism mechanism) {
+ invariant(*_level == ReadConcernLevel::kMajorityReadConcern);
+ _majorityReadMechanism = mechanism;
+}
+
+ReadConcernArgs::MajorityReadMechanism ReadConcernArgs::getMajorityReadMechanism() const {
+ invariant(*_level == ReadConcernLevel::kMajorityReadConcern);
+ return _majorityReadMechanism;
+}
+
Status ReadConcernArgs::upconvertReadConcernLevelToSnapshot() {
if (_level && *_level != ReadConcernLevel::kSnapshotReadConcern &&
*_level != ReadConcernLevel::kMajorityReadConcern &&
diff --git a/src/mongo/db/repl/read_concern_args.h b/src/mongo/db/repl/read_concern_args.h
index e5f3381cfb4..9cd82318aa1 100644
--- a/src/mongo/db/repl/read_concern_args.h
+++ b/src/mongo/db/repl/read_concern_args.h
@@ -55,6 +55,20 @@ public:
static const std::string kAtClusterTimeFieldName;
static const std::string kLevelFieldName;
+ /**
+ * Represents the internal mechanism an operation uses to satisfy 'majority' read concern.
+ */
+ enum class MajorityReadMechanism {
+ // The storage engine will read from a historical, majority committed snapshot of data. This
+ // is the default mechanism.
+ kMajoritySnapshot,
+
+ // A mechanism to be used when the storage engine does not support reading from a historical
+ // snapshot. A query will read from a local (potentially uncommitted) snapshot, and, after
+ // reading data, will block until it knows that data has become majority committed.
+ kSpeculative
+ };
+
static ReadConcernArgs& get(OperationContext* opCtx);
static const ReadConcernArgs& get(const OperationContext* opCtx);
@@ -97,6 +111,20 @@ public:
Status upconvertReadConcernLevelToSnapshot();
/**
+ * Sets the mechanism we should use to satisfy 'majority' reads.
+ *
+ * Invalid to call unless the read concern level is 'kMajorityReadConcern'.
+ */
+ void setMajorityReadMechanism(MajorityReadMechanism m);
+
+ /**
+ * Returns the mechanism to use for satisfying 'majority' read concern.
+ *
+ * Invalid to call unless the read concern level is 'kMajorityReadConcern'.
+ */
+ MajorityReadMechanism getMajorityReadMechanism() const;
+
+ /**
* Appends level and afterOpTime.
*/
void appendInfo(BSONObjBuilder* builder) const;
@@ -152,6 +180,12 @@ private:
* If the read concern was upconverted, the original read concern level.
*/
boost::optional<ReadConcernLevel> _originalLevel;
+
+ /**
+ * The mechanism to use for satisfying 'majority' reads. Only meaningful if the read concern
+ * level is 'majority'.
+ */
+ MajorityReadMechanism _majorityReadMechanism{MajorityReadMechanism::kMajoritySnapshot};
};
} // namespace repl
diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp
index c6296b5281b..68da28a9c5e 100644
--- a/src/mongo/db/service_entry_point_common.cpp
+++ b/src/mongo/db/service_entry_point_common.cpp
@@ -235,6 +235,17 @@ StatusWith<repl::ReadConcernArgs> _extractReadConcern(const CommandInvocation* i
<< readConcernArgs.toString()};
}
+
+ // If this command invocation asked for 'majority' read concern, supports blocking majority
+ // reads, and storage engine support for majority reads is disabled, then we set the majority
+ // read mechanism appropriately i.e. we utilize "speculative" read behavior.
+ if (readConcernArgs.getLevel() == repl::ReadConcernLevel::kMajorityReadConcern &&
+ invocation->allowsSpeculativeMajorityReads() &&
+ !serverGlobalParams.enableMajorityReadConcern) {
+ readConcernArgs.setMajorityReadMechanism(
+ repl::ReadConcernArgs::MajorityReadMechanism::kSpeculative);
+ }
+
return readConcernArgs;
}