diff options
author | Mathias Stearn <mathias@10gen.com> | 2013-12-20 14:57:18 -0500 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2014-01-21 12:55:49 -0500 |
commit | d0037946dc103ffa648f7e8937f2c55351b03c53 (patch) | |
tree | 4b249ff3088fe64a234754b513e771f7acdaa8b6 /src/mongo/db/pipeline/document_source.cpp | |
parent | 8bab6b0c9fad64286c22d928bbe8ebfae7e8b2c4 (diff) | |
download | mongo-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.cpp | 138 |
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(); - } } |