summaryrefslogtreecommitdiff
path: root/src/mongo/s/chunk_manager.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/s/chunk_manager.h')
-rw-r--r--src/mongo/s/chunk_manager.h257
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);
}