diff options
author | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-08-17 12:11:32 -0400 |
---|---|---|
committer | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-08-23 10:05:02 -0400 |
commit | 01a1b877bc7d103646ecc8608a8df89d74de1324 (patch) | |
tree | 7355fdfbca4f6d235bfe5fd414520c18c1a28c41 /src/mongo | |
parent | 5c115e6ad38cd81e96c05ff2be5af17baeaedd68 (diff) | |
download | mongo-01a1b877bc7d103646ecc8608a8df89d74de1324.tar.gz |
SERVER-24439 code cleanup for collation shard targeting
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/pipeline/document_source_geo_near.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/query/collation/collation_spec.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/collation/collation_spec.h | 3 | ||||
-rw-r--r-- | src/mongo/db/query/collation/collator_factory_mock.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/s/migration_destination_manager.cpp | 12 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager.cpp | 37 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager.h | 11 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager_targeter.cpp | 169 | ||||
-rw-r--r-- | src/mongo/s/chunk_manager_targeter.h | 8 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_find_and_modify_cmd.cpp | 43 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_index_filter_cmd.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_map_reduce_cmd.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_pipeline_cmd.cpp | 15 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_plan_cache_cmd.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_shard_collection_cmd.cpp | 6 | ||||
-rw-r--r-- | src/mongo/s/commands/commands_public.cpp | 22 | ||||
-rw-r--r-- | src/mongo/s/shard_key_pattern.cpp | 10 | ||||
-rw-r--r-- | src/mongo/s/shard_key_pattern.h | 2 |
18 files changed, 172 insertions, 190 deletions
diff --git a/src/mongo/db/pipeline/document_source_geo_near.cpp b/src/mongo/db/pipeline/document_source_geo_near.cpp index ce9695b8acd..903b7f0985a 100644 --- a/src/mongo/db/pipeline/document_source_geo_near.cpp +++ b/src/mongo/db/pipeline/document_source_geo_near.cpp @@ -147,10 +147,7 @@ BSONObj DocumentSourceGeoNear::buildGeoNearCmd() const { if (pExpCtx->getCollator()) { geoNear.append("collation", pExpCtx->getCollator()->getSpec().toBSON()); } else { - BSONObjBuilder collationBuilder(geoNear.subobjStart("collation")); - collationBuilder.append(CollationSpec::kLocaleField, - CollationSpec::kSimpleBinaryComparison); - collationBuilder.doneFast(); + geoNear.append("collation", CollationSpec::kSimpleSpec); } geoNear.append("spherical", spherical); diff --git a/src/mongo/db/query/collation/collation_spec.cpp b/src/mongo/db/query/collation/collation_spec.cpp index fd4fa4dc906..e831e89c999 100644 --- a/src/mongo/db/query/collation/collation_spec.cpp +++ b/src/mongo/db/query/collation/collation_spec.cpp @@ -53,6 +53,8 @@ const char* CollationSpec::kAlternateNonIgnorable = "non-ignorable"; const char* CollationSpec::kAlternateShifted = "shifted"; const char* CollationSpec::kMaxVariablePunct = "punct"; const char* CollationSpec::kMaxVariableSpace = "space"; +const BSONObj CollationSpec::kSimpleSpec = + BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison); BSONObj CollationSpec::toBSON() const { BSONObjBuilder builder; diff --git a/src/mongo/db/query/collation/collation_spec.h b/src/mongo/db/query/collation/collation_spec.h index 756a975990f..1878517d496 100644 --- a/src/mongo/db/query/collation/collation_spec.h +++ b/src/mongo/db/query/collation/collation_spec.h @@ -113,6 +113,9 @@ struct CollationSpec { static const char* kMaxVariablePunct; static const char* kMaxVariableSpace; + // Collation spec which the user can supply to represent the "simple" locale. + static const BSONObj kSimpleSpec; + /** * Constructs a CollationSpec with no locale, where all other fields have their default values. */ diff --git a/src/mongo/db/query/collation/collator_factory_mock.cpp b/src/mongo/db/query/collation/collator_factory_mock.cpp index 13784517d1d..7d7c69341d9 100644 --- a/src/mongo/db/query/collation/collator_factory_mock.cpp +++ b/src/mongo/db/query/collation/collator_factory_mock.cpp @@ -41,8 +41,7 @@ namespace mongo { StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryMock::makeFromBSON( const BSONObj& spec) { - if (SimpleBSONObjComparator::kInstance.evaluate( - spec == BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison))) { + if (SimpleBSONObjComparator::kInstance.evaluate(spec == CollationSpec::kSimpleSpec)) { return {nullptr}; } auto collator = diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp index 66dd805d857..3e4ad61b94a 100644 --- a/src/mongo/db/s/migration_destination_manager.cpp +++ b/src/mongo/db/s/migration_destination_manager.cpp @@ -47,6 +47,7 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" #include "mongo/db/ops/delete.h" +#include "mongo/db/query/collation/collation_spec.h" #include "mongo/db/range_deleter_service.h" #include "mongo/db/repl/repl_client_info.h" #include "mongo/db/repl/replication_coordinator_global.h" @@ -528,12 +529,11 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn, if (spec["collation"]) { indexSpecsWithCollation.push_back(spec.getOwned()); } else { - indexSpecsWithCollation.emplace_back(BSONObjBuilder() - .appendElements(spec) - .append("collation", - BSON("locale" - << "simple")) - .obj()); + indexSpecsWithCollation.emplace_back( + BSONObjBuilder() + .appendElements(spec) + .append("collation", CollationSpec::kSimpleSpec) + .obj()); } } diff --git a/src/mongo/s/chunk_manager.cpp b/src/mongo/s/chunk_manager.cpp index 8cb5b7fcb71..cc7275e138c 100644 --- a/src/mongo/s/chunk_manager.cpp +++ b/src/mongo/s/chunk_manager.cpp @@ -464,15 +464,17 @@ Status ChunkManager::createFirstChunks(OperationContext* txn, return Status::OK(); } -shared_ptr<Chunk> ChunkManager::findIntersectingChunk(OperationContext* txn, - const BSONObj& shardKey, - const CollatorInterface* collator) const { +StatusWith<shared_ptr<Chunk>> ChunkManager::findIntersectingChunk(OperationContext* txn, + const BSONObj& shardKey, + const BSONObj& collation) const { { - if (collator) { + const bool hasSimpleCollation = (collation.isEmpty() && !_defaultCollator) || + SimpleBSONObjComparator::kInstance.evaluate(collation == CollationSpec::kSimpleSpec); + if (!hasSimpleCollation) { for (BSONElement elt : shardKey) { if (CollationIndexKey::isCollatableType(elt.type())) { - msgasserted(ErrorCodes::ShardKeyNotFound, - "cannot target single shard due to collation"); + return Status(ErrorCodes::ShardKeyNotFound, + "cannot target single shard due to collation"); } } } @@ -512,8 +514,12 @@ shared_ptr<Chunk> ChunkManager::findIntersectingChunk(OperationContext* txn, shared_ptr<Chunk> ChunkManager::findIntersectingChunkWithSimpleCollation( OperationContext* txn, const BSONObj& shardKey) const { - const CollatorInterface* collator = nullptr; - return findIntersectingChunk(txn, shardKey, collator); + auto chunk = findIntersectingChunk(txn, shardKey, CollationSpec::kSimpleSpec); + + // findIntersectingChunk() should succeed in targeting a single shard, since we have the simple + // collation. + massertStatusOK(chunk.getStatus()); + return chunk.getValue(); } void ChunkManager::getShardIdsForQuery(OperationContext* txn, @@ -541,18 +547,11 @@ void ChunkManager::getShardIdsForQuery(OperationContext* txn, // Fast path for targeting equalities on the shard key. auto shardKeyToFind = _keyPattern.extractShardKeyFromQuery(*cq); - if (shardKeyToFind.isOK() && !shardKeyToFind.getValue().isEmpty()) { - try { - auto chunk = findIntersectingChunk(txn, shardKeyToFind.getValue(), cq->getCollator()); - shardIds->insert(chunk->getShardId()); + if (!shardKeyToFind.isEmpty()) { + auto chunk = findIntersectingChunk(txn, shardKeyToFind, collation); + if (chunk.isOK()) { + shardIds->insert(chunk.getValue()->getShardId()); return; - } catch (const MsgAssertionException& msg) { - - // If we failed to find the intersecting chunk for a reason other than the inability to - // target a single shard, throw. - if (msg.getCode() != ErrorCodes::ShardKeyNotFound) { - throw msg; - } } } diff --git a/src/mongo/s/chunk_manager.h b/src/mongo/s/chunk_manager.h index caf4e8088bd..35b16ace0da 100644 --- a/src/mongo/s/chunk_manager.h +++ b/src/mongo/s/chunk_manager.h @@ -128,10 +128,15 @@ public: * For instance, to locate the chunk for document {a : "foo" , b : "bar"} * when the shard key is {a : "hashed"}, you can call * findIntersectingChunk() on {a : hash("foo") } + * + * If 'collation' is empty, we use the collection default collation for targeting. + * + * Returns the error status ShardKeyNotFound if unable to target a single shard due to the + * collation. */ - std::shared_ptr<Chunk> findIntersectingChunk(OperationContext* txn, - const BSONObj& shardKey, - const CollatorInterface* collator) const; + StatusWith<std::shared_ptr<Chunk>> findIntersectingChunk(OperationContext* txn, + const BSONObj& shardKey, + const BSONObj& collation) const; /* * Finds the intersecting chunk, assuming the simple collation. diff --git a/src/mongo/s/chunk_manager_targeter.cpp b/src/mongo/s/chunk_manager_targeter.cpp index 53d887914eb..2c07c609cee 100644 --- a/src/mongo/s/chunk_manager_targeter.cpp +++ b/src/mongo/s/chunk_manager_targeter.cpp @@ -34,9 +34,10 @@ #include <boost/thread/tss.hpp> +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/operation_context.h" +#include "mongo/db/query/canonical_query.h" #include "mongo/db/query/collation/collation_index_key.h" -#include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/s/chunk.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/config.h" @@ -116,25 +117,24 @@ UpdateType getUpdateExprType(const BSONObj& updateExpr) { * { _id : { $lt : 30 } } => false * { foo : <anything> } => false */ -bool isExactIdQuery(OperationContext* txn, - const BSONObj& query, - const CollatorInterface* collator, - ChunkManager* manager) { - StatusWith<BSONObj> status = virtualIdShardKey.extractShardKeyFromQuery(txn, query); - if (!status.isOK()) { +bool isExactIdQuery(OperationContext* txn, const CanonicalQuery& query, ChunkManager* manager) { + auto shardKey = virtualIdShardKey.extractShardKeyFromQuery(query); + BSONElement idElt = shardKey["_id"]; + + if (!idElt) { return false; } - BSONElement idElt = status.getValue()["_id"]; + if (CollationIndexKey::isCollatableType(idElt.type()) && manager && + !query.getQueryRequest().getCollation().isEmpty() && + !CollatorInterface::collatorsMatch(query.getCollator(), manager->getDefaultCollator())) { - bool hasCollectionDefaultCollation = true; - if (manager) { - hasCollectionDefaultCollation = - CollatorInterface::collatorsMatch(collator, manager->getDefaultCollator()); + // The collation applies to the _id field, but the user specified a collation which doesn't + // match the collection default. + return false; } - return idElt && - (hasCollectionDefaultCollation || !CollationIndexKey::isCollatableType(idElt.type())); + return true; } void refreshBackoff() { @@ -334,10 +334,7 @@ Status ChunkManagerTargeter::targetInsert(OperationContext* txn, // Target the shard key or database primary if (!shardKey.isEmpty()) { - - // Use the simple binary comparison collation. - const CollatorInterface* collator = nullptr; - return targetShardKey(txn, shardKey, collator, doc.objsize(), endpoint); + return targetShardKey(txn, shardKey, CollationSpec::kSimpleSpec, doc.objsize(), endpoint); } else { if (!_primary) { return Status(ErrorCodes::NamespaceNotFound, @@ -414,28 +411,14 @@ Status ChunkManagerTargeter::targetUpdate(OperationContext* txn, } } - // Construct the collator for the update. Use the collation from the update if specified, and - // the collection default collation otherwise. - BSONObj updateCollation = updateDoc.isCollationSet() ? updateDoc.getCollation() : BSONObj(); - std::unique_ptr<CollatorInterface> updateCollator; - if (!updateCollation.isEmpty()) { - auto statusWithCollator = CollatorFactoryInterface::get(txn->getServiceContext()) - ->makeFromBSON(updateDoc.getCollation()); - if (!statusWithCollator.isOK()) { - return statusWithCollator.getStatus(); - } - updateCollator = std::move(statusWithCollator.getValue()); - } - const CollatorInterface* collator = !updateCollation.isEmpty() - ? updateCollator.get() - : (_manager ? _manager->getDefaultCollator() : nullptr); + const BSONObj collation = updateDoc.isCollationSet() ? updateDoc.getCollation() : BSONObj(); // Target the shard key, query, or replacement doc if (!shardKey.isEmpty()) { // We can't rely on our query targeting to be exact ShardEndpoint* endpoint = NULL; Status result = targetShardKey( - txn, shardKey, collator, (query.objsize() + updateExpr.objsize()), &endpoint); + txn, shardKey, collation, (query.objsize() + updateExpr.objsize()), &endpoint); if (result.isOK()) { endpoints->push_back(endpoint); return result; @@ -447,24 +430,43 @@ Status ChunkManagerTargeter::targetUpdate(OperationContext* txn, // Upserts are required to target a single shard. if (_manager && updateDoc.getUpsert()) { return Status(ErrorCodes::ShardKeyNotFound, - stream() << "upsert " << updateDoc.toBSON() - << " does not contain shard key for pattern " - << _manager->getShardKeyPattern().toString()); + str::stream() << "An upsert on a sharded collection must contain the shard " + "key and have the simple collation. Update request: " + << updateDoc.toBSON() + << ", shard key pattern: " + << _manager->getShardKeyPattern().toString()); + } + + // Parse update query. + auto qr = stdx::make_unique<QueryRequest>(getNS()); + qr->setFilter(updateDoc.getQuery()); + if (!collation.isEmpty()) { + qr->setCollation(collation); + } + auto cq = CanonicalQuery::canonicalize(txn, std::move(qr), ExtensionsCallbackNoop()); + if (!cq.isOK()) { + return Status(cq.getStatus().code(), + str::stream() << "Could not parse update query " << updateDoc.getQuery() + << causedBy(cq.getStatus())); } // Single (non-multi) updates must target a single shard or be exact-ID. - if (_manager && !updateDoc.getMulti() && - !isExactIdQuery(txn, updateDoc.getQuery(), collator, _manager.get())) { + if (_manager && !updateDoc.getMulti() && !isExactIdQuery(txn, *cq.getValue(), _manager.get())) { return Status(ErrorCodes::ShardKeyNotFound, - stream() << "update " << updateDoc.toBSON() - << " does not contain _id or shard key for pattern " - << _manager->getShardKeyPattern().toString()); + str::stream() + << "A single update on a sharded collection must contain an exact " + "match on _id (and have the collection default collation) or " + "contain the shard key (and have the simple collation). Update " + "request: " + << updateDoc.toBSON() + << ", shard key pattern: " + << _manager->getShardKeyPattern().toString()); } if (updateType == UpdateType_OpStyle) { - return targetQuery(txn, query, updateCollation, endpoints); + return targetQuery(txn, query, collation, endpoints); } else { - return targetDoc(txn, updateExpr, updateCollation, endpoints); + return targetDoc(txn, updateExpr, collation, endpoints); } } @@ -491,28 +493,14 @@ Status ChunkManagerTargeter::targetDelete(OperationContext* txn, shardKey = status.getValue(); } - // Construct the collator for the delete. Use the collation from the delete if specified, and - // the collection default collation otherwise. - BSONObj deleteCollation = deleteDoc.isCollationSet() ? deleteDoc.getCollation() : BSONObj(); - std::unique_ptr<CollatorInterface> deleteCollator; - if (!deleteCollation.isEmpty()) { - auto statusWithCollator = CollatorFactoryInterface::get(txn->getServiceContext()) - ->makeFromBSON(deleteDoc.getCollation()); - if (!statusWithCollator.isOK()) { - return statusWithCollator.getStatus(); - } - deleteCollator = std::move(statusWithCollator.getValue()); - } - const CollatorInterface* collator = !deleteCollation.isEmpty() - ? deleteCollator.get() - : (_manager ? _manager->getDefaultCollator() : nullptr); + const BSONObj collation = deleteDoc.isCollationSet() ? deleteDoc.getCollation() : BSONObj(); // Target the shard key or delete query if (!shardKey.isEmpty()) { // We can't rely on our query targeting to be exact ShardEndpoint* endpoint = NULL; - Status result = targetShardKey(txn, shardKey, collator, 0, &endpoint); + Status result = targetShardKey(txn, shardKey, collation, 0, &endpoint); if (result.isOK()) { endpoints->push_back(endpoint); return result; @@ -521,16 +509,34 @@ Status ChunkManagerTargeter::targetDelete(OperationContext* txn, // We failed to target a single shard. + // Parse delete query. + auto qr = stdx::make_unique<QueryRequest>(getNS()); + qr->setFilter(deleteDoc.getQuery()); + if (!collation.isEmpty()) { + qr->setCollation(collation); + } + auto cq = CanonicalQuery::canonicalize(txn, std::move(qr), ExtensionsCallbackNoop()); + if (!cq.isOK()) { + return Status(cq.getStatus().code(), + str::stream() << "Could not parse delete query " << deleteDoc.getQuery() + << causedBy(cq.getStatus())); + } + // Single deletes must target a single shard or be exact-ID. if (_manager && deleteDoc.getLimit() == 1 && - !isExactIdQuery(txn, deleteDoc.getQuery(), collator, _manager.get())) { + !isExactIdQuery(txn, *cq.getValue(), _manager.get())) { return Status(ErrorCodes::ShardKeyNotFound, - stream() << "delete " << deleteDoc.toBSON() - << " does not contain _id or shard key for pattern " - << _manager->getShardKeyPattern().toString()); + str::stream() + << "A single delete on a sharded collection must contain an exact " + "match on _id (and have the collection default collation) or " + "contain the shard key (and have the simple collation). Delete " + "request: " + << deleteDoc.toBSON() + << ", shard key pattern: " + << _manager->getShardKeyPattern().toString()); } - return targetQuery(txn, deleteDoc.getQuery(), deleteCollation, endpoints); + return targetQuery(txn, deleteDoc.getQuery(), collation, endpoints); } Status ChunkManagerTargeter::targetDoc(OperationContext* txn, @@ -573,33 +579,26 @@ Status ChunkManagerTargeter::targetQuery(OperationContext* txn, Status ChunkManagerTargeter::targetShardKey(OperationContext* txn, const BSONObj& shardKey, - const CollatorInterface* collator, + const BSONObj& collation, long long estDataSize, ShardEndpoint** endpoint) const { invariant(NULL != _manager); - try { - auto chunk = _manager->findIntersectingChunk(txn, shardKey, collator); - - // Track autosplit stats for sharded collections - // Note: this is only best effort accounting and is not accurate. - if (estDataSize > 0) { - _stats->chunkSizeDelta[chunk->getMin()] += estDataSize; - } + auto chunk = _manager->findIntersectingChunk(txn, shardKey, collation); + if (!chunk.isOK()) { + return chunk.getStatus(); + } - *endpoint = - new ShardEndpoint(chunk->getShardId(), _manager->getVersion(chunk->getShardId())); + // Track autosplit stats for sharded collections + // Note: this is only best effort accounting and is not accurate. + if (estDataSize > 0) { + _stats->chunkSizeDelta[chunk.getValue()->getMin()] += estDataSize; + } - return Status::OK(); - } catch (const MsgAssertionException& msg) { - if (msg.getCode() == ErrorCodes::ShardKeyNotFound) { - return msg.toStatus(); - } + *endpoint = new ShardEndpoint(chunk.getValue()->getShardId(), + _manager->getVersion(chunk.getValue()->getShardId())); - // If we failed to find the intersecting chunk for a reason other than inability to target a - // single shard. - throw msg; - } + return Status::OK(); } Status ChunkManagerTargeter::targetCollection(vector<ShardEndpoint*>* endpoints) const { diff --git a/src/mongo/s/chunk_manager_targeter.h b/src/mongo/s/chunk_manager_targeter.h index b1f5e05defc..25ad4b417b4 100644 --- a/src/mongo/s/chunk_manager_targeter.h +++ b/src/mongo/s/chunk_manager_targeter.h @@ -128,6 +128,8 @@ private: * Returns a vector of ShardEndpoints where a document might need to be placed. * * Returns !OK with message if replacement could not be targeted + * + * If 'collation' is empty, we use the collection default collation for targeting. */ Status targetDoc(OperationContext* txn, const BSONObj& doc, @@ -138,6 +140,8 @@ private: * Returns a vector of ShardEndpoints for a potentially multi-shard query. * * Returns !OK with message if query could not be targeted. + * + * If 'collation' is empty, we use the collection default collation for targeting. */ Status targetQuery(OperationContext* txn, const BSONObj& query, @@ -149,10 +153,12 @@ private: * * Also has the side effect of updating the chunks stats with an estimate of the amount of * data targeted at this shard key. + * + * If 'collation' is empty, we use the collection default collation for targeting. */ Status targetShardKey(OperationContext* txn, const BSONObj& doc, - const CollatorInterface* collator, + const BSONObj& collation, long long estDataSize, ShardEndpoint** endpoint) const; diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp index 2da2b90f85e..bea947aedda 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -120,24 +120,15 @@ public: } BSONObj shardKey = status.getValue(); + auto chunk = chunkMgr->findIntersectingChunk(txn, shardKey, collation); - // Construct collator for targeting. - std::unique_ptr<CollatorInterface> collator; - if (!collation.isEmpty()) { - auto statusWithCollator = CollatorFactoryInterface::get(txn->getServiceContext()) - ->makeFromBSON(collation); - if (!statusWithCollator.isOK()) { - return statusWithCollator.getStatus(); - } - collator = std::move(statusWithCollator.getValue()); + if (!chunk.isOK()) { + uasserted(ErrorCodes::ShardKeyNotFound, + "findAndModify must target a single shard, but was not able to due " + "to non-simple collation"); } - auto chunk = chunkMgr->findIntersectingChunk( - txn, - shardKey, - !collation.isEmpty() ? collator.get() : chunkMgr->getDefaultCollator()); - - shard = Grid::get(txn)->shardRegistry()->getShard(txn, chunk->getShardId()); + shard = Grid::get(txn)->shardRegistry()->getShard(txn, chunk.getValue()->getShardId()); } BSONObjBuilder explainCmd; @@ -208,25 +199,19 @@ public: } BSONObj shardKey = status.getValue(); + auto chunk = chunkMgr->findIntersectingChunk(txn, shardKey, collation); - // Construct collator for targeting. - std::unique_ptr<CollatorInterface> collator; - if (!collation.isEmpty()) { - auto statusWithCollator = - CollatorFactoryInterface::get(txn->getServiceContext())->makeFromBSON(collation); - if (!statusWithCollator.isOK()) { - return appendCommandStatus(result, statusWithCollator.getStatus()); - } - collator = std::move(statusWithCollator.getValue()); + if (!chunk.isOK()) { + uasserted(ErrorCodes::ShardKeyNotFound, + "findAndModify must target a single shard, but was not able to due to " + "non-simple collation"); } - auto chunk = chunkMgr->findIntersectingChunk( - txn, shardKey, !collation.isEmpty() ? collator.get() : chunkMgr->getDefaultCollator()); - - bool ok = _runCommand(txn, conf, chunkMgr, chunk->getShardId(), nss, cmdObj, result); + bool ok = + _runCommand(txn, conf, chunkMgr, chunk.getValue()->getShardId(), nss, cmdObj, result); if (ok) { // check whether split is necessary (using update object for size heuristic) - chunk->splitIfShould(txn, cmdObj.getObjectField("update").objsize()); + chunk.getValue()->splitIfShould(txn, cmdObj.getObjectField("update").objsize()); } return ok; diff --git a/src/mongo/s/commands/cluster_index_filter_cmd.cpp b/src/mongo/s/commands/cluster_index_filter_cmd.cpp index 3a0824cddbf..52cdebea5d5 100644 --- a/src/mongo/s/commands/cluster_index_filter_cmd.cpp +++ b/src/mongo/s/commands/cluster_index_filter_cmd.cpp @@ -107,9 +107,8 @@ public: // commands are tied to query shape (data has no effect on query shape). vector<Strategy::CommandResult> results; const BSONObj query; - const BSONObj collation = - BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison); - Strategy::commandOp(txn, dbname, cmdObj, options, nss.ns(), query, collation, &results); + Strategy::commandOp( + txn, dbname, cmdObj, options, nss.ns(), query, CollationSpec::kSimpleSpec, &results); // Set value of first shard result's "ok" field. bool clusterCmdResult = true; diff --git a/src/mongo/s/commands/cluster_map_reduce_cmd.cpp b/src/mongo/s/commands/cluster_map_reduce_cmd.cpp index 55dacd87207..efae5d2c4d1 100644 --- a/src/mongo/s/commands/cluster_map_reduce_cmd.cpp +++ b/src/mongo/s/commands/cluster_map_reduce_cmd.cpp @@ -525,15 +525,13 @@ public: try { const BSONObj query; - const BSONObj simpleCollation = - BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison); Strategy::commandOp(txn, outDB, finalCmdObj, 0, outputCollNss.ns(), query, - simpleCollation, + CollationSpec::kSimpleSpec, &mrCommandResults); ok = true; } catch (DBException& e) { diff --git a/src/mongo/s/commands/cluster_pipeline_cmd.cpp b/src/mongo/s/commands/cluster_pipeline_cmd.cpp index cf429b47cbd..99420f0ce57 100644 --- a/src/mongo/s/commands/cluster_pipeline_cmd.cpp +++ b/src/mongo/s/commands/cluster_pipeline_cmd.cpp @@ -175,16 +175,10 @@ public: chunkMgr->getShardKeyPattern().extractShardKeyFromQuery(txn, firstMatchQuery)); bool singleShard = false; if (!shardKeyMatches.isEmpty()) { - try { - auto chunk = - chunkMgr->findIntersectingChunk(txn, shardKeyMatches, mergeCtx->getCollator()); + auto chunk = chunkMgr->findIntersectingChunk( + txn, shardKeyMatches, request.getValue().getCollation()); + if (chunk.isOK()) { singleShard = true; - } catch (const MsgAssertionException& msg) { - if (msg.getCode() == ErrorCodes::ShardKeyNotFound) { - singleShard = false; - } else { - throw msg; - } } } @@ -293,8 +287,7 @@ public: mergeCmd.setField("collation", mergeCtx->getCollator() ? Value(mergeCtx->getCollator()->getSpec().toBSON()) - : Value(Document{{CollationSpec::kLocaleField, - CollationSpec::kSimpleBinaryComparison}})); + : Value(Document{CollationSpec::kSimpleSpec})); } string outputNsOrEmpty; diff --git a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp index bb053e15f26..fea10e3de88 100644 --- a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp +++ b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp @@ -123,9 +123,8 @@ bool ClusterPlanCacheCmd::run(OperationContext* txn, // commands are tied to query shape (data has no effect on query shape). vector<Strategy::CommandResult> results; const BSONObj query; - const BSONObj collation = - BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison); - Strategy::commandOp(txn, dbName, cmdObj, options, nss.ns(), query, collation, &results); + Strategy::commandOp( + txn, dbName, cmdObj, options, nss.ns(), query, CollationSpec::kSimpleSpec, &results); // Set value of first shard result's "ok" field. bool clusterCmdResult = true; diff --git a/src/mongo/s/commands/cluster_shard_collection_cmd.cpp b/src/mongo/s/commands/cluster_shard_collection_cmd.cpp index 8bc1b75825d..2d4d55bff4c 100644 --- a/src/mongo/s/commands/cluster_shard_collection_cmd.cpp +++ b/src/mongo/s/commands/cluster_shard_collection_cmd.cpp @@ -403,11 +403,7 @@ public: // Only need to call ensureIndex on primary shard, since indexes get copied to // receiving shard whenever a migrate occurs. Status status = clusterCreateIndex( - txn, - nss.ns(), - proposedKey, - BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison), - careAboutUnique); + txn, nss.ns(), proposedKey, CollationSpec::kSimpleSpec, careAboutUnique); if (!status.isOK()) { errmsg = str::stream() << "ensureIndex failed to create index on " << "primary shard: " << status.reason(); diff --git a/src/mongo/s/commands/commands_public.cpp b/src/mongo/s/commands/commands_public.cpp index e74e4abd1ef..a8babdb81d8 100644 --- a/src/mongo/s/commands/commands_public.cpp +++ b/src/mongo/s/commands/commands_public.cpp @@ -461,9 +461,8 @@ public: vector<Strategy::CommandResult> results; const BSONObj query; - const BSONObj collation = - BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison); - Strategy::commandOp(txn, dbName, cmdObj, options, cm->getns(), query, collation, &results); + Strategy::commandOp( + txn, dbName, cmdObj, options, cm->getns(), query, CollationSpec::kSimpleSpec, &results); BSONObjBuilder rawResBuilder(output.subobjStart("raw")); bool isValid = true; @@ -1383,9 +1382,8 @@ public: BSONObj finder = BSON("files_id" << cmdObj.firstElement()); vector<Strategy::CommandResult> results; - const BSONObj collation = - BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison); - Strategy::commandOp(txn, dbName, cmdObj, 0, fullns, finder, collation, &results); + Strategy::commandOp( + txn, dbName, cmdObj, 0, fullns, finder, CollationSpec::kSimpleSpec, &results); verify(results.size() == 1); // querying on shard key so should only talk to one shard BSONObj res = results.begin()->result; @@ -1417,11 +1415,15 @@ public: BSONObj finder = BSON("files_id" << cmdObj.firstElement() << "n" << n); vector<Strategy::CommandResult> results; - const BSONObj collation = - BSON(CollationSpec::kLocaleField << CollationSpec::kSimpleBinaryComparison); try { - Strategy::commandOp( - txn, dbName, shardCmd, 0, fullns, finder, collation, &results); + Strategy::commandOp(txn, + dbName, + shardCmd, + 0, + fullns, + finder, + CollationSpec::kSimpleSpec, + &results); } catch (DBException& e) { // This is handled below and logged Strategy::CommandResult errResult; diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index 3ec6bd8809e..1a8e77658e1 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -282,9 +282,9 @@ StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(OperationContext* return extractShardKeyFromQuery(*query); } -StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(const CanonicalQuery& query) const { +BSONObj ShardKeyPattern::extractShardKeyFromQuery(const CanonicalQuery& query) const { if (!isValid()) - return StatusWith<BSONObj>(BSONObj()); + return BSONObj(); // Extract equalities from query. EqualityMatches equalities; @@ -297,7 +297,7 @@ StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(const CanonicalQue // NOTE: Failure to extract equality matches just means we return no shard key - it's not // an error we propagate if (!eqStatus.isOK()) - return StatusWith<BSONObj>(BSONObj()); + return BSONObj(); // Extract key from equalities // NOTE: The method below is equivalent to constructing a BSONObj and running @@ -312,7 +312,7 @@ StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(const CanonicalQue BSONElement equalEl = findEqualityElement(equalities, patternPath); if (!isShardKeyElement(equalEl, false)) - return StatusWith<BSONObj>(BSONObj()); + return BSONObj(); if (isHashedPattern()) { keyBuilder.append( @@ -326,7 +326,7 @@ StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(const CanonicalQue } dassert(isShardKey(keyBuilder.asTempObj())); - return StatusWith<BSONObj>(keyBuilder.obj()); + return keyBuilder.obj(); } bool ShardKeyPattern::isUniqueIndexCompatible(const BSONObj& uniqueIndexPattern) const { diff --git a/src/mongo/s/shard_key_pattern.h b/src/mongo/s/shard_key_pattern.h index 1a8cfe91cd5..52858a0100e 100644 --- a/src/mongo/s/shard_key_pattern.h +++ b/src/mongo/s/shard_key_pattern.h @@ -166,7 +166,7 @@ public: */ StatusWith<BSONObj> extractShardKeyFromQuery(OperationContext* txn, const BSONObj& basicQuery) const; - StatusWith<BSONObj> extractShardKeyFromQuery(const CanonicalQuery& query) const; + BSONObj extractShardKeyFromQuery(const CanonicalQuery& query) const; /** * Returns true if the shard key pattern can ensure that the unique index pattern is |