summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Grebennicov <denis.grebennicov@Deniss-MacBook-Pro-2.local>2021-04-15 13:11:51 +0200
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-05-04 09:42:23 +0000
commit3d62d53403edf06f3eaee84913dd6571a9af1132 (patch)
tree871cefdc9a2fa32e57b08e184173e45d39940839
parent91e5ed924afeda96bdf0e67d9f491ae1aa3082fd (diff)
downloadmongo-3d62d53403edf06f3eaee84913dd6571a9af1132.tar.gz
SERVER-55058 More move optimizations for Document/Value
-rw-r--r--src/mongo/db/exec/document_value/document.cpp12
-rw-r--r--src/mongo/db/exec/document_value/document.h19
-rw-r--r--src/mongo/db/exec/document_value/document_value_test.cpp28
-rw-r--r--src/mongo/db/exec/document_value/value.cpp11
-rw-r--r--src/mongo/db/exec/document_value/value.h22
-rw-r--r--src/mongo/db/exec/document_value/value_internal.h6
-rw-r--r--src/mongo/db/exec/projection_executor_utils.cpp2
-rw-r--r--src/mongo/db/pipeline/accumulator_js_reduce.cpp2
-rw-r--r--src/mongo/db/pipeline/accumulator_merge_objects.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_change_stream_transform.cpp9
-rw-r--r--src/mongo/db/pipeline/document_source_group.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_redact.cpp4
-rw-r--r--src/mongo/db/pipeline/expression.cpp2
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());
}