/** * Copyright (C) 2017 10gen 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/catalog/type_shard_collection.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/s/catalog/type_collection.h" #include "mongo/util/assert_util.h" namespace mongo { const NamespaceString ShardCollectionType::ConfigNS( NamespaceString::kShardConfigCollectionsCollectionName); const BSONField ShardCollectionType::ns("_id"); const BSONField ShardCollectionType::uuid("uuid"); const BSONField ShardCollectionType::epoch("epoch"); const BSONField ShardCollectionType::keyPattern("key"); const BSONField ShardCollectionType::defaultCollation("defaultCollation"); const BSONField ShardCollectionType::unique("unique"); const BSONField ShardCollectionType::refreshing("refreshing"); const BSONField ShardCollectionType::lastRefreshedCollectionVersion( "lastRefreshedCollectionVersion"); const BSONField ShardCollectionType::enterCriticalSectionCounter( "enterCriticalSectionCounter"); ShardCollectionType::ShardCollectionType(NamespaceString nss, boost::optional uuid, OID epoch, const KeyPattern& keyPattern, const BSONObj& defaultCollation, bool unique) : _nss(std::move(nss)), _uuid(uuid), _epoch(std::move(epoch)), _keyPattern(keyPattern.toBSON()), _defaultCollation(defaultCollation.getOwned()), _unique(unique) {} StatusWith ShardCollectionType::fromBSON(const BSONObj& source) { NamespaceString nss; { std::string ns; Status status = bsonExtractStringField(source, ShardCollectionType::ns.name(), &ns); if (!status.isOK()) { return status; } nss = NamespaceString{ns}; } boost::optional uuid; { BSONElement uuidElem; Status status = bsonExtractTypedField( source, ShardCollectionType::uuid.name(), BSONType::BinData, &uuidElem); if (status.isOK()) { auto uuidWith = UUID::parse(uuidElem); if (!uuidWith.isOK()) return uuidWith.getStatus(); uuid = uuidWith.getValue(); } else if (status == ErrorCodes::NoSuchKey) { // The field is not set, which is okay. } else { return status; } } OID epoch; { BSONElement oidElem; Status status = bsonExtractTypedField( source, ShardCollectionType::epoch.name(), BSONType::jstOID, &oidElem); if (!status.isOK()) return status; epoch = oidElem.OID(); } BSONElement collKeyPattern; Status status = bsonExtractTypedField( source, ShardCollectionType::keyPattern.name(), Object, &collKeyPattern); if (!status.isOK()) { return status; } BSONObj obj = collKeyPattern.Obj(); if (obj.isEmpty()) { return Status(ErrorCodes::ShardKeyNotFound, str::stream() << "Empty shard key. Failed to parse: " << source.toString()); } KeyPattern pattern(obj.getOwned()); BSONObj collation; { BSONElement defaultCollation; Status status = bsonExtractTypedField( source, ShardCollectionType::defaultCollation.name(), Object, &defaultCollation); if (status.isOK()) { BSONObj obj = defaultCollation.Obj(); if (obj.isEmpty()) { return Status(ErrorCodes::BadValue, "empty defaultCollation"); } collation = obj.getOwned(); } else if (status != ErrorCodes::NoSuchKey) { return status; } } bool unique; { Status status = bsonExtractBooleanField(source, ShardCollectionType::unique.name(), &unique); if (!status.isOK()) { return status; } } ShardCollectionType shardCollectionType( std::move(nss), uuid, std::move(epoch), pattern, collation, unique); // Below are optional fields. { bool refreshing; Status status = bsonExtractBooleanField(source, ShardCollectionType::refreshing.name(), &refreshing); if (status.isOK()) { shardCollectionType.setRefreshing(refreshing); } else if (status == ErrorCodes::NoSuchKey) { // The field is not set yet, which is okay. } else { return status; } } { if (!source[lastRefreshedCollectionVersion.name()].eoo()) { auto statusWithLastRefreshedCollectionVersion = ChunkVersion::parseFromBSONWithFieldAndSetEpoch( source, lastRefreshedCollectionVersion.name(), epoch); if (!statusWithLastRefreshedCollectionVersion.isOK()) { return statusWithLastRefreshedCollectionVersion.getStatus(); } shardCollectionType.setLastRefreshedCollectionVersion( std::move(statusWithLastRefreshedCollectionVersion.getValue())); } } return shardCollectionType; } BSONObj ShardCollectionType::toBSON() const { BSONObjBuilder builder; builder.append(ns.name(), _nss.ns()); if (_uuid) { _uuid->appendToBuilder(&builder, uuid.name()); } builder.append(epoch.name(), _epoch); builder.append(keyPattern.name(), _keyPattern.toBSON()); if (!_defaultCollation.isEmpty()) { builder.append(defaultCollation.name(), _defaultCollation); } builder.append(unique.name(), _unique); if (_refreshing) { builder.append(refreshing.name(), _refreshing.get()); } if (_lastRefreshedCollectionVersion) { builder.appendTimestamp(lastRefreshedCollectionVersion.name(), _lastRefreshedCollectionVersion->toLong()); } return builder.obj(); } std::string ShardCollectionType::toString() const { return toBSON().toString(); } void ShardCollectionType::setUUID(UUID uuid) { _uuid = uuid; } void ShardCollectionType::setNss(NamespaceString nss) { invariant(nss.isValid()); _nss = std::move(nss); } void ShardCollectionType::setEpoch(OID epoch) { invariant(epoch.isSet()); _epoch = std::move(epoch); } void ShardCollectionType::setKeyPattern(const KeyPattern& keyPattern) { invariant(!keyPattern.toBSON().isEmpty()); _keyPattern = keyPattern; } bool ShardCollectionType::getRefreshing() const { invariant(_refreshing); return _refreshing.get(); } const ChunkVersion& ShardCollectionType::getLastRefreshedCollectionVersion() const { invariant(_lastRefreshedCollectionVersion); return _lastRefreshedCollectionVersion.get(); } } // namespace mongo