From d8b0d028e3895b32b86f3e6878d4bc34dd8c7fc8 Mon Sep 17 00:00:00 2001 From: Kaloian Manassiev Date: Sun, 19 Mar 2017 18:49:08 -0400 Subject: SERVER-27681 Remove duplicated ShardKeyPattern functionality from CollectionMetadata --- src/mongo/s/shard_key_pattern.cpp | 121 +++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 54 deletions(-) (limited to 'src/mongo/s/shard_key_pattern.cpp') diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index bce1698ecb3..3518a7e9cc2 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -44,33 +44,19 @@ namespace mongo { -using std::make_pair; -using std::pair; using std::shared_ptr; using std::string; using std::unique_ptr; using std::vector; using pathsupport::EqualityMatches; -using mongoutils::str::stream; const int ShardKeyPattern::kMaxShardKeySizeBytes = 512; const unsigned int ShardKeyPattern::kMaxFlattenedInCombinations = 4000000; -Status ShardKeyPattern::checkShardKeySize(const BSONObj& shardKey) { - if (shardKey.objsize() <= kMaxShardKeySizeBytes) - return Status::OK(); - - return Status(ErrorCodes::ShardKeyTooBig, - stream() << "shard keys must be less than " << kMaxShardKeySizeBytes - << " bytes, but key " - << shardKey - << " is " - << shardKey.objsize() - << " bytes"); -} +namespace { -static bool isHashedPatternEl(const BSONElement& el) { +bool isHashedPatternEl(const BSONElement& el) { return el.type() == String && el.String() == IndexNames::HASHED; } @@ -79,26 +65,23 @@ static bool isHashedPatternEl(const BSONElement& el) { * i) a hashed single field, e.g. { a : "hashed" }, or * ii) a compound list of ascending, potentially-nested field paths, e.g. { a : 1 , b.c : 1 } */ -static std::vector> parseShardKeyPattern(const BSONObj& keyPattern) { +std::vector> parseShardKeyPattern(const BSONObj& keyPattern) { std::vector> parsedPaths; - BSONObjIterator patternIt(keyPattern); - while (patternIt.more()) { - BSONElement patternEl = patternIt.next(); - parsedPaths.push_back(stdx::make_unique(patternEl.fieldNameStringData())); - const FieldRef& patternPath = *parsedPaths.back(); + for (const auto& patternEl : keyPattern) { + auto newFieldRef(stdx::make_unique(patternEl.fieldNameStringData())); // Empty path - if (patternPath.numParts() == 0) + if (newFieldRef->numParts() == 0) return {}; // Extra "." in path? - if (patternPath.dottedField() != patternEl.fieldNameStringData()) + if (newFieldRef->dottedField() != patternEl.fieldNameStringData()) return {}; // Empty parts of the path, ".."? - for (size_t i = 0; i < patternPath.numParts(); ++i) { - if (patternPath.getPart(i).size() == 0) + for (size_t i = 0; i < newFieldRef->numParts(); ++i) { + if (newFieldRef->getPart(i).empty()) return {}; } @@ -109,18 +92,48 @@ static std::vector> parseShardKeyPattern(const BSONObj } else if (patternEl.numberInt() != 1) { return {}; } + + parsedPaths.emplace_back(std::move(newFieldRef)); } return parsedPaths; } +bool isShardKeyElement(const BSONElement& element, bool allowRegex) { + if (element.eoo() || element.type() == Array) + return false; + + // TODO: Disallow regex all the time + if (!allowRegex && element.type() == RegEx) + return false; + + if (element.type() == Object && !element.embeddedObject().okForStorage()) + return false; + + return true; +} + +} // namespace + +Status ShardKeyPattern::checkShardKeySize(const BSONObj& shardKey) { + if (shardKey.objsize() <= kMaxShardKeySizeBytes) + return Status::OK(); + + return {ErrorCodes::ShardKeyTooBig, + str::stream() << "shard keys must be less than " << kMaxShardKeySizeBytes + << " bytes, but key " + << shardKey + << " is " + << shardKey.objsize() + << " bytes"}; +} + ShardKeyPattern::ShardKeyPattern(const BSONObj& keyPattern) : _keyPatternPaths(parseShardKeyPattern(keyPattern)), _keyPattern(_keyPatternPaths.empty() ? BSONObj() : keyPattern) {} ShardKeyPattern::ShardKeyPattern(const KeyPattern& keyPattern) - : _keyPatternPaths(parseShardKeyPattern(keyPattern.toBSON())), - _keyPattern(_keyPatternPaths.empty() ? KeyPattern(BSONObj()) : keyPattern) {} + : ShardKeyPattern(keyPattern.toBSON()) {} bool ShardKeyPattern::isValid() const { return !_keyPattern.toBSON().isEmpty(); @@ -134,6 +147,10 @@ const KeyPattern& ShardKeyPattern::getKeyPattern() const { return _keyPattern; } +const std::vector>& ShardKeyPattern::getKeyPatternFields() const { + return _keyPatternPaths; +} + const BSONObj& ShardKeyPattern::toBSON() const { return _keyPattern.toBSON(); } @@ -142,30 +159,22 @@ string ShardKeyPattern::toString() const { return toBSON().toString(); } -static bool isShardKeyElement(const BSONElement& element, bool allowRegex) { - // TODO: Disallow regex all the time - if (element.eoo() || element.type() == Array || (!allowRegex && element.type() == RegEx) || - (element.type() == Object && !element.embeddedObject().okForStorage())) - return false; - return true; -} - bool ShardKeyPattern::isShardKey(const BSONObj& shardKey) const { // Shard keys are always of the form: { 'nested.path' : value, 'nested.path2' : value } if (!isValid()) return false; - BSONObjIterator patternIt(_keyPattern.toBSON()); - while (patternIt.more()) { - BSONElement patternEl = patternIt.next(); + const auto& keyPatternBSON = _keyPattern.toBSON(); + for (const auto& patternEl : keyPatternBSON) { BSONElement keyEl = shardKey[patternEl.fieldNameStringData()]; + if (!isShardKeyElement(keyEl, true)) return false; } - return true; + return shardKey.nFields() == keyPatternBSON.nFields(); } BSONObj ShardKeyPattern::normalizeShardKey(const BSONObj& shardKey) const { @@ -350,18 +359,21 @@ BoundList ShardKeyPattern::flattenBounds(const IndexBounds& indexBounds) const { return BoundList(); } } - // To construct our bounds we will generate intervals based on bounds for - // the first field, then compound intervals based on constraints for the first - // 2 fields, then compound intervals for the first 3 fields, etc. - // As we loop through the fields, we start generating new intervals that will later - // get extended in another iteration of the loop. We define these partially constructed - // intervals using pairs of BSONObjBuilders (shared_ptrs, since after one iteration of the - // loop they still must exist outside their scope). - typedef vector, shared_ptr>> BoundBuilders; + + // To construct our bounds we will generate intervals based on bounds for the first field, then + // compound intervals based on constraints for the first 2 fields, then compound intervals for + // the first 3 fields, etc. + // + // As we loop through the fields, we start generating new intervals that will later get extended + // in another iteration of the loop. We define these partially constructed intervals using pairs + // of BSONObjBuilders (shared_ptrs, since after one iteration of the loop they still must exist + // outside their scope). + typedef vector, std::shared_ptr>> + BoundBuilders; BoundBuilders builders; - builders.push_back(make_pair(shared_ptr(new BSONObjBuilder()), - shared_ptr(new BSONObjBuilder()))); + builders.emplace_back(shared_ptr(new BSONObjBuilder()), + shared_ptr(new BSONObjBuilder())); BSONObjIterator keyIter(_keyPattern.toBSON()); // until equalityOnly is false, we are just dealing with equality (no range or $in queries). bool equalityOnly = true; @@ -403,9 +415,8 @@ BoundList ShardKeyPattern::flattenBounds(const IndexBounds& indexBounds) const { uassert(17439, "combinatorial limit of $in partitioning of results exceeded", newBuilders.size() < kMaxFlattenedInCombinations); - newBuilders.push_back( // - make_pair(shared_ptr(new BSONObjBuilder()), - shared_ptr(new BSONObjBuilder()))); + newBuilders.emplace_back(shared_ptr(new BSONObjBuilder()), + shared_ptr(new BSONObjBuilder())); newBuilders.back().first->appendElements(first); newBuilders.back().second->appendElements(second); newBuilders.back().first->appendAs(interval->start, fieldName); @@ -424,9 +435,11 @@ BoundList ShardKeyPattern::flattenBounds(const IndexBounds& indexBounds) const { } } } + BoundList ret; for (BoundBuilders::const_iterator i = builders.begin(); i != builders.end(); ++i) - ret.push_back(make_pair(i->first->obj(), i->second->obj())); + ret.emplace_back(i->first->obj(), i->second->obj()); + return ret; } -- cgit v1.2.1