diff options
Diffstat (limited to 'src/mongo/s/chunk_manager.h')
| -rw-r--r-- | src/mongo/s/chunk_manager.h | 257 |
1 files changed, 54 insertions, 203 deletions
diff --git a/src/mongo/s/chunk_manager.h b/src/mongo/s/chunk_manager.h index 39755b418a9..00c75957d37 100644 --- a/src/mongo/s/chunk_manager.h +++ b/src/mongo/s/chunk_manager.h @@ -41,6 +41,7 @@ #include "mongo/s/resharding/type_collection_fields_gen.h" #include "mongo/s/shard_key_pattern.h" #include "mongo/s/type_collection_common_types_gen.h" +#include "mongo/stdx/unordered_map.h" #include "mongo/util/concurrency/ticketholder.h" #include "mongo/util/read_through_cache.h" @@ -51,24 +52,13 @@ struct QuerySolutionNode; class ChunkManager; struct ShardVersionTargetingInfo { - ShardVersionTargetingInfo(const ShardVersionTargetingInfo& other) - : shardVersion(other.shardVersion), - validAfter(other.validAfter), - isStale(other.isStale.load()) {} - - ShardVersionTargetingInfo(const OID& epoch, const Timestamp& timestamp); - ShardVersionTargetingInfo(ChunkVersion shardVersion, Timestamp validAfter) - : shardVersion(std::move(shardVersion)), validAfter(std::move(validAfter)) {} + // Indicates whether the shard is stale and thus needs a catalog cache refresh + AtomicWord<bool> isStale{false}; // Max chunk version for the shard ChunkVersion shardVersion; - // Max validAfter for the shard, effectively this is the timestamp of the latest placement - // change that occurred on a particular shard. - Timestamp validAfter; - - // Indicates whether the shard is stale and thus needs a catalog cache refresh - AtomicWord<bool> isStale{false}; + ShardVersionTargetingInfo(const OID& epoch, const Timestamp& timestamp); }; // Map from a shard to a struct indicating both the max chunk version on that shard and whether the @@ -81,174 +71,73 @@ using ShardVersionMap = stdx::unordered_map<ShardId, ShardVersionTargetingInfo, * underlying implementation. */ class ChunkMap { -public: - // Vector of chunks ordered by max key in ascending order. + // Vector of chunks ordered by max key. using ChunkVector = std::vector<std::shared_ptr<ChunkInfo>>; - using ChunkVectorMap = std::map<std::string, std::shared_ptr<ChunkVector>>; - - explicit ChunkMap(OID epoch, const Timestamp& timestamp, size_t chunkVectorSize) - : _collectionVersion(0, 0, epoch, timestamp), - _collTimestamp(timestamp), - _maxChunkVectorSize(chunkVectorSize) {} - size_t size() const; - - // Max version across all chunks - ChunkVersion getVersion() const { - return _collectionVersion; - } - - size_t getMaxChunkVectorSize() const { - return _maxChunkVectorSize; +public: + explicit ChunkMap(OID epoch, const Timestamp& timestamp, size_t initialCapacity = 0) + : _collectionVersion(0, 0, epoch, timestamp), _collTimestamp(timestamp) { + _chunkMap.reserve(initialCapacity); } - const ShardVersionMap& getShardVersionsMap() const { - return _shardVersions; + size_t size() const { + return _chunkMap.size(); } - const ChunkVectorMap& getChunkVectorMap() const { - return _chunkVectorMap; + ChunkVersion getVersion() const { + return _collectionVersion; } - - /* - * Invoke the given handler for each std::shared_ptr<ChunkInfo> contained in this chunk map - * until either all matching chunks have been processed or @handler returns false. - * - * Chunks are yielded in ascending order of shardkey (e.g. minKey to maxKey); - * - * When shardKey is provided the function will start yileding from the chunk that contains the - * given shard key. - */ template <typename Callable> void forEach(Callable&& handler, const BSONObj& shardKey = BSONObj()) const { - if (shardKey.isEmpty()) { - for (const auto& mapIt : _chunkVectorMap) { - for (const auto& chunkInfoPtr : *(mapIt.second)) { - if (!handler(chunkInfoPtr)) - return; - } - } - - return; - } + auto it = shardKey.isEmpty() ? _chunkMap.begin() : _findIntersectingChunk(shardKey); - auto shardKeyString = ShardKeyPattern::toKeyString(shardKey); - - const auto mapItBegin = _chunkVectorMap.upper_bound(shardKeyString); - for (auto mapIt = mapItBegin; mapIt != _chunkVectorMap.end(); mapIt++) { - const auto& chunkVector = *(mapIt->second); - auto it = mapIt == mapItBegin ? _findIntersectingChunkIterator(shardKeyString, - chunkVector.begin(), - chunkVector.end(), - true /*isMaxInclusive*/) - : chunkVector.begin(); - for (; it != chunkVector.end(); ++it) { - if (!handler(*it)) - return; - } + for (; it != _chunkMap.end(); ++it) { + if (!handler(*it)) + break; } } - - /* - * Invoke the given @handler for each std::shared_ptr<ChunkInfo> that overlaps with range [@min, - * @max] until either all matching chunks have been processed or @handler returns false. - * - * Chunks are yielded in ascending order of shardkey (e.g. minKey to maxKey); - * - * When @isMaxInclusive is true also the chunk whose minKey is equal to @max will be yielded. - */ template <typename Callable> void forEachOverlappingChunk(const BSONObj& min, const BSONObj& max, bool isMaxInclusive, Callable&& handler) const { - const auto minShardKeyStr = ShardKeyPattern::toKeyString(min); - const auto maxShardKeyStr = ShardKeyPattern::toKeyString(max); - const auto bounds = - _overlappingVectorSlotBounds(minShardKeyStr, maxShardKeyStr, isMaxInclusive); - for (auto mapIt = bounds.first; mapIt != bounds.second; ++mapIt) { - - const auto& chunkVector = *(mapIt->second); - - const auto chunkItBegin = [&] { - if (mapIt == bounds.first) { - // On first vector we need to start from chunk that contain the given minKey - return _findIntersectingChunkIterator(minShardKeyStr, - chunkVector.begin(), - chunkVector.end(), - true /* isMaxInclusive */); - } - return chunkVector.begin(); - }(); - - const auto chunkItEnd = [&] { - if (mapIt == std::prev(bounds.second)) { - // On last vector we need to skip all chunks that are greater than the give - // maxKey - auto it = _findIntersectingChunkIterator( - maxShardKeyStr, chunkItBegin, chunkVector.end(), isMaxInclusive); - return it == chunkVector.end() ? it : ++it; - } - return chunkVector.end(); - }(); - - for (auto chunkIt = chunkItBegin; chunkIt != chunkItEnd; ++chunkIt) { - if (!handler(*chunkIt)) - return; - } + const auto bounds = _overlappingBounds(min, max, isMaxInclusive); + + for (auto it = bounds.first; it != bounds.second; ++it) { + if (!handler(*it)) + break; } } + ShardVersionMap constructShardVersionMap() const; std::shared_ptr<ChunkInfo> findIntersectingChunk(const BSONObj& shardKey) const; - ChunkMap createMerged(ChunkVector changedChunks) const; + void appendChunk(const std::shared_ptr<ChunkInfo>& chunk); - BSONObj toBSON() const; + ChunkMap createMerged(const std::vector<std::shared_ptr<ChunkInfo>>& changedChunks) const; - std::string toString() const; + BSONObj toBSON() const; private: - ChunkVector::const_iterator _findIntersectingChunkIterator(const std::string& shardKeyString, - ChunkVector::const_iterator first, - ChunkVector::const_iterator last, - bool isMaxInclusive) const; - - std::pair<ChunkVectorMap::const_iterator, ChunkVectorMap::const_iterator> - _overlappingVectorSlotBounds(const std::string& minShardKeyStr, - const std::string& maxShardKeyStr, - bool isMaxInclusive) const; - ChunkMap _makeUpdated(ChunkVector&& changedChunks) const; - - void _updateShardVersionFromDiscardedChunk(const ChunkInfo& chunk); - void _updateShardVersionFromUpdateChunk(const ChunkInfo& chunk, - const ShardVersionMap& oldShardVersions); - void _commitUpdatedChunkVector(std::shared_ptr<ChunkVector>&& chunkVectorPtr, - bool checkMaxKeyConsistency); - void _mergeAndCommitUpdatedChunkVector(ChunkVectorMap::const_iterator pos, - std::shared_ptr<ChunkVector>&& chunkVectorPtr); - void _splitAndCommitUpdatedChunkVector(ChunkVectorMap::const_iterator pos, - std::shared_ptr<ChunkVector>&& chunkVectorPtr); - - ChunkVectorMap _chunkVectorMap; + ChunkVector::const_iterator _findIntersectingChunk(const BSONObj& shardKey, + bool isMaxInclusive = true) const; + std::pair<ChunkVector::const_iterator, ChunkVector::const_iterator> _overlappingBounds( + const BSONObj& min, const BSONObj& max, bool isMaxInclusive) const; + + ChunkVector _chunkMap; // Max version across all chunks ChunkVersion _collectionVersion; - // The representation of shard versions and staleness indicators for this namespace. If a - // shard does not exist, it will not have an entry in the map. - // Note: this declaration must not be moved before _chunkMap since it is initialized by using - // the _chunkVectorMap instance. - ShardVersionMap _shardVersions; - // Represents the timestamp present in config.collections for this ChunkMap. + // + // Note that due to the way Phase 1 of the FCV upgrade writes timestamps to chunks + // (non-atomically), it is possible that chunks exist with timestamps, but the corresponding + // config.collections entry doesn't. In this case, the chunks timestamp should be ignored when + // computing the collection version and we should use _collTimestamp instead. Timestamp _collTimestamp; - - // Maximum size of chunk vectors stored in the chunk vector map. - // Bigger vectors will imply slower incremental refreshes (more chunks to copy) but - // faster map copy (less chunk vector pointers to copy). - size_t _maxChunkVectorSize; }; /** @@ -339,7 +228,6 @@ public: */ void setAllShardsRefreshed(); - // Max version across all chunks ChunkVersion getVersion() const { return _chunkMap.getVersion(); } @@ -348,26 +236,14 @@ public: * Retrieves the shard version for the given shard. Will throw a ShardInvalidatedForTargeting * exception if the shard is marked as stale. */ - ChunkVersion getVersion(const ShardId& shardId) const { - return _getVersion(shardId, true).shardVersion; - } + ChunkVersion getVersion(const ShardId& shardId) const; /** * Retrieves the shard version for the given shard. Will not throw if the shard is marked as * stale. Only use when logging the given chunk version -- if the caller must execute logic * based on the returned version, use getVersion() instead. */ - ChunkVersion getVersionForLogging(const ShardId& shardId) const { - return _getVersion(shardId, false).shardVersion; - } - - /** - * Retrieves the maximum validAfter timestamp for the given shard. Will throw a - * ShardInvalidatedForTargeting exception if the shard is marked as stale. - */ - Timestamp getMaxValidAfter(const ShardId& shardId) const { - return _getVersion(shardId, true).validAfter; - } + ChunkVersion getVersionForLogging(const ShardId& shardId) const; size_t numChunks() const { return _chunkMap.size(); @@ -401,6 +277,11 @@ public: */ int getNShardsOwningChunks() const; + /** + * Returns true if, for this shard, the chunks are identical in both chunk managers + */ + bool compatibleWith(const RoutingTableHistory& other, const ShardId& shard) const; + std::string toString() const; bool uuidMatches(const UUID& uuid) const { @@ -442,7 +323,7 @@ private: bool allowMigrations, ChunkMap chunkMap); - ShardVersionTargetingInfo _getVersion(const ShardId& shardId, bool throwOnStaleShard) const; + ChunkVersion _getVersion(const ShardId& shardName, bool throwOnStaleShard) const; // Namespace to which this routing information corresponds NamespaceString _nss; @@ -675,27 +556,10 @@ public: return _rt->optRt->getVersion(); } - /** - * Retrieves the placement version for the given shard. Will throw a - * ShardInvalidatedForTargeting exception if the shard is marked as stale. - */ ChunkVersion getVersion(const ShardId& shardId) const { return _rt->optRt->getVersion(shardId); } - /** - * Retrieves the maximum validAfter timestamp for the given shard. Will throw a - * ShardInvalidatedForTargeting exception if the shard is marked as stale. - */ - Timestamp getMaxValidAfter(const ShardId& shardId) const { - return _rt->optRt->getMaxValidAfter(shardId); - } - - /** - * Retrieves the placement version for the given shard. Will not throw if the shard is marked as - * stale. Only use when logging the given chunk version -- if the caller must execute logic - * based on the returned version, use getVersion() instead. - */ ChunkVersion getVersionForLogging(const ShardId& shardId) const { return _rt->optRt->getVersionForLogging(shardId); } @@ -711,23 +575,6 @@ public: }); } - template <typename Callable> - void forEachOverlappingChunk(const BSONObj& min, - const BSONObj& max, - bool isMaxInclusive, - Callable&& handler) const { - _rt->optRt->forEachOverlappingChunk( - min, - max, - isMaxInclusive, - [this, handler = std::forward<Callable>(handler)](const auto& chunkInfo) mutable { - if (!handler(Chunk{*chunkInfo, _clusterTime})) { - return false; - } - return true; - }); - } - /** * Returns true if a document with the given "shardKey" is owned by the shard with the given * "shardId" in this routing table. If "shardKey" is empty returns false. If "shardKey" is not a @@ -778,15 +625,12 @@ public: /** * Finds the shard IDs for a given filter and collation. If collation is empty, we use the - * collection default collation for targeting. If 'bypassIsFieldHashedCheck' is true, it skips - * checking if the shard key was hashed and assumes that any non-collatable shard key was not - * hashed from a collatable type. + * collection default collation for targeting. */ void getShardIdsForQuery(boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& query, const BSONObj& collation, - std::set<ShardId>* shardIds, - bool bypassIsFieldHashedCheck = false) const; + std::set<ShardId>* shardIds) const; /** * Returns all shard ids which contain chunks overlapping the range [min, max]. Please note the @@ -835,6 +679,13 @@ public: */ static ChunkManager makeAtTime(const ChunkManager& cm, Timestamp clusterTime); + /** + * Returns true if, for this shard, the chunks are identical in both chunk managers + */ + bool compatibleWith(const ChunkManager& other, const ShardId& shard) const { + return _rt->optRt->compatibleWith(*other._rt->optRt, shard); + } + bool uuidMatches(const UUID& uuid) const { return _rt->optRt->uuidMatches(uuid); } |
