Status CatalogManagerReplicaSet::getAllShards(OperationContext* txn, vector<ShardType>* shards) { auto findStatus = _exhaustiveFindOnConfig(txn, NamespaceString(ShardType::ConfigNS), BSONObj(), // no query filter BSONObj(), // no sort boost::none); // no limit if (!findStatus.isOK()) { return findStatus.getStatus(); } for (const BSONObj& doc : findStatus.getValue().value) { auto shardRes = ShardType::fromBSON(doc); if (!shardRes.isOK()) { shards->clear(); return {ErrorCodes::FailedToParse, stream() << "Failed to parse shard with id (" << doc[ShardType::name()].toString() << "): " << shardRes.getStatus().toString()}; } shards->push_back(shardRes.getValue()); } return Status::OK(); }
Status CatalogManagerReplicaSet::getTagsForCollection(OperationContext* txn, const std::string& collectionNs, std::vector<TagsType>* tags) { tags->clear(); auto findStatus = _exhaustiveFindOnConfig(txn, NamespaceString(TagsType::ConfigNS), BSON(TagsType::ns(collectionNs)), BSON(TagsType::min() << 1), boost::none); // no limit if (!findStatus.isOK()) { return findStatus.getStatus(); } for (const BSONObj& obj : findStatus.getValue().value) { auto tagRes = TagsType::fromBSON(obj); if (!tagRes.isOK()) { tags->clear(); return Status(ErrorCodes::FailedToParse, str::stream() << "Failed to parse tag: " << tagRes.getStatus().toString()); } tags->push_back(tagRes.getValue()); } return Status::OK(); }
StatusWith<string> CatalogManagerReplicaSet::getTagForChunk(OperationContext* txn, const std::string& collectionNs, const ChunkType& chunk) { BSONObj query = BSON(TagsType::ns(collectionNs) << TagsType::min() << BSON("$lte" << chunk.getMin()) << TagsType::max() << BSON("$gte" << chunk.getMax())); auto findStatus = _exhaustiveFindOnConfig(txn, NamespaceString(TagsType::ConfigNS), query, BSONObj(), 1); if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto& docs = findStatus.getValue().value; if (docs.empty()) { return string{}; } invariant(docs.size() == 1); BSONObj tagsDoc = docs.front(); const auto tagsResult = TagsType::fromBSON(tagsDoc); if (!tagsResult.isOK()) { return {ErrorCodes::FailedToParse, stream() << "error while parsing " << TagsType::ConfigNS << " document: " << tagsDoc << " : " << tagsResult.getStatus().toString()}; } return tagsResult.getValue().getTag(); }
StatusWith<SettingsType> CatalogManagerReplicaSet::getGlobalSettings(OperationContext* txn, const string& key) { auto findStatus = _exhaustiveFindOnConfig( txn, NamespaceString(SettingsType::ConfigNS), BSON(SettingsType::key(key)), BSONObj(), 1); if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto& docs = findStatus.getValue().value; if (docs.empty()) { return {ErrorCodes::NoMatchingDocument, str::stream() << "can't find settings document with key: " << key}; } BSONObj settingsDoc = docs.front(); StatusWith<SettingsType> settingsResult = SettingsType::fromBSON(settingsDoc); if (!settingsResult.isOK()) { return {ErrorCodes::FailedToParse, str::stream() << "error while parsing settings document: " << settingsDoc << " : " << settingsResult.getStatus().toString()}; } const SettingsType& settings = settingsResult.getValue(); Status validationStatus = settings.validate(); if (!validationStatus.isOK()) { return validationStatus; } return settingsResult; }
Status CatalogManagerReplicaSet::getDatabasesForShard(OperationContext* txn, const string& shardName, vector<string>* dbs) { auto findStatus = _exhaustiveFindOnConfig(txn, NamespaceString(DatabaseType::ConfigNS), BSON(DatabaseType::primary(shardName)), BSONObj(), boost::none); // no limit if (!findStatus.isOK()) { return findStatus.getStatus(); } for (const BSONObj& obj : findStatus.getValue().value) { string dbName; Status status = bsonExtractStringField(obj, DatabaseType::name(), &dbName); if (!status.isOK()) { dbs->clear(); return status; } dbs->push_back(dbName); } return Status::OK(); }
StatusWith<OpTimePair<CollectionType>> CatalogManagerReplicaSet::getCollection( OperationContext* txn, const std::string& collNs) { auto configShard = grid.shardRegistry()->getShard(txn, "config"); auto statusFind = _exhaustiveFindOnConfig(txn, NamespaceString(CollectionType::ConfigNS), BSON(CollectionType::fullNs(collNs)), BSONObj(), 1); if (!statusFind.isOK()) { return statusFind.getStatus(); } const auto& retOpTimePair = statusFind.getValue(); const auto& retVal = retOpTimePair.value; if (retVal.empty()) { return Status(ErrorCodes::NamespaceNotFound, stream() << "collection " << collNs << " not found"); } invariant(retVal.size() == 1); auto parseStatus = CollectionType::fromBSON(retVal.front()); if (!parseStatus.isOK()) { return parseStatus.getStatus(); } return OpTimePair<CollectionType>(parseStatus.getValue(), retOpTimePair.opTime); }
StatusWith<VersionType> CatalogManagerReplicaSet::_getConfigVersion(OperationContext* txn) { const auto configShard = grid.shardRegistry()->getShard(txn, "config"); const auto readHostStatus = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHostStatus.isOK()) { return readHostStatus.getStatus(); } auto readHost = readHostStatus.getValue(); auto findStatus = _exhaustiveFindOnConfig(readHost, NamespaceString(VersionType::ConfigNS), BSONObj(), BSONObj(), boost::none /* no limit */); if (!findStatus.isOK()) { return findStatus.getStatus(); } auto queryResults = findStatus.getValue().value; if (queryResults.size() > 1) { return {ErrorCodes::RemoteValidationError, str::stream() << "should only have 1 document in " << VersionType::ConfigNS}; } if (queryResults.empty()) { auto countStatus = _runCountCommandOnConfig(readHost, NamespaceString(ShardType::ConfigNS), BSONObj()); if (!countStatus.isOK()) { return countStatus.getStatus(); } const auto& shardCount = countStatus.getValue(); if (shardCount > 0) { // Version document doesn't exist, but config.shards is not empty. Assuming that // the current config metadata is pre v2.4. VersionType versionInfo; versionInfo.setMinCompatibleVersion(UpgradeHistory_UnreportedVersion); versionInfo.setCurrentVersion(UpgradeHistory_UnreportedVersion); return versionInfo; } VersionType versionInfo; versionInfo.setMinCompatibleVersion(UpgradeHistory_EmptyVersion); versionInfo.setCurrentVersion(UpgradeHistory_EmptyVersion); return versionInfo; } BSONObj versionDoc = queryResults.front(); auto versionTypeResult = VersionType::fromBSON(versionDoc); if (!versionTypeResult.isOK()) { return Status(ErrorCodes::UnsupportedFormat, str::stream() << "invalid config version document: " << versionDoc << versionTypeResult.getStatus().toString()); } return versionTypeResult.getValue(); }
Status CatalogManagerReplicaSet::_checkDbDoesNotExist(OperationContext* txn, const string& dbName, DatabaseType* db) { BSONObjBuilder queryBuilder; queryBuilder.appendRegex( DatabaseType::name(), (string) "^" + pcrecpp::RE::QuoteMeta(dbName) + "$", "i"); const auto configShard = grid.shardRegistry()->getShard(txn, "config"); const auto readHost = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHost.isOK()) { return readHost.getStatus(); } auto findStatus = _exhaustiveFindOnConfig(readHost.getValue(), NamespaceString(DatabaseType::ConfigNS), queryBuilder.obj(), BSONObj(), 1); if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto& docs = findStatus.getValue().value; if (docs.empty()) { return Status::OK(); } BSONObj dbObj = docs.front(); std::string actualDbName = dbObj[DatabaseType::name()].String(); if (actualDbName == dbName) { if (db) { auto parseDBStatus = DatabaseType::fromBSON(dbObj); if (!parseDBStatus.isOK()) { return parseDBStatus.getStatus(); } *db = parseDBStatus.getValue(); } return Status(ErrorCodes::NamespaceExists, str::stream() << "database " << dbName << " already exists"); } return Status(ErrorCodes::DatabaseDifferCase, str::stream() << "can't have 2 databases that just differ on case " << " have: " << actualDbName << " want to add: " << dbName); }
Status CatalogManagerReplicaSet::getCollections(OperationContext* txn, const std::string* dbName, std::vector<CollectionType>* collections, OpTime* opTime) { BSONObjBuilder b; if (dbName) { invariant(!dbName->empty()); b.appendRegex(CollectionType::fullNs(), string(str::stream() << "^" << pcrecpp::RE::QuoteMeta(*dbName) << "\\.")); } auto configShard = grid.shardRegistry()->getShard(txn, "config"); auto readHost = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHost.isOK()) { return readHost.getStatus(); } auto findStatus = _exhaustiveFindOnConfig(readHost.getValue(), NamespaceString(CollectionType::ConfigNS), b.obj(), BSONObj(), boost::none); // no limit if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto& docsOpTimePair = findStatus.getValue(); for (const BSONObj& obj : docsOpTimePair.value) { const auto collectionResult = CollectionType::fromBSON(obj); if (!collectionResult.isOK()) { collections->clear(); return {ErrorCodes::FailedToParse, str::stream() << "error while parsing " << CollectionType::ConfigNS << " document: " << obj << " : " << collectionResult.getStatus().toString()}; } collections->push_back(collectionResult.getValue()); } if (opTime) { *opTime = docsOpTimePair.opTime; } return Status::OK(); }
StatusWith<OpTimePair<DatabaseType>> CatalogManagerReplicaSet::getDatabase( OperationContext* txn, const std::string& dbName) { invariant(nsIsDbOnly(dbName)); // The two databases that are hosted on the config server are config and admin if (dbName == "config" || dbName == "admin") { DatabaseType dbt; dbt.setName(dbName); dbt.setSharded(false); dbt.setPrimary("config"); return OpTimePair<DatabaseType>(dbt); } const auto configShard = grid.shardRegistry()->getShard(txn, "config"); const auto readHost = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHost.isOK()) { return readHost.getStatus(); } auto findStatus = _exhaustiveFindOnConfig(readHost.getValue(), NamespaceString(DatabaseType::ConfigNS), BSON(DatabaseType::name(dbName)), BSONObj(), 1); if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto& docsWithOpTime = findStatus.getValue(); if (docsWithOpTime.value.empty()) { return {ErrorCodes::DatabaseNotFound, stream() << "database " << dbName << " not found"}; } invariant(docsWithOpTime.value.size() == 1); auto parseStatus = DatabaseType::fromBSON(docsWithOpTime.value.front()); if (!parseStatus.isOK()) { return parseStatus.getStatus(); } return OpTimePair<DatabaseType>(parseStatus.getValue(), docsWithOpTime.opTime); }
Status CatalogManagerReplicaSet::getChunks(OperationContext* txn, const BSONObj& query, const BSONObj& sort, boost::optional<int> limit, vector<ChunkType>* chunks, OpTime* opTime) { chunks->clear(); auto configShard = grid.shardRegistry()->getShard(txn, "config"); auto readHostStatus = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHostStatus.isOK()) { return readHostStatus.getStatus(); } // Convert boost::optional<int> to boost::optional<long long>. auto longLimit = limit ? boost::optional<long long>(*limit) : boost::none; auto findStatus = _exhaustiveFindOnConfig( readHostStatus.getValue(), NamespaceString(ChunkType::ConfigNS), query, sort, longLimit); if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto chunkDocsOpTimePair = findStatus.getValue(); for (const BSONObj& obj : chunkDocsOpTimePair.value) { auto chunkRes = ChunkType::fromBSON(obj); if (!chunkRes.isOK()) { chunks->clear(); return {ErrorCodes::FailedToParse, stream() << "Failed to parse chunk with id (" << obj[ChunkType::name()].toString() << "): " << chunkRes.getStatus().toString()}; } chunks->push_back(chunkRes.getValue()); } if (opTime) { *opTime = chunkDocsOpTimePair.opTime; } return Status::OK(); }
StatusWith<std::string> CatalogManagerReplicaSet::_generateNewShardName(OperationContext* txn) { const auto configShard = grid.shardRegistry()->getShard(txn, "config"); const auto readHost = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHost.isOK()) { return readHost.getStatus(); } BSONObjBuilder shardNameRegex; shardNameRegex.appendRegex(ShardType::name(), "^shard"); auto findStatus = _exhaustiveFindOnConfig(readHost.getValue(), NamespaceString(ShardType::ConfigNS), shardNameRegex.obj(), BSON(ShardType::name() << -1), 1); if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto& docs = findStatus.getValue().value; int count = 0; if (!docs.empty()) { const auto shardStatus = ShardType::fromBSON(docs.front()); if (!shardStatus.isOK()) { return shardStatus.getStatus(); } std::istringstream is(shardStatus.getValue().getName().substr(5)); is >> count; count++; } // TODO fix so that we can have more than 10000 automatically generated shard names if (count < 9999) { std::stringstream ss; ss << "shard" << std::setfill('0') << std::setw(4) << count; return ss.str(); } return Status(ErrorCodes::OperationFailed, "unable to generate new shard name"); }