Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/mongo/db/exec/document_value/document_metadata_fields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

#include "mongo/bson/bsonobjbuilder.h"

#include "mongo/s/shard_id.h"

namespace mongo {

namespace {
Expand Down Expand Up @@ -173,6 +175,10 @@ void DocumentMetadataFields::serializeForSorter(BufBuilder& buf) const {
buf.appendNum(static_cast<char>(MetaType::kIndexKey + 1));
getIndexKey().appendSelfToBufBuilder(buf);
}
if (hasShardName()) {
buf.appendNum(static_cast<char>(MetaType::kShardName + 1));
buf.appendStr(getShardName());
}
buf.appendNum(static_cast<char>(0));
}

Expand Down Expand Up @@ -201,6 +207,8 @@ void DocumentMetadataFields::deserializeForSorter(BufReader& buf, DocumentMetada
} else if (marker == static_cast<char>(MetaType::kIndexKey) + 1) {
out->setIndexKey(
BSONObj::deserializeForSorter(buf, BSONObj::SorterDeserializeSettings()));
} else if (marker == static_cast<char>(MetaType::kShardName) + 1) {
out->setShardName(ShardId(std::string(buf.readCStr())));
} else {
uasserted(28744, "Unrecognized marker, unable to deserialize buffer");
}
Expand Down
21 changes: 21 additions & 0 deletions src/mongo/db/exec/document_value/document_metadata_fields.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/**
Expand Down Expand Up @@ -64,6 +65,7 @@ class DocumentMetadataFields {
kSearchScore,
kSortKey,
kTextScore,
kShardName,

// New fields must be added before the kNumFields sentinel.
kNumFields
Expand Down Expand Up @@ -302,6 +304,24 @@ class DocumentMetadataFields {
_holder->recordId = rid;
}

bool hasShardName() const {
return _holder && _holder->metaFields.test(MetaType::kShardName);
}

ShardId getShardName() const {
invariant(hasShardName());
return _holder->shardName;
}

void setShardName(ShardId shardName) {
if (!_holder) {
_holder = std::make_unique<MetadataHolder>();
}

_holder->metaFields.set(MetaType::kShardName);
_holder->shardName = shardName;
}

void serializeForSorter(BufBuilder& buf) const;

private:
Expand All @@ -323,6 +343,7 @@ class DocumentMetadataFields {
Value searchHighlights;
BSONObj indexKey;
RecordId recordId;
ShardId shardName;
};

// Null until the first setter is called, at which point a MetadataHolder struct is allocated.
Expand Down
11 changes: 11 additions & 0 deletions src/mongo/db/exec/document_value/document_metadata_fields_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down
20 changes: 15 additions & 5 deletions src/mongo/db/exec/projection_exec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another example of code that is going to be deleted soon, as part of our efforts to consolidate the implementations of find projection and agg projection. Ideally, the only place where we would have to change projection execution code would in the $meta agg expression:

Value ExpressionMeta::evaluate(const Document& root, Variables* variables) const {
const auto& metadata = root.metadata();
switch (_metaType) {
case MetaType::kTextScore:
return metadata.hasTextScore() ? Value(metadata.getTextScore()) : Value();
case MetaType::kRandVal:
return metadata.hasRandVal() ? Value(metadata.getRandVal()) : Value();
case MetaType::kSearchScore:
return metadata.hasSearchScore() ? Value(metadata.getSearchScore()) : Value();
case MetaType::kSearchHighlights:
return metadata.hasSearchHighlights() ? Value(metadata.getSearchHighlights()) : Value();
case MetaType::kGeoNearDist:
return metadata.hasGeoNearDistance() ? Value(metadata.getGeoNearDistance()) : Value();
case MetaType::kGeoNearPoint:
return metadata.hasGeoNearPoint() ? Value(metadata.getGeoNearPoint()) : Value();
case MetaType::kRecordId:
// Be sure that a RecordId can be represented by a long long.
static_assert(RecordId::kMinRepr >= std::numeric_limits<long long>::min());
static_assert(RecordId::kMaxRepr <= std::numeric_limits<long long>::max());
return metadata.hasRecordId()
? Value{static_cast<long long>(metadata.getRecordId().repr())}
: Value();
case MetaType::kIndexKey:
return metadata.hasIndexKey() ? Value(metadata.getIndexKey()) : Value();
case MetaType::kSortKey:
return metadata.hasSortKey()
? Value(DocumentMetadataFields::serializeSortKey(metadata.isSingleElementKey(),
metadata.getSortKey()))
: Value();
default:
MONGO_UNREACHABLE;
}
MONGO_UNREACHABLE;
}

We would need new code there that would know how to handle a $meta:"shardName" expression.

_meta[e.fieldName()] = META_SHARD_NAME;
_needsShardName = true;
} else {
// This shouldn't happen, should be caught by parsing.
MONGO_UNREACHABLE;
Expand Down Expand Up @@ -202,7 +205,8 @@ StatusWith<BSONObj> ProjectionExec::project(const BSONObj& in,
Value geoNearPoint,
const BSONObj& sortKey,
const boost::optional<const double> textScore,
const int64_t recordId) const {
const int64_t recordId,
const StringData& shardName) const {
BSONObjBuilder bob;
MatchDetails matchDetails;

Expand All @@ -217,15 +221,16 @@ StatusWith<BSONObj> 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<BSONObj> ProjectionExec::projectCovered(const std::vector<IndexKeyDatum>& keyData,
const boost::optional<const double> geoDistance,
Value geoNearPoint,
const BSONObj& sortKey,
const boost::optional<const double> textScore,
const int64_t recordId) const {
const int64_t recordId,
const StringData& shardName) const {
invariant(!_include);
BSONObjBuilder bob;
// Go field by field.
Expand Down Expand Up @@ -270,15 +275,16 @@ StatusWith<BSONObj> ProjectionExec::projectCovered(const std::vector<IndexKeyDat
}

bob.appendElements(projectedDoc.getObject());
return {addMeta(std::move(bob), geoDistance, geoNearPoint, sortKey, textScore, recordId)};
return {addMeta(std::move(bob), geoDistance, geoNearPoint, sortKey, textScore, recordId, shardName)};
}

BSONObj ProjectionExec::addMeta(BSONObjBuilder bob,
const boost::optional<const double> geoDistance,
Value geoNearPoint,
const BSONObj& sortKey,
const boost::optional<const double> 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:
Expand All @@ -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);
Expand Down
18 changes: 15 additions & 3 deletions src/mongo/db/exec/projection_exec.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class ProjectionExec {
META_RECORDID,
META_SORT_KEY,
META_TEXT_SCORE,
META_SHARD_NAME,
};

/**
Expand Down Expand Up @@ -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.
*/
Expand All @@ -124,7 +132,8 @@ class ProjectionExec {
Value geoNearPoint = Value{},
const BSONObj& sortKey = BSONObj(),
const boost::optional<const double> 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
Expand All @@ -137,7 +146,8 @@ class ProjectionExec {
Value geoNearPoint = Value{},
const BSONObj& sortKey = BSONObj(),
const boost::optional<const double> 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
Expand All @@ -157,7 +167,8 @@ class ProjectionExec {
Value geoNearPoint,
const BSONObj& sortKey,
const boost::optional<const double> textScore,
const int64_t recordId) const;
const int64_t recordId,
const StringData& shardName) const;

//
// Initialization
Expand Down Expand Up @@ -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
Expand Down
14 changes: 12 additions & 2 deletions src/mongo/db/exec/shard_filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -53,8 +54,10 @@ const char* ShardFilterStage::kStageType = "SHARDING_FILTER";
ShardFilterStage::ShardFilterStage(OperationContext* opCtx,
ScopedCollectionMetadata metadata,
WorkingSet* ws,
std::unique_ptr<PlanStage> child)
: PlanStage(kStageType, opCtx), _ws(ws), _shardFilterer(std::move(metadata)) {
std::unique_ptr<PlanStage> child,
bool wantShardName)
: PlanStage(kStageType, opCtx), _ws(ws), _shardFilterer(std::move(metadata)),
_wantShardName(wantShardName) {
_children.emplace_back(std::move(child));
}

Expand Down Expand Up @@ -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().toString());
}
}

// If we're here either we have shard state and our doc passed, or we have no shard
Expand Down
9 changes: 8 additions & 1 deletion src/mongo/db/exec/shard_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class ShardFilterStage final : public PlanStage {
ShardFilterStage(OperationContext* opCtx,
ScopedCollectionMetadata metadata,
WorkingSet* ws,
std::unique_ptr<PlanStage> child);
std::unique_ptr<PlanStage> child,
bool wantShardName);
~ShardFilterStage();

bool isEOF() final;
Expand All @@ -91,6 +92,10 @@ class ShardFilterStage final : public PlanStage {
static const char* kStageType;

private:
bool wantShardName() const {
return _wantShardName;
}

WorkingSet* _ws;

// Stats
Expand All @@ -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
8 changes: 7 additions & 1 deletion src/mongo/db/pipeline/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
* it in the license file.
*/


#include "mongo/platform/basic.h"

#include "mongo/db/pipeline/expression.h"
Expand Down Expand Up @@ -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<DocumentMetadataFields::MetaType> kMetaNameToMetaType = {
Expand All @@ -2558,6 +2558,7 @@ const StringMap<DocumentMetadataFields::MetaType> kMetaNameToMetaType = {
{searchScoreName, MetaType::kSearchScore},
{sortKeyName, MetaType::kSortKey},
{textScoreName, MetaType::kTextScore},
{shardName, MetaType::kShardName},
};

const stdx::unordered_map<DocumentMetadataFields::MetaType, StringData> kMetaTypeToMetaName = {
Expand All @@ -2570,6 +2571,7 @@ const stdx::unordered_map<DocumentMetadataFields::MetaType, StringData> kMetaTyp
{MetaType::kSearchScore, searchScoreName},
{MetaType::kSortKey, sortKeyName},
{MetaType::kTextScore, textScoreName},
{MetaType::kShardName, shardName},
};

} // namespace
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions src/mongo/db/pipeline/pipeline_d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> createRandomCursorEx
sampleSize / (numRecords * kMaxSampleRatioForRandCursor), kMaxSampleRatioForRandCursor);
// The trial plan is SHARDING_FILTER-MULTI_ITERATOR.
auto randomCursorPlan =
std::make_unique<ShardFilterStage>(opCtx, shardMetadata, ws.get(), std::move(root));
std::make_unique<ShardFilterStage>(opCtx, shardMetadata, ws.get(), std::move(root), false);
// The backup plan is SHARDING_FILTER-COLLSCAN.
std::unique_ptr<PlanStage> collScanPlan = std::make_unique<CollectionScan>(
opCtx, coll, CollectionScanParams{}, ws.get(), nullptr);
collScanPlan = std::make_unique<ShardFilterStage>(
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<TrialStage>(opCtx,
ws.get(),
Expand Down
Loading