/**
* 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 .
*
* 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/db/query/query_request.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 kNoConnectionVersioning[] = "noConnectionVersioning";
} // namespace
SetShardVersionRequest::SetShardVersionRequest(ConnectionString configServer,
ShardId shardName,
ConnectionString shardConnectionString)
: _init(true),
_isAuthoritative(true),
_configServer(std::move(configServer)),
_shardName(std::move(shardName)),
_shardCS(std::move(shardConnectionString)) {}
SetShardVersionRequest::SetShardVersionRequest(ConnectionString configServer,
ShardId shardName,
ConnectionString shardConnectionString,
NamespaceString nss,
ChunkVersion version,
bool isAuthoritative)
: _init(false),
_isAuthoritative(isAuthoritative),
_configServer(std::move(configServer)),
_shardName(std::move(shardName)),
_shardCS(std::move(shardConnectionString)),
_nss(std::move(nss)),
_version(std::move(version)) {}
SetShardVersionRequest::SetShardVersionRequest() = default;
SetShardVersionRequest SetShardVersionRequest::makeForInit(
const ConnectionString& configServer,
const ShardId& shardName,
const ConnectionString& shardConnectionString) {
return SetShardVersionRequest(configServer, shardName, shardConnectionString);
}
SetShardVersionRequest SetShardVersionRequest::makeForInitNoPersist(
const ConnectionString& configServer,
const ShardId& shardName,
const ConnectionString& shardConnectionString) {
auto ssv = SetShardVersionRequest(configServer, shardName, shardConnectionString);
ssv._noConnectionVersioning = true;
return ssv;
}
SetShardVersionRequest SetShardVersionRequest::makeForVersioning(
const ConnectionString& configServer,
const ShardId& shardName,
const ConnectionString& shardConnectionString,
const NamespaceString& nss,
const ChunkVersion& nssVersion,
bool isAuthoritative) {
invariant(nss.isValid());
return SetShardVersionRequest(
configServer, shardName, shardConnectionString, nss, nssVersion, isAuthoritative);
}
SetShardVersionRequest SetShardVersionRequest::makeForVersioningNoPersist(
const ConnectionString& configServer,
const ShardId& shardName,
const ConnectionString& shard,
const NamespaceString& nss,
const ChunkVersion& nssVersion,
bool isAuthoritative) {
auto ssv = makeForVersioning(configServer, shardName, shard, nss, nssVersion, isAuthoritative);
ssv._noConnectionVersioning = true;
return ssv;
}
StatusWith 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());
}
{
std::string shardName;
Status status = bsonExtractStringField(cmdObj, kShardName, &shardName);
request._shardName = ShardId(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;
}
{
Status status = bsonExtractBooleanFieldWithDefault(
cmdObj, kAuthoritative, false, &request._isAuthoritative);
if (!status.isOK())
return status;
}
{
Status status = bsonExtractBooleanFieldWithDefault(
cmdObj, kNoConnectionVersioning, false, &request._noConnectionVersioning);
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);
}
{
auto versionStatus = ChunkVersion::parseFromBSONForSetShardVersion(cmdObj);
if (!versionStatus.isOK())
return versionStatus.getStatus();
request._version = versionStatus.getValue();
}
return request;
}
BSONObj SetShardVersionRequest::toBSON() const {
BSONObjBuilder cmdBuilder;
cmdBuilder.append(kCmdName, _init ? "" : _nss.get().ns());
cmdBuilder.append(kInit, _init);
cmdBuilder.append(kAuthoritative, _isAuthoritative);
cmdBuilder.append(kConfigServer, _configServer.toString());
cmdBuilder.append(kShardName, _shardName.toString());
cmdBuilder.append(kShardConnectionString, _shardCS.toString());
if (_init) {
// Always include a 30 second timeout on sharding state initialization, to work around
// SERVER-21458.
cmdBuilder.append(QueryRequest::cmdOptionMaxTimeMS, 30000);
} else {
_version.get().appendForSetShardVersion(&cmdBuilder);
}
if (_noConnectionVersioning) {
cmdBuilder.append(kNoConnectionVersioning, true);
}
return cmdBuilder.obj();
}
const NamespaceString& SetShardVersionRequest::getNS() const {
invariant(!_init);
return _nss.get();
}
const ChunkVersion SetShardVersionRequest::getNSVersion() const {
invariant(!_init);
return _version.get();
}
} // namespace mongo