Status Balancer::moveSingleChunk(OperationContext* txn, const ChunkType& chunk, const ShardId& newShardId, uint64_t maxChunkSizeBytes, const MigrationSecondaryThrottleOptions& secondaryThrottle, bool waitForDelete) { auto moveAllowedStatus = _chunkSelectionPolicy->checkMoveAllowed(txn, chunk, newShardId); if (!moveAllowedStatus.isOK()) { return moveAllowedStatus; } MigrationManager migrationManager; auto migrationStatuses = migrationManager.scheduleMigrations( txn, {MigrationManager::MigrationRequest(MigrateInfo(chunk.getNS(), newShardId, chunk), maxChunkSizeBytes, secondaryThrottle, waitForDelete)}); invariant(migrationStatuses.size() == 1); auto scopedCMStatus = ScopedChunkManager::getExisting(txn, NamespaceString(chunk.getNS())); if (!scopedCMStatus.isOK()) { return scopedCMStatus.getStatus(); } auto scopedCM = std::move(scopedCMStatus.getValue()); ChunkManager* const cm = scopedCM.cm(); cm->reload(txn); return migrationStatuses.begin()->second; }
StatusWith<boost::optional<MigrateInfo>> BalancerChunkSelectionPolicyImpl::selectSpecificChunkToMove(OperationContext* opCtx, const ChunkType& chunk) { auto shardStatsStatus = _clusterStats->getStats(opCtx); if (!shardStatsStatus.isOK()) { return shardStatsStatus.getStatus(); } const auto& shardStats = shardStatsStatus.getValue(); auto routingInfoStatus = Grid::get(opCtx)->catalogCache()->getShardedCollectionRoutingInfoWithRefresh(opCtx, chunk.getNS()); if (!routingInfoStatus.isOK()) { return routingInfoStatus.getStatus(); } const auto cm = routingInfoStatus.getValue().cm().get(); const auto collInfoStatus = createCollectionDistributionStatus(opCtx, shardStats, cm); if (!collInfoStatus.isOK()) { return collInfoStatus.getStatus(); } const DistributionStatus& distribution = collInfoStatus.getValue(); return BalancerPolicy::balanceSingleChunk(chunk, shardStats, distribution); }
StatusWith<boost::optional<MigrateInfo>> BalancerChunkSelectionPolicyImpl::selectSpecificChunkToMove(OperationContext* txn, const ChunkType& chunk) { auto shardStatsStatus = _clusterStats->getStats(txn); if (!shardStatsStatus.isOK()) { return shardStatsStatus.getStatus(); } const auto shardStats = std::move(shardStatsStatus.getValue()); const NamespaceString nss(chunk.getNS()); auto scopedCMStatus = ScopedChunkManager::getExisting(txn, nss); if (!scopedCMStatus.isOK()) { return scopedCMStatus.getStatus(); } auto scopedCM = std::move(scopedCMStatus.getValue()); ChunkManager* const cm = scopedCM.cm(); auto collInfoStatus = createCollectionDistributionInfo(txn, shardStats, cm); if (!collInfoStatus.isOK()) { return collInfoStatus.getStatus(); } auto collInfo = std::move(collInfoStatus.getValue()); return BalancerPolicy::balanceSingleChunk(chunk, shardStats, std::get<0>(collInfo)); }
StatusWith<boost::optional<MigrateInfo>> BalancerChunkSelectionPolicyImpl::selectSpecificChunkToMove(OperationContext* txn, const ChunkType& chunk) { const NamespaceString nss(chunk.getNS()); auto scopedCMStatus = ScopedChunkManager::getExisting(txn, nss); if (!scopedCMStatus.isOK()) { return scopedCMStatus.getStatus(); } auto scopedCM = std::move(scopedCMStatus.getValue()); ChunkManager* const cm = scopedCM.cm(); auto tagForChunkStatus = Grid::get(txn)->catalogManager(txn)->getTagForChunk(txn, nss.ns(), chunk); if (!tagForChunkStatus.isOK()) { return tagForChunkStatus.getStatus(); } auto shardStatsStatus = _clusterStats->getStats(txn); if (!shardStatsStatus.isOK()) { return shardStatsStatus.getStatus(); } auto collInfo = createCollectionDistributionInfo(shardStatsStatus.getValue(), cm); ShardToChunksMap shardToChunksMap = std::move(std::get<0>(collInfo)); DistributionStatus distStatus(shardStatsStatus.getValue(), shardToChunksMap); const ShardId newShardId(distStatus.getBestReceieverShard(tagForChunkStatus.getValue())); if (newShardId.empty() || newShardId == chunk.getShard()) { return boost::optional<MigrateInfo>(); } return boost::optional<MigrateInfo>{MigrateInfo(nss.ns(), newShardId, chunk)}; }
Status Balancer::moveSingleChunk(OperationContext* txn, const ChunkType& chunk, const ShardId& newShardId, uint64_t maxChunkSizeBytes, const MigrationSecondaryThrottleOptions& secondaryThrottle, bool waitForDelete) { auto moveAllowedStatus = _chunkSelectionPolicy->checkMoveAllowed(txn, chunk, newShardId); if (!moveAllowedStatus.isOK()) { return moveAllowedStatus; } return executeSingleMigration(txn, MigrateInfo(chunk.getNS(), newShardId, chunk), maxChunkSizeBytes, secondaryThrottle, waitForDelete); }
Chunk::Chunk(OperationContext* txn, ChunkManager* manager, const ChunkType& from) : _manager(manager), _lastmod(from.getVersion()), _dataWritten(mkDataWritten()) { string ns = from.getNS(); _shardId = from.getShard(); verify(_lastmod.isSet()); _min = from.getMin().getOwned(); _max = from.getMax().getOwned(); _jumbo = from.getJumbo(); uassert(10170, "Chunk needs a ns", !ns.empty()); uassert(13327, "Chunk ns must match server ns", ns == _manager->getns()); uassert(10172, "Chunk needs a min", !_min.isEmpty()); uassert(10173, "Chunk needs a max", !_max.isEmpty()); uassert(10171, "Chunk needs a server", grid.shardRegistry()->getShard(txn, _shardId)); }
Status BalancerChunkSelectionPolicyImpl::checkMoveAllowed(OperationContext* txn, const ChunkType& chunk, const ShardId& newShardId) { auto shardStatsStatus = _clusterStats->getStats(txn); if (!shardStatsStatus.isOK()) { return shardStatsStatus.getStatus(); } auto shardStats = std::move(shardStatsStatus.getValue()); const NamespaceString nss(chunk.getNS()); auto scopedCMStatus = ScopedChunkManager::getExisting(txn, nss); if (!scopedCMStatus.isOK()) { return scopedCMStatus.getStatus(); } auto scopedCM = std::move(scopedCMStatus.getValue()); ChunkManager* const cm = scopedCM.cm(); auto collInfoStatus = createCollectionDistributionInfo(txn, shardStats, cm); if (!collInfoStatus.isOK()) { return collInfoStatus.getStatus(); } auto collInfo = std::move(collInfoStatus.getValue()); DistributionStatus distribution = std::move(std::get<0>(collInfo)); auto newShardIterator = std::find_if(shardStats.begin(), shardStats.end(), [&newShardId](const ClusterStatistics::ShardStatistics& stat) { return stat.shardId == newShardId; }); if (newShardIterator == shardStats.end()) { return {ErrorCodes::ShardNotFound, str::stream() << "Unable to find constraints information for shard " << newShardId << ". Move to this shard will be disallowed."}; } return BalancerPolicy::isShardSuitableReceiver(*newShardIterator, distribution.getTagForChunk(chunk)); }
Status BalancerChunkSelectionPolicyImpl::checkMoveAllowed(OperationContext* opCtx, const ChunkType& chunk, const ShardId& newShardId) { auto shardStatsStatus = _clusterStats->getStats(opCtx); if (!shardStatsStatus.isOK()) { return shardStatsStatus.getStatus(); } auto shardStats = std::move(shardStatsStatus.getValue()); auto routingInfoStatus = Grid::get(opCtx)->catalogCache()->getShardedCollectionRoutingInfoWithRefresh(opCtx, chunk.getNS()); if (!routingInfoStatus.isOK()) { return routingInfoStatus.getStatus(); } const auto cm = routingInfoStatus.getValue().cm().get(); const auto collInfoStatus = createCollectionDistributionStatus(opCtx, shardStats, cm); if (!collInfoStatus.isOK()) { return collInfoStatus.getStatus(); } const DistributionStatus& distribution = collInfoStatus.getValue(); auto newShardIterator = std::find_if(shardStats.begin(), shardStats.end(), [&newShardId](const ClusterStatistics::ShardStatistics& stat) { return stat.shardId == newShardId; }); if (newShardIterator == shardStats.end()) { return {ErrorCodes::ShardNotFound, str::stream() << "Unable to find constraints information for shard " << newShardId << ". Move to this shard will be disallowed."}; } return BalancerPolicy::isShardSuitableReceiver(*newShardIterator, distribution.getTagForChunk(chunk)); }
Status Balancer::rebalanceSingleChunk(OperationContext* txn, const ChunkType& chunk) { auto migrateStatus = _chunkSelectionPolicy->selectSpecificChunkToMove(txn, chunk); if (!migrateStatus.isOK()) { return migrateStatus.getStatus(); } auto migrateInfo = std::move(migrateStatus.getValue()); if (!migrateInfo) { LOG(1) << "Unable to find more appropriate location for chunk " << redact(chunk.toString()); return Status::OK(); } auto balancerConfig = Grid::get(txn)->getBalancerConfiguration(); Status refreshStatus = balancerConfig->refreshAndCheck(txn); if (!refreshStatus.isOK()) { return refreshStatus; } MigrationManager migrationManager; auto migrationStatuses = migrationManager.scheduleMigrations( txn, {MigrationManager::MigrationRequest(std::move(*migrateInfo), balancerConfig->getMaxChunkSizeBytes(), balancerConfig->getSecondaryThrottle(), balancerConfig->waitForDelete())}); invariant(migrationStatuses.size() == 1); auto scopedCMStatus = ScopedChunkManager::getExisting(txn, NamespaceString(chunk.getNS())); if (!scopedCMStatus.isOK()) { return scopedCMStatus.getStatus(); } auto scopedCM = std::move(scopedCMStatus.getValue()); ChunkManager* const cm = scopedCM.cm(); cm->reload(txn); return migrationStatuses.begin()->second; }
BSONObj buildApplyOpsCmd( const OwnedPointerVector<ChunkType>& chunksToMerge, const ChunkVersion& currShardVersion, const ChunkVersion& newMergedVersion ) { BSONObjBuilder applyOpsCmdB; BSONArrayBuilder updatesB( applyOpsCmdB.subarrayStart( "applyOps" ) ); // The chunk we'll be "expanding" is the first chunk const ChunkType* chunkToMerge = *chunksToMerge.begin(); // Fill in details not tracked by metadata ChunkType mergedChunk; chunkToMerge->cloneTo( &mergedChunk ); mergedChunk.setName( Chunk::genID( chunkToMerge->getNS(), chunkToMerge->getMin() ) ); mergedChunk.setMax( ( *chunksToMerge.vector().rbegin() )->getMax() ); mergedChunk.setVersion( newMergedVersion ); updatesB.append( buildOpMergeChunk( mergedChunk ) ); // Don't remove chunk we're expanding OwnedPointerVector<ChunkType>::const_iterator it = chunksToMerge.begin(); for ( ++it; it != chunksToMerge.end(); ++it ) { ChunkType* chunkToMerge = *it; chunkToMerge->setName( Chunk::genID( chunkToMerge->getNS(), chunkToMerge->getMin() ) ); updatesB.append( buildOpRemoveChunk( *chunkToMerge ) ); } updatesB.done(); applyOpsCmdB.append( "preCondition", buildOpPrecond( chunkToMerge->getNS(), chunkToMerge->getShard(), currShardVersion ) ); return applyOpsCmdB.obj(); }