diff options
author | Denis Grebennicov <denis.grebennicov@Deniss-MacBook-Pro-2.local> | 2021-04-15 13:11:51 +0200 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-05-04 09:42:23 +0000 |
commit | 3d62d53403edf06f3eaee84913dd6571a9af1132 (patch) | |
tree | 871cefdc9a2fa32e57b08e184173e45d39940839 | |
parent | 91e5ed924afeda96bdf0e67d9f491ae1aa3082fd (diff) | |
download | mongo-3d62d53403edf06f3eaee84913dd6571a9af1132.tar.gz |
SERVER-55058 More move optimizations for Document/Value
-rw-r--r-- | src/mongo/db/exec/document_value/document.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/exec/document_value/document.h | 19 | ||||
-rw-r--r-- | src/mongo/db/exec/document_value/document_value_test.cpp | 28 | ||||
-rw-r--r-- | src/mongo/db/exec/document_value/value.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/exec/document_value/value.h | 22 | ||||
-rw-r--r-- | src/mongo/db/exec/document_value/value_internal.h | 6 | ||||
-rw-r--r-- | src/mongo/db/exec/projection_executor_utils.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/accumulator_js_reduce.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/accumulator_merge_objects.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_change_stream_transform.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_group.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_redact.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 2 |
13 files changed, 106 insertions, 15 deletions
diff --git a/src/mongo/db/exec/document_value/document.cpp b/src/mongo/db/exec/document_value/document.cpp index f9c37fb91ac..9e639d321ff 100644 --- a/src/mongo/db/exec/document_value/document.cpp +++ b/src/mongo/db/exec/document_value/document.cpp @@ -518,7 +518,7 @@ Document Document::fromBsonWithMetaData(const BSONObj& bson) { return md.freeze(); } -Document Document::getOwned() const { +Document Document::getOwned() const& { if (isOwned()) { return *this; } else { @@ -528,6 +528,16 @@ Document Document::getOwned() const { } } +Document Document::getOwned() && { + if (isOwned()) { + return std::move(*this); + } else { + MutableDocument md(std::move(*this)); + md.makeOwned(); + return md.freeze(); + } +} + MutableDocument::MutableDocument(size_t expectedFields) : _storageHolder(nullptr), _storage(_storageHolder) { if (expectedFields) { diff --git a/src/mongo/db/exec/document_value/document.h b/src/mongo/db/exec/document_value/document.h index 439c88f1cc2..526fa10eb60 100644 --- a/src/mongo/db/exec/document_value/document.h +++ b/src/mongo/db/exec/document_value/document.h @@ -311,7 +311,8 @@ public: /** * Returns a document that owns the underlying BSONObj. */ - Document getOwned() const; + Document getOwned() const&; + Document getOwned() &&; /** * Returns true if the underlying BSONObj is owned. @@ -515,6 +516,10 @@ public: storage().appendField(fieldName, ValueElement::Kind::kInserted) = val; } + void addField(StringData fieldName, Value&& val) { + storage().appendField(fieldName, ValueElement::Kind::kInserted) = std::move(val); + } + /** Update field by key. If there is no field with that key, add one. * * If the new value is missing(), the field is logically removed. @@ -525,6 +530,9 @@ public: void setField(StringData key, const Value& val) { getField(key) = val; } + void setField(StringData key, Value&& val) { + getField(key) = std::move(val); + } MutableValue getField(StringData key) { return MutableValue(storage().getField(key, DocumentStorage::LookupPolicy::kCacheOnly)); } @@ -539,6 +547,9 @@ public: void setField(Position pos, const Value& val) { getField(pos) = val; } + void setField(Position pos, Value&& val) { + getField(pos) = std::move(val); + } MutableValue getField(Position pos) { return MutableValue(storage().getField(pos).val); } @@ -561,12 +572,18 @@ public: void setNestedField(const FieldPath& dottedField, const Value& val) { getNestedField(dottedField) = val; } + void setNestedField(const FieldPath& dottedField, Value&& val) { + getNestedField(dottedField) = std::move(val); + } /// Takes positions vector from Document::getNestedField. All fields in path must exist. MutableValue getNestedField(const std::vector<Position>& positions); void setNestedField(const std::vector<Position>& positions, const Value& val) { getNestedField(positions) = val; } + void setNestedField(const std::vector<Position>& positions, Value&& val) { + getNestedField(positions) = std::move(val); + } /** * Copies all metadata from source if it has any. diff --git a/src/mongo/db/exec/document_value/document_value_test.cpp b/src/mongo/db/exec/document_value/document_value_test.cpp index 6ca845670a3..421da707001 100644 --- a/src/mongo/db/exec/document_value/document_value_test.cpp +++ b/src/mongo/db/exec/document_value/document_value_test.cpp @@ -372,6 +372,23 @@ public: Document final = md.freeze(); ASSERT_EQUALS(3ULL, final.computeSize()); assertRoundTrips(final); + + // Add field to the document as an lvalue. + MutableDocument md1; + Value v1(1); + md1.addField("a", v1); + ASSERT_VALUE_EQ(md1.peek().getField("a"), v1); + + // Set field to the document as an lvalue. + Value v2(2); + md1.setField("a", v2); + ASSERT_VALUE_EQ(md1.peek().getField("a"), v2); + + // Set nested field to the document as an lvalue. + FieldPath xxyyzz("xx.yy.zz"); + Value v3("nested"_sd); + md1.setNestedField(xxyyzz, v3); + ASSERT_VALUE_EQ(md1.peek().getNestedField(xxyyzz), v3); } }; @@ -1157,6 +1174,17 @@ public: ASSERT_EQUALS(-.3, document["banana"].getDouble()); ASSERT_EQUALS(Object, value.getType()); assertRoundTrips(value); + + MutableDocument md1; + Value v(1); + md1.addField("a", v); + + MutableDocument md2; + // Construct Value from an rvalue. + md2.addField("nested", Value(md1.freeze())); + + ASSERT_VALUE_EQ(md2.peek().getNestedField("nested.a"), v); + ASSERT_DOCUMENT_EQ(md1.freeze(), mongo::Document()); } }; diff --git a/src/mongo/db/exec/document_value/value.cpp b/src/mongo/db/exec/document_value/value.cpp index f69bdb313f0..29e5680a303 100644 --- a/src/mongo/db/exec/document_value/value.cpp +++ b/src/mongo/db/exec/document_value/value.cpp @@ -131,6 +131,10 @@ void ValueStorage::putDocument(const Document& d) { putRefCountable(d._storage); } +void ValueStorage::putDocument(Document&& d) { + putRefCountable(std::move(d._storage)); +} + void ValueStorage::putVector(boost::intrusive_ptr<RCVector>&& vec) { fassert(16485, bool(vec)); putRefCountable(std::move(vec)); @@ -159,7 +163,14 @@ Document ValueStorage::getDocument() const { // not in header because document is fwd declared Value::Value(const BSONObj& obj) : _storage(Object, Document(obj.getOwned())) {} + +// An option of providing 'Value(Document)' was rejected in favor of 'Value(const Document&)' and +// 'Value(Document&&)' overloads, and lvalue/rvalue reference overloads of callees, since +// 'Value(Document)' option with a lvalue parameter would result in one extra move operation in +// 'ValueStorage::putDocument()'. Value::Value(const Document& doc) : _storage(Object, doc.isOwned() ? doc : doc.getOwned()) {} +Value::Value(Document&& doc) + : _storage(Object, doc.isOwned() ? std::move(doc) : std::move(doc).getOwned()) {} Value::Value(const BSONElement& elem) : _storage(elem.type()) { switch (elem.type()) { diff --git a/src/mongo/db/exec/document_value/value.h b/src/mongo/db/exec/document_value/value.h index 072ff9e0a18..c89fedcf092 100644 --- a/src/mongo/db/exec/document_value/value.h +++ b/src/mongo/db/exec/document_value/value.h @@ -32,6 +32,7 @@ #include "mongo/base/static_assert.h" #include "mongo/base/string_data.h" #include "mongo/db/exec/document_value/value_internal.h" +#include "mongo/util/concepts.h" #include "mongo/util/uuid.h" namespace mongo { @@ -102,6 +103,7 @@ public: explicit Value(StringData value) : _storage(String, value) {} explicit Value(const std::string& value) : _storage(String, StringData(value)) {} explicit Value(const Document& doc); + explicit Value(Document&& doc); explicit Value(const BSONObj& obj); explicit Value(const BSONArray& arr); explicit Value(const std::vector<BSONObj>& vec); @@ -128,6 +130,11 @@ public: */ explicit Value(const char*) = delete; + Value(const Value&) = default; + Value(Value&&) = default; + Value& operator=(const Value&) = default; + Value& operator=(Value&&) = default; + /** * Prevent implicit conversions to the accepted argument types. */ @@ -397,14 +404,22 @@ inline void swap(mongo::Value& lhs, mongo::Value& rhs) { lhs.swap(rhs); } +MONGO_MAKE_BOOL_TRAIT(CanConstructValueFrom, + (typename T), + (T), + (T val), + // + Value(std::forward<T>(val))); + /** * This class is identical to Value, but supports implicit creation from any of the types explicitly * supported by Value. */ class ImplicitValue : public Value { public: - template <typename T> - ImplicitValue(T arg) : Value(std::move(arg)) {} + TEMPLATE(typename T) + REQUIRES(CanConstructValueFrom<T>) + ImplicitValue(T&& arg) : Value(std::forward<T>(arg)) {} ImplicitValue(std::initializer_list<ImplicitValue> values) : Value(convertToValues(values)) {} @@ -412,6 +427,7 @@ public: static std::vector<Value> convertToValues(const std::vector<int>& vec) { std::vector<Value> values; + values.reserve(vec.size()); for_each(vec.begin(), vec.end(), ([&](const int& val) { values.emplace_back(val); })); return values; } @@ -421,6 +437,7 @@ public: */ static Value convertToValue(const std::vector<ImplicitValue>& vec) { std::vector<Value> values; + values.reserve(vec.size()); for_each( vec.begin(), vec.end(), ([&](const ImplicitValue& val) { values.push_back(val); })); return Value(values); @@ -431,6 +448,7 @@ public: */ static std::vector<Value> convertToValues(const std::vector<ImplicitValue>& list) { std::vector<Value> values; + values.reserve(list.size()); for (const ImplicitValue& val : list) { values.push_back(val); } diff --git a/src/mongo/db/exec/document_value/value_internal.h b/src/mongo/db/exec/document_value/value_internal.h index 19bded8ea42..b19af0e728f 100644 --- a/src/mongo/db/exec/document_value/value_internal.h +++ b/src/mongo/db/exec/document_value/value_internal.h @@ -123,6 +123,11 @@ public: type = t; putDocument(d); } + ValueStorage(BSONType t, Document&& d) { + zero(); + type = t; + putDocument(std::move(d)); + } ValueStorage(BSONType t, boost::intrusive_ptr<RCVector>&& a) { zero(); type = t; @@ -228,6 +233,7 @@ public: void putString(StringData s); void putVector(boost::intrusive_ptr<RCVector>&& v); void putDocument(const Document& d); + void putDocument(Document&& d); void putRegEx(const BSONRegEx& re); void putBinData(const BSONBinData& bd) { putRefCountable(RCString::create(StringData(static_cast<const char*>(bd.data), bd.length))); diff --git a/src/mongo/db/exec/projection_executor_utils.cpp b/src/mongo/db/exec/projection_executor_utils.cpp index 1cbc04531c9..b77b330ff05 100644 --- a/src/mongo/db/exec/projection_executor_utils.cpp +++ b/src/mongo/db/exec/projection_executor_utils.cpp @@ -180,7 +180,7 @@ Value applyFindSliceProjectionHelper(const Document& input, } MutableDocument output(input); - output.setField(fieldName, val); + output.setField(fieldName, std::move(val)); return Value{output.freeze()}; } } // namespace diff --git a/src/mongo/db/pipeline/accumulator_js_reduce.cpp b/src/mongo/db/pipeline/accumulator_js_reduce.cpp index fcc01b061bd..e7192465d7c 100644 --- a/src/mongo/db/pipeline/accumulator_js_reduce.cpp +++ b/src/mongo/db/pipeline/accumulator_js_reduce.cpp @@ -165,7 +165,7 @@ Value AccumulatorInternalJsReduce::getValue(bool toBeMerged) { if (toBeMerged) { MutableDocument output; output.addField("k", _key); - output.addField("v", result); + output.addField("v", std::move(result)); return Value(output.freeze()); } else { return result; diff --git a/src/mongo/db/pipeline/accumulator_merge_objects.cpp b/src/mongo/db/pipeline/accumulator_merge_objects.cpp index 5eb03eed74b..8804a8a0f05 100644 --- a/src/mongo/db/pipeline/accumulator_merge_objects.cpp +++ b/src/mongo/db/pipeline/accumulator_merge_objects.cpp @@ -80,7 +80,7 @@ void AccumulatorMergeObjects::processInternal(const Value& input, bool merging) if (pair.second.missing()) continue; - _output.setField(pair.first, pair.second); + _output.setField(pair.first, std::move(pair.second)); } _memUsageBytes = sizeof(*this) + _output.getApproximateSize(); } diff --git a/src/mongo/db/pipeline/document_source_change_stream_transform.cpp b/src/mongo/db/pipeline/document_source_change_stream_transform.cpp index 1eb9611f2c8..fcb3d898a3c 100644 --- a/src/mongo/db/pipeline/document_source_change_stream_transform.cpp +++ b/src/mongo/db/pipeline/document_source_change_stream_transform.cpp @@ -361,21 +361,22 @@ Document DocumentSourceChangeStreamTransform::applyTransformation(const Document } // Add the post-image, pre-image, namespace, documentKey and other fields as appropriate. - doc.addField(DocumentSourceChangeStream::kFullDocumentField, fullDocument); + doc.addField(DocumentSourceChangeStream::kFullDocumentField, std::move(fullDocument)); if (_includePreImageOptime) { // Set 'kFullDocumentBeforeChangeField' to the pre-image optime. The DSCSLookupPreImage // stage will replace this optime with the actual pre-image taken from the oplog. - doc.addField(DocumentSourceChangeStream::kFullDocumentBeforeChangeField, preImageOpTime); + doc.addField(DocumentSourceChangeStream::kFullDocumentBeforeChangeField, + std::move(preImageOpTime)); } doc.addField(DocumentSourceChangeStream::kNamespaceField, operationType == DocumentSourceChangeStream::kDropDatabaseOpType ? Value(Document{{"db", nss.db()}}) : Value(Document{{"db", nss.db()}, {"coll", nss.coll()}})); - doc.addField(DocumentSourceChangeStream::kDocumentKeyField, documentKey); + doc.addField(DocumentSourceChangeStream::kDocumentKeyField, std::move(documentKey)); // Note that 'updateDescription' might be the 'missing' value, in which case it will not be // serialized. - doc.addField("updateDescription", updateDescription); + doc.addField("updateDescription", std::move(updateDescription)); return doc.freeze(); } diff --git a/src/mongo/db/pipeline/document_source_group.cpp b/src/mongo/db/pipeline/document_source_group.cpp index c4ca7bc932f..a92a05386c5 100644 --- a/src/mongo/db/pipeline/document_source_group.cpp +++ b/src/mongo/db/pipeline/document_source_group.cpp @@ -749,7 +749,7 @@ Document DocumentSourceGroup::makeDocument(const Value& id, // we return null in this case so return objects are predictable out.addField(_accumulatedFields[i].fieldName, Value(BSONNULL)); } else { - out.addField(_accumulatedFields[i].fieldName, val); + out.addField(_accumulatedFields[i].fieldName, std::move(val)); } } diff --git a/src/mongo/db/pipeline/document_source_redact.cpp b/src/mongo/db/pipeline/document_source_redact.cpp index 8fcc1a6c826..eaefcdf672b 100644 --- a/src/mongo/db/pipeline/document_source_redact.cpp +++ b/src/mongo/db/pipeline/document_source_redact.cpp @@ -150,9 +150,9 @@ boost::optional<Document> DocumentSourceRedact::redactObject(const Document& roo const Document::FieldPair field(fields.next()); // This changes CURRENT so don't read from variables after this - const Value val = redactValue(field.second, root); + Value val = redactValue(field.second, root); if (!val.missing()) { - out.addField(field.first, val); + out.addField(field.first, std::move(val)); } } return out.freeze(); diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 4746d3a253c..7a8fa4ec464 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -655,7 +655,7 @@ Value ExpressionObjectToArray::evaluate(const Document& root, Variables* variabl Document::FieldPair pair = iter.next(); MutableDocument keyvalue; keyvalue.addField("k", Value(pair.first)); - keyvalue.addField("v", pair.second); + keyvalue.addField("v", std::move(pair.second)); output.push_back(keyvalue.freezeToValue()); } |