summaryrefslogtreecommitdiff
path: root/src/mongo/db/s/collection_metadata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/s/collection_metadata.cpp')
-rw-r--r--src/mongo/db/s/collection_metadata.cpp197
1 files changed, 56 insertions, 141 deletions
diff --git a/src/mongo/db/s/collection_metadata.cpp b/src/mongo/db/s/collection_metadata.cpp
index b18e325adb0..0b4cf09e59e 100644
--- a/src/mongo/db/s/collection_metadata.cpp
+++ b/src/mongo/db/s/collection_metadata.cpp
@@ -49,7 +49,6 @@ CollectionMetadata::CollectionMetadata(const BSONObj& keyPattern,
_collVersion(collectionVersion),
_shardVersion(shardVersion),
_chunksMap(std::move(shardChunksMap)),
- _pendingMap(SimpleBSONObjComparator::kInstance.makeBSONObjIndexedMap<CachedChunkInfo>()),
_rangesMap(SimpleBSONObjComparator::kInstance.makeBSONObjIndexedMap<CachedChunkInfo>()) {
invariant(_shardKeyPattern.isValid());
@@ -61,16 +60,24 @@ CollectionMetadata::CollectionMetadata(const BSONObj& keyPattern,
invariant(!_shardVersion.isSet());
return;
}
-
invariant(_shardVersion.isSet());
- // Load the chunk information, coallesceing their ranges. The version for this shard would be
+ _rebuildRangesMap();
+}
+
+CollectionMetadata::~CollectionMetadata() = default;
+
+void CollectionMetadata::_rebuildRangesMap() {
+ _rangesMap.clear();
+
+ // Load the chunk information, coalescing their ranges. The version for this shard would be
// the highest version for any of the chunks.
+
BSONObj min, max;
for (const auto& entry : _chunksMap) {
- BSONObj currMin = entry.first;
- BSONObj currMax = entry.second.getMaxKey();
+ BSONObj const& currMin = entry.first;
+ BSONObj const& currMax = entry.second.getMaxKey();
// Coalesce the chunk's bounds in ranges if they are adjacent chunks
if (min.isEmpty()) {
@@ -96,54 +103,9 @@ CollectionMetadata::CollectionMetadata(const BSONObj& keyPattern,
_rangesMap.emplace(min, CachedChunkInfo(max, ChunkVersion::IGNORED()));
}
-CollectionMetadata::~CollectionMetadata() = default;
-
-std::unique_ptr<CollectionMetadata> CollectionMetadata::cloneMinusPending(
- const ChunkType& chunk) const {
- invariant(rangeMapContains(_pendingMap, chunk.getMin(), chunk.getMax()));
-
- auto metadata(stdx::make_unique<CollectionMetadata>(
- _shardKeyPattern.toBSON(), getCollVersion(), getShardVersion(), getChunks()));
- metadata->_pendingMap = _pendingMap;
-
- metadata->_pendingMap.erase(chunk.getMin());
-
- return metadata;
-}
-
-std::unique_ptr<CollectionMetadata> CollectionMetadata::clonePlusPending(
- const ChunkType& chunk) const {
- invariant(!rangeMapOverlaps(_chunksMap, chunk.getMin(), chunk.getMax()));
-
- auto metadata(stdx::make_unique<CollectionMetadata>(
- _shardKeyPattern.toBSON(), getCollVersion(), getShardVersion(), getChunks()));
- metadata->_pendingMap = _pendingMap;
-
- // 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.emplace(chunk.getMin(),
- CachedChunkInfo(chunk.getMax(), ChunkVersion::IGNORED()));
-
- return metadata;
+std::unique_ptr<CollectionMetadata> CollectionMetadata::clone() const {
+ return stdx::make_unique<CollectionMetadata>(
+ _shardKeyPattern.toBSON(), getCollVersion(), getShardVersion(), getChunks());
}
bool CollectionMetadata::keyBelongsToMe(const BSONObj& key) const {
@@ -158,18 +120,6 @@ bool CollectionMetadata::keyBelongsToMe(const BSONObj& key) const {
return rangeContains(it->first, it->second.getMaxKey(), key);
}
-bool CollectionMetadata::keyIsPending(const BSONObj& key) const {
- if (_pendingMap.empty()) {
- return false;
- }
-
- auto it = _pendingMap.upper_bound(key);
- if (it != _pendingMap.begin())
- it--;
-
- return rangeContains(it->first, it->second.getMaxKey(), key);
-}
-
bool CollectionMetadata::getNextChunk(const BSONObj& lookupKey, ChunkType* chunk) const {
RangeMap::const_iterator upperChunkIt = _chunksMap.upper_bound(lookupKey);
RangeMap::const_iterator lowerChunkIt = upperChunkIt;
@@ -238,6 +188,10 @@ Status CollectionMetadata::checkChunkIsValid(const ChunkType& chunk) {
return Status::OK();
}
+bool CollectionMetadata::rangeOverlapsChunk(ChunkRange const& range) {
+ return rangeMapOverlaps(_rangesMap, range.getMin(), range.getMax());
+}
+
void CollectionMetadata::toBSONBasic(BSONObjBuilder& bb) const {
_collVersion.addToBSON(bb, "collVersion");
_shardVersion.addToBSON(bb, "shardVersion");
@@ -256,97 +210,58 @@ void CollectionMetadata::toBSONChunks(BSONArrayBuilder& bb) const {
}
}
-void CollectionMetadata::toBSONPending(BSONArrayBuilder& bb) const {
- if (_pendingMap.empty())
- return;
-
- for (RangeMap::const_iterator it = _pendingMap.begin(); it != _pendingMap.end(); ++it) {
- BSONArrayBuilder pendingBB(bb.subarrayStart());
- pendingBB.append(it->first);
- pendingBB.append(it->second.getMaxKey());
- pendingBB.done();
- }
-}
-
std::string CollectionMetadata::toStringBasic() const {
return str::stream() << "collection version: " << _collVersion.toString()
<< ", shard version: " << _shardVersion.toString();
}
-bool CollectionMetadata::getNextOrphanRange(const BSONObj& origLookupKey, KeyRange* range) const {
+bool CollectionMetadata::getNextOrphanRange(RangeMap const& receivingChunks,
+ const BSONObj& origLookupKey,
+ KeyRange* range) const {
BSONObj lookupKey = origLookupKey;
BSONObj maxKey = getMaxKey(); // so we don't keep rebuilding
while (lookupKey.woCompare(maxKey) < 0) {
- RangeMap::const_iterator lowerChunkIt = _chunksMap.end();
- RangeMap::const_iterator upperChunkIt = _chunksMap.end();
-
- if (!_chunksMap.empty()) {
- upperChunkIt = _chunksMap.upper_bound(lookupKey);
- lowerChunkIt = upperChunkIt;
- if (upperChunkIt != _chunksMap.begin())
- --lowerChunkIt;
- else
- lowerChunkIt = _chunksMap.end();
- }
-
- // If we overlap, continue after the overlap
- // TODO: Could optimize slightly by finding next non-contiguous chunk
- if (lowerChunkIt != _chunksMap.end() &&
- lowerChunkIt->second.getMaxKey().woCompare(lookupKey) > 0) {
- lookupKey = lowerChunkIt->second.getMaxKey();
- continue;
- }
-
- RangeMap::const_iterator lowerPendingIt = _pendingMap.end();
- RangeMap::const_iterator upperPendingIt = _pendingMap.end();
-
- if (!_pendingMap.empty()) {
- upperPendingIt = _pendingMap.upper_bound(lookupKey);
- lowerPendingIt = upperPendingIt;
- if (upperPendingIt != _pendingMap.begin())
- --lowerPendingIt;
- else
- lowerPendingIt = _pendingMap.end();
- }
-
- // If we overlap, continue after the overlap
- // TODO: Could optimize slightly by finding next non-contiguous chunk
- if (lowerPendingIt != _pendingMap.end() &&
- lowerPendingIt->second.getMaxKey().woCompare(lookupKey) > 0) {
- lookupKey = lowerPendingIt->second.getMaxKey();
- continue;
- }
-
- //
- // We know that the lookup key is not covered by a chunk or pending range, and where the
- // previous chunk and pending chunks are. Now we fill in the bounds as the closest
- // bounds of the surrounding ranges in both maps.
- //
range->keyPattern = _shardKeyPattern.toBSON();
range->minKey = getMinKey();
range->maxKey = maxKey;
- if (lowerChunkIt != _chunksMap.end() &&
- lowerChunkIt->second.getMaxKey().woCompare(range->minKey) > 0) {
- range->minKey = lowerChunkIt->second.getMaxKey();
- }
-
- if (upperChunkIt != _chunksMap.end() && upperChunkIt->first.woCompare(range->maxKey) < 0) {
- range->maxKey = upperChunkIt->first;
- }
-
- if (lowerPendingIt != _pendingMap.end() &&
- lowerPendingIt->second.getMaxKey().woCompare(range->minKey) > 0) {
- range->minKey = lowerPendingIt->second.getMaxKey();
- }
+ auto patchUp = [&](auto const& map) {
+ auto lowerIt = map.end(), upperIt = map.end();
+
+ if (!map.empty()) {
+ upperIt = map.upper_bound(lookupKey);
+ lowerIt = upperIt;
+ if (upperIt != map.begin())
+ --lowerIt;
+ else
+ lowerIt = map.end();
+ }
+
+ // If we overlap, continue after the overlap
+ // TODO: Could optimize slightly by finding next non-contiguous chunk
+ if (lowerIt != map.end() && lowerIt->second.getMaxKey().woCompare(lookupKey) > 0) {
+ lookupKey = lowerIt->second.getMaxKey();
+ return false;
+ }
+
+ // We know that the lookup key is not covered by a chunk or pending range, and where the
+ // previous chunk and pending chunks are. Now we fill in the bounds as the closest
+ // bounds of the surrounding ranges in both maps.
+ if (lowerIt != _chunksMap.end() &&
+ lowerIt->second.getMaxKey().woCompare(range->minKey) > 0) {
+ range->minKey = lowerIt->second.getMaxKey();
+ }
+ if (upperIt != _chunksMap.end() && upperIt->first.woCompare(range->maxKey) < 0) {
+ range->maxKey = upperIt->first;
+ }
+ return true;
+ };
- if (upperPendingIt != _pendingMap.end() &&
- upperPendingIt->first.woCompare(range->maxKey) < 0) {
- range->maxKey = upperPendingIt->first;
+ // side effects on *range are safe even if we go around again.
+ if (patchUp(_chunksMap) && patchUp(receivingChunks)) {
+ return true;
}
-
- return true;
}
return false;