void DistributionStatus::populateShardToChunksMap(const ShardStatisticsVector& allShards, const ChunkManager& chunkMgr, ShardToChunksMap* shardToChunksMap) { // Makes sure there is an entry in shardToChunksMap for every shard. for (const auto& stat : allShards) { (*shardToChunksMap)[stat.shardId]; } const ChunkMap& chunkMap = chunkMgr.getChunkMap(); for (ChunkMap::const_iterator it = chunkMap.begin(); it != chunkMap.end(); ++it) { const ChunkPtr chunkPtr = it->second; ChunkType chunk; chunk.setNS(chunkMgr.getns()); chunk.setMin(chunkPtr->getMin().getOwned()); chunk.setMax(chunkPtr->getMax().getOwned()); chunk.setJumbo(chunkPtr->isJumbo()); // TODO: is this reliable? const string shardName(chunkPtr->getShardId()); chunk.setShard(shardName); (*shardToChunksMap)[shardName].push_back(chunk); } }
StatusWith<MigrateInfoVector> BalancerChunkSelectionPolicyImpl::_getMigrateCandidatesForCollection( OperationContext* txn, const NamespaceString& nss, const ShardStatisticsVector& shardStats, bool aggressiveBalanceHint) { // Ensure the database exists auto dbStatus = Grid::get(txn)->catalogCache()->getDatabase(txn, nss.db().toString()); if (!dbStatus.isOK()) { return {dbStatus.getStatus().code(), str::stream() << "Database " << nss.ns() << " was not found due to " << dbStatus.getStatus().toString()}; } shared_ptr<DBConfig> db = dbStatus.getValue(); invariant(db); // Ensure that the collection is sharded shared_ptr<ChunkManager> cm = db->getChunkManagerIfExists(txn, nss.ns(), true); if (!cm) { return {ErrorCodes::NamespaceNotSharded, str::stream() << "Collection " << nss.ns() << " does not exist or is not sharded."}; } if (cm->getChunkMap().empty()) { return {ErrorCodes::NamespaceNotSharded, str::stream() << "Collection " << nss.ns() << " does not have any chunks."}; } ShardToChunksMap shardToChunksMap; std::set<BSONObj> allChunkMinimums; for (const auto& entry : cm->getChunkMap()) { const auto& chunkEntry = entry.second; ChunkType chunk; chunk.setMin(chunkEntry->getMin()); chunk.setMax(chunkEntry->getMax()); chunk.setJumbo(chunkEntry->isJumbo()); shardToChunksMap[chunkEntry->getShardId()].push_back(chunk); allChunkMinimums.insert(chunkEntry->getMin()); } for (const auto& stat : shardStats) { // This loop just makes sure there is an entry in shardToChunksMap for every shard, which we // plan to consider. shardToChunksMap[stat.shardId]; } DistributionStatus distStatus(shardStats, shardToChunksMap); { vector<TagsType> collectionTags; Status status = grid.catalogManager(txn)->getTagsForCollection(txn, nss.ns(), &collectionTags); if (!status.isOK()) { return status; } for (const auto& tagInfo : collectionTags) { BSONObj min = cm->getShardKeyPattern().getKeyPattern().extendRangeBound( tagInfo.getMinKey(), false); if (!allChunkMinimums.count(min)) { // This tag falls somewhere at the middle of a chunk. Therefore we must skip // balancing this collection until it is split at the next iteration. // // TODO: We should be able to just skip chunks, which straddle tags and still make // some progress balancing. return {ErrorCodes::IllegalOperation, str::stream() << "Tag boundaries " << tagInfo.toString() << " fall in the middle of an existing chunk. Balancing for collection " << nss.ns() << " will be postponed until the chunk is split appropriately."}; } // TODO: TagRange contains all the information from TagsType except for the namespace, // so maybe the two can be merged at some point in order to avoid the transformation // below. if (!distStatus.addTagRange(TagRange(tagInfo.getMinKey().getOwned(), tagInfo.getMaxKey().getOwned(), tagInfo.getTag()))) { return {ErrorCodes::BadValue, str::stream() << "Tag ranges are not valid for collection " << nss.ns() << ". Balancing for this collection will be skipped until " "the ranges are fixed."}; } } } unique_ptr<MigrateInfo> migrateInfo( BalancerPolicy::balance(nss.ns(), distStatus, aggressiveBalanceHint)); if (migrateInfo) { return MigrateInfoVector{*migrateInfo}; } return MigrateInfoVector{}; }