summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@10gen.com>2016-04-26 14:34:03 -0400
committerDianna Hohensee <dianna.hohensee@10gen.com>2016-04-27 14:14:35 -0400
commit21c359f605f773f55d9f494caa9a72273b49139f (patch)
treed33c64fc4890d97cc6f89f556c4c2cc11bd0e7b4 /src/mongo
parentc56106e308d27b7dc25843e9ab0e4dded1f820c0 (diff)
downloadmongo-21c359f605f773f55d9f494caa9a72273b49139f.tar.gz
SERVER-23496 adding ShardLocal class, child class of Shard
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/repl/storage_interface_impl_test.cpp6
-rw-r--r--src/mongo/db/storage/ephemeral_for_test/SConscript1
-rw-r--r--src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.cpp10
-rw-r--r--src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h2
-rw-r--r--src/mongo/db/storage/kv/kv_engine_test_snapshots.cpp1
-rw-r--r--src/mongo/s/client/SConscript34
-rw-r--r--src/mongo/s/client/shard.cpp42
-rw-r--r--src/mongo/s/client/shard.h48
-rw-r--r--src/mongo/s/client/shard_local.cpp143
-rw-r--r--src/mongo/s/client/shard_local.h73
-rw-r--r--src/mongo/s/client/shard_local_test.cpp208
-rw-r--r--src/mongo/s/client/shard_remote.h4
12 files changed, 523 insertions, 49 deletions
diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp
index 087780f8afa..9b8cdabd32a 100644
--- a/src/mongo/db/repl/storage_interface_impl_test.cpp
+++ b/src/mongo/db/repl/storage_interface_impl_test.cpp
@@ -190,4 +190,10 @@ TEST_F(StorageInterfaceImplTest, MinValid) {
ASSERT_TRUE(recoveryUnit->waitUntilDurableCalled);
}
+TEST_F(StorageInterfaceImplTest, SnapshotNotSupported) {
+ auto txn = getClient()->makeOperationContext();
+ Status status = txn->recoveryUnit()->setReadFromMajorityCommittedSnapshot();
+ ASSERT_EQUALS(status, ErrorCodes::CommandNotSupported);
+}
+
} // namespace
diff --git a/src/mongo/db/storage/ephemeral_for_test/SConscript b/src/mongo/db/storage/ephemeral_for_test/SConscript
index 88e38cdcfbb..02e848fa9c2 100644
--- a/src/mongo/db/storage/ephemeral_for_test/SConscript
+++ b/src/mongo/db/storage/ephemeral_for_test/SConscript
@@ -25,6 +25,7 @@ env.Library(
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/catalog/collection_options',
'$BUILD_DIR/mongo/db/index/index_descriptor',
+ '$BUILD_DIR/mongo/db/repl/repl_coordinator_global',
'$BUILD_DIR/mongo/db/storage/index_entry_comparison',
'$BUILD_DIR/mongo/db/storage/journal_listener',
'$BUILD_DIR/mongo/util/foundation',
diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.cpp
index ef80739cd31..c94d659ac53 100644
--- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.cpp
+++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.cpp
@@ -32,6 +32,7 @@
#include "mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h"
+#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/storage/sorted_data_interface.h"
#include "mongo/util/log.h"
@@ -66,4 +67,13 @@ void EphemeralForTestRecoveryUnit::abortUnitOfWork() {
std::terminate();
}
}
+
+Status EphemeralForTestRecoveryUnit::setReadFromMajorityCommittedSnapshot() {
+ if (!repl::getGlobalReplicationCoordinator()->isReplEnabled()) {
+ return Status::OK();
+ } else {
+ return {ErrorCodes::CommandNotSupported,
+ "Current storage engine does not support majority readConcerns"};
+ }
+}
}
diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h
index 4b7925248e4..7de00846992 100644
--- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h
+++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h
@@ -58,6 +58,8 @@ public:
virtual void abandonSnapshot() {}
+ Status setReadFromMajorityCommittedSnapshot() final;
+
virtual void registerChange(Change* change) {
_changes.push_back(ChangePtr(change));
}
diff --git a/src/mongo/db/storage/kv/kv_engine_test_snapshots.cpp b/src/mongo/db/storage/kv/kv_engine_test_snapshots.cpp
index 874c94c8cde..0af84c354de 100644
--- a/src/mongo/db/storage/kv/kv_engine_test_snapshots.cpp
+++ b/src/mongo/db/storage/kv/kv_engine_test_snapshots.cpp
@@ -204,7 +204,6 @@ TEST_F(SnapshotManagerTests, ConsistentIfNotSupported) {
auto ru = op->recoveryUnit();
ASSERT(!ru->isReadingFromMajorityCommittedSnapshot());
ASSERT(!ru->getMajorityCommittedSnapshot());
- ASSERT_EQ(ru->setReadFromMajorityCommittedSnapshot(), ErrorCodes::CommandNotSupported);
}
TEST_F(SnapshotManagerTests, FailsWithNoCommittedSnapshot) {
diff --git a/src/mongo/s/client/SConscript b/src/mongo/s/client/SConscript
index 6754a18de16..64d064b3e4b 100644
--- a/src/mongo/s/client/SConscript
+++ b/src/mongo/s/client/SConscript
@@ -6,7 +6,6 @@ env.Library(
target='sharding_client',
source=[
'dbclient_multi_command.cpp',
- 'shard.cpp',
'shard_connection.cpp',
'shard_factory.cpp',
'shard_registry.cpp',
@@ -21,6 +20,7 @@ env.Library(
'$BUILD_DIR/mongo/executor/connection_pool_stats',
'$BUILD_DIR/mongo/executor/task_executor_pool',
'$BUILD_DIR/mongo/rpc/metadata',
+ 'shard_interface',
],
LIBDEPS_TAGS=[
# Circular with both coreshard and coredb! Also relies on some
@@ -58,3 +58,35 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/util/net/network',
]
)
+
+env.Library(
+ target='shard_interface',
+ source=[
+ 'shard.cpp',
+ ],
+)
+
+env.Library(
+ target='shard_local',
+ source=[
+ 'shard_local.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/client/clientdriver',
+ 'shard_interface'
+ ],
+)
+
+env.CppUnitTest(
+ target='shard_local_test',
+ source=[
+ 'shard_local_test.cpp',
+ ],
+ LIBDEPS=[
+ 'shard_local',
+ '$BUILD_DIR/mongo/db/repl/replmocks',
+ '$BUILD_DIR/mongo/db/serveronly',
+ '$BUILD_DIR/mongo/db/service_context_d_test_fixture',
+ ],
+ NO_CRUTCH = True,
+)
diff --git a/src/mongo/s/client/shard.cpp b/src/mongo/s/client/shard.cpp
index 963e746e8a8..06908cb4dd7 100644
--- a/src/mongo/s/client/shard.cpp
+++ b/src/mongo/s/client/shard.cpp
@@ -1,29 +1,29 @@
/**
- * Copyright (C) 2008-2015 MongoDB Inc.
+ * Copyright (C) 2016 MongoDB Inc.
*
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
*
- * 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
- * GNU Affero General Public License for more details.
+ * 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
+ * GNU Affero General Public License for more details.
*
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
- * 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 GNU Affero General 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.
+ * 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 GNU Affero General 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::kSharding
diff --git a/src/mongo/s/client/shard.h b/src/mongo/s/client/shard.h
index 11efad1d348..db71e1b944b 100644
--- a/src/mongo/s/client/shard.h
+++ b/src/mongo/s/client/shard.h
@@ -1,29 +1,29 @@
/**
- * Copyright (C) 2008-2015 MongoDB Inc.
+ * Copyright (C) 2016 MongoDB Inc.
*
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
*
- * 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
- * GNU Affero General Public License for more details.
+ * 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
+ * GNU Affero General Public License for more details.
*
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
- * 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 GNU Affero General 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.
+ * 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 GNU Affero General 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
@@ -31,12 +31,14 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/client/connection_string.h"
#include "mongo/client/read_preference.h"
-#include "mongo/client/remote_command_targeter.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/repl/optime.h"
namespace mongo {
+class OperationContext;
+class RemoteCommandTargeter;
+
using ShardId = std::string;
/**
@@ -84,7 +86,7 @@ public:
*
* This is only valid to call on ShardRemote instances.
*/
- virtual std::shared_ptr<RemoteCommandTargeter> getTargeter() = 0;
+ virtual std::shared_ptr<RemoteCommandTargeter> getTargeter() const = 0;
/**
* Notifies the RemoteCommandTargeter owned by the shard of a particular mode of failure for
diff --git a/src/mongo/s/client/shard_local.cpp b/src/mongo/s/client/shard_local.cpp
new file mode 100644
index 00000000000..337089aa76c
--- /dev/null
+++ b/src/mongo/s/client/shard_local.cpp
@@ -0,0 +1,143 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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::kSharding
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/s/client/shard_local.h"
+
+#include "mongo/base/status.h"
+#include "mongo/base/status_with.h"
+#include "mongo/client/remote_command_targeter.h"
+#include "mongo/db/curop.h"
+#include "mongo/db/dbdirectclient.h"
+#include "mongo/db/repl/repl_client_info.h"
+#include "mongo/db/repl/replication_coordinator_global.h"
+#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/rpc/unique_message.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+
+const ConnectionString ShardLocal::getConnString() const {
+ MONGO_UNREACHABLE;
+}
+
+std::shared_ptr<RemoteCommandTargeter> ShardLocal::getTargeter() const {
+ MONGO_UNREACHABLE;
+};
+
+const ConnectionString ShardLocal::originalConnString() const {
+ MONGO_UNREACHABLE;
+}
+
+void ShardLocal::updateReplSetMonitor(const HostAndPort& remoteHost,
+ const Status& remoteCommandStatus) {
+ MONGO_UNREACHABLE;
+}
+
+std::string ShardLocal::toString() const {
+ return getId() + ":<local>";
+}
+
+StatusWith<Shard::CommandResponse> ShardLocal::_runCommand(OperationContext* txn,
+ const ReadPreferenceSetting& unused,
+ const std::string& dbName,
+ const BSONObj& cmdObj,
+ const BSONObj& metadata) {
+ try {
+ DBDirectClient client(txn);
+ rpc::UniqueReply commandResponse =
+ client.runCommandWithMetadata(dbName, cmdObj.firstElementFieldName(), metadata, cmdObj);
+ BSONObj responseReply = commandResponse->getCommandReply().getOwned();
+ BSONObj responseMetadata = commandResponse->getMetadata().getOwned();
+ return Shard::CommandResponse{responseReply, responseMetadata};
+ } catch (const DBException& ex) {
+ return ex.toStatus();
+ }
+}
+
+StatusWith<Shard::QueryResponse> ShardLocal::_exhaustiveFindOnConfig(
+ OperationContext* txn,
+ const ReadPreferenceSetting& readPref,
+ const NamespaceString& nss,
+ const BSONObj& query,
+ const BSONObj& sort,
+ boost::optional<long long> limit) {
+ // Set up operation context with majority read snapshot so correct optime can be retrieved.
+ Status status = txn->recoveryUnit()->setReadFromMajorityCommittedSnapshot();
+ auto replCoord = repl::ReplicationCoordinator::get(txn);
+
+ // Ensure timeout is set on the txn so we don't wait forever for the snapshot.
+ // TODO (SERVER-18277): Remove this
+ CurOp::get(txn)->ensureStarted();
+
+ // Wait until a snapshot is available.
+ while (status == ErrorCodes::ReadConcernMajorityNotAvailableYet) {
+ LOG(1) << "Waiting for ReadFromMajorityCommittedSnapshot to become available";
+ replCoord->waitUntilSnapshotCommitted(txn, SnapshotName::min());
+ status = txn->recoveryUnit()->setReadFromMajorityCommittedSnapshot();
+ }
+
+ if (!status.isOK()) {
+ return status;
+ }
+
+ DBDirectClient client(txn);
+ Query fullQuery(query);
+ if (!sort.isEmpty()) {
+ fullQuery.sort(sort);
+ }
+ fullQuery.readPref(readPref.pref, BSONArray());
+
+ try {
+ std::unique_ptr<DBClientCursor> cursor =
+ client.query(nss.ns().c_str(), fullQuery, limit.get_value_or(0));
+
+ if (!cursor) {
+ return {ErrorCodes::OperationFailed,
+ str::stream() << "Failed to establish a cursor for reading " << nss.ns()
+ << " from local storage"};
+ }
+
+ std::vector<BSONObj> documentVector;
+ while (cursor->more()) {
+ BSONObj document = cursor->nextSafe().getOwned();
+ documentVector.push_back(std::move(document));
+ }
+
+ return Shard::QueryResponse{std::move(documentVector),
+ replCoord->getCurrentCommittedSnapshotOpTime()};
+ } catch (const DBException& ex) {
+ return ex.toStatus();
+ }
+}
+
+
+} // namespace mongo
diff --git a/src/mongo/s/client/shard_local.h b/src/mongo/s/client/shard_local.h
new file mode 100644
index 00000000000..e2330a059b4
--- /dev/null
+++ b/src/mongo/s/client/shard_local.h
@@ -0,0 +1,73 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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/disallow_copying.h"
+#include "mongo/client/dbclientinterface.h"
+#include "mongo/s/client/shard.h"
+
+namespace mongo {
+
+class ShardLocal : public Shard {
+ MONGO_DISALLOW_COPYING(ShardLocal);
+
+public:
+ explicit ShardLocal(const ShardId& id) : Shard(id) {}
+
+ ~ShardLocal() = default;
+
+ /**
+ * These functions are implemented for the Shard interface's sake. They should not be called on
+ * ShardLocal because doing so triggers invariants.
+ */
+ const ConnectionString getConnString() const override;
+ const ConnectionString originalConnString() const override;
+ std::shared_ptr<RemoteCommandTargeter> getTargeter() const override;
+ void updateReplSetMonitor(const HostAndPort& remoteHost,
+ const Status& remoteCommandStatus) override;
+
+ std::string toString() const override;
+
+private:
+ StatusWith<Shard::CommandResponse> _runCommand(OperationContext* txn,
+ const ReadPreferenceSetting& unused,
+ const std::string& dbName,
+ const BSONObj& cmdObj,
+ const BSONObj& metadata) override;
+
+ StatusWith<Shard::QueryResponse> _exhaustiveFindOnConfig(
+ OperationContext* txn,
+ const ReadPreferenceSetting& readPref,
+ const NamespaceString& nss,
+ const BSONObj& query,
+ const BSONObj& sort,
+ boost::optional<long long> limit) override;
+};
+
+} // namespace mongo
diff --git a/src/mongo/s/client/shard_local_test.cpp b/src/mongo/s/client/shard_local_test.cpp
new file mode 100644
index 00000000000..ac0dc929ee4
--- /dev/null
+++ b/src/mongo/s/client/shard_local_test.cpp
@@ -0,0 +1,208 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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/platform/basic.h"
+
+#include "mongo/s/client/shard_local.h"
+
+#include "mongo/client/read_preference.h"
+#include "mongo/db/client.h"
+#include "mongo/db/catalog/database_holder.h"
+#include "mongo/db/db_raii.h"
+#include "mongo/db/query/find_and_modify_request.h"
+#include "mongo/db/repl/replication_coordinator_global.h"
+#include "mongo/db/repl/replication_coordinator_mock.h"
+#include "mongo/db/service_context_d_test_fixture.h"
+#include "mongo/db/write_concern_options.h"
+
+namespace mongo {
+namespace {
+
+class ShardLocalTest : public ServiceContextMongoDTest {
+protected:
+ ServiceContext::UniqueOperationContext _txn;
+ ShardLocal* _shardLocal;
+
+ /**
+ * Sets up and runs a FindAndModify command with ShardLocal's runCommand. Finds a document in
+ * namespace "nss" that matches "find" and updates the document with "set". Upsert and new are
+ * set to true in the FindAndModify request.
+ */
+ StatusWith<Shard::CommandResponse> runFindAndModifyRunCommand(NamespaceString nss,
+ BSONObj find,
+ BSONObj set);
+ /**
+ * Facilitates running a find query by supplying the redundant parameters. Finds documents in
+ * namespace "nss" that match "query" and returns "limit" (if there are that many) number of
+ * documents in "sort" order.
+ */
+ StatusWith<Shard::QueryResponse> runFindQuery(NamespaceString nss,
+ BSONObj query,
+ BSONObj sort,
+ boost::optional<long long> limit);
+
+private:
+ void setUp() override;
+ void tearDown() override;
+};
+
+void ShardLocalTest::setUp() {
+ ServiceContextMongoDTest::setUp();
+ Client::initThreadIfNotAlready();
+ _txn = getGlobalServiceContext()->makeOperationContext(&cc());
+ _shardLocal = new ShardLocal("shardOrConfig");
+ const repl::ReplSettings replSettings = {};
+ repl::setGlobalReplicationCoordinator(new repl::ReplicationCoordinatorMock(replSettings));
+}
+
+void ShardLocalTest::tearDown() {
+ _txn.reset();
+ ServiceContextMongoDTest::tearDown();
+ repl::setGlobalReplicationCoordinator(nullptr);
+}
+
+StatusWith<Shard::CommandResponse> ShardLocalTest::runFindAndModifyRunCommand(NamespaceString nss,
+ BSONObj find,
+ BSONObj set) {
+ FindAndModifyRequest findAndModifyRequest = FindAndModifyRequest::makeUpdate(nss, find, set);
+ findAndModifyRequest.setUpsert(true);
+ findAndModifyRequest.setShouldReturnNew(true);
+ findAndModifyRequest.setWriteConcern(WriteConcernOptions(
+ WriteConcernOptions::kMajority, WriteConcernOptions::SyncMode::UNSET, Seconds(15)));
+
+ return _shardLocal->runCommand(_txn.get(),
+ ReadPreferenceSetting{ReadPreference::PrimaryOnly},
+ nss.db().toString(),
+ findAndModifyRequest.toBSON(),
+ BSONObj());
+}
+
+/**
+ * Takes a FindAndModify command's BSON response and parses it for the returned "value" field.
+ */
+BSONObj extractFindAndModifyNewObj(const BSONObj& responseObj) {
+ const auto& newDocElem = responseObj["value"];
+ ASSERT(!newDocElem.eoo());
+ ASSERT(newDocElem.isABSONObj());
+ return newDocElem.Obj();
+}
+
+StatusWith<Shard::QueryResponse> ShardLocalTest::runFindQuery(NamespaceString nss,
+ BSONObj query,
+ BSONObj sort,
+ boost::optional<long long> limit) {
+ return _shardLocal->exhaustiveFindOnConfig(
+ _txn.get(), ReadPreferenceSetting{ReadPreference::PrimaryOnly}, nss, query, sort, limit);
+}
+
+TEST_F(ShardLocalTest, RunCommand) {
+ NamespaceString nss("foo.bar");
+ StatusWith<Shard::CommandResponse> findAndModifyResponse = runFindAndModifyRunCommand(
+ nss, BSON("fooItem" << 1), BSON("$set" << BSON("fooRandom" << 254)));
+
+ Shard::CommandResponse commandResponse = unittest::assertGet(findAndModifyResponse);
+ BSONObj newDocument = extractFindAndModifyNewObj(commandResponse.response);
+
+ ASSERT_EQUALS(1, newDocument["fooItem"].numberInt());
+ ASSERT_EQUALS(254, newDocument["fooRandom"].numberInt());
+}
+
+TEST_F(ShardLocalTest, FindOneWithoutLimit) {
+ NamespaceString nss("foo.bar");
+
+ // Set up documents to be queried.
+ StatusWith<Shard::CommandResponse> findAndModifyResponse = runFindAndModifyRunCommand(
+ nss, BSON("fooItem" << 1), BSON("$set" << BSON("fooRandom" << 254)));
+ ASSERT_OK(findAndModifyResponse.getStatus());
+ findAndModifyResponse = runFindAndModifyRunCommand(
+ nss, BSON("fooItem" << 3), BSON("$set" << BSON("fooRandom" << 452)));
+ ASSERT_OK(findAndModifyResponse.getStatus());
+
+ // Find a single document.
+ StatusWith<Shard::QueryResponse> response =
+ runFindQuery(nss, BSON("fooItem" << 3), BSONObj(), boost::none);
+ Shard::QueryResponse queryResponse = unittest::assertGet(response);
+
+ std::vector<BSONObj> docs = queryResponse.docs;
+ const unsigned long size = 1;
+ ASSERT_EQUALS(size, docs.size());
+ BSONObj foundDoc = docs[0];
+ ASSERT_EQUALS(3, foundDoc["fooItem"].numberInt());
+ ASSERT_EQUALS(452, foundDoc["fooRandom"].numberInt());
+}
+
+TEST_F(ShardLocalTest, FindManyWithLimit) {
+ NamespaceString nss("foo.bar");
+
+ // Set up documents to be queried.
+ StatusWith<Shard::CommandResponse> findAndModifyResponse = runFindAndModifyRunCommand(
+ nss, BSON("fooItem" << 1), BSON("$set" << BSON("fooRandom" << 254)));
+ ASSERT_OK(findAndModifyResponse.getStatus());
+ findAndModifyResponse = runFindAndModifyRunCommand(
+ nss, BSON("fooItem" << 2), BSON("$set" << BSON("fooRandom" << 444)));
+ ASSERT_OK(findAndModifyResponse.getStatus());
+ findAndModifyResponse = runFindAndModifyRunCommand(
+ nss, BSON("fooItem" << 3), BSON("$set" << BSON("fooRandom" << 452)));
+ ASSERT_OK(findAndModifyResponse.getStatus());
+
+ // Find 2 of 3 documents.
+ StatusWith<Shard::QueryResponse> response =
+ runFindQuery(nss, BSONObj(), BSON("fooItem" << 1), 2LL);
+ Shard::QueryResponse queryResponse = unittest::assertGet(response);
+
+ std::vector<BSONObj> docs = queryResponse.docs;
+ const unsigned long size = 2;
+ ASSERT_EQUALS(size, docs.size());
+ BSONObj firstDoc = docs[0];
+ ASSERT_EQUALS(1, firstDoc["fooItem"].numberInt());
+ ASSERT_EQUALS(254, firstDoc["fooRandom"].numberInt());
+ BSONObj secondDoc = docs[1];
+ ASSERT_EQUALS(2, secondDoc["fooItem"].numberInt());
+ ASSERT_EQUALS(444, secondDoc["fooRandom"].numberInt());
+}
+
+TEST_F(ShardLocalTest, FindNoMatchingDocumentsEmpty) {
+ NamespaceString nss("foo.bar");
+
+ // Set up a document.
+ StatusWith<Shard::CommandResponse> findAndModifyResponse = runFindAndModifyRunCommand(
+ nss, BSON("fooItem" << 1), BSON("$set" << BSON("fooRandom" << 254)));
+ ASSERT_OK(findAndModifyResponse.getStatus());
+
+ // Run a query that won't find any results.
+ StatusWith<Shard::QueryResponse> response =
+ runFindQuery(nss, BSON("fooItem" << 3), BSONObj(), boost::none);
+ Shard::QueryResponse queryResponse = unittest::assertGet(response);
+
+ std::vector<BSONObj> docs = queryResponse.docs;
+ const unsigned long size = 0;
+ ASSERT_EQUALS(size, docs.size());
+}
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/s/client/shard_remote.h b/src/mongo/s/client/shard_remote.h
index 3c943f81b9b..35befdf8417 100644
--- a/src/mongo/s/client/shard_remote.h
+++ b/src/mongo/s/client/shard_remote.h
@@ -36,8 +36,6 @@
namespace mongo {
-using ShardId = std::string;
-
/*
* Maintains the targeting and command execution logic for a single shard. Performs polling of
* the shard (if replica set).
@@ -61,7 +59,7 @@ public:
return _originalConnString;
}
- std::shared_ptr<RemoteCommandTargeter> getTargeter() override {
+ std::shared_ptr<RemoteCommandTargeter> getTargeter() const override {
return _targeter;
}