summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/document_source.cpp
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2013-12-20 14:57:18 -0500
committerMathias Stearn <mathias@10gen.com>2014-01-21 12:55:49 -0500
commitd0037946dc103ffa648f7e8937f2c55351b03c53 (patch)
tree4b249ff3088fe64a234754b513e771f7acdaa8b6 /src/mongo/db/pipeline/document_source.cpp
parent8bab6b0c9fad64286c22d928bbe8ebfae7e8b2c4 (diff)
downloadmongo-d0037946dc103ffa648f7e8937f2c55351b03c53.tar.gz
SERVER-12180 Clean up dependency tracking code
Behavior changes (none effect semantics of pipeline, just implementation): * We now track what we know about fields and metadata separately. This allows us to prove that we won't need the text score if we see a $group or $out. * If we don't need any fields from the source document we now use a projection that will return an empty document, or just the text score if it is needed. We used to use {_id: 0} which returned all other fields. Code organization changes: * Dependencies are now tracked using a dedicated struct rather than a set<string> with some magic strings. * ParsedDeps is now a proper class rather than a typedef. * Removed ExpressionFieldPath::_baseVar since its former role is fulfilled better by _variable.
Diffstat (limited to 'src/mongo/db/pipeline/document_source.cpp')
-rw-r--r--src/mongo/db/pipeline/document_source.cpp138
1 files changed, 0 insertions, 138 deletions
diff --git a/src/mongo/db/pipeline/document_source.cpp b/src/mongo/db/pipeline/document_source.cpp
index f07739479e3..d4c21fca2fd 100644
--- a/src/mongo/db/pipeline/document_source.cpp
+++ b/src/mongo/db/pipeline/document_source.cpp
@@ -59,8 +59,6 @@ namespace mongo {
void DocumentSource::dispose() {
if ( pSource ) {
- // This is required for the DocumentSourceCursor to release its read lock, see
- // SERVER-6123.
pSource->dispose();
}
}
@@ -71,140 +69,4 @@ namespace mongo {
array.push_back(entry);
}
}
-
- BSONObj DocumentSource::depsToProjection(const set<string>& deps) {
- BSONObjBuilder bb;
-
- bool needId = false;
-
- string last;
- for (set<string>::const_iterator it(deps.begin()), end(deps.end()); it!=end; ++it) {
- if (str::startsWith(*it, "_id") && (it->size() == 3 || (*it)[3] == '.')) {
- // _id and subfields are handled specially due in part to SERVER-7502
- needId = true;
- continue;
- }
-
- if (str::startsWith(*it, '$')) {
- if (*it == "$textScore") {
- // textScore metadata
- bb.append(Document::metaFieldTextScore, BSON("$meta" << "textScore"));
- continue;
- }
- }
-
- if (!last.empty() && str::startsWith(*it, last)) {
- // we are including a parent of *it so we don't need to include this field
- // explicitly. In fact, due to SERVER-6527 if we included this field, the parent
- // wouldn't be fully included. This logic relies on on set iterators going in
- // lexicographic order so that a string is always directly before of all fields it
- // prefixes.
- continue;
- }
-
- last = *it + '.';
- bb.append(*it, 1);
- }
-
- if (needId) // we are explicit either way
- bb.append("_id", 1);
- else
- bb.append("_id", 0);
-
- return bb.obj();
- }
-
- // Taken as a whole, these three functions should produce the same output document given the
- // same deps set as mongo::Projection::transform would on the output of depsToProjection. The
- // only exceptions are that we correctly handle the case where no fields are needed and we don't
- // need to work around the above mentioned bug with subfields of _id (SERVER-7502). This is
- // tested in a DEV block in DocumentSourceCursor::findNext().
- //
- // Output from this function is input for the next two
- //
- // ParsedDeps is a simple recursive look-up table. For each field in a ParsedDeps:
- // If the value has type==Bool, the whole field is needed
- // If the value has type==Object, the fields in the subobject are needed
- // All other fields should be missing which means not needed
- DocumentSource::ParsedDeps DocumentSource::parseDeps(const set<string>& deps) {
- MutableDocument md;
-
- string last;
- for (set<string>::const_iterator it(deps.begin()), end(deps.end()); it!=end; ++it) {
- if (str::startsWith(*it, '$')) {
- // documentFromBsonWithDeps doesn't handle meta data
- if (*it == "$textScore")
- return ParsedDeps();
- }
-
- if (!last.empty() && str::startsWith(*it, last)) {
- // we are including a parent of *it so we don't need to include this field
- // explicitly. In fact, if we included this field, the parent wouldn't be fully
- // included. This logic relies on on set iterators going in lexicographic order so
- // that a string is always directly before of all fields it prefixes.
- continue;
- }
- last = *it + '.';
- md.setNestedField(*it, Value(true));
- }
-
- return md.freeze();
- }
-
- // Helper for next function
- static Value arrayHelper(const BSONObj& bson, const DocumentSource::ParsedDeps& neededFields) {
- BSONObjIterator it(bson);
-
- vector<Value> values;
- while (it.more()) {
- BSONElement bsonElement(it.next());
- if (bsonElement.type() == Object) {
- Document sub = DocumentSource::documentFromBsonWithDeps(
- bsonElement.embeddedObject(),
- neededFields);
- values.push_back(Value(sub));
- }
-
- if (bsonElement.type() == Array) {
- values.push_back(arrayHelper(bsonElement.embeddedObject(), neededFields));
- }
- }
-
- return Value::consume(values);
- }
-
- Document DocumentSource::documentFromBsonWithDeps(const BSONObj& bson,
- const ParsedDeps& neededFields) {
- MutableDocument md(neededFields.size());
-
- BSONObjIterator it(bson);
- while (it.more()) {
- BSONElement bsonElement (it.next());
- StringData fieldName = bsonElement.fieldNameStringData();
- Value isNeeded = neededFields[fieldName];
-
- if (isNeeded.missing())
- continue;
-
- if (isNeeded.getType() == Bool) {
- md.addField(fieldName, Value(bsonElement));
- continue;
- }
-
- dassert(isNeeded.getType() == Object);
-
- if (bsonElement.type() == Object) {
- Document sub = documentFromBsonWithDeps(bsonElement.embeddedObject(),
- isNeeded.getDocument());
- md.addField(fieldName, Value(sub));
- }
-
- if (bsonElement.type() == Array) {
- md.addField(fieldName, arrayHelper(bsonElement.embeddedObject(),
- isNeeded.getDocument()));
- }
- }
-
- return md.freeze();
- }
}