summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTess Avitabile <tess.avitabile@mongodb.com>2016-08-17 12:11:32 -0400
committerTess Avitabile <tess.avitabile@mongodb.com>2016-08-23 10:05:02 -0400
commit01a1b877bc7d103646ecc8608a8df89d74de1324 (patch)
tree7355fdfbca4f6d235bfe5fd414520c18c1a28c41
parent5c115e6ad38cd81e96c05ff2be5af17baeaedd68 (diff)
downloadmongo-01a1b877bc7d103646ecc8608a8df89d74de1324.tar.gz
SERVER-24439 code cleanup for collation shard targeting
-rw-r--r--src/mongo/db/pipeline/document_source_geo_near.cpp5
-rw-r--r--src/mongo/db/query/collation/collation_spec.cpp2
-rw-r--r--src/mongo/db/query/collation/collation_spec.h3
-rw-r--r--src/mongo/db/query/collation/collator_factory_mock.cpp3
-rw-r--r--src/mongo/db/s/migration_destination_manager.cpp12
-rw-r--r--src/mongo/s/chunk_manager.cpp37
-rw-r--r--src/mongo/s/chunk_manager.h11
-rw-r--r--src/mongo/s/chunk_manager_targeter.cpp169
-rw-r--r--src/mongo/s/chunk_manager_targeter.h8
-rw-r--r--src/mongo/s/commands/cluster_find_and_modify_cmd.cpp43
-rw-r--r--src/mongo/s/commands/cluster_index_filter_cmd.cpp5
-rw-r--r--src/mongo/s/commands/cluster_map_reduce_cmd.cpp4
-rw-r--r--src/mongo/s/commands/cluster_pipeline_cmd.cpp15
-rw-r--r--src/mongo/s/commands/cluster_plan_cache_cmd.cpp5
-rw-r--r--src/mongo/s/commands/cluster_shard_collection_cmd.cpp6
-rw-r--r--src/mongo/s/commands/commands_public.cpp22
-rw-r--r--src/mongo/s/shard_key_pattern.cpp10
-rw-r--r--src/mongo/s/shard_key_pattern.h2
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