summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/s/SConscript22
-rw-r--r--src/mongo/s/catalog/replset/catalog_manager_replica_set.cpp30
-rw-r--r--src/mongo/s/catalog/replset/catalog_manager_replica_set_shard_collection_test.cpp41
-rw-r--r--src/mongo/s/set_shard_version_request.cpp214
-rw-r--r--src/mongo/s/set_shard_version_request.h147
-rw-r--r--src/mongo/s/set_shard_version_request_test.cpp219
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