From 651d5bd1fcc36cbaffb69f46617b81937fbf94c4 Mon Sep 17 00:00:00 2001 From: krk Date: Thu, 4 Jul 2019 21:39:22 +0200 Subject: [PATCH 1/7] SERVER-41854 Add meta projection $shardName. --- src/mongo/db/SConscript | 2 + .../document_metadata_fields.cpp | 6 + .../document_value/document_metadata_fields.h | 20 ++++ .../document_metadata_fields_test.cpp | 11 ++ src/mongo/db/exec/projection_exec.cpp | 20 +++- src/mongo/db/exec/projection_exec.h | 18 ++- src/mongo/db/exec/shard_name.cpp | 104 ++++++++++++++++++ src/mongo/db/exec/shard_name.h | 70 ++++++++++++ src/mongo/db/exec/shard_namer.h | 47 ++++++++ src/mongo/db/exec/shard_namer_impl.cpp | 47 ++++++++ src/mongo/db/exec/shard_namer_impl.h | 52 +++++++++ src/mongo/db/query/get_executor.cpp | 3 +- src/mongo/db/query/parsed_projection.cpp | 7 +- src/mongo/db/query/parsed_projection.h | 6 + src/mongo/db/query/planner_analysis.cpp | 7 +- src/mongo/db/query/query_request.cpp | 29 +++-- src/mongo/db/query/query_request.h | 13 +++ src/mongo/db/query/query_solution.cpp | 26 +++++ src/mongo/db/query/query_solution.h | 29 +++++ src/mongo/db/query/stage_builder.cpp | 12 ++ src/mongo/db/query/stage_types.h | 1 + 21 files changed, 512 insertions(+), 18 deletions(-) create mode 100644 src/mongo/db/exec/shard_name.cpp create mode 100644 src/mongo/db/exec/shard_name.h create mode 100644 src/mongo/db/exec/shard_namer.h create mode 100644 src/mongo/db/exec/shard_namer_impl.cpp create mode 100644 src/mongo/db/exec/shard_namer_impl.h diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 0170303b829d9..1707214584a1c 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1027,6 +1027,8 @@ env.Library( 'exec/return_key.cpp', 'exec/shard_filter.cpp', 'exec/shard_filterer_impl.cpp', + 'exec/shard_name.cpp', + 'exec/shard_namer_impl.cpp', 'exec/skip.cpp', 'exec/sort.cpp', 'exec/sort_key_generator.cpp', diff --git a/src/mongo/db/exec/document_value/document_metadata_fields.cpp b/src/mongo/db/exec/document_value/document_metadata_fields.cpp index c7c2e4d202da8..01a3ff36ff932 100644 --- a/src/mongo/db/exec/document_value/document_metadata_fields.cpp +++ b/src/mongo/db/exec/document_value/document_metadata_fields.cpp @@ -173,6 +173,10 @@ void DocumentMetadataFields::serializeForSorter(BufBuilder& buf) const { buf.appendNum(static_cast(MetaType::kIndexKey + 1)); getIndexKey().appendSelfToBufBuilder(buf); } + if (hasShardName()) { + buf.appendNum(static_cast(MetaType::kShardName + 1)); + buf.appendStr(getShardName()); + } buf.appendNum(static_cast(0)); } @@ -201,6 +205,8 @@ void DocumentMetadataFields::deserializeForSorter(BufReader& buf, DocumentMetada } else if (marker == static_cast(MetaType::kIndexKey) + 1) { out->setIndexKey( BSONObj::deserializeForSorter(buf, BSONObj::SorterDeserializeSettings())); + } else if (marker == static_cast(MetaType::kShardName) + 1) { + out->setShardName(buf.readCStr()); } else { uasserted(28744, "Unrecognized marker, unable to deserialize buffer"); } diff --git a/src/mongo/db/exec/document_value/document_metadata_fields.h b/src/mongo/db/exec/document_value/document_metadata_fields.h index ef4627b14c6b0..ecb70ef84ae71 100644 --- a/src/mongo/db/exec/document_value/document_metadata_fields.h +++ b/src/mongo/db/exec/document_value/document_metadata_fields.h @@ -64,6 +64,7 @@ class DocumentMetadataFields { kSearchScore, kSortKey, kTextScore, + kShardName, // New fields must be added before the kNumFields sentinel. kNumFields @@ -302,6 +303,24 @@ class DocumentMetadataFields { _holder->recordId = rid; } + bool hasShardName() const { + return _holder && _holder->metaFields.test(MetaType::kShardName); + } + + StringData getShardName() const { + invariant(hasShardName()); + return _holder->shardName; + } + + void setShardName(StringData shardName) { + if (!_holder) { + _holder = std::make_unique(); + } + + _holder->metaFields.set(MetaType::kShardName); + _holder->shardName = shardName; + } + void serializeForSorter(BufBuilder& buf) const; private: @@ -323,6 +342,7 @@ class DocumentMetadataFields { Value searchHighlights; BSONObj indexKey; RecordId recordId; + StringData shardName; }; // Null until the first setter is called, at which point a MetadataHolder struct is allocated. diff --git a/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp b/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp index b19127ef22634..e4571b0404c59 100644 --- a/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp +++ b/src/mongo/db/exec/document_value/document_metadata_fields_test.cpp @@ -48,6 +48,7 @@ TEST(DocumentMetadataFieldsTest, AllMetadataRoundtripsThroughSerialization) { metadata.setSearchScore(5.4); metadata.setSearchHighlights(Value{"foo"_sd}); metadata.setIndexKey(BSON("b" << 1)); + metadata.setShardName("bar"); BufBuilder builder; metadata.serializeForSorter(builder); @@ -64,6 +65,7 @@ TEST(DocumentMetadataFieldsTest, AllMetadataRoundtripsThroughSerialization) { ASSERT_EQ(deserialized.getSearchScore(), 5.4); ASSERT_VALUE_EQ(deserialized.getSearchHighlights(), Value{"foo"_sd}); ASSERT_BSONOBJ_EQ(deserialized.getIndexKey(), BSON("b" << 1)); + ASSERT_EQ(deserialized.getShardName(), "bar"); } TEST(DocumentMetadataFieldsTest, HasMethodsReturnFalseForEmptyMetadata) { @@ -77,6 +79,7 @@ TEST(DocumentMetadataFieldsTest, HasMethodsReturnFalseForEmptyMetadata) { ASSERT_FALSE(metadata.hasSearchScore()); ASSERT_FALSE(metadata.hasSearchHighlights()); ASSERT_FALSE(metadata.hasIndexKey()); + ASSERT_FALSE(metadata.hasShardName()); } TEST(DocumentMetadataFieldsTest, HasMethodsReturnTrueForInitializedMetadata) { @@ -114,6 +117,10 @@ TEST(DocumentMetadataFieldsTest, HasMethodsReturnTrueForInitializedMetadata) { ASSERT_FALSE(metadata.hasIndexKey()); metadata.setIndexKey(BSON("b" << 1)); ASSERT_TRUE(metadata.hasIndexKey()); + + ASSERT_FALSE(metadata.hasShardName()); + metadata.setShardName("bar"); + ASSERT_TRUE(metadata.hasShardName()); } TEST(DocumentMetadataFieldsTest, MoveConstructor) { @@ -126,6 +133,7 @@ TEST(DocumentMetadataFieldsTest, MoveConstructor) { metadata.setSearchScore(5.4); metadata.setSearchHighlights(Value{"foo"_sd}); metadata.setIndexKey(BSON("b" << 1)); + metadata.setShardName("bar"); DocumentMetadataFields moveConstructed(std::move(metadata)); ASSERT_TRUE(moveConstructed); @@ -138,6 +146,7 @@ TEST(DocumentMetadataFieldsTest, MoveConstructor) { ASSERT_EQ(moveConstructed.getSearchScore(), 5.4); ASSERT_VALUE_EQ(moveConstructed.getSearchHighlights(), Value{"foo"_sd}); ASSERT_BSONOBJ_EQ(moveConstructed.getIndexKey(), BSON("b" << 1)); + ASSERT_EQ(moveConstructed.getShardName(), "bar"); ASSERT_FALSE(metadata); } @@ -152,6 +161,7 @@ TEST(DocumentMetadataFieldsTest, MoveAssignmentOperator) { metadata.setSearchScore(5.4); metadata.setSearchHighlights(Value{"foo"_sd}); metadata.setIndexKey(BSON("b" << 1)); + metadata.setShardName("bar"); DocumentMetadataFields moveAssigned; moveAssigned.setTextScore(12.3); @@ -167,6 +177,7 @@ TEST(DocumentMetadataFieldsTest, MoveAssignmentOperator) { ASSERT_EQ(moveAssigned.getSearchScore(), 5.4); ASSERT_VALUE_EQ(moveAssigned.getSearchHighlights(), Value{"foo"_sd}); ASSERT_BSONOBJ_EQ(moveAssigned.getIndexKey(), BSON("b" << 1)); + ASSERT_EQ(moveAssigned.getShardName(), "bar"); ASSERT_FALSE(metadata); } diff --git a/src/mongo/db/exec/projection_exec.cpp b/src/mongo/db/exec/projection_exec.cpp index bf212a0b44b6d..a49d8fa8b9cc4 100644 --- a/src/mongo/db/exec/projection_exec.cpp +++ b/src/mongo/db/exec/projection_exec.cpp @@ -116,6 +116,9 @@ ProjectionExec::ProjectionExec(OperationContext* opCtx, } else if (e2.valuestr() == QueryRequest::metaGeoNearDistance) { _meta[e.fieldName()] = META_GEONEAR_DIST; _needsGeoNearDistance = true; + } else if (e2.valuestr() == QueryRequest::metaShardName) { + _meta[e.fieldName()] = META_SHARD_NAME; + _needsShardName = true; } else { // This shouldn't happen, should be caught by parsing. MONGO_UNREACHABLE; @@ -202,7 +205,8 @@ StatusWith ProjectionExec::project(const BSONObj& in, Value geoNearPoint, const BSONObj& sortKey, const boost::optional textScore, - const int64_t recordId) const { + const int64_t recordId, + const StringData& shardName) const { BSONObjBuilder bob; MatchDetails matchDetails; @@ -217,7 +221,7 @@ StatusWith ProjectionExec::project(const BSONObj& in, if (!projStatus.isOK()) return projStatus; else - return {addMeta(std::move(bob), geoDistance, geoNearPoint, sortKey, textScore, recordId)}; + return {addMeta(std::move(bob), geoDistance, geoNearPoint, sortKey, textScore, recordId, shardName)}; } StatusWith ProjectionExec::projectCovered(const std::vector& keyData, @@ -225,7 +229,8 @@ StatusWith ProjectionExec::projectCovered(const std::vector textScore, - const int64_t recordId) const { + const int64_t recordId, + const StringData& shardName) const { invariant(!_include); BSONObjBuilder bob; // Go field by field. @@ -270,7 +275,7 @@ StatusWith ProjectionExec::projectCovered(const std::vector textScore, - const int64_t recordId) const { + const int64_t recordId, + const StringData& shardName) const { for (MetaMap::const_iterator it = _meta.begin(); it != _meta.end(); ++it) { switch (it->second) { case META_GEONEAR_DIST: @@ -299,6 +305,10 @@ BSONObj ProjectionExec::addMeta(BSONObjBuilder bob, bob.append(it->first, sortKey); break; } + case META_SHARD_NAME: { + bob.append(it->first, shardName); + break; + } case META_RECORDID: invariant(recordId != 0); bob.append(it->first, recordId); diff --git a/src/mongo/db/exec/projection_exec.h b/src/mongo/db/exec/projection_exec.h index 784fe2fb209cf..029d9ee94b624 100644 --- a/src/mongo/db/exec/projection_exec.h +++ b/src/mongo/db/exec/projection_exec.h @@ -63,6 +63,7 @@ class ProjectionExec { META_RECORDID, META_SORT_KEY, META_TEXT_SCORE, + META_SHARD_NAME, }; /** @@ -108,6 +109,13 @@ class ProjectionExec { return _needsTextScore; } + /** + * Indicates whether 'shardName' is going to be used in 'project()'. + */ + bool needsShardName() const { + return _needsShardName; + } + /** * Returns false if there are no meta fields to project. */ @@ -124,7 +132,8 @@ class ProjectionExec { Value geoNearPoint = Value{}, const BSONObj& sortKey = BSONObj(), const boost::optional textScore = boost::none, - const int64_t recordId = 0) const; + const int64_t recordId = 0, + const StringData& shardName = StringData("")) const; /** * Performs a projection given index 'KeyData' to directly retrieve results. This function @@ -137,7 +146,8 @@ class ProjectionExec { Value geoNearPoint = Value{}, const BSONObj& sortKey = BSONObj(), const boost::optional textScore = boost::none, - const int64_t recordId = 0) const; + const int64_t recordId = 0, + const StringData& shardName = StringData("")) const; /** * Determines if calls to the project method require that this object was created with the full @@ -157,7 +167,8 @@ class ProjectionExec { Value geoNearPoint, const BSONObj& sortKey, const boost::optional textScore, - const int64_t recordId) const; + const int64_t recordId, + const StringData& shardName) const; // // Initialization @@ -251,6 +262,7 @@ class ProjectionExec { bool _needsGeoNearDistance = false; bool _needsGeoNearPoint = false; bool _needsTextScore = false; + bool _needsShardName = false; // The collator this projection should use to compare strings. Needed for projection operators // that perform matching (e.g. elemMatch projection). If null, the collation is a simple binary diff --git a/src/mongo/db/exec/shard_name.cpp b/src/mongo/db/exec/shard_name.cpp new file mode 100644 index 0000000000000..7d5e236a3ad2e --- /dev/null +++ b/src/mongo/db/exec/shard_name.cpp @@ -0,0 +1,104 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/exec/shard_name.h" + +#include + +#include "mongo/db/exec/filter.h" +#include "mongo/db/exec/scoped_timer.h" +#include "mongo/db/exec/working_set_common.h" +#include "mongo/s/shard_key_pattern.h" + +namespace mongo { + +using std::shared_ptr; +using std::unique_ptr; +using std::vector; +using std::string; + +// static +const char* ShardNameStage::kStageType = "SHARD_NAME"; + +ShardNameStage::ShardNameStage(OperationContext* opCtx, + ScopedCollectionMetadata metadata, + WorkingSet* ws, + std::unique_ptr child) + : PlanStage(kStageType, opCtx), _ws(ws), _shardNamer(std::move(metadata)) { + _children.emplace_back(std::move(child)); +} + +ShardNameStage::~ShardNameStage() {} + +bool ShardNameStage::isEOF() { + return child()->isEOF(); +} + +PlanStage::StageState ShardNameStage::doWork(WorkingSetID* out) { + // If we've returned as many results as we're limited to, isEOF will be true. + if (isEOF()) { + return PlanStage::IS_EOF; + } + + StageState status = child()->work(out); + + if (PlanStage::ADVANCED == status) { + // If we're sharded make sure to add shardName to the output. + if (_shardNamer.isCollectionSharded()) { + WorkingSetMember* member = _ws->get(*out); + const StringData shardName = _shardNamer.shardName(); + + // Populate the working set member with the shard name and return it. + member->metadata().setShardName(shardName); + } + + // If we're here either we have shard state and added the shardName, or we have no shard + // state. Either way, we advance. + return status; + } + + return status; +} + +unique_ptr ShardNameStage::getStats() { + _commonStats.isEOF = isEOF(); + unique_ptr ret = + std::make_unique(_commonStats, STAGE_SHARD_NAME); + ret->children.emplace_back(child()->getStats()); + return ret; +} + +const SpecificStats* ShardNameStage::getSpecificStats() const { + // No specific stats are tracked for the shard name stage. + return nullptr; +} + +} // namespace mongo diff --git a/src/mongo/db/exec/shard_name.h b/src/mongo/db/exec/shard_name.h new file mode 100644 index 0000000000000..2c1edeb944ad9 --- /dev/null +++ b/src/mongo/db/exec/shard_name.h @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/db/exec/plan_stage.h" +#include "mongo/db/exec/shard_namer_impl.h" + +namespace mongo { + +class ShardNameStage final : public PlanStage { +public: + ShardNameStage(OperationContext* opCtx, + ScopedCollectionMetadata metadata, + WorkingSet* ws, + std::unique_ptr child); + ~ShardNameStage(); + + bool isEOF() final; + StageState doWork(WorkingSetID* out) final; + + StageType stageType() const final { + return STAGE_SHARD_NAME; + } + + std::unique_ptr getStats() final; + + const SpecificStats* getSpecificStats() const final; + + static const char* kStageType; + +private: + WorkingSet* _ws; + + // Note: it is important that this owns the ScopedCollectionMetadata from the time this stage + // is constructed. See ScopedCollectionMetadata class comment and MetadataManager comment for + // details. The existence of the ScopedCollectionMetadata prevents data which may have been + // migrated from being deleted while the query is still active. If we didn't hold one + // ScopedCollectionMetadata for the entire query, it'd be possible for data which the query + // needs to read to be deleted while it's still running. + ShardNamerImpl _shardNamer; +}; + +} // namespace mongo diff --git a/src/mongo/db/exec/shard_namer.h b/src/mongo/db/exec/shard_namer.h new file mode 100644 index 0000000000000..4944ea7863272 --- /dev/null +++ b/src/mongo/db/exec/shard_namer.h @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/db/matcher/matchable.h" +#include "mongo/db/operation_context.h" + +namespace mongo { + +/** + * Interface for naming shards, to be used by both the find and agg execution trees. + */ +class ShardNamer { +public: + virtual ~ShardNamer() = default; + + virtual const StringData shardName() const = 0; + virtual bool isCollectionSharded() const = 0; +}; +} // namespace mongo diff --git a/src/mongo/db/exec/shard_namer_impl.cpp b/src/mongo/db/exec/shard_namer_impl.cpp new file mode 100644 index 0000000000000..6c2404a0150b0 --- /dev/null +++ b/src/mongo/db/exec/shard_namer_impl.cpp @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/exec/shard_namer_impl.h" + +#include "mongo/db/matcher/matchable.h" +#include "mongo/db/s/scoped_collection_metadata.h" + +namespace mongo { + +ShardNamerImpl::ShardNamerImpl(ScopedCollectionMetadata md) : _metadata(std::move(md)), + _shardName(isCollectionSharded() ? _metadata->shardId() : StringData("")) { +} + +const StringData ShardNamerImpl::shardName() const { + return _shardName; +} + +} // namespace mongo diff --git a/src/mongo/db/exec/shard_namer_impl.h b/src/mongo/db/exec/shard_namer_impl.h new file mode 100644 index 0000000000000..0725ca1b027e5 --- /dev/null +++ b/src/mongo/db/exec/shard_namer_impl.h @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2019-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include "mongo/db/exec/shard_namer.h" +#include "mongo/db/matcher/matchable.h" +#include "mongo/db/s/scoped_collection_metadata.h" + +namespace mongo { + +class ShardNamerImpl : public ShardNamer { +public: + ShardNamerImpl(ScopedCollectionMetadata md); + + const StringData shardName() const override; + + bool isCollectionSharded() const override { + return _metadata->isSharded(); + } + +private: + ScopedCollectionMetadata _metadata; + const StringData _shardName; +}; +} // namespace mongo diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index ced708e90dcad..4a50514e7c185 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -418,7 +418,8 @@ StatusWith prepareExecution(OperationContext* opCtx, // document, so we don't support covered projections. However, we might use the // simple inclusion fast path. // Stuff the right data into the params depending on what proj impl we use. - if (!cqProjection->isSimple()) { + if (!cqProjection->isSimple() || + canonicalQuery->metadataDeps()[DocumentMetadataFields::kShardName]) { root = std::make_unique( canonicalQuery->getExpCtx(), canonicalQuery->getQueryRequest().getProj(), diff --git a/src/mongo/db/query/parsed_projection.cpp b/src/mongo/db/query/parsed_projection.cpp index 165a27e66bb61..700d26d87d558 100644 --- a/src/mongo/db/query/parsed_projection.cpp +++ b/src/mongo/db/query/parsed_projection.cpp @@ -60,6 +60,7 @@ Status ParsedProjection::make(OperationContext* opCtx, bool wantGeoNearPoint = false; bool wantGeoNearDistance = false; bool wantSortKey = false; + bool wantShardName = false; // Until we see a positional or elemMatch operator we're normal. ArrayOpType arrayOpType = ARRAY_OP_NORMAL; @@ -161,7 +162,8 @@ Status ParsedProjection::make(OperationContext* opCtx, e2.valuestr() != QueryRequest::metaRecordId && e2.valuestr() != QueryRequest::metaGeoNearDistance && e2.valuestr() != QueryRequest::metaGeoNearPoint && - e2.valuestr() != QueryRequest::metaSortKey) { + e2.valuestr() != QueryRequest::metaSortKey && + e2.valuestr() != QueryRequest::metaShardName) { return Status(ErrorCodes::BadValue, "unsupported $meta operator: " + e2.str()); } @@ -174,6 +176,8 @@ Status ParsedProjection::make(OperationContext* opCtx, wantGeoNearPoint = true; } else if (e2.valuestr() == QueryRequest::metaSortKey) { wantSortKey = true; + } else if (e2.valuestr() == QueryRequest::metaShardName) { + wantShardName = true; } // Of the $meta projections, only sortKey can be covered. @@ -270,6 +274,7 @@ Status ParsedProjection::make(OperationContext* opCtx, pp->_wantGeoNearPoint = wantGeoNearPoint; pp->_wantGeoNearDistance = wantGeoNearDistance; pp->_wantSortKey = wantSortKey; + pp->_wantShardName = wantShardName; // If it's possible to compute the projection in a covered fashion, populate _requiredFields // so the planner can perform projection analysis. diff --git a/src/mongo/db/query/parsed_projection.h b/src/mongo/db/query/parsed_projection.h index 1d9063acf05ec..50efc91ab19f3 100644 --- a/src/mongo/db/query/parsed_projection.h +++ b/src/mongo/db/query/parsed_projection.h @@ -104,6 +104,10 @@ class ParsedProjection { return _wantSortKey; } + bool wantShardName() const { + return _wantShardName; + } + /** * Returns true if the element at 'path' is preserved entirely after this projection is applied, * and false otherwise. For example, the projection {a: 1} will preserve the element located at @@ -192,6 +196,8 @@ class ParsedProjection { // Whether this projection includes a sortKey meta-projection. bool _wantSortKey = false; + bool _wantShardName = false; + bool _hasDottedFieldPath = false; }; diff --git a/src/mongo/db/query/planner_analysis.cpp b/src/mongo/db/query/planner_analysis.cpp index 27405653ae712..a2767fc9bbf7d 100644 --- a/src/mongo/db/query/planner_analysis.cpp +++ b/src/mongo/db/query/planner_analysis.cpp @@ -384,7 +384,12 @@ std::unique_ptr analyzeProjection(const CanonicalQuery& query, } } } - + auto wantShardName = query.metadataDeps()[DocumentMetadataFields::kShardName]; + if (wantShardName) { + auto shardNameNode = std::make_unique(); + shardNameNode->children.push_back(solnRoot.release()); + solnRoot = std::move(shardNameNode); + } return std::make_unique( addSortKeyGeneratorStageIfNeeded(query, hasSortStage, std::move(solnRoot)), *query.root(), diff --git a/src/mongo/db/query/query_request.cpp b/src/mongo/db/query/query_request.cpp index d50d8a10f4db7..3bff497e43b97 100644 --- a/src/mongo/db/query/query_request.cpp +++ b/src/mongo/db/query/query_request.cpp @@ -61,6 +61,7 @@ const string QueryRequest::metaGeoNearPoint("geoNearPoint"); const string QueryRequest::metaRecordId("recordId"); const string QueryRequest::metaSortKey("sortKey"); const string QueryRequest::metaTextScore("textScore"); +const string QueryRequest::metaShardName("shardName"); const string QueryRequest::kAllowDiskUseField("allowDiskUse"); @@ -600,9 +601,10 @@ Status QueryRequest::validate() const { BSONObjIterator projIt(_proj); while (projIt.more()) { BSONElement projElt = projIt.next(); - if (isTextScoreMeta(projElt)) { + if (isTextScoreMeta(projElt) || isShardNameMeta(projElt)) { BSONElement sortElt = _sort[projElt.fieldName()]; - if (!sortElt.eoo() && !isTextScoreMeta(sortElt)) { + if (!sortElt.eoo() && ((isTextScoreMeta(projElt) && !isTextScoreMeta(sortElt)) || + (isShardNameMeta(projElt) && !isShardNameMeta(sortElt)))) { return Status(ErrorCodes::BadValue, "can't have a non-$meta sort on a $meta projection"); } @@ -617,9 +619,10 @@ Status QueryRequest::validate() const { BSONObjIterator sortIt(_sort); while (sortIt.more()) { BSONElement sortElt = sortIt.next(); - if (isTextScoreMeta(sortElt)) { + if (isTextScoreMeta(sortElt) || isShardNameMeta(sortElt)) { BSONElement projElt = _proj[sortElt.fieldName()]; - if (projElt.eoo() || !isTextScoreMeta(projElt)) { + if (projElt.eoo() || (isTextScoreMeta(sortElt) && !isTextScoreMeta(projElt)) || + (isShardNameMeta(sortElt) && !isShardNameMeta(projElt))) { return Status(ErrorCodes::BadValue, "must have $meta projection for all $meta sort keys"); } @@ -704,8 +707,8 @@ StatusWith QueryRequest::parseMaxTimeMS(BSONElement maxTimeMSElt) { } // static -bool QueryRequest::isTextScoreMeta(BSONElement elt) { - // elt must be foo: {$meta: "textScore"} +bool QueryRequest::isMeta(BSONElement elt, const string& metaName) { + // elt must be foo: {$meta: "metaName"} if (mongo::Object != elt.type()) { return false; } @@ -722,7 +725,7 @@ bool QueryRequest::isTextScoreMeta(BSONElement elt) { if (mongo::String != metaElt.type()) { return false; } - if (QueryRequest::metaTextScore != metaElt.valuestr()) { + if (metaName != metaElt.valuestr()) { return false; } // must have exactly 1 element @@ -732,6 +735,18 @@ bool QueryRequest::isTextScoreMeta(BSONElement elt) { return true; } +// static +bool QueryRequest::isTextScoreMeta(BSONElement elt) { + // elt must be foo: {$meta: "textScore"} + return isMeta(elt, QueryRequest::metaTextScore); +} + +// static +bool QueryRequest::isShardNameMeta(BSONElement elt) { + // elt must be foo: {$meta: "shardName"} + return isMeta(elt, QueryRequest::metaShardName); +} + // static bool QueryRequest::isValidSortOrder(const BSONObj& sortObj) { BSONObjIterator i(sortObj); diff --git a/src/mongo/db/query/query_request.h b/src/mongo/db/query/query_request.h index a204e45c39b61..30ca49e5ebb6f 100644 --- a/src/mongo/db/query/query_request.h +++ b/src/mongo/db/query/query_request.h @@ -109,6 +109,12 @@ class QueryRequest { */ static bool isTextScoreMeta(BSONElement elt); + /** + * Helper function to identify shard name. + * Example: {a: {$meta: "shardName"}} + */ + static bool isShardNameMeta(BSONElement elt); + /** * Helper function to validate a sort object. * Returns true if each element satisfies one of: @@ -138,6 +144,7 @@ class QueryRequest { static const std::string metaRecordId; static const std::string metaSortKey; static const std::string metaTextScore; + static const std::string metaShardName; // Allow using disk during the find command. static const std::string kAllowDiskUseField; @@ -434,6 +441,12 @@ class QueryRequest { int queryOptions); private: + /** + * Helper function to identify meta with names. + * Example: {a: {$meta: "textScore"}} for metaName=metaTextScore. + */ + static bool isMeta(BSONElement elt, const std::string& metaName); + static StatusWith> parseFromFindCommand( std::unique_ptr qr, const BSONObj& cmdObj, bool isExplain); Status init(int ntoskip, diff --git a/src/mongo/db/query/query_solution.cpp b/src/mongo/db/query/query_solution.cpp index 320f54978a454..377d4d2ea3ad2 100644 --- a/src/mongo/db/query/query_solution.cpp +++ b/src/mongo/db/query/query_solution.cpp @@ -1144,6 +1144,32 @@ QuerySolutionNode* ShardingFilterNode::clone() const { return copy; } +// +// ShardNameNode +// + +void ShardNameNode::appendToString(str::stream* ss, int indent) const { + addIndent(ss, indent); + *ss << "SHARD_NAME\n"; + if (nullptr != filter) { + addIndent(ss, indent + 1); + StringBuilder sb; + *ss << "filter:\n"; + filter->debugString(sb, indent + 2); + *ss << sb.str(); + } + addCommon(ss, indent); + addIndent(ss, indent + 1); + *ss << "Child:" << '\n'; + children[0]->appendToString(ss, indent + 2); +} + +QuerySolutionNode* ShardNameNode::clone() const { + ShardNameNode* copy = new ShardNameNode(); + cloneBaseData(copy); + return copy; +} + // // DistinctNode // diff --git a/src/mongo/db/query/query_solution.h b/src/mongo/db/query/query_solution.h index 109241a2d54d4..7484765b0bb81 100644 --- a/src/mongo/db/query/query_solution.h +++ b/src/mongo/db/query/query_solution.h @@ -939,6 +939,35 @@ struct ShardingFilterNode : public QuerySolutionNode { QuerySolutionNode* clone() const; }; +/** + * If we're answering a query on a that has shardName metadata, docs must be appended with + * the shard name. + */ +struct ShardNameNode : public QuerySolutionNode { + ShardNameNode() {} + virtual ~ShardNameNode() {} + + virtual StageType getType() const { + return STAGE_SHARD_NAME; + } + virtual void appendToString(str::stream* ss, int indent) const; + + bool fetched() const { + return children[0]->fetched(); + } + bool hasField(const std::string& field) const { + return children[0]->hasField(field); + } + bool sortedByDiskLoc() const { + return children[0]->sortedByDiskLoc(); + } + const BSONObjSet& getSort() const { + return children[0]->getSort(); + } + + QuerySolutionNode* clone() const; +}; + /** * Distinct queries only want one value for a given field. We run an index scan but * *always* skip over the current key to the next key. diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index a3cc6aee999a8..c676e1a457268 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -54,6 +54,7 @@ #include "mongo/db/exec/projection.h" #include "mongo/db/exec/return_key.h" #include "mongo/db/exec/shard_filter.h" +#include "mongo/db/exec/shard_name.h" #include "mongo/db/exec/skip.h" #include "mongo/db/exec/sort.h" #include "mongo/db/exec/sort_key_generator.h" @@ -278,6 +279,17 @@ std::unique_ptr buildStages(OperationContext* opCtx, return std::make_unique( opCtx, css->getOrphansFilter(opCtx, collection), ws, std::move(childStage)); } + case STAGE_SHARD_NAME: { + warning() << "building stage: STAGE_SHARD_NAME"; + const ShardNameNode* fn = static_cast(root); + auto childStage = buildStages(opCtx, collection, cq, qsol, fn->children[0], ws); + if (nullptr == childStage) { + return nullptr; + } + + auto css = CollectionShardingState::get(opCtx, collection->ns()); + return std::make_unique(opCtx, css->getCurrentMetadata(), ws, std::move(childStage)); + } case STAGE_DISTINCT_SCAN: { const DistinctNode* dn = static_cast(root); diff --git a/src/mongo/db/query/stage_types.h b/src/mongo/db/query/stage_types.h index 17a67f1169f2c..3c6d07b7e39ec 100644 --- a/src/mongo/db/query/stage_types.h +++ b/src/mongo/db/query/stage_types.h @@ -89,6 +89,7 @@ enum StageType { STAGE_RECORD_STORE_FAST_COUNT, STAGE_RETURN_KEY, STAGE_SHARDING_FILTER, + STAGE_SHARD_NAME, STAGE_SKIP, STAGE_SORT, STAGE_SORT_KEY_GENERATOR, From 83814a6fcfb73471ba7ea64505ec06be6fbc36f5 Mon Sep 17 00:00:00 2001 From: krk Date: Fri, 18 Oct 2019 18:40:50 +0200 Subject: [PATCH 2/7] Remove meta-sort shardName condition in query_request. --- src/mongo/db/query/query_request.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mongo/db/query/query_request.cpp b/src/mongo/db/query/query_request.cpp index 3bff497e43b97..b2e9fdb8b3f93 100644 --- a/src/mongo/db/query/query_request.cpp +++ b/src/mongo/db/query/query_request.cpp @@ -621,8 +621,7 @@ Status QueryRequest::validate() const { BSONElement sortElt = sortIt.next(); if (isTextScoreMeta(sortElt) || isShardNameMeta(sortElt)) { BSONElement projElt = _proj[sortElt.fieldName()]; - if (projElt.eoo() || (isTextScoreMeta(sortElt) && !isTextScoreMeta(projElt)) || - (isShardNameMeta(sortElt) && !isShardNameMeta(projElt))) { + if (projElt.eoo() || (isTextScoreMeta(sortElt) && !isTextScoreMeta(projElt))) { return Status(ErrorCodes::BadValue, "must have $meta projection for all $meta sort keys"); } From 189caf83e74d4ba8e2e8a080fdf8ab072adddc0c Mon Sep 17 00:00:00 2001 From: krk Date: Fri, 18 Oct 2019 19:01:53 +0200 Subject: [PATCH 3/7] Delete ShardNamer interface. --- src/mongo/db/SConscript | 1 - src/mongo/db/exec/shard_name.cpp | 12 +++--- src/mongo/db/exec/shard_name.h | 10 ----- src/mongo/db/exec/shard_namer.h | 47 ----------------------- src/mongo/db/exec/shard_namer_impl.cpp | 47 ----------------------- src/mongo/db/exec/shard_namer_impl.h | 52 -------------------------- src/mongo/db/query/stage_builder.cpp | 9 ++--- 7 files changed, 9 insertions(+), 169 deletions(-) delete mode 100644 src/mongo/db/exec/shard_namer.h delete mode 100644 src/mongo/db/exec/shard_namer_impl.cpp delete mode 100644 src/mongo/db/exec/shard_namer_impl.h diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 1707214584a1c..75be642b0f74c 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1028,7 +1028,6 @@ env.Library( 'exec/shard_filter.cpp', 'exec/shard_filterer_impl.cpp', 'exec/shard_name.cpp', - 'exec/shard_namer_impl.cpp', 'exec/skip.cpp', 'exec/sort.cpp', 'exec/sort_key_generator.cpp', diff --git a/src/mongo/db/exec/shard_name.cpp b/src/mongo/db/exec/shard_name.cpp index 7d5e236a3ad2e..909d153589aba 100644 --- a/src/mongo/db/exec/shard_name.cpp +++ b/src/mongo/db/exec/shard_name.cpp @@ -36,6 +36,7 @@ #include "mongo/db/exec/filter.h" #include "mongo/db/exec/scoped_timer.h" #include "mongo/db/exec/working_set_common.h" +#include "mongo/db/s/sharding_state.h" #include "mongo/s/shard_key_pattern.h" namespace mongo { @@ -49,12 +50,11 @@ using std::string; const char* ShardNameStage::kStageType = "SHARD_NAME"; ShardNameStage::ShardNameStage(OperationContext* opCtx, - ScopedCollectionMetadata metadata, WorkingSet* ws, std::unique_ptr child) - : PlanStage(kStageType, opCtx), _ws(ws), _shardNamer(std::move(metadata)) { + : PlanStage(kStageType, opCtx), _ws(ws) { _children.emplace_back(std::move(child)); -} + } ShardNameStage::~ShardNameStage() {} @@ -72,12 +72,12 @@ PlanStage::StageState ShardNameStage::doWork(WorkingSetID* out) { if (PlanStage::ADVANCED == status) { // If we're sharded make sure to add shardName to the output. - if (_shardNamer.isCollectionSharded()) { + auto sharding = ShardingState::get(this->getOpCtx()); + if (sharding->enabled()) { WorkingSetMember* member = _ws->get(*out); - const StringData shardName = _shardNamer.shardName(); // Populate the working set member with the shard name and return it. - member->metadata().setShardName(shardName); + member->metadata().setShardName(sharding->shardId()); } // If we're here either we have shard state and added the shardName, or we have no shard diff --git a/src/mongo/db/exec/shard_name.h b/src/mongo/db/exec/shard_name.h index 2c1edeb944ad9..19d4531f5cdfc 100644 --- a/src/mongo/db/exec/shard_name.h +++ b/src/mongo/db/exec/shard_name.h @@ -30,14 +30,12 @@ #pragma once #include "mongo/db/exec/plan_stage.h" -#include "mongo/db/exec/shard_namer_impl.h" namespace mongo { class ShardNameStage final : public PlanStage { public: ShardNameStage(OperationContext* opCtx, - ScopedCollectionMetadata metadata, WorkingSet* ws, std::unique_ptr child); ~ShardNameStage(); @@ -57,14 +55,6 @@ class ShardNameStage final : public PlanStage { private: WorkingSet* _ws; - - // Note: it is important that this owns the ScopedCollectionMetadata from the time this stage - // is constructed. See ScopedCollectionMetadata class comment and MetadataManager comment for - // details. The existence of the ScopedCollectionMetadata prevents data which may have been - // migrated from being deleted while the query is still active. If we didn't hold one - // ScopedCollectionMetadata for the entire query, it'd be possible for data which the query - // needs to read to be deleted while it's still running. - ShardNamerImpl _shardNamer; }; } // namespace mongo diff --git a/src/mongo/db/exec/shard_namer.h b/src/mongo/db/exec/shard_namer.h deleted file mode 100644 index 4944ea7863272..0000000000000 --- a/src/mongo/db/exec/shard_namer.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/matcher/matchable.h" -#include "mongo/db/operation_context.h" - -namespace mongo { - -/** - * Interface for naming shards, to be used by both the find and agg execution trees. - */ -class ShardNamer { -public: - virtual ~ShardNamer() = default; - - virtual const StringData shardName() const = 0; - virtual bool isCollectionSharded() const = 0; -}; -} // namespace mongo diff --git a/src/mongo/db/exec/shard_namer_impl.cpp b/src/mongo/db/exec/shard_namer_impl.cpp deleted file mode 100644 index 6c2404a0150b0..0000000000000 --- a/src/mongo/db/exec/shard_namer_impl.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (C) 2019-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/exec/shard_namer_impl.h" - -#include "mongo/db/matcher/matchable.h" -#include "mongo/db/s/scoped_collection_metadata.h" - -namespace mongo { - -ShardNamerImpl::ShardNamerImpl(ScopedCollectionMetadata md) : _metadata(std::move(md)), - _shardName(isCollectionSharded() ? _metadata->shardId() : StringData("")) { -} - -const StringData ShardNamerImpl::shardName() const { - return _shardName; -} - -} // namespace mongo diff --git a/src/mongo/db/exec/shard_namer_impl.h b/src/mongo/db/exec/shard_namer_impl.h deleted file mode 100644 index 0725ca1b027e5..0000000000000 --- a/src/mongo/db/exec/shard_namer_impl.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (C) 2019-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/exec/shard_namer.h" -#include "mongo/db/matcher/matchable.h" -#include "mongo/db/s/scoped_collection_metadata.h" - -namespace mongo { - -class ShardNamerImpl : public ShardNamer { -public: - ShardNamerImpl(ScopedCollectionMetadata md); - - const StringData shardName() const override; - - bool isCollectionSharded() const override { - return _metadata->isSharded(); - } - -private: - ScopedCollectionMetadata _metadata; - const StringData _shardName; -}; -} // namespace mongo diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index c676e1a457268..8cf9f360a3358 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -283,12 +283,9 @@ std::unique_ptr buildStages(OperationContext* opCtx, warning() << "building stage: STAGE_SHARD_NAME"; const ShardNameNode* fn = static_cast(root); auto childStage = buildStages(opCtx, collection, cq, qsol, fn->children[0], ws); - if (nullptr == childStage) { - return nullptr; - } - - auto css = CollectionShardingState::get(opCtx, collection->ns()); - return std::make_unique(opCtx, css->getCurrentMetadata(), ws, std::move(childStage)); + return childStage == nullptr + ? nullptr + : std::make_unique(opCtx, ws, std::move(childStage)); } case STAGE_DISTINCT_SCAN: { const DistinctNode* dn = static_cast(root); From 1a6a031932bef30733fd42ad56476b45f9b9f11d Mon Sep 17 00:00:00 2001 From: krk Date: Fri, 18 Oct 2019 20:07:32 +0200 Subject: [PATCH 4/7] Delete ShardNameStage and move functionality to ShardFilterStage. --- src/mongo/db/SConscript | 1 - src/mongo/db/exec/shard_filter.cpp | 14 +++- src/mongo/db/exec/shard_filter.h | 9 +- src/mongo/db/exec/shard_name.cpp | 104 ------------------------ src/mongo/db/exec/shard_name.h | 60 -------------- src/mongo/db/pipeline/pipeline_d.cpp | 4 +- src/mongo/db/query/get_executor.cpp | 4 +- src/mongo/db/query/planner_analysis.cpp | 9 +- src/mongo/db/query/query_solution.cpp | 31 +------ src/mongo/db/query/query_solution.h | 35 ++------ src/mongo/db/query/stage_builder.cpp | 12 +-- src/mongo/db/query/stage_types.h | 1 - 12 files changed, 39 insertions(+), 245 deletions(-) delete mode 100644 src/mongo/db/exec/shard_name.cpp delete mode 100644 src/mongo/db/exec/shard_name.h diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 75be642b0f74c..0170303b829d9 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1027,7 +1027,6 @@ env.Library( 'exec/return_key.cpp', 'exec/shard_filter.cpp', 'exec/shard_filterer_impl.cpp', - 'exec/shard_name.cpp', 'exec/skip.cpp', 'exec/sort.cpp', 'exec/sort_key_generator.cpp', diff --git a/src/mongo/db/exec/shard_filter.cpp b/src/mongo/db/exec/shard_filter.cpp index 3ca72e989a02a..8cbf177d48311 100644 --- a/src/mongo/db/exec/shard_filter.cpp +++ b/src/mongo/db/exec/shard_filter.cpp @@ -38,6 +38,7 @@ #include "mongo/db/exec/filter.h" #include "mongo/db/exec/scoped_timer.h" #include "mongo/db/exec/working_set_common.h" +#include "mongo/db/s/sharding_state.h" #include "mongo/s/shard_key_pattern.h" #include "mongo/util/log.h" @@ -53,8 +54,10 @@ const char* ShardFilterStage::kStageType = "SHARDING_FILTER"; ShardFilterStage::ShardFilterStage(OperationContext* opCtx, ScopedCollectionMetadata metadata, WorkingSet* ws, - std::unique_ptr child) - : PlanStage(kStageType, opCtx), _ws(ws), _shardFilterer(std::move(metadata)) { + std::unique_ptr child, + bool wantShardName) + : PlanStage(kStageType, opCtx), _ws(ws), _shardFilterer(std::move(metadata)), + _wantShardName(wantShardName) { _children.emplace_back(std::move(child)); } @@ -104,6 +107,13 @@ PlanStage::StageState ShardFilterStage::doWork(WorkingSetID* out) { ++_specificStats.chunkSkips; return PlanStage::NEED_TIME; } + + if(wantShardName()) { + auto sharding = ShardingState::get(this->getOpCtx()); + + // Populate the working set member with the shard name and return it. + member->metadata().setShardName(sharding->shardId()); + } } // If we're here either we have shard state and our doc passed, or we have no shard diff --git a/src/mongo/db/exec/shard_filter.h b/src/mongo/db/exec/shard_filter.h index 5fdb2a2a2476b..b29053af6b00e 100644 --- a/src/mongo/db/exec/shard_filter.h +++ b/src/mongo/db/exec/shard_filter.h @@ -74,7 +74,8 @@ class ShardFilterStage final : public PlanStage { ShardFilterStage(OperationContext* opCtx, ScopedCollectionMetadata metadata, WorkingSet* ws, - std::unique_ptr child); + std::unique_ptr child, + bool wantShardName); ~ShardFilterStage(); bool isEOF() final; @@ -91,6 +92,10 @@ class ShardFilterStage final : public PlanStage { static const char* kStageType; private: + bool wantShardName() const { + return _wantShardName; + } + WorkingSet* _ws; // Stats @@ -103,6 +108,8 @@ class ShardFilterStage final : public PlanStage { // ScopedCollectionMetadata for the entire query, it'd be possible for data which the query // needs to read to be deleted while it's still running. ShardFiltererImpl _shardFilterer; + + bool _wantShardName; }; } // namespace mongo diff --git a/src/mongo/db/exec/shard_name.cpp b/src/mongo/db/exec/shard_name.cpp deleted file mode 100644 index 909d153589aba..0000000000000 --- a/src/mongo/db/exec/shard_name.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (C) 2019-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/exec/shard_name.h" - -#include - -#include "mongo/db/exec/filter.h" -#include "mongo/db/exec/scoped_timer.h" -#include "mongo/db/exec/working_set_common.h" -#include "mongo/db/s/sharding_state.h" -#include "mongo/s/shard_key_pattern.h" - -namespace mongo { - -using std::shared_ptr; -using std::unique_ptr; -using std::vector; -using std::string; - -// static -const char* ShardNameStage::kStageType = "SHARD_NAME"; - -ShardNameStage::ShardNameStage(OperationContext* opCtx, - WorkingSet* ws, - std::unique_ptr child) - : PlanStage(kStageType, opCtx), _ws(ws) { - _children.emplace_back(std::move(child)); - } - -ShardNameStage::~ShardNameStage() {} - -bool ShardNameStage::isEOF() { - return child()->isEOF(); -} - -PlanStage::StageState ShardNameStage::doWork(WorkingSetID* out) { - // If we've returned as many results as we're limited to, isEOF will be true. - if (isEOF()) { - return PlanStage::IS_EOF; - } - - StageState status = child()->work(out); - - if (PlanStage::ADVANCED == status) { - // If we're sharded make sure to add shardName to the output. - auto sharding = ShardingState::get(this->getOpCtx()); - if (sharding->enabled()) { - WorkingSetMember* member = _ws->get(*out); - - // Populate the working set member with the shard name and return it. - member->metadata().setShardName(sharding->shardId()); - } - - // If we're here either we have shard state and added the shardName, or we have no shard - // state. Either way, we advance. - return status; - } - - return status; -} - -unique_ptr ShardNameStage::getStats() { - _commonStats.isEOF = isEOF(); - unique_ptr ret = - std::make_unique(_commonStats, STAGE_SHARD_NAME); - ret->children.emplace_back(child()->getStats()); - return ret; -} - -const SpecificStats* ShardNameStage::getSpecificStats() const { - // No specific stats are tracked for the shard name stage. - return nullptr; -} - -} // namespace mongo diff --git a/src/mongo/db/exec/shard_name.h b/src/mongo/db/exec/shard_name.h deleted file mode 100644 index 19d4531f5cdfc..0000000000000 --- a/src/mongo/db/exec/shard_name.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (C) 2019-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/exec/plan_stage.h" - -namespace mongo { - -class ShardNameStage final : public PlanStage { -public: - ShardNameStage(OperationContext* opCtx, - WorkingSet* ws, - std::unique_ptr child); - ~ShardNameStage(); - - bool isEOF() final; - StageState doWork(WorkingSetID* out) final; - - StageType stageType() const final { - return STAGE_SHARD_NAME; - } - - std::unique_ptr getStats() final; - - const SpecificStats* getSpecificStats() const final; - - static const char* kStageType; - -private: - WorkingSet* _ws; -}; - -} // namespace mongo diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index 59bf5c596a08f..0fdc830bd360f 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -167,12 +167,12 @@ StatusWith> createRandomCursorEx sampleSize / (numRecords * kMaxSampleRatioForRandCursor), kMaxSampleRatioForRandCursor); // The trial plan is SHARDING_FILTER-MULTI_ITERATOR. auto randomCursorPlan = - std::make_unique(opCtx, shardMetadata, ws.get(), std::move(root)); + std::make_unique(opCtx, shardMetadata, ws.get(), std::move(root), false); // The backup plan is SHARDING_FILTER-COLLSCAN. std::unique_ptr collScanPlan = std::make_unique( opCtx, coll, CollectionScanParams{}, ws.get(), nullptr); collScanPlan = std::make_unique( - opCtx, shardMetadata, ws.get(), std::move(collScanPlan)); + opCtx, shardMetadata, ws.get(), std::move(collScanPlan), false); // Place a TRIAL stage at the root of the plan tree, and pass it the trial and backup plans. root = std::make_unique(opCtx, ws.get(), diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 4a50514e7c185..7a4f774fbdd72 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -382,12 +382,14 @@ StatusWith prepareExecution(OperationContext* opCtx, // Might have to filter out orphaned docs. if (plannerParams.options & QueryPlannerParams::INCLUDE_SHARD_FILTER) { + auto wantShardName = canonicalQuery->metadataDeps()[DocumentMetadataFields::kShardName]; root = std::make_unique( opCtx, CollectionShardingState::get(opCtx, canonicalQuery->nss()) ->getOrphansFilter(opCtx, collection), ws, - std::move(root)); + std::move(root), + wantShardName); } const auto* cqProjection = canonicalQuery->getProj(); diff --git a/src/mongo/db/query/planner_analysis.cpp b/src/mongo/db/query/planner_analysis.cpp index a2767fc9bbf7d..01ad93c767afe 100644 --- a/src/mongo/db/query/planner_analysis.cpp +++ b/src/mongo/db/query/planner_analysis.cpp @@ -384,12 +384,6 @@ std::unique_ptr analyzeProjection(const CanonicalQuery& query, } } } - auto wantShardName = query.metadataDeps()[DocumentMetadataFields::kShardName]; - if (wantShardName) { - auto shardNameNode = std::make_unique(); - shardNameNode->children.push_back(solnRoot.release()); - solnRoot = std::move(shardNameNode); - } return std::make_unique( addSortKeyGeneratorStageIfNeeded(query, hasSortStage, std::move(solnRoot)), *query.root(), @@ -767,7 +761,8 @@ std::unique_ptr QueryPlannerAnalysis::analyzeDataAccess( } } - ShardingFilterNode* sfn = new ShardingFilterNode(); + auto wantShardName = query.metadataDeps()[DocumentMetadataFields::kShardName]; + ShardingFilterNode* sfn = new ShardingFilterNode(wantShardName); sfn->children.push_back(solnRoot.release()); solnRoot.reset(sfn); } diff --git a/src/mongo/db/query/query_solution.cpp b/src/mongo/db/query/query_solution.cpp index 377d4d2ea3ad2..109711b05728e 100644 --- a/src/mongo/db/query/query_solution.cpp +++ b/src/mongo/db/query/query_solution.cpp @@ -1125,32 +1125,9 @@ QuerySolutionNode* GeoNear2DSphereNode::clone() const { void ShardingFilterNode::appendToString(str::stream* ss, int indent) const { addIndent(ss, indent); *ss << "SHARDING_FILTER\n"; - if (nullptr != filter) { - addIndent(ss, indent + 1); - StringBuilder sb; - *ss << "filter:\n"; - filter->debugString(sb, indent + 2); - *ss << sb.str(); + if (wantShardName()) { + *ss << "with shard name\n"; } - addCommon(ss, indent); - addIndent(ss, indent + 1); - *ss << "Child:" << '\n'; - children[0]->appendToString(ss, indent + 2); -} - -QuerySolutionNode* ShardingFilterNode::clone() const { - ShardingFilterNode* copy = new ShardingFilterNode(); - cloneBaseData(copy); - return copy; -} - -// -// ShardNameNode -// - -void ShardNameNode::appendToString(str::stream* ss, int indent) const { - addIndent(ss, indent); - *ss << "SHARD_NAME\n"; if (nullptr != filter) { addIndent(ss, indent + 1); StringBuilder sb; @@ -1164,8 +1141,8 @@ void ShardNameNode::appendToString(str::stream* ss, int indent) const { children[0]->appendToString(ss, indent + 2); } -QuerySolutionNode* ShardNameNode::clone() const { - ShardNameNode* copy = new ShardNameNode(); +QuerySolutionNode* ShardingFilterNode::clone() const { + ShardingFilterNode* copy = new ShardingFilterNode(this->wantShardName()); cloneBaseData(copy); return copy; } diff --git a/src/mongo/db/query/query_solution.h b/src/mongo/db/query/query_solution.h index 7484765b0bb81..17f489251760e 100644 --- a/src/mongo/db/query/query_solution.h +++ b/src/mongo/db/query/query_solution.h @@ -915,7 +915,7 @@ struct GeoNear2DSphereNode : public QuerySolutionNode { * through the pipeline. */ struct ShardingFilterNode : public QuerySolutionNode { - ShardingFilterNode() {} + ShardingFilterNode(bool wantShardName): _wantShardName(wantShardName) {} virtual ~ShardingFilterNode() {} virtual StageType getType() const { @@ -935,37 +935,14 @@ struct ShardingFilterNode : public QuerySolutionNode { const BSONObjSet& getSort() const { return children[0]->getSort(); } - - QuerySolutionNode* clone() const; -}; - -/** - * If we're answering a query on a that has shardName metadata, docs must be appended with - * the shard name. - */ -struct ShardNameNode : public QuerySolutionNode { - ShardNameNode() {} - virtual ~ShardNameNode() {} - - virtual StageType getType() const { - return STAGE_SHARD_NAME; - } - virtual void appendToString(str::stream* ss, int indent) const; - - bool fetched() const { - return children[0]->fetched(); - } - bool hasField(const std::string& field) const { - return children[0]->hasField(field); - } - bool sortedByDiskLoc() const { - return children[0]->sortedByDiskLoc(); - } - const BSONObjSet& getSort() const { - return children[0]->getSort(); + bool wantShardName() const { + return _wantShardName; } QuerySolutionNode* clone() const; + +private: + bool _wantShardName; }; /** diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index 8cf9f360a3358..6f008f5b2b4fc 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -54,7 +54,6 @@ #include "mongo/db/exec/projection.h" #include "mongo/db/exec/return_key.h" #include "mongo/db/exec/shard_filter.h" -#include "mongo/db/exec/shard_name.h" #include "mongo/db/exec/skip.h" #include "mongo/db/exec/sort.h" #include "mongo/db/exec/sort_key_generator.h" @@ -277,15 +276,8 @@ std::unique_ptr buildStages(OperationContext* opCtx, auto css = CollectionShardingState::get(opCtx, collection->ns()); return std::make_unique( - opCtx, css->getOrphansFilter(opCtx, collection), ws, std::move(childStage)); - } - case STAGE_SHARD_NAME: { - warning() << "building stage: STAGE_SHARD_NAME"; - const ShardNameNode* fn = static_cast(root); - auto childStage = buildStages(opCtx, collection, cq, qsol, fn->children[0], ws); - return childStage == nullptr - ? nullptr - : std::make_unique(opCtx, ws, std::move(childStage)); + opCtx, css->getOrphansFilter(opCtx, collection), ws, std::move(childStage), + fn->wantShardName()); } case STAGE_DISTINCT_SCAN: { const DistinctNode* dn = static_cast(root); diff --git a/src/mongo/db/query/stage_types.h b/src/mongo/db/query/stage_types.h index 3c6d07b7e39ec..17a67f1169f2c 100644 --- a/src/mongo/db/query/stage_types.h +++ b/src/mongo/db/query/stage_types.h @@ -89,7 +89,6 @@ enum StageType { STAGE_RECORD_STORE_FAST_COUNT, STAGE_RETURN_KEY, STAGE_SHARDING_FILTER, - STAGE_SHARD_NAME, STAGE_SKIP, STAGE_SORT, STAGE_SORT_KEY_GENERATOR, From 6ce6063ae2c433ea3edd5daac79ae4c127c2f906 Mon Sep 17 00:00:00 2001 From: krk Date: Fri, 18 Oct 2019 20:14:20 +0200 Subject: [PATCH 5/7] Remove wantShardName from ParsedProjection. --- src/mongo/db/query/parsed_projection.cpp | 4 ---- src/mongo/db/query/parsed_projection.h | 6 ------ 2 files changed, 10 deletions(-) diff --git a/src/mongo/db/query/parsed_projection.cpp b/src/mongo/db/query/parsed_projection.cpp index 700d26d87d558..ed839e877a152 100644 --- a/src/mongo/db/query/parsed_projection.cpp +++ b/src/mongo/db/query/parsed_projection.cpp @@ -60,7 +60,6 @@ Status ParsedProjection::make(OperationContext* opCtx, bool wantGeoNearPoint = false; bool wantGeoNearDistance = false; bool wantSortKey = false; - bool wantShardName = false; // Until we see a positional or elemMatch operator we're normal. ArrayOpType arrayOpType = ARRAY_OP_NORMAL; @@ -176,8 +175,6 @@ Status ParsedProjection::make(OperationContext* opCtx, wantGeoNearPoint = true; } else if (e2.valuestr() == QueryRequest::metaSortKey) { wantSortKey = true; - } else if (e2.valuestr() == QueryRequest::metaShardName) { - wantShardName = true; } // Of the $meta projections, only sortKey can be covered. @@ -274,7 +271,6 @@ Status ParsedProjection::make(OperationContext* opCtx, pp->_wantGeoNearPoint = wantGeoNearPoint; pp->_wantGeoNearDistance = wantGeoNearDistance; pp->_wantSortKey = wantSortKey; - pp->_wantShardName = wantShardName; // If it's possible to compute the projection in a covered fashion, populate _requiredFields // so the planner can perform projection analysis. diff --git a/src/mongo/db/query/parsed_projection.h b/src/mongo/db/query/parsed_projection.h index 50efc91ab19f3..1d9063acf05ec 100644 --- a/src/mongo/db/query/parsed_projection.h +++ b/src/mongo/db/query/parsed_projection.h @@ -104,10 +104,6 @@ class ParsedProjection { return _wantSortKey; } - bool wantShardName() const { - return _wantShardName; - } - /** * Returns true if the element at 'path' is preserved entirely after this projection is applied, * and false otherwise. For example, the projection {a: 1} will preserve the element located at @@ -196,8 +192,6 @@ class ParsedProjection { // Whether this projection includes a sortKey meta-projection. bool _wantSortKey = false; - bool _wantShardName = false; - bool _hasDottedFieldPath = false; }; From 8d8ee4211e15e4f40954e816500651622fe3cecb Mon Sep 17 00:00:00 2001 From: krk Date: Sat, 19 Oct 2019 12:36:58 +0200 Subject: [PATCH 6/7] Use ShardId instead of StringData for shardName. --- .../db/exec/document_value/document_metadata_fields.cpp | 4 +++- .../db/exec/document_value/document_metadata_fields.h | 7 ++++--- src/mongo/db/exec/shard_filter.cpp | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/mongo/db/exec/document_value/document_metadata_fields.cpp b/src/mongo/db/exec/document_value/document_metadata_fields.cpp index 01a3ff36ff932..3d28bcbd4edf4 100644 --- a/src/mongo/db/exec/document_value/document_metadata_fields.cpp +++ b/src/mongo/db/exec/document_value/document_metadata_fields.cpp @@ -33,6 +33,8 @@ #include "mongo/bson/bsonobjbuilder.h" +#include "mongo/s/shard_id.h" + namespace mongo { namespace { @@ -206,7 +208,7 @@ void DocumentMetadataFields::deserializeForSorter(BufReader& buf, DocumentMetada out->setIndexKey( BSONObj::deserializeForSorter(buf, BSONObj::SorterDeserializeSettings())); } else if (marker == static_cast(MetaType::kShardName) + 1) { - out->setShardName(buf.readCStr()); + out->setShardName(ShardId(std::string(buf.readCStr()))); } else { uasserted(28744, "Unrecognized marker, unable to deserialize buffer"); } diff --git a/src/mongo/db/exec/document_value/document_metadata_fields.h b/src/mongo/db/exec/document_value/document_metadata_fields.h index ecb70ef84ae71..a340d26097375 100644 --- a/src/mongo/db/exec/document_value/document_metadata_fields.h +++ b/src/mongo/db/exec/document_value/document_metadata_fields.h @@ -34,6 +34,7 @@ #include "mongo/bson/bsonobj.h" #include "mongo/db/exec/document_value/value.h" #include "mongo/db/record_id.h" +#include "mongo/s/shard_id.h" namespace mongo { /** @@ -307,12 +308,12 @@ class DocumentMetadataFields { return _holder && _holder->metaFields.test(MetaType::kShardName); } - StringData getShardName() const { + ShardId getShardName() const { invariant(hasShardName()); return _holder->shardName; } - void setShardName(StringData shardName) { + void setShardName(ShardId shardName) { if (!_holder) { _holder = std::make_unique(); } @@ -342,7 +343,7 @@ class DocumentMetadataFields { Value searchHighlights; BSONObj indexKey; RecordId recordId; - StringData shardName; + ShardId shardName; }; // Null until the first setter is called, at which point a MetadataHolder struct is allocated. diff --git a/src/mongo/db/exec/shard_filter.cpp b/src/mongo/db/exec/shard_filter.cpp index 8cbf177d48311..bd048df21513f 100644 --- a/src/mongo/db/exec/shard_filter.cpp +++ b/src/mongo/db/exec/shard_filter.cpp @@ -112,7 +112,7 @@ PlanStage::StageState ShardFilterStage::doWork(WorkingSetID* out) { auto sharding = ShardingState::get(this->getOpCtx()); // Populate the working set member with the shard name and return it. - member->metadata().setShardName(sharding->shardId()); + member->metadata().setShardName(sharding->shardId().toString()); } } From 62fac41c509c46575c618cb1509f5529f0984f2a Mon Sep 17 00:00:00 2001 From: krk Date: Sat, 19 Oct 2019 12:37:15 +0200 Subject: [PATCH 7/7] Evaluate ShardName metadata in ExpressionMeta. --- src/mongo/db/pipeline/expression.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index e69ff21aa5d12..d37d13e8ae4c3 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -27,7 +27,6 @@ * it in the license file. */ - #include "mongo/platform/basic.h" #include "mongo/db/pipeline/expression.h" @@ -2546,6 +2545,7 @@ const std::string geoNearPointName = "geoNearPoint"; const std::string recordIdName = "recordId"; const std::string indexKeyName = "indexKey"; const std::string sortKeyName = "sortKey"; +const std::string shardName = "shardName"; using MetaType = DocumentMetadataFields::MetaType; const StringMap kMetaNameToMetaType = { @@ -2558,6 +2558,7 @@ const StringMap kMetaNameToMetaType = { {searchScoreName, MetaType::kSearchScore}, {sortKeyName, MetaType::kSortKey}, {textScoreName, MetaType::kTextScore}, + {shardName, MetaType::kShardName}, }; const stdx::unordered_map kMetaTypeToMetaName = { @@ -2570,6 +2571,7 @@ const stdx::unordered_map kMetaTyp {MetaType::kSearchScore, searchScoreName}, {MetaType::kSortKey, sortKeyName}, {MetaType::kTextScore, textScoreName}, + {MetaType::kShardName, shardName}, }; } // namespace @@ -2643,6 +2645,10 @@ Value ExpressionMeta::evaluate(const Document& root, Variables* variables) const ? Value(DocumentMetadataFields::serializeSortKey(metadata.isSingleElementKey(), metadata.getSortKey())) : Value(); + case MetaType::kShardName: + return metadata.hasShardName() + ? Value(metadata.getShardName().toString()) + : Value(); default: MONGO_UNREACHABLE; }