StatusWith<string> CatalogManagerReplicaSet::getTagForChunk(OperationContext* txn, const std::string& collectionNs, const ChunkType& chunk) { auto configShard = grid.shardRegistry()->getShard(txn, "config"); auto readHostStatus = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHostStatus.isOK()) { return readHostStatus.getStatus(); } BSONObj query = BSON(TagsType::ns(collectionNs) << TagsType::min() << BSON("$lte" << chunk.getMin()) << TagsType::max() << BSON("$gte" << chunk.getMax())); auto findStatus = _exhaustiveFindOnConfig( readHostStatus.getValue(), 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<string> DistributionStatus::getTagForSingleChunk(const string& configServer, const string& ns, const ChunkType& chunk) { BSONObj tagRangeDoc; try { ScopedDbConnection conn(configServer, 30); Query query(QUERY(TagsType::ns(ns) << TagsType::min() << BSON("$lte" << chunk.getMin()) << TagsType::max() << BSON("$gte" << chunk.getMax()))); tagRangeDoc = conn->findOne(TagsType::ConfigNS, query); conn.done(); } catch (const DBException& excep) { return StatusWith<string>(excep.toStatus()); } if (tagRangeDoc.isEmpty()) { return StatusWith<string>(""); } TagsType tagRange; string errMsg; if (!tagRange.parseBSON(tagRangeDoc, &errMsg)) { return StatusWith<string>(ErrorCodes::FailedToParse, errMsg); } return StatusWith<string>(tagRange.getTag()); }
void MetadataManager::beginReceive(const ChunkRange& range) { stdx::lock_guard<stdx::mutex> scopedLock(_managerLock); // Collection is not known to be sharded if the active metadata tracker is null invariant(_activeMetadataTracker); // If range is contained within pending chunks, this means a previous migration must have failed // and we need to clean all overlaps RangeVector overlappedChunks; getRangeMapOverlap(_receivingChunks, range.getMin(), range.getMax(), &overlappedChunks); for (const auto& overlapChunkMin : overlappedChunks) { auto itRecv = _receivingChunks.find(overlapChunkMin.first); invariant(itRecv != _receivingChunks.end()); const ChunkRange receivingRange(itRecv->first, itRecv->second); _receivingChunks.erase(itRecv); // Make sure any potentially partially copied chunks are scheduled to be cleaned up _addRangeToClean_inlock(receivingRange); } // Need to ensure that the background range deleter task won't delete the range we are about to // receive _removeRangeToClean_inlock(range, Status::OK()); _receivingChunks.insert(std::make_pair(range.getMin().getOwned(), range.getMax().getOwned())); // For compatibility with the current range deleter, update the pending chunks on the collection // metadata to include the chunk being received ChunkType chunk; chunk.setMin(range.getMin()); chunk.setMax(range.getMax()); _setActiveMetadata_inlock(_activeMetadataTracker->metadata->clonePlusPending(chunk)); }
void ShardingState::donateChunk(OperationContext* txn, const string& ns, const BSONObj& min, const BSONObj& max, ChunkVersion version) { invariant(txn->lockState()->isCollectionLockedForMode(ns, MODE_X)); stdx::lock_guard<stdx::mutex> lk(_mutex); CollectionMetadataMap::const_iterator it = _collMetadata.find(ns); verify(it != _collMetadata.end()); shared_ptr<CollectionMetadata> p = it->second; // empty shards should have version 0 version = (p->getNumChunks() > 1) ? version : ChunkVersion(0, 0, p->getCollVersion().epoch()); ChunkType chunk; chunk.setMin(min); chunk.setMax(max); string errMsg; shared_ptr<CollectionMetadata> cloned(p->cloneMigrate(chunk, version, &errMsg)); // uassert to match old behavior, TODO: report errors w/o throwing uassert(16855, errMsg, NULL != cloned.get()); // TODO: a bit dangerous to have two different zero-version states - no-metadata and // no-version _collMetadata[ns] = cloned; }
BSONObj BalanceChunkRequest::serializeToRebalanceCommandForConfig(const ChunkType& chunk) { invariantOK(chunk.validate()); BSONObjBuilder cmdBuilder; cmdBuilder.append(kConfigSvrMoveChunk, 1); cmdBuilder.appendElements(chunk.toBSON()); return cmdBuilder.obj(); }
void QueueDispatcher<ChunkType>::receive ( ChunkType ret ) { queue.push_front( ret.getChunks() ); if ( ! ret.isAsync() ) { haveEndOfInput = true; } if ( !isActive ) { // schedule self with IO service io.post(bind(&QueueDispatcher::senderLoop, this)); } }
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)); }
BSONObj buildOpMergeChunk(const ChunkType& mergedChunk) { BSONObjBuilder opB; // Op basics opB.append("op", "u"); opB.appendBool("b", false); // no upserting opB.append("ns", ChunkType::ConfigNS); // New object opB.append("o", mergedChunk.toBSON()); // Query object opB.append("o2", BSON(ChunkType::name(mergedChunk.getName()))); return opB.obj(); }
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); }
std::unique_ptr<CollectionMetadata> CollectionMetadata::cloneMinusPending( const ChunkType& chunk) const { invariant(rangeMapContains(_pendingMap, chunk.getMin(), chunk.getMax())); unique_ptr<CollectionMetadata> metadata(stdx::make_unique<CollectionMetadata>()); metadata->_keyPattern = _keyPattern.getOwned(); metadata->fillKeyPatternFields(); metadata->_pendingMap = _pendingMap; metadata->_pendingMap.erase(chunk.getMin()); metadata->_chunksMap = _chunksMap; metadata->_rangesMap = _rangesMap; metadata->_shardVersion = _shardVersion; metadata->_collVersion = _collVersion; invariant(metadata->isValid()); return metadata; }
bool ShardingState::notePending(OperationContext* txn, const string& ns, const BSONObj& min, const BSONObj& max, const OID& epoch, string* errMsg) { invariant(txn->lockState()->isCollectionLockedForMode(ns, MODE_X)); stdx::lock_guard<stdx::mutex> lk(_mutex); CollectionMetadataMap::const_iterator it = _collMetadata.find(ns); if (it == _collMetadata.end()) { *errMsg = str::stream() << "could not note chunk " << "[" << min << "," << max << ")" << " as pending because the local metadata for " << ns << " has changed"; return false; } shared_ptr<CollectionMetadata> metadata = it->second; // This can currently happen because drops aren't synchronized with in-migrations // The idea for checking this here is that in the future we shouldn't have this problem if (metadata->getCollVersion().epoch() != epoch) { *errMsg = str::stream() << "could not note chunk " << "[" << min << "," << max << ")" << " as pending because the epoch for " << ns << " has changed from " << epoch << " to " << metadata->getCollVersion().epoch(); return false; } ChunkType chunk; chunk.setMin(min); chunk.setMax(max); shared_ptr<CollectionMetadata> cloned(metadata->clonePlusPending(chunk, errMsg)); if (!cloned) return false; _collMetadata[ns] = cloned; return true; }
BSONObj buildOpRemoveChunk(const ChunkType& chunkToRemove) { BSONObjBuilder opB; // Op basics opB.append("op", "d"); // delete opB.append("ns", ChunkType::ConfigNS); opB.append("o", BSON(ChunkType::name(chunkToRemove.getName()))); return opB.obj(); }
bool ShardingState::forgetPending( const string& ns, const BSONObj& min, const BSONObj& max, const OID& epoch, string* errMsg ) { scoped_lock lk( _mutex ); CollectionMetadataMap::const_iterator it = _collMetadata.find( ns ); if ( it == _collMetadata.end() ) { *errMsg = str::stream() << "no need to forget pending chunk " << "[" << min << "," << max << ")" << " because the local metadata for " << ns << " has changed"; return false; } CollectionMetadataPtr metadata = it->second; // This can currently happen because drops aren't synchronized with in-migrations // The idea for checking this here is that in the future we shouldn't have this problem if ( metadata->getCollVersion().epoch() != epoch ) { *errMsg = str::stream() << "no need to forget pending chunk " << "[" << min << "," << max << ")" << " because the epoch for " << ns << " has changed from " << epoch << " to " << metadata->getCollVersion().epoch(); return false; } ChunkType chunk; chunk.setMin( min ); chunk.setMax( max ); CollectionMetadataPtr cloned( metadata->cloneMinusPending( chunk, errMsg ) ); if ( !cloned ) return false; _collMetadata[ns] = cloned; return true; }
TEST_F(MergeChunkTests, CompoundMerge) { const NamespaceString nss("foo.bar"); const BSONObj kp = BSON("x" << 1 << "y" << 1); const OID epoch = OID::gen(); vector<KeyRange> ranges; // Setup chunk metadata ranges.push_back( KeyRange(nss.ns(), BSON("x" << 0 << "y" << 1), BSON("x" << 1 << "y" << 0), kp)); ranges.push_back( KeyRange(nss.ns(), BSON("x" << 1 << "y" << 0), BSON("x" << 2 << "y" << 1), kp)); storeCollectionRanges(nss, shardName(), ranges, ChunkVersion(1, 0, epoch)); // Get latest version ChunkVersion latestVersion; ShardingState::get(getGlobalServiceContext()) ->refreshMetadataNow(&_txn, nss.ns(), &latestVersion); ShardingState::get(getGlobalServiceContext())->resetMetadata(nss.ns()); // Do merge string errMsg; bool result = mergeChunks( &_txn, nss, BSON("x" << 0 << "y" << 1), BSON("x" << 2 << "y" << 1), epoch, &errMsg); ASSERT_EQUALS(errMsg, ""); ASSERT(result); // Verify result CollectionMetadataPtr metadata = ShardingState::get(getGlobalServiceContext())->getCollectionMetadata(nss.ns()); ChunkType chunk; ASSERT(metadata->getNextChunk(BSON("x" << 0 << "y" << 1), &chunk)); ASSERT(chunk.getMin().woCompare(BSON("x" << 0 << "y" << 1)) == 0); ASSERT(chunk.getMax().woCompare(BSON("x" << 2 << "y" << 1)) == 0); ASSERT_EQUALS(metadata->getNumChunks(), 1u); ASSERT_EQUALS(metadata->getShardVersion().majorVersion(), latestVersion.majorVersion()); ASSERT_GREATER_THAN(metadata->getShardVersion().minorVersion(), latestVersion.minorVersion()); assertWrittenAsMerged(ranges); }
BSONObj buildMergeLogEntry( const OwnedPointerVector<ChunkType>& chunksToMerge, const ChunkVersion& currShardVersion, const ChunkVersion& newMergedVersion ) { BSONObjBuilder logDetailB; BSONArrayBuilder mergedB( logDetailB.subarrayStart( "merged" ) ); for ( OwnedPointerVector<ChunkType>::const_iterator it = chunksToMerge.begin(); it != chunksToMerge.end(); ++it ) { ChunkType* chunkToMerge = *it; mergedB.append( chunkToMerge->toBSON() ); } mergedB.done(); currShardVersion.addToBSON( logDetailB, "prevShardVersion" ); newMergedVersion.addToBSON( logDetailB, "mergedVersion" ); return logDetailB.obj(); }
Status CollectionMetadata::checkChunkIsValid(const ChunkType& chunk) { ChunkType existingChunk; if (!getNextChunk(chunk.getMin(), &existingChunk)) { return {ErrorCodes::IncompatibleShardingMetadata, str::stream() << "Chunk with bounds " << ChunkRange(chunk.getMin(), chunk.getMax()).toString() << " is not owned by this shard."}; } if (existingChunk.getMin().woCompare(chunk.getMin()) || existingChunk.getMax().woCompare(chunk.getMax())) { return {ErrorCodes::IncompatibleShardingMetadata, str::stream() << "Unable to find chunk with the exact bounds " << ChunkRange(chunk.getMin(), chunk.getMax()).toString() << " at collection version " << getCollVersion().toString()}; } return Status::OK(); }
std::unique_ptr<CollectionMetadata> CollectionMetadata::clonePlusPending( const ChunkType& chunk) const { invariant(!rangeMapOverlaps(_chunksMap, chunk.getMin(), chunk.getMax())); unique_ptr<CollectionMetadata> metadata(stdx::make_unique<CollectionMetadata>()); metadata->_keyPattern = _keyPattern.getOwned(); metadata->fillKeyPatternFields(); metadata->_pendingMap = _pendingMap; metadata->_chunksMap = _chunksMap; metadata->_rangesMap = _rangesMap; metadata->_shardVersion = _shardVersion; metadata->_collVersion = _collVersion; // If there are any pending chunks on the interval to be added this is ok, since pending chunks // aren't officially tracked yet and something may have changed on servers we do not see yet. // // We remove any chunks we overlap because the remote request starting a chunk migration is what // is authoritative. if (rangeMapOverlaps(_pendingMap, chunk.getMin(), chunk.getMax())) { RangeVector pendingOverlap; getRangeMapOverlap(_pendingMap, chunk.getMin(), chunk.getMax(), &pendingOverlap); warning() << "new pending chunk " << redact(rangeToString(chunk.getMin(), chunk.getMax())) << " overlaps existing pending chunks " << redact(overlapToString(pendingOverlap)) << ", a migration may not have completed"; for (RangeVector::iterator it = pendingOverlap.begin(); it != pendingOverlap.end(); ++it) { metadata->_pendingMap.erase(it->first); } } // The pending map entry cannot contain a specific chunk version because we don't know what // version would be generated for it at commit time. That's why we insert an IGNORED value. metadata->_pendingMap.insert( make_pair(chunk.getMin(), CachedChunkInfo(chunk.getMax(), ChunkVersion::IGNORED()))); invariant(metadata->isValid()); return metadata; }
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; }
void ShardingState::splitChunk( const string& ns, const BSONObj& min, const BSONObj& max, const vector<BSONObj>& splitKeys, ChunkVersion version ) { scoped_lock lk( _mutex ); CollectionMetadataMap::const_iterator it = _collMetadata.find( ns ); verify( it != _collMetadata.end() ) ; ChunkType chunk; chunk.setMin( min ); chunk.setMax( max ); string errMsg; CollectionMetadataPtr cloned( it->second->cloneSplit( chunk, splitKeys, version, &errMsg ) ); // uassert to match old behavior, TODO: report errors w/o throwing uassert( 16857, errMsg, NULL != cloned.get() ); _collMetadata[ns] = cloned; }
boost::optional<MigrateInfo> BalancerPolicy::balanceSingleChunk( const ChunkType& chunk, const ShardStatisticsVector& shardStats, const DistributionStatus& distribution) { const string tag = distribution.getTagForChunk(chunk); ShardId newShardId = _getLeastLoadedReceiverShard(shardStats, distribution, tag, {}); if (!newShardId.isValid() || newShardId == chunk.getShard()) { return boost::optional<MigrateInfo>(); } return MigrateInfo(distribution.nss().ns(), newShardId, chunk); }
BSONObj BalanceChunkRequest::serializeToMoveCommandForConfig( const ChunkType& chunk, const ShardId& newShardId, int64_t maxChunkSizeBytes, const MigrationSecondaryThrottleOptions& secondaryThrottle, bool waitForDelete) { invariantOK(chunk.validate()); BSONObjBuilder cmdBuilder; cmdBuilder.append(kConfigSvrMoveChunk, 1); cmdBuilder.appendElements(chunk.toBSON()); cmdBuilder.append(kToShardId, newShardId); cmdBuilder.append(kMaxChunkSizeBytes, static_cast<long long>(maxChunkSizeBytes)); { BSONObjBuilder secondaryThrottleBuilder(cmdBuilder.subobjStart(kSecondaryThrottle)); secondaryThrottle.append(&secondaryThrottleBuilder); secondaryThrottleBuilder.doneFast(); } cmdBuilder.append(kWaitForDelete, waitForDelete); return cmdBuilder.obj(); }
std::unique_ptr<CollectionMetadata> CollectionMetadata::cloneMigrate( const ChunkType& chunk, const ChunkVersion& newCollectionVersion) const { invariant(newCollectionVersion.epoch() == _collVersion.epoch()); invariant(newCollectionVersion > _collVersion); invariant(rangeMapContains(_chunksMap, chunk.getMin(), chunk.getMax())); unique_ptr<CollectionMetadata> metadata(stdx::make_unique<CollectionMetadata>()); metadata->_keyPattern = _keyPattern.getOwned(); metadata->fillKeyPatternFields(); metadata->_pendingMap = _pendingMap; metadata->_chunksMap = _chunksMap; metadata->_chunksMap.erase(chunk.getMin()); metadata->_shardVersion = (metadata->_chunksMap.empty() ? ChunkVersion(0, 0, newCollectionVersion.epoch()) : newCollectionVersion); metadata->_collVersion = newCollectionVersion; metadata->fillRanges(); invariant(metadata->isValid()); return metadata; }
string DistributionStatus::getTagForChunk(const ChunkType& chunk) const { const auto minIntersect = _tagRanges.upper_bound(chunk.getMin()); const auto maxIntersect = _tagRanges.lower_bound(chunk.getMax()); // We should never have a partial overlap with a chunk range. If it happens, treat it as if this // chunk doesn't belong to a tag if (minIntersect != maxIntersect) { return ""; } if (minIntersect == _tagRanges.end()) { return ""; } const TagRange& intersectRange = minIntersect->second; // Check for containment if (intersectRange.min <= chunk.getMin() && chunk.getMax() <= intersectRange.max) { return intersectRange.tag; } return ""; }
void MetadataManager::forgetReceive(const ChunkRange& range) { stdx::lock_guard<stdx::mutex> scopedLock(_managerLock); { auto it = _receivingChunks.find(range.getMin()); invariant(it != _receivingChunks.end()); // Verify entire ChunkRange is identical, not just the min key. invariant(it->second == range.getMax()); _receivingChunks.erase(it); } // This is potentially a partially received data, which needs to be cleaned up _addRangeToClean_inlock(range); // For compatibility with the current range deleter, update the pending chunks on the collection // metadata to exclude the chunk being received, which was added in beginReceive ChunkType chunk; chunk.setMin(range.getMin()); chunk.setMax(range.getMax()); _setActiveMetadata_inlock(_activeMetadataTracker->metadata->cloneMinusPending(chunk)); }
Status ChunkManager::createFirstChunks(OperationContext* txn, const ShardId& primaryShardId, const vector<BSONObj>* initPoints, const set<ShardId>* initShardIds) { // TODO distlock? // TODO: Race condition if we shard the collection and insert data while we split across // the non-primary shard. vector<BSONObj> splitPoints; vector<ShardId> shardIds; calcInitSplitsAndShards(txn, primaryShardId, initPoints, initShardIds, &splitPoints, &shardIds); // this is the first chunk; start the versioning from scratch ChunkVersion version(1, 0, OID::gen()); log() << "going to create " << splitPoints.size() + 1 << " chunk(s) for: " << _ns << " using new epoch " << version.epoch(); for (unsigned i = 0; i <= splitPoints.size(); i++) { BSONObj min = i == 0 ? _keyPattern.getKeyPattern().globalMin() : splitPoints[i - 1]; BSONObj max = i < splitPoints.size() ? splitPoints[i] : _keyPattern.getKeyPattern().globalMax(); ChunkType chunk; chunk.setName(Chunk::genID(_ns, min)); chunk.setNS(_ns); chunk.setMin(min); chunk.setMax(max); chunk.setShard(shardIds[i % shardIds.size()]); chunk.setVersion(version); Status status = grid.catalogManager(txn) ->insertConfigDocument(txn, ChunkType::ConfigNS, chunk.toBSON()); if (!status.isOK()) { const string errMsg = str::stream() << "Creating first chunks failed: " << status.reason(); error() << errMsg; return Status(status.code(), errMsg); } version.incMinor(); } _version = ChunkVersion(0, 0, version.epoch()); return Status::OK(); }
std::unique_ptr<CollectionMetadata> CollectionMetadata::clonePlusPending( const ChunkType& chunk) const { invariant(!rangeMapOverlaps(_chunksMap, chunk.getMin(), chunk.getMax())); unique_ptr<CollectionMetadata> metadata(stdx::make_unique<CollectionMetadata>()); metadata->_keyPattern = _keyPattern.getOwned(); metadata->fillKeyPatternFields(); metadata->_pendingMap = _pendingMap; metadata->_chunksMap = _chunksMap; metadata->_rangesMap = _rangesMap; metadata->_shardVersion = _shardVersion; metadata->_collVersion = _collVersion; // If there are any pending chunks on the interval to be added this is ok, since pending // chunks aren't officially tracked yet and something may have changed on servers we do not // see yet. // We remove any chunks we overlap, the remote request starting a chunk migration must have // been authoritative. if (rangeMapOverlaps(_pendingMap, chunk.getMin(), chunk.getMax())) { RangeVector pendingOverlap; getRangeMapOverlap(_pendingMap, chunk.getMin(), chunk.getMax(), &pendingOverlap); warning() << "new pending chunk " << rangeToString(chunk.getMin(), chunk.getMax()) << " overlaps existing pending chunks " << overlapToString(pendingOverlap) << ", a migration may not have completed"; for (RangeVector::iterator it = pendingOverlap.begin(); it != pendingOverlap.end(); ++it) { metadata->_pendingMap.erase(it->first); } } metadata->_pendingMap.insert(make_pair(chunk.getMin(), chunk.getMax())); invariant(metadata->isValid()); return metadata; }
void ShardingState::splitChunk(OperationContext* txn, const string& ns, const BSONObj& min, const BSONObj& max, const vector<BSONObj>& splitKeys, ChunkVersion version) { invariant(txn->lockState()->isCollectionLockedForMode(ns, MODE_X)); stdx::lock_guard<stdx::mutex> lk(_mutex); CollectionMetadataMap::const_iterator it = _collMetadata.find(ns); verify(it != _collMetadata.end()); ChunkType chunk; chunk.setMin(min); chunk.setMax(max); string errMsg; shared_ptr<CollectionMetadata> cloned( it->second->cloneSplit(chunk, splitKeys, version, &errMsg)); // uassert to match old behavior, TODO: report errors w/o throwing uassert(16857, errMsg, NULL != cloned.get()); _collMetadata[ns] = cloned; }
Status findAllChunks(const ConnectionString& configLoc, const string& ns, OwnedPointerVector<ChunkType>* chunks) { scoped_ptr<ScopedDbConnection> connPtr; scoped_ptr<DBClientCursor> cursor; try { connPtr.reset(ScopedDbConnection::getInternalScopedDbConnection(configLoc, 30)); ScopedDbConnection& conn = *connPtr; scoped_ptr<DBClientCursor> cursor(_safeCursor(conn->query(ChunkType::ConfigNS, BSON(ChunkType::ns(ns))))); while (cursor->more()) { BSONObj chunkDoc = cursor->nextSafe(); ChunkType* chunk = new ChunkType(); string errMsg; if (!chunk->parseBSON(chunkDoc, &errMsg) || !chunk->isValid(&errMsg)) { connPtr->done(); return Status(ErrorCodes::UnsupportedFormat, stream() << "invalid chunk " << chunkDoc << " read from the config server" << causedBy(errMsg)); } chunks->mutableVector().push_back(chunk); } } catch (const DBException& e) { return e.toStatus(); } connPtr->done(); return Status::OK(); }
MigrateInfo MigrationType::toMigrateInfo() const { ChunkType chunk; chunk.setNS(_nss); chunk.setShard(_fromShard); chunk.setMin(_min); chunk.setMax(_max); chunk.setVersion(_chunkVersion); return MigrateInfo(_toShard, chunk); }
string DistributionStatus::getTagForChunk(const ChunkType& chunk) const { if (_tagRanges.size() == 0) return ""; const BSONObj min(chunk.getMin()); map<BSONObj, TagRange>::const_iterator i = _tagRanges.upper_bound(min); if (i == _tagRanges.end()) return ""; const TagRange& range = i->second; if (min < range.min) return ""; return range.tag; }