diff options
author | Esha Maharishi <esha.maharishi@mongodb.com> | 2016-05-09 18:59:26 -0400 |
---|---|---|
committer | Esha Maharishi <esha.maharishi@mongodb.com> | 2016-05-09 19:05:17 -0400 |
commit | 78c38583efe92db429ed0cb611dd0919f2d890ea (patch) | |
tree | a701de0a5ce77c938a1081c9baba0c4c3b09e1b8 /src | |
parent | 2ebae874958646e2359ebf72a0718c861ee05726 (diff) | |
download | mongo-78c38583efe92db429ed0cb611dd0919f2d890ea.tar.gz |
Revert "SERVER-23336 replace ShardResolver with RemoteCommandTargeter::findHost"
This reverts commit d1957fd1f86510c37a893ec3c51140cf004407d5.
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/s/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/s/cluster_write.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_get_last_error_cmd.cpp | 17 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_write_cmd.cpp | 18 | ||||
-rw-r--r-- | src/mongo/s/dbclient_shard_resolver.cpp | 102 | ||||
-rw-r--r-- | src/mongo/s/dbclient_shard_resolver.h | 70 | ||||
-rw-r--r-- | src/mongo/s/mock_shard_resolver.h | 53 | ||||
-rw-r--r-- | src/mongo/s/shard_resolver.h | 61 | ||||
-rw-r--r-- | src/mongo/s/write_ops/SConscript | 7 | ||||
-rw-r--r-- | src/mongo/s/write_ops/batch_write_exec.cpp | 48 | ||||
-rw-r--r-- | src/mongo/s/write_ops/batch_write_exec.h | 6 | ||||
-rw-r--r-- | src/mongo/s/write_ops/batch_write_exec_test.cpp | 139 |
12 files changed, 388 insertions, 138 deletions
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 237810f6c31..38cfbdb9cb3 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -126,6 +126,7 @@ env.Library( source=[ 'chunk_manager_targeter.cpp', 'cluster_write.cpp', + 'dbclient_shard_resolver.cpp', ], LIBDEPS=[ 'client/sharding_client', diff --git a/src/mongo/s/cluster_write.cpp b/src/mongo/s/cluster_write.cpp index 4299dbe807c..a2400d59250 100644 --- a/src/mongo/s/cluster_write.cpp +++ b/src/mongo/s/cluster_write.cpp @@ -44,6 +44,7 @@ #include "mongo/s/chunk_manager_targeter.h" #include "mongo/s/client/dbclient_multi_command.h" #include "mongo/s/config.h" +#include "mongo/s/dbclient_shard_resolver.h" #include "mongo/s/grid.h" #include "mongo/s/mongos_options.h" #include "mongo/s/write_ops/batch_write_exec.h" @@ -272,8 +273,9 @@ void ClusterWriter::write(OperationContext* txn, return; } + DBClientShardResolver resolver; DBClientMultiCommand dispatcher; - BatchWriteExec exec(&targeter, &dispatcher); + BatchWriteExec exec(&targeter, &resolver, &dispatcher); exec.executeBatch(txn, *request, response, &_stats); } diff --git a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp index 5a79dadfa89..25f073a831e 100644 --- a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp +++ b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp @@ -34,10 +34,8 @@ #include "mongo/db/commands.h" #include "mongo/db/lasterror.h" #include "mongo/s/client/dbclient_multi_command.h" -#include "mongo/client/remote_command_targeter.h" -#include "mongo/s/client/shard_registry.h" #include "mongo/s/cluster_last_error_info.h" -#include "mongo/s/grid.h" +#include "mongo/s/dbclient_shard_resolver.h" #include "mongo/s/write_ops/batch_downconvert.h" namespace mongo { @@ -110,19 +108,12 @@ public: const ConnectionString& shardEndpoint = it->first; const HostOpTime& hot = it->second; - const ReadPreferenceSetting readPref(ReadPreference::PrimaryOnly, TagSet()); - auto shard = grid.shardRegistry()->getShard(txn, shardEndpoint.toString()); - if (!shard) { - result.append("errmsg", "Could not find shard with id " + shardEndpoint.toString()); - return false; - } - auto swHostAndPort = shard->getTargeter()->findHost(readPref); - if (!swHostAndPort.isOK()) { + ConnectionString resolvedHost; + status = DBClientShardResolver::findMaster(shardEndpoint, &resolvedHost); + if (!status.isOK()) { break; } - ConnectionString resolvedHost(swHostAndPort.getValue()); - resolvedHostOpTimes[resolvedHost] = hot; } diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp index eafdb4940a8..470c5c2d789 100644 --- a/src/mongo/s/commands/cluster_write_cmd.cpp +++ b/src/mongo/s/commands/cluster_write_cmd.cpp @@ -30,7 +30,6 @@ #include "mongo/base/error_codes.h" #include "mongo/base/owned_pointer_vector.h" -#include "mongo/client/remote_command_targeter.h" #include "mongo/db/client.h" #include "mongo/db/client_basic.h" #include "mongo/db/commands.h" @@ -44,6 +43,7 @@ #include "mongo/s/cluster_last_error_info.h" #include "mongo/s/cluster_write.h" #include "mongo/s/commands/cluster_explain.h" +#include "mongo/s/dbclient_shard_resolver.h" #include "mongo/s/grid.h" #include "mongo/s/write_ops/batch_upconvert.h" #include "mongo/s/write_ops/batched_command_request.h" @@ -259,6 +259,7 @@ private: return status; } + DBClientShardResolver resolver; DBClientMultiCommand dispatcher; // Assemble requests @@ -266,18 +267,11 @@ private: ++it) { const ShardEndpoint* endpoint = *it; - const ReadPreferenceSetting readPref(ReadPreference::PrimaryOnly, TagSet()); - auto shard = grid.shardRegistry()->getShard(txn, endpoint->shardName); - if (!shard) { - return Status(ErrorCodes::ShardNotFound, - "Could not find shard with id " + endpoint->shardName); - } - auto swHostAndPort = shard->getTargeter()->findHost(readPref); - if (!swHostAndPort.isOK()) { - return swHostAndPort.getStatus(); - } + ConnectionString host; + Status status = resolver.chooseWriteHost(txn, endpoint->shardName, &host); + if (!status.isOK()) + return status; - ConnectionString host(swHostAndPort.getValue()); dispatcher.addCommand(host, dbName, command); } diff --git a/src/mongo/s/dbclient_shard_resolver.cpp b/src/mongo/s/dbclient_shard_resolver.cpp new file mode 100644 index 00000000000..3d2a32db338 --- /dev/null +++ b/src/mongo/s/dbclient_shard_resolver.cpp @@ -0,0 +1,102 @@ +/** + * Copyright (C) 2013 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/dbclient_shard_resolver.h" + +#include <set> + +#include "mongo/client/replica_set_monitor.h" +#include "mongo/s/client/shard.h" +#include "mongo/s/client/shard_registry.h" +#include "mongo/s/grid.h" + +namespace mongo { + +using std::string; + +Status DBClientShardResolver::chooseWriteHost(OperationContext* txn, + const string& shardName, + ConnectionString* shardHost) const { + // Internally uses our shard cache, does no reload + std::shared_ptr<Shard> shard = grid.shardRegistry()->getShard(txn, shardName); + if (!shard) { + return Status(ErrorCodes::ShardNotFound, + str::stream() << "unknown shard name " << shardName); + } + + return findMaster(shard->getConnString(), shardHost); +} + +Status DBClientShardResolver::findMaster(const ConnectionString& connString, + ConnectionString* resolvedHost) { + if (connString.type() == ConnectionString::MASTER) { + *resolvedHost = connString; + return Status::OK(); + } + + dassert(connString.type() == ConnectionString::SET); + + // + // If we need to, then get the particular node we're targeting in the replica set + // + + // Don't create the monitor unless we need to - fast path + ReplicaSetMonitorPtr replMonitor = ReplicaSetMonitor::get(connString.getSetName()); + + if (!replMonitor) { + // Slow path + std::set<HostAndPort> seedServers(connString.getServers().begin(), + connString.getServers().end()); + ReplicaSetMonitor::createIfNeeded(connString.getSetName(), seedServers); + + replMonitor = ReplicaSetMonitor::get(connString.getSetName()); + } + + if (!replMonitor) { + return Status(ErrorCodes::ReplicaSetNotFound, + str::stream() << "unknown replica set " << connString.getSetName()); + } + + try { + // This can throw when we don't find a master! + HostAndPort masterHostAndPort = replMonitor->getMasterOrUassert(); + *resolvedHost = + fassertStatusOK(28687, ConnectionString::parse(masterHostAndPort.toString())); + return Status::OK(); + } catch (const DBException&) { + return Status(ErrorCodes::HostNotFound, + string("could not contact primary for replica set ") + + replMonitor->getName()); + } + + MONGO_UNREACHABLE; +} + +} // namespace mongo diff --git a/src/mongo/s/dbclient_shard_resolver.h b/src/mongo/s/dbclient_shard_resolver.h new file mode 100644 index 00000000000..ba70bdf1dc3 --- /dev/null +++ b/src/mongo/s/dbclient_shard_resolver.h @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2013 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/s/shard_resolver.h" + +namespace mongo { + +/** + * ShardResolver based on the Shard and ReplicaSetMonitor caches. + * + * TODO: Currently it's possible for the shard resolver to be stale after we target and remove + * a shard. We need to figure out how to refresh. + */ +class DBClientShardResolver : public ShardResolver { +public: + DBClientShardResolver() {} + + virtual ~DBClientShardResolver() {} + + /** + * Returns the current host ConnectionString for a write to a shard. + * + * Note: Does *not* trigger a refresh of either the shard or replica set monitor caches, + * though refreshes may happen unexpectedly between calls. + * + * Returns ShardNotFound if the shard name is unknown + * Returns ReplicaSetNotFound if the replica set is not being tracked + * Returns !OK with message if the shard host could not be found for other reasons. + */ + Status chooseWriteHost(OperationContext* txn, + const std::string& shardName, + ConnectionString* shardHost) const override; + + /** + * Resolves a replica set connection string to a master or returns an error. + * + * Returns HostNotFound if the master is not reachable + * Returns ReplicaSetNotFound if the replica set is not being tracked + */ + static Status findMaster(const ConnectionString& connString, ConnectionString* resolvedHost); +}; + +} // namespace mongo diff --git a/src/mongo/s/mock_shard_resolver.h b/src/mongo/s/mock_shard_resolver.h new file mode 100644 index 00000000000..d2263274436 --- /dev/null +++ b/src/mongo/s/mock_shard_resolver.h @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2013 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 <string> + +#include "mongo/base/status.h" +#include "mongo/client/dbclientinterface.h" +#include "mongo/s/shard_resolver.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { + +class MockShardResolver : public ShardResolver { +public: + virtual ~MockShardResolver() {} + + Status chooseWriteHost(OperationContext* txn, + const std::string& shardName, + ConnectionString* shardHost) const { + *shardHost = + unittest::assertGet(ConnectionString::parse(std::string("$") + shardName + ":12345")); + return Status::OK(); + } +}; + +} // namespace mongo diff --git a/src/mongo/s/shard_resolver.h b/src/mongo/s/shard_resolver.h new file mode 100644 index 00000000000..4a0fa53f48c --- /dev/null +++ b/src/mongo/s/shard_resolver.h @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2013 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 <string> + +#include "mongo/base/status.h" +#include "mongo/client/dbclientinterface.h" +#include "mongo/s/shard_resolver.h" + +namespace mongo { + +class OperationContext; + +/** + * Given a shard name, the ShardResolver resolves a particular host on that shard to contact. + * + * TODO: Internally, this is backed by a cache - do we need explicit refresh mechanisms built + * into this interface? + */ +class ShardResolver { +public: + virtual ~ShardResolver() {} + + /** + * Returns a host we can use for write ops to this shard. + * + * Returns !OK with message if the shard host could not be found for other reasons. + */ + virtual Status chooseWriteHost(OperationContext* txn, + const std::string& shardName, + ConnectionString* shardHost) const = 0; +}; + +} // namespace mongo diff --git a/src/mongo/s/write_ops/SConscript b/src/mongo/s/write_ops/SConscript index 1e0091f9d3f..92e3427e873 100644 --- a/src/mongo/s/write_ops/SConscript +++ b/src/mongo/s/write_ops/SConscript @@ -34,8 +34,6 @@ env.Library( LIBDEPS=[
'batch_write_types',
'$BUILD_DIR/mongo/client/connection_string',
- '$BUILD_DIR/mongo/s/client/sharding_client',
- '$BUILD_DIR/mongo/s/coreshard',
],
)
@@ -77,7 +75,6 @@ env.CppUnitTest( 'cluster_write_op',
'$BUILD_DIR/mongo/db/range_arithmetic',
'$BUILD_DIR/mongo/db/service_context',
- '$BUILD_DIR/mongo/s/sharding_test_fixture',
]
)
@@ -90,7 +87,5 @@ env.CppUnitTest( LIBDEPS=[
'cluster_write_op',
'cluster_write_op_conversion',
- '$BUILD_DIR/mongo/s/sharding_test_fixture',
- '$BUILD_DIR/mongo/s/mongoscore',
- ],
+ ]
)
diff --git a/src/mongo/s/write_ops/batch_write_exec.cpp b/src/mongo/s/write_ops/batch_write_exec.cpp index d803fbaf32b..e056e05609c 100644 --- a/src/mongo/s/write_ops/batch_write_exec.cpp +++ b/src/mongo/s/write_ops/batch_write_exec.cpp @@ -37,10 +37,7 @@ #include "mongo/base/status.h" #include "mongo/bson/util/builder.h" #include "mongo/client/connection_string.h" -#include "mongo/client/remote_command_targeter.h" #include "mongo/s/client/multi_command_dispatch.h" -#include "mongo/s/client/shard_registry.h" -#include "mongo/s/grid.h" #include "mongo/s/write_ops/batch_write_op.h" #include "mongo/s/write_ops/write_error_detail.h" #include "mongo/util/log.h" @@ -51,8 +48,10 @@ using std::make_pair; using std::stringstream; using std::vector; -BatchWriteExec::BatchWriteExec(NSTargeter* targeter, MultiCommandDispatch* dispatcher) - : _targeter(targeter), _dispatcher(dispatcher) {} +BatchWriteExec::BatchWriteExec(NSTargeter* targeter, + ShardResolver* resolver, + MultiCommandDispatch* dispatcher) + : _targeter(targeter), _resolver(resolver), _dispatcher(dispatcher) {} namespace { @@ -170,43 +169,22 @@ void BatchWriteExec::executeBatch(OperationContext* txn, continue; // Figure out what host we need to dispatch our targeted batch - bool resolvedHost = true; - const ReadPreferenceSetting readPref(ReadPreference::PrimaryOnly, TagSet()); - auto shard = - grid.shardRegistry()->getShard(txn, nextBatch->getEndpoint().shardName); - - if (!shard) { - Status status = Status(ErrorCodes::ShardNotFound, - str::stream() << "unknown shard name " - << nextBatch->getEndpoint().shardName); - resolvedHost = false; + ConnectionString shardHost; + Status resolveStatus = + _resolver->chooseWriteHost(txn, nextBatch->getEndpoint().shardName, &shardHost); + if (!resolveStatus.isOK()) { + ++stats->numResolveErrors; // Record a resolve failure // TODO: It may be necessary to refresh the cache if stale, or maybe just // cancel and retarget the batch WriteErrorDetail error; - buildErrorFrom(status, &error); - LOG(4) << "unable to send write batch to " << nextBatch->getEndpoint().shardName - << causedBy(status); - batchOp.noteBatchError(*nextBatch, error); - } + buildErrorFrom(resolveStatus, &error); - auto swHostAndPort = shard->getTargeter()->findHost(readPref); - if (!swHostAndPort.isOK()) { - resolvedHost = false; + LOG(4) << "unable to send write batch to " << shardHost.toString() + << causedBy(resolveStatus.toString()); - // Record a resolve failure - // TODO: It may be necessary to refresh the cache if stale, or maybe just - // cancel and retarget the batch - WriteErrorDetail error; - buildErrorFrom(swHostAndPort.getStatus(), &error); - LOG(4) << "unable to send write batch to " << nextBatch->getEndpoint().shardName - << causedBy(swHostAndPort.getStatus()); batchOp.noteBatchError(*nextBatch, error); - } - - if (!resolvedHost) { - ++stats->numResolveErrors; // We're done with this batch // Clean up when we can't resolve a host @@ -216,8 +194,6 @@ void BatchWriteExec::executeBatch(OperationContext* txn, continue; } - ConnectionString shardHost(swHostAndPort.getValue()); - // If we already have a batch for this host, wait until the next time OwnedHostBatchMap::MapType::iterator pendingIt = pendingBatches.find(shardHost); if (pendingIt != pendingBatches.end()) diff --git a/src/mongo/s/write_ops/batch_write_exec.h b/src/mongo/s/write_ops/batch_write_exec.h index 739e16a046d..e29a80a9a72 100644 --- a/src/mongo/s/write_ops/batch_write_exec.h +++ b/src/mongo/s/write_ops/batch_write_exec.h @@ -36,6 +36,7 @@ #include "mongo/bson/timestamp.h" #include "mongo/db/repl/optime.h" #include "mongo/s/ns_targeter.h" +#include "mongo/s/shard_resolver.h" #include "mongo/s/write_ops/batched_command_request.h" #include "mongo/s/write_ops/batched_command_response.h" @@ -64,7 +65,7 @@ class BatchWriteExec { MONGO_DISALLOW_COPYING(BatchWriteExec); public: - BatchWriteExec(NSTargeter* targeter, MultiCommandDispatch* dispatcher); + BatchWriteExec(NSTargeter* targeter, ShardResolver* resolver, MultiCommandDispatch* dispatcher); /** * Executes a client batch write request by sending child batches to several shard @@ -82,6 +83,9 @@ private: NSTargeter* _targeter; // Not owned here + ShardResolver* _resolver; + + // Not owned here MultiCommandDispatch* _dispatcher; }; diff --git a/src/mongo/s/write_ops/batch_write_exec_test.cpp b/src/mongo/s/write_ops/batch_write_exec_test.cpp index 74b84e4503c..bf0e4c8685a 100644 --- a/src/mongo/s/write_ops/batch_write_exec_test.cpp +++ b/src/mongo/s/write_ops/batch_write_exec_test.cpp @@ -28,19 +28,14 @@ #include "mongo/platform/basic.h" -#include "mongo/s/write_ops/batch_write_exec.h" - #include "mongo/base/owned_pointer_vector.h" -#include "mongo/client/remote_command_targeter_mock.h" -#include "mongo/client/remote_command_targeter_factory_mock.h" -#include "mongo/s/catalog/type_shard.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/s/client/mock_multi_write_command.h" -#include "mongo/s/client/shard_registry.h" #include "mongo/s/mock_ns_targeter.h" -#include "mongo/s/sharding_test_fixture.h" +#include "mongo/s/mock_shard_resolver.h" +#include "mongo/s/write_ops/batch_write_exec.h" #include "mongo/s/write_ops/batched_command_request.h" #include "mongo/s/write_ops/batched_command_response.h" -#include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" namespace mongo { @@ -51,60 +46,35 @@ using std::vector; namespace { -const HostAndPort kTestShardHost = HostAndPort("FakeHost", 12345); -const HostAndPort kTestConfigShardHost = HostAndPort("FakeConfigHost", 12345); -const string shardName = "FakeShard"; - /** * Mimics a single shard backend for a particular collection which can be initialized with a * set of write command results to return. */ -class BatchWriteExecTest : public ShardingTestFixture { +class MockSingleShardBackend { public: - BatchWriteExecTest() = default; - ~BatchWriteExecTest() = default; - - void setUp() override { - ShardingTestFixture::setUp(); - getMessagingPort()->setRemote(HostAndPort("ClientHost", 12345)); - - // Set up the RemoteCommandTargeter for the config shard. - configTargeter()->setFindHostReturnValue(kTestConfigShardHost); - - // Add a RemoteCommandTargeter for the data shard. - std::unique_ptr<RemoteCommandTargeterMock> targeter( - stdx::make_unique<RemoteCommandTargeterMock>()); - targeter->setConnectionStringReturnValue(ConnectionString(kTestShardHost)); - targeter->setFindHostReturnValue(kTestShardHost); - targeterFactory()->addTargeterToReturn(ConnectionString(kTestShardHost), - std::move(targeter)); - - // Set up the shard registry to contain the fake shard. - ShardType shardType; - shardType.setName(shardName); - shardType.setHost(kTestShardHost.toString()); - std::vector<ShardType> shards{shardType}; - setupShards(shards); - - // Set up the namespace targeter to target the fake shard. - ShardEndpoint endpoint(shardName, ChunkVersion::IGNORED()); + MockSingleShardBackend(OperationContext* txn, const NamespaceString& nss) { + // Initialize targeting to a mock shard + ShardEndpoint endpoint("shard", ChunkVersion::IGNORED()); vector<MockRange*> mockRanges; mockRanges.push_back( new MockRange(endpoint, nss, BSON("x" << MINKEY), BSON("x" << MAXKEY))); - nsTargeter.init(mockRanges); + targeter.init(mockRanges); + + // Get the connection string for the mock shard + resolver.chooseWriteHost(txn, mockRanges.front()->endpoint.shardName, &shardHost); - // Make the batch write executor use the mock backend. - exec.reset(new BatchWriteExec(&nsTargeter, &dispatcher)); + // Executor using the mock backend + exec.reset(new BatchWriteExec(&targeter, &resolver, &dispatcher)); } void setMockResults(const vector<MockWriteResult*>& results) { dispatcher.init(results); } - ConnectionString shardHost{kTestShardHost}; - NamespaceString nss{"foo.bar"}; + ConnectionString shardHost; - MockNSTargeter nsTargeter; + MockNSTargeter targeter; + MockShardResolver resolver; MockMultiWriteCommand dispatcher; unique_ptr<BatchWriteExec> exec; @@ -114,11 +84,16 @@ public: // Tests for the BatchWriteExec // -TEST_F(BatchWriteExecTest, SingleOp) { +TEST(BatchWriteExecTests, SingleOp) { // // Basic execution test // + OperationContextNoop txn; + NamespaceString nss("foo.bar"); + + MockSingleShardBackend backend(&txn, nss); + BatchedCommandRequest request(BatchedCommandRequest::BatchType_Insert); request.setNS(nss); request.setOrdered(false); @@ -128,25 +103,30 @@ TEST_F(BatchWriteExecTest, SingleOp) { BatchedCommandResponse response; BatchWriteExecStats stats; - exec->executeBatch(operationContext(), request, &response, &stats); + backend.exec->executeBatch(&txn, request, &response, &stats); ASSERT(response.getOk()); ASSERT_EQUALS(stats.numRounds, 1); } -TEST_F(BatchWriteExecTest, SingleOpError) { +TEST(BatchWriteExecTests, SingleOpError) { // // Basic error test // + OperationContextNoop txn; + NamespaceString nss("foo.bar"); + + MockSingleShardBackend backend(&txn, nss); + vector<MockWriteResult*> mockResults; BatchedCommandResponse errResponse; errResponse.setOk(false); errResponse.setErrCode(ErrorCodes::UnknownError); errResponse.setErrMessage("mock error"); - mockResults.push_back(new MockWriteResult(shardHost, errResponse)); + mockResults.push_back(new MockWriteResult(backend.shardHost, errResponse)); - setMockResults(mockResults); + backend.setMockResults(mockResults); BatchedCommandRequest request(BatchedCommandRequest::BatchType_Insert); request.setNS(nss); @@ -157,7 +137,7 @@ TEST_F(BatchWriteExecTest, SingleOpError) { BatchedCommandResponse response; BatchWriteExecStats stats; - exec->executeBatch(operationContext(), request, &response, &stats); + backend.exec->executeBatch(&txn, request, &response, &stats); ASSERT(response.getOk()); ASSERT_EQUALS(response.getN(), 0); ASSERT(response.isErrDetailsSet()); @@ -172,11 +152,14 @@ TEST_F(BatchWriteExecTest, SingleOpError) { // Test retryable errors // -TEST_F(BatchWriteExecTest, StaleOp) { +TEST(BatchWriteExecTests, StaleOp) { // // Retry op in exec b/c of stale config // + OperationContextNoop txn; + NamespaceString nss("foo.bar"); + // Insert request BatchedCommandRequest request(BatchedCommandRequest::BatchType_Insert); request.setNS(nss); @@ -185,28 +168,33 @@ TEST_F(BatchWriteExecTest, StaleOp) { // Do single-target, single doc batch write op request.getInsertRequest()->addToDocuments(BSON("x" << 1)); + MockSingleShardBackend backend(&txn, nss); + vector<MockWriteResult*> mockResults; WriteErrorDetail error; error.setErrCode(ErrorCodes::StaleShardVersion); error.setErrMessage("mock stale error"); - mockResults.push_back(new MockWriteResult(shardHost, error)); + mockResults.push_back(new MockWriteResult(backend.shardHost, error)); - setMockResults(mockResults); + backend.setMockResults(mockResults); // Execute request BatchedCommandResponse response; BatchWriteExecStats stats; - exec->executeBatch(operationContext(), request, &response, &stats); + backend.exec->executeBatch(&txn, request, &response, &stats); ASSERT(response.getOk()); ASSERT_EQUALS(stats.numStaleBatches, 1); } -TEST_F(BatchWriteExecTest, MultiStaleOp) { +TEST(BatchWriteExecTests, MultiStaleOp) { // // Retry op in exec multiple times b/c of stale config // + OperationContextNoop txn; + NamespaceString nss("foo.bar"); + // Insert request BatchedCommandRequest request(BatchedCommandRequest::BatchType_Insert); request.setNS(nss); @@ -215,32 +203,37 @@ TEST_F(BatchWriteExecTest, MultiStaleOp) { // Do single-target, single doc batch write op request.getInsertRequest()->addToDocuments(BSON("x" << 1)); + MockSingleShardBackend backend(&txn, nss); + vector<MockWriteResult*> mockResults; WriteErrorDetail error; error.setErrCode(ErrorCodes::StaleShardVersion); error.setErrMessage("mock stale error"); for (int i = 0; i < 3; i++) { - mockResults.push_back(new MockWriteResult(shardHost, error)); + mockResults.push_back(new MockWriteResult(backend.shardHost, error)); } - setMockResults(mockResults); + backend.setMockResults(mockResults); // Execute request BatchedCommandResponse response; BatchWriteExecStats stats; - exec->executeBatch(operationContext(), request, &response, &stats); + backend.exec->executeBatch(&txn, request, &response, &stats); ASSERT(response.getOk()); ASSERT_EQUALS(stats.numStaleBatches, 3); } -TEST_F(BatchWriteExecTest, TooManyStaleOp) { +TEST(BatchWriteExecTests, TooManyStaleOp) { // // Retry op in exec too many times (without refresh) b/c of stale config - // (The mock nsTargeter doesn't report progress on refresh) + // (The mock targeter doesn't report progress on refresh) // We should report a no progress error for everything in the batch // + OperationContextNoop txn; + NamespaceString nss("foo.bar"); + // Insert request BatchedCommandRequest request(BatchedCommandRequest::BatchType_Insert); request.setNS(nss); @@ -250,20 +243,23 @@ TEST_F(BatchWriteExecTest, TooManyStaleOp) { request.getInsertRequest()->addToDocuments(BSON("x" << 1)); request.getInsertRequest()->addToDocuments(BSON("x" << 2)); + MockSingleShardBackend backend(&txn, nss); + vector<MockWriteResult*> mockResults; WriteErrorDetail error; error.setErrCode(ErrorCodes::StaleShardVersion); error.setErrMessage("mock stale error"); for (int i = 0; i < 10; i++) { - mockResults.push_back(new MockWriteResult(shardHost, error, request.sizeWriteOps())); + mockResults.push_back( + new MockWriteResult(backend.shardHost, error, request.sizeWriteOps())); } - setMockResults(mockResults); + backend.setMockResults(mockResults); // Execute request BatchedCommandResponse response; BatchWriteExecStats stats; - exec->executeBatch(operationContext(), request, &response, &stats); + backend.exec->executeBatch(&txn, request, &response, &stats); ASSERT(response.getOk()); ASSERT_EQUALS(response.getN(), 0); ASSERT(response.isErrDetailsSet()); @@ -271,11 +267,14 @@ TEST_F(BatchWriteExecTest, TooManyStaleOp) { ASSERT_EQUALS(response.getErrDetailsAt(1)->getErrCode(), ErrorCodes::NoProgressMade); } -TEST_F(BatchWriteExecTest, ManyStaleOpWithMigration) { +TEST(BatchWriteExecTests, ManyStaleOpWithMigration) { // // Retry op in exec many times b/c of stale config, but simulate remote migrations occurring // + OperationContextNoop txn; + NamespaceString nss("foo.bar"); + // Insert request BatchedCommandRequest request(BatchedCommandRequest::BatchType_Insert); request.setNS(nss); @@ -284,20 +283,22 @@ TEST_F(BatchWriteExecTest, ManyStaleOpWithMigration) { // Do single-target, single doc batch write op request.getInsertRequest()->addToDocuments(BSON("x" << 1)); + MockSingleShardBackend backend(&txn, nss); + vector<MockWriteResult*> mockResults; WriteErrorDetail error; error.setErrCode(ErrorCodes::StaleShardVersion); error.setErrMessage("mock stale error"); for (int i = 0; i < 10; i++) { - mockResults.push_back(new MockWriteResult(shardHost, error)); + mockResults.push_back(new MockWriteResult(backend.shardHost, error)); } - setMockResults(mockResults); + backend.setMockResults(mockResults); // Execute request BatchedCommandResponse response; BatchWriteExecStats stats; - exec->executeBatch(operationContext(), request, &response, &stats); + backend.exec->executeBatch(&txn, request, &response, &stats); ASSERT(response.getOk()); ASSERT_EQUALS(stats.numStaleBatches, 6); |