diff options
-rw-r--r-- | src/mongo/s/SConscript | 22 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp | 30 | ||||
-rw-r--r-- | src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp | 41 | ||||
-rw-r--r-- | src/mongo/s/set_shard_version_request.cpp | 214 | ||||
-rw-r--r-- | src/mongo/s/set_shard_version_request.h | 147 | ||||
-rw-r--r-- | src/mongo/s/set_shard_version_request_test.cpp | 219 |
6 files changed, 653 insertions, 20 deletions
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 1669b744cbe..705f48744c9 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -32,9 +32,11 @@ env.Library( target='common', source=[ 'chunk_diff.cpp', + 'set_shard_version_request.cpp', ], LIBDEPS=[ 'catalog/catalog_types', + '$BUILD_DIR/mongo/client/connection_string', ] ) @@ -49,23 +51,29 @@ env.Library( ) env.CppUnitTest( + target='chunk_diff_test', + source=[ + 'chunk_diff_test.cpp', + ], + LIBDEPS=[ + 'common', + ] +) + +env.CppUnitTest( target='chunk_version_test', source=[ 'chunk_version_test.cpp', ], LIBDEPS=[ - '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/client/clientdriver', - '$BUILD_DIR/mongo/db/common', - '$BUILD_DIR/mongo/db/range_arithmetic', - 'catalog/catalog_types', + 'common', ] ) env.CppUnitTest( - target='chunk_diff_test', + target='set_shard_version_request_test', source=[ - 'chunk_diff_test.cpp', + 'set_shard_version_request_test.cpp', ], LIBDEPS=[ 'common', diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp index 99b797b0336..5204bca6432 100644 --- a/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp +++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp @@ -63,6 +63,7 @@ #include "mongo/s/chunk_manager.h" #include "mongo/s/config.h" #include "mongo/s/grid.h" +#include "mongo/s/set_shard_version_request.h" #include "mongo/s/shard_key_pattern.h" #include "mongo/s/write_ops/batched_command_request.h" #include "mongo/s/write_ops/batched_command_response.h" @@ -211,13 +212,28 @@ Status CatalogManagerReplicaSet::shardCollection(OperationContext* txn, collInfo.save(ns); manager->reload(true); - // TODO(spencer) SERVER-19319: Send setShardVersion to primary shard so it knows to start - // rejecting unversioned writes. - - BSONObj finishDetail = BSON("version" - << ""); // TODO(spencer) SERVER-19319 Report actual version used - - logChange(txn->getClient()->clientAddress(true), "shardCollection", ns, finishDetail); + // Tell the primary mongod to refresh its data + // TODO: Think the real fix here is for mongos to just + // assume that all collections are sharded, when we get there + SetShardVersionRequest ssv = + SetShardVersionRequest::makeForVersioning(_configServerConnectionString, + dbPrimaryShardId, + primaryShard->getConnString(), + NamespaceString(ns), + manager->getVersion(), + true); + + auto ssvStatus = grid.shardRegistry()->runCommandWithNotMasterRetries( + dbPrimaryShardId, "admin", ssv.toBSON()); + if (!ssvStatus.isOK()) { + warning() << "could not update initial version of " << ns << " on shard primary " + << dbPrimaryShardId << ssvStatus.getStatus(); + } + + logChange(txn->getClient()->clientAddress(true), + "shardCollection", + ns, + BSON("version" << manager->getVersion().toString())); return Status::OK(); } diff --git a/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp b/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp index c366a48aee5..05a73346816 100644 --- a/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp +++ b/src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp @@ -49,6 +49,7 @@ #include "mongo/s/chunk.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" +#include "mongo/s/set_shard_version_request.h" #include "mongo/s/shard_key_pattern.h" #include "mongo/s/write_ops/batched_command_request.h" #include "mongo/s/write_ops/batched_command_response.h" @@ -237,6 +238,27 @@ public: }); } + void expectSetShardVersion(const HostAndPort& expectedTargetHost, + const string& expectedNs, + const ChunkVersion& expectedChunkVersion) { + onCommand([&](const RemoteCommandRequest& request) { + ASSERT_EQ(expectedTargetHost, request.target); + + SetShardVersionRequest ssv = + assertGet(SetShardVersionRequest::parseFromBSON(request.cmdObj)); + + ASSERT(!ssv.isInit()); + ASSERT(ssv.isAuthoritative()); + ASSERT_EQ(catalogManager()->connectionString().toString(), + ssv.getConfigServer().toString()); + ASSERT_EQ(expectedTargetHost.toString(), ssv.getShardConnectionString().toString()); + ASSERT_EQ(expectedNs, ssv.getNS().ns()); + ASSERT_EQ(expectedChunkVersion.toString(), ssv.getNSVersion().toString()); + + return BSON("ok" << true); + }); + } + protected: const HostAndPort configHost{"configHost1"}; const HostAndPort clientHost{"clientHost1"}; @@ -404,14 +426,16 @@ TEST_F(ShardCollectionTest, noInitialChunksOrData) { expectReloadChunks(ns, {expectedChunk}); expectLoadNewestChunk(ns, expectedChunk); + // Expect the set shard version for that namespace + expectSetShardVersion(shardHost, ns, actualVersion); + // Respond to request to write final changelog entry indicating success. expectChangeLogInsert(configHost, clientHost.toString(), network()->now(), "shardCollection", ns, - BSON("version" - << "")); + BSON("version" << actualVersion.toString())); future.timed_get(kFutureTimeout); } @@ -421,6 +445,7 @@ TEST_F(ShardCollectionTest, withInitialChunks) { const HostAndPort shard0Host{"shardHost0"}; const HostAndPort shard1Host{"shardHost1"}; const HostAndPort shard2Host{"shardHost2"}; + ShardType shard0; shard0.setName("shard0"); shard0.setHost(shard0Host.toString()); @@ -581,14 +606,16 @@ TEST_F(ShardCollectionTest, withInitialChunks) { expectReloadChunks(ns, expectedChunks); expectLoadNewestChunk(ns, expectedChunks[4]); + // Expect the set shard version for that namespace + expectSetShardVersion(shard0Host, ns, expectedChunks[4].getVersion()); + // Respond to request to write final changelog entry indicating success. expectChangeLogInsert(configHost, clientHost.toString(), network()->now(), "shardCollection", ns, - BSON("version" - << "")); + BSON("version" << expectedChunks[4].getVersion().toString())); future.timed_get(kFutureTimeout); } @@ -759,14 +786,16 @@ TEST_F(ShardCollectionTest, withInitialData) { expectReloadChunks(ns, expectedChunks); expectLoadNewestChunk(ns, expectedChunks[4]); + // Expect the set shard version for that namespace + expectSetShardVersion(shardHost, ns, expectedChunks[4].getVersion()); + // Respond to request to write final changelog entry indicating success. expectChangeLogInsert(configHost, clientHost.toString(), network()->now(), "shardCollection", ns, - BSON("version" - << "")); + BSON("version" << expectedChunks[4].getVersion().toString())); future.timed_get(kFutureTimeout); } diff --git a/src/mongo/s/set_shard_version_request.cpp b/src/mongo/s/set_shard_version_request.cpp new file mode 100644 index 00000000000..5c869c22f01 --- /dev/null +++ b/src/mongo/s/set_shard_version_request.cpp @@ -0,0 +1,214 @@ +/** + * Copyright (C) 2015 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/set_shard_version_request.h" + +#include "mongo/base/status_with.h" +#include "mongo/bson/bsonobj.h" +#include "mongo/bson/bsonobjbuilder.h" +#include "mongo/bson/util/bson_extract.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/mongoutils/str.h" + +namespace mongo { +namespace { + +const char kCmdName[] = "setShardVersion"; +const char kConfigServer[] = "configdb"; +const char kShardName[] = "shard"; +const char kShardConnectionString[] = "shardHost"; +const char kInit[] = "init"; +const char kAuthoritative[] = "authoritative"; +const char kVersion[] = "version"; + +} // namespace + +SetShardVersionRequest::SetShardVersionRequest(ConnectionString configServer, + std::string shardName, + ConnectionString shardConnectionString) + : _init(true), + _configServer(std::move(configServer)), + _shardName(std::move(shardName)), + _shardCS(std::move(shardConnectionString)) {} + +SetShardVersionRequest::SetShardVersionRequest(ConnectionString configServer, + std::string shardName, + ConnectionString shardConnectionString, + NamespaceString nss, + ChunkVersion version, + bool isAuthoritative) + : _init(false), + _configServer(std::move(configServer)), + _shardName(std::move(shardName)), + _shardCS(std::move(shardConnectionString)), + _nss(std::move(nss)), + _version(std::move(version)), + _isAuthoritative(isAuthoritative) {} + +SetShardVersionRequest::SetShardVersionRequest() = default; + +SetShardVersionRequest SetShardVersionRequest::makeForInit( + const ConnectionString& configServer, + const std::string& shardName, + const ConnectionString& shardConnectionString) { + return SetShardVersionRequest(configServer, shardName, shardConnectionString); +} + +SetShardVersionRequest SetShardVersionRequest::makeForVersioning( + const ConnectionString& configServer, + const std::string& shardName, + const ConnectionString& shardConnectionString, + const NamespaceString& nss, + const ChunkVersion& nssVersion, + bool isAuthoritative) { + return SetShardVersionRequest( + configServer, shardName, shardConnectionString, nss, nssVersion, isAuthoritative); +} + +StatusWith<SetShardVersionRequest> SetShardVersionRequest::parseFromBSON(const BSONObj& cmdObj) { + SetShardVersionRequest request; + + { + std::string configServer; + Status status = bsonExtractStringField(cmdObj, kConfigServer, &configServer); + if (!status.isOK()) + return status; + + auto configServerStatus = ConnectionString::parse(configServer); + if (!configServerStatus.isOK()) + return configServerStatus.getStatus(); + + request._configServer = std::move(configServerStatus.getValue()); + } + + { + Status status = bsonExtractStringField(cmdObj, kShardName, &request._shardName); + if (!status.isOK()) + return status; + } + + { + std::string shardCS; + Status status = bsonExtractStringField(cmdObj, kShardConnectionString, &shardCS); + if (!status.isOK()) + return status; + + auto shardCSStatus = ConnectionString::parse(shardCS); + if (!shardCSStatus.isOK()) + return shardCSStatus.getStatus(); + + request._shardCS = std::move(shardCSStatus.getValue()); + } + + { + Status status = bsonExtractBooleanFieldWithDefault(cmdObj, kInit, false, &request._init); + if (!status.isOK()) + return status; + } + + if (request.isInit()) { + return request; + } + + // Only initialize the version information if this is not an "init" request + + { + std::string ns; + Status status = bsonExtractStringField(cmdObj, kCmdName, &ns); + if (!status.isOK()) + return status; + + NamespaceString nss(ns); + + if (!nss.isValid()) { + return {ErrorCodes::InvalidNamespace, + str::stream() << ns << " is not a valid namespace"}; + } + + request._nss = std::move(nss); + } + + { + bool canParse; + + ChunkVersion chunkVersion = ChunkVersion::fromBSON(cmdObj, kVersion, &canParse); + if (!canParse) { + return {ErrorCodes::BadValue, "Unable to parse shard version"}; + } + + request._version = std::move(chunkVersion); + } + + { + bool isAuthoritative; + Status status = + bsonExtractBooleanFieldWithDefault(cmdObj, kAuthoritative, false, &isAuthoritative); + if (!status.isOK()) + return status; + + request._isAuthoritative = isAuthoritative; + } + + return request; +} + +BSONObj SetShardVersionRequest::toBSON() const { + BSONObjBuilder cmdBuilder; + + cmdBuilder.append(kCmdName, _init ? "" : _nss.get().ns()); + cmdBuilder.append(kInit, _init); + cmdBuilder.append(kConfigServer, _configServer.toString()); + cmdBuilder.append(kShardName, _shardName); + cmdBuilder.append(kShardConnectionString, _shardCS.toString()); + + if (!_init) { + _version.get().addToBSON(cmdBuilder, kVersion); + cmdBuilder.append(kAuthoritative, isAuthoritative()); + } + + return cmdBuilder.obj(); +} + +const NamespaceString& SetShardVersionRequest::getNS() const { + invariant(!_init); + return _nss.get(); +} + +const ChunkVersion SetShardVersionRequest::getNSVersion() const { + invariant(!_init); + return _version.get(); +} + +bool SetShardVersionRequest::isAuthoritative() const { + invariant(!_init); + return _isAuthoritative.get_value_or(false); +} + +} // namespace mongo diff --git a/src/mongo/s/set_shard_version_request.h b/src/mongo/s/set_shard_version_request.h new file mode 100644 index 00000000000..881c2a3bfe5 --- /dev/null +++ b/src/mongo/s/set_shard_version_request.h @@ -0,0 +1,147 @@ +/** + * Copyright (C) 2015 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 <boost/optional.hpp> +#include <string> + +#include "mongo/client/connection_string.h" +#include "mongo/db/namespace_string.h" +#include "mongo/s/chunk_version.h" + +namespace mongo { + +class BSONObj; +struct ChunkVersion; +template <typename T> +class StatusWith; + +/** + * Encapsulates the parsing and construction logic for the SetShardVersion command. + */ +class SetShardVersionRequest { +public: + /** + * Constructs a new set shard version request, which is of the "init" type, meaning it has no + * namespace or version information associated with it and the init flag is set. + */ + static SetShardVersionRequest makeForInit(const ConnectionString& configServer, + const std::string& shardName, + const ConnectionString& shardConnectionString); + + /** + * Constructs a new set shard version request, which is of the "versioning" type, meaning it has + * both initialization data and namespace and version information associated with it. + */ + static SetShardVersionRequest makeForVersioning(const ConnectionString& configServer, + const std::string& shardName, + const ConnectionString& shard, + const NamespaceString& nss, + const ChunkVersion& nssVersion, + bool isAuthoritative); + + /** + * Parses an SSV request from a set shard version command. + */ + static StatusWith<SetShardVersionRequest> parseFromBSON(const BSONObj& cmdObj); + + /** + * Produces a BSON representation of the request, which can be used for sending as a command. + */ + BSONObj toBSON() const; + + /** + * Returns whether this is an "init" type of request, where we only have the config server + * information and the identity that the targeted shard should assume or it contains namespace + * version as well. If this value is true, it is illegal to access anything other than the + * config server, shard name and shard connection string fields. + */ + bool isInit() const { + return _init; + } + + const ConnectionString& getConfigServer() const { + return _configServer; + } + + const std::string& getShardName() const { + return _shardName; + } + + const ConnectionString& getShardConnectionString() const { + return _shardCS; + } + + /** + * Returns the namespace associated with this set shard version request. It is illegal to access + * this field if isInit() returns true. + */ + const NamespaceString& getNS() const; + + /** + * Returns the version of the namespace associated with this set shard version request. It is + * illegal to access this field if isInit() returns true. + */ + const ChunkVersion getNSVersion() const; + + /** + * Returns whether this request should force the version to be set instead of it being reloaded + * and recalculated from the metadata. It is illegal to access this field if isInit() returns + * true. + */ + bool isAuthoritative() const; + +private: + SetShardVersionRequest(ConnectionString configServer, + std::string shardName, + ConnectionString shardConnectionString); + + SetShardVersionRequest(ConnectionString configServer, + std::string shardName, + ConnectionString shardConnectionString, + NamespaceString nss, + ChunkVersion nssVersion, + bool isAuthoritative); + + SetShardVersionRequest(); + + bool _init{false}; + + ConnectionString _configServer; + + std::string _shardName; + ConnectionString _shardCS; + + // These values are only set if _init is false + boost::optional<NamespaceString> _nss; + boost::optional<ChunkVersion> _version; + boost::optional<bool> _isAuthoritative; +}; + +} // namespace mongo diff --git a/src/mongo/s/set_shard_version_request_test.cpp b/src/mongo/s/set_shard_version_request_test.cpp new file mode 100644 index 00000000000..a71026e67d0 --- /dev/null +++ b/src/mongo/s/set_shard_version_request_test.cpp @@ -0,0 +1,219 @@ +/** + * Copyright (C) 2015 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/bson/bsonmisc.h" +#include "mongo/bson/oid.h" +#include "mongo/s/set_shard_version_request.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { + +using unittest::assertGet; + +namespace { + +const ConnectionString configCS = ConnectionString::forReplicaSet( + "ConfigRS", {HostAndPort{"configHost1:27017"}, HostAndPort{"configHost2:27017"}}); + +const ConnectionString shardCS = ConnectionString::forReplicaSet( + "ShardRS", {HostAndPort{"shardHost1:12345"}, HostAndPort{"shardHost2:12345"}}); + +TEST(SetShardVersionRequest, ParseInit) { + SetShardVersionRequest request = + assertGet(SetShardVersionRequest::parseFromBSON( + BSON("setShardVersion" + << "" + << "init" << true << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString()))); + + ASSERT(request.isInit()); + ASSERT_EQ(request.getConfigServer().toString(), configCS.toString()); + ASSERT_EQ(request.getShardName(), "TestShard"); + ASSERT_EQ(request.getShardConnectionString().toString(), shardCS.toString()); +} + +TEST(SetShardVersionRequest, ParseFull) { + const ChunkVersion chunkVersion(1, 2, OID::gen()); + + SetShardVersionRequest request = + assertGet(SetShardVersionRequest::parseFromBSON( + BSON("setShardVersion" + << "db.coll" + << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString() << "version" + << Timestamp(chunkVersion.toLong()) << "versionEpoch" << chunkVersion.epoch()))); + + ASSERT(!request.isInit()); + ASSERT(!request.isAuthoritative()); + ASSERT_EQ(request.getConfigServer().toString(), configCS.toString()); + ASSERT_EQ(request.getShardName(), "TestShard"); + ASSERT_EQ(request.getShardConnectionString().toString(), shardCS.toString()); + ASSERT_EQ(request.getNS().toString(), "db.coll"); + ASSERT_EQ(request.getNSVersion().majorVersion(), chunkVersion.majorVersion()); + ASSERT_EQ(request.getNSVersion().minorVersion(), chunkVersion.minorVersion()); + ASSERT_EQ(request.getNSVersion().epoch(), chunkVersion.epoch()); +} + +TEST(SetShardVersionRequest, ParseFullAuhtoritative) { + const ChunkVersion chunkVersion(1, 2, OID::gen()); + + SetShardVersionRequest request = + assertGet(SetShardVersionRequest::parseFromBSON( + BSON("setShardVersion" + << "db.coll" + << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString() << "version" + << Timestamp(chunkVersion.toLong()) << "versionEpoch" << chunkVersion.epoch() + << "authoritative" << true))); + + ASSERT(!request.isInit()); + ASSERT(request.isAuthoritative()); + ASSERT_EQ(request.getConfigServer().toString(), configCS.toString()); + ASSERT_EQ(request.getShardName(), "TestShard"); + ASSERT_EQ(request.getShardConnectionString().toString(), shardCS.toString()); + ASSERT_EQ(request.getNS().toString(), "db.coll"); + ASSERT_EQ(request.getNSVersion().majorVersion(), chunkVersion.majorVersion()); + ASSERT_EQ(request.getNSVersion().minorVersion(), chunkVersion.minorVersion()); + ASSERT_EQ(request.getNSVersion().epoch(), chunkVersion.epoch()); +} + +TEST(SetShardVersionRequest, ParseInitNoConfigServer) { + auto ssvStatus = + SetShardVersionRequest::parseFromBSON(BSON("setShardVersion" + << "" + << "init" << true << "shard" + << "TestShard" + << "shardHost" << shardCS.toString())); + + ASSERT_EQ(ErrorCodes::NoSuchKey, ssvStatus.getStatus().code()); +} + +TEST(SetShardVersionRequest, ParseFullNoNS) { + const ChunkVersion chunkVersion(1, 2, OID::gen()); + + auto ssvStatus = + SetShardVersionRequest::parseFromBSON(BSON("setShardVersion" + << "" + << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString() << "version" + << Timestamp(chunkVersion.toLong()) + << "versionEpoch" << chunkVersion.epoch())); + + ASSERT_EQ(ErrorCodes::InvalidNamespace, ssvStatus.getStatus().code()); +} + +TEST(SetShardVersionRequest, ParseFullNSContainsDBOnly) { + const ChunkVersion chunkVersion(1, 2, OID::gen()); + + auto ssvStatus = + SetShardVersionRequest::parseFromBSON(BSON("setShardVersion" + << "dbOnly" + << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString() << "version" + << Timestamp(chunkVersion.toLong()) + << "versionEpoch" << chunkVersion.epoch())); + + ASSERT_EQ(ErrorCodes::InvalidNamespace, ssvStatus.getStatus().code()); +} + +TEST(SetShardVersionRequest, ToSSVCommandInit) { + SetShardVersionRequest ssv = + SetShardVersionRequest::makeForInit(configCS, "TestShard", shardCS); + + ASSERT(ssv.isInit()); + ASSERT_EQ(ssv.getConfigServer().toString(), configCS.toString()); + ASSERT_EQ(ssv.getShardName(), "TestShard"); + ASSERT_EQ(ssv.getShardConnectionString().toString(), shardCS.toString()); + + ASSERT_EQ(ssv.toBSON(), + BSON("setShardVersion" + << "" + << "init" << true << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString())); +} + +TEST(SetShardVersionRequest, ToSSVCommandFull) { + const ChunkVersion chunkVersion(1, 2, OID::gen()); + + SetShardVersionRequest ssv = SetShardVersionRequest::makeForVersioning( + configCS, "TestShard", shardCS, NamespaceString("db.coll"), chunkVersion, false); + + ASSERT(!ssv.isInit()); + ASSERT(!ssv.isAuthoritative()); + ASSERT_EQ(ssv.getConfigServer().toString(), configCS.toString()); + ASSERT_EQ(ssv.getShardName(), "TestShard"); + ASSERT_EQ(ssv.getShardConnectionString().toString(), shardCS.toString()); + ASSERT_EQ(ssv.getNS().ns(), "db.coll"); + ASSERT_EQ(ssv.getNSVersion().toBSONWithPrefix("version"), + chunkVersion.toBSONWithPrefix("version")); + + ASSERT_EQ(ssv.toBSON(), + BSON("setShardVersion" + << "db.coll" + << "init" << false << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString() << "version" + << Timestamp(chunkVersion.toLong()) << "versionEpoch" << chunkVersion.epoch() + << "authoritative" << false)); +} + +TEST(SetShardVersionRequest, ToSSVCommandFullAuthoritative) { + const ChunkVersion chunkVersion(1, 2, OID::gen()); + + SetShardVersionRequest ssv = SetShardVersionRequest::makeForVersioning( + configCS, "TestShard", shardCS, NamespaceString("db.coll"), chunkVersion, true); + + ASSERT(!ssv.isInit()); + ASSERT(ssv.isAuthoritative()); + ASSERT_EQ(ssv.getConfigServer().toString(), configCS.toString()); + ASSERT_EQ(ssv.getShardName(), "TestShard"); + ASSERT_EQ(ssv.getShardConnectionString().toString(), shardCS.toString()); + ASSERT_EQ(ssv.getNS().ns(), "db.coll"); + ASSERT_EQ(ssv.getNSVersion().toBSONWithPrefix("version"), + chunkVersion.toBSONWithPrefix("version")); + + ASSERT_EQ(ssv.toBSON(), + BSON("setShardVersion" + << "db.coll" + << "init" << false << "configdb" << configCS.toString() << "shard" + << "TestShard" + << "shardHost" << shardCS.toString() << "version" + << Timestamp(chunkVersion.toLong()) << "versionEpoch" << chunkVersion.epoch() + << "authoritative" << true)); +} + +} // namespace +} // namespace mongo |