diff options
author | Dianna Hohensee <dianna.hohensee@10gen.com> | 2016-04-26 14:34:03 -0400 |
---|---|---|
committer | Dianna Hohensee <dianna.hohensee@10gen.com> | 2016-04-27 14:14:35 -0400 |
commit | 21c359f605f773f55d9f494caa9a72273b49139f (patch) | |
tree | d33c64fc4890d97cc6f89f556c4c2cc11bd0e7b4 /src/mongo | |
parent | c56106e308d27b7dc25843e9ab0e4dded1f820c0 (diff) | |
download | mongo-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.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/storage/ephemeral_for_test/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_recovery_unit.h | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/kv/kv_engine_test_snapshots.cpp | 1 | ||||
-rw-r--r-- | src/mongo/s/client/SConscript | 34 | ||||
-rw-r--r-- | src/mongo/s/client/shard.cpp | 42 | ||||
-rw-r--r-- | src/mongo/s/client/shard.h | 48 | ||||
-rw-r--r-- | src/mongo/s/client/shard_local.cpp | 143 | ||||
-rw-r--r-- | src/mongo/s/client/shard_local.h | 73 | ||||
-rw-r--r-- | src/mongo/s/client/shard_local_test.cpp | 208 | ||||
-rw-r--r-- | src/mongo/s/client/shard_remote.h | 4 |
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; } |