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(); }
void DocumentSourceCursor::loadBatch() { if (!_cursorId) { dispose(); return; } // We have already validated the sharding version when we constructed the cursor // so we shouldn't check it again. Lock::DBRead lk(_ns); Client::Context ctx(_ns, storageGlobalParams.dbpath, /*doVersion=*/false); ClientCursorPin pin(_cursorId); ClientCursor* cursor = pin.c(); uassert(16950, "Cursor deleted. Was the collection or database dropped?", cursor); Runner* runner = cursor->getRunner(); runner->restoreState(); int memUsageBytes = 0; BSONObj obj; Runner::RunnerState state; while ((state = runner->getNext(&obj, NULL)) == Runner::RUNNER_ADVANCED) { if (_haveDeps && !_projectionInQuery) { _currentBatch.push_back(documentFromBsonWithDeps(obj, _dependencies)); } else { _currentBatch.push_back(Document::fromBsonWithMetaData(obj)); } if (_limit) { if (++_docsAddedToBatches == _limit->getLimit()) { break; } verify(_docsAddedToBatches < _limit->getLimit()); } memUsageBytes += _currentBatch.back().getApproximateSize(); if (memUsageBytes > MaxBytesToReturnToClientAtOnce) { // End this batch and prepare cursor for yielding. runner->saveState(); cc().curop()->yielded(); return; } } // If we got here, there won't be any more documents, so destroy the cursor and runner. _cursorId = 0; pin.deleteUnderlying(); uassert(16028, "collection or index disappeared when cursor yielded", state != Runner::RUNNER_DEAD); uassert(17285, "cursor encountered an error", state != Runner::RUNNER_ERROR); massert(17286, str::stream() << "Unexpected return from Runner::getNext: " << state, state == Runner::RUNNER_EOF || state == Runner::RUNNER_ADVANCED); }
void DocumentSourceCursor::loadBatch() { if (!_cursorId) { dispose(); return; } // We have already validated the sharding version when we constructed the cursor // so we shouldn't check it again. Lock::DBRead lk(ns); Client::Context ctx(ns, storageGlobalParams.dbpath, /*doVersion=*/false); ClientCursorPin pin(_cursorId); ClientCursor* cursor = pin.c(); uassert(16950, "Cursor deleted. Was the collection or database dropped?", cursor); cursor->c()->recoverFromYield(); int memUsageBytes = 0; for( ; cursor->ok(); cursor->advance() ) { yieldSometimes(cursor); if ( !cursor->ok() ) { // The cursor was exhausted during the yield. break; } if ( !cursor->currentMatches() || cursor->currentIsDup() ) continue; // grab the matching document if (canUseCoveredIndex(cursor)) { // Can't have collection metadata if we are here BSONObj indexKey = cursor->currKey(); _currentBatch.push_back(Document(cursor->c()->keyFieldsOnly()->hydrate(indexKey))); } else { BSONObj next = cursor->current(); // check to see if this is a new object we don't own yet // because of a chunk migration if (_collMetadata) { KeyPattern kp( _collMetadata->getKeyPattern() ); if ( !_collMetadata->keyBelongsToMe( kp.extractSingleKey( next ) ) ) continue; } _currentBatch.push_back(_projection ? documentFromBsonWithDeps(next, _dependencies) : Document(next)); } if (_limit) { if (++_docsAddedToBatches == _limit->getLimit()) { break; } verify(_docsAddedToBatches < _limit->getLimit()); } memUsageBytes += _currentBatch.back().getApproximateSize(); if (memUsageBytes > MaxBytesToReturnToClientAtOnce) { // End this batch and prepare cursor for yielding. cursor->advance(); if (cursor->c()->supportYields()) { ClientCursor::YieldData data; cursor->prepareToYield(data); } else { cursor->c()->noteLocation(); } return; } } // If we got here, there aren't any more documents. // The Cursor must be released, see SERVER-6123. pin.release(); ClientCursor::erase(_cursorId); _cursorId = 0; _collMetadata.reset(); }
void DocumentSourceCursor::findNext() { unstarted = false; if ( !_cursorWithContext ) { pCurrent = Document(); hasCurrent = false; return; } for( ; cursor()->ok(); cursor()->advance() ) { yieldSometimes(); if ( !cursor()->ok() ) { // The cursor was exhausted during the yield. break; } if ( !cursor()->currentMatches() || cursor()->currentIsDup() ) continue; // grab the matching document if (canUseCoveredIndex()) { // Can't have collection metadata if we are here BSONObj indexKey = cursor()->currKey(); pCurrent = Document(cursor()->c()->keyFieldsOnly()->hydrate(indexKey)); } else { BSONObj next = cursor()->current(); // check to see if this is a new object we don't own yet // because of a chunk migration if (collMetadata()) { KeyPattern kp( collMetadata()->getKeyPattern() ); if ( !collMetadata()->keyBelongsToMe( kp.extractSingleKey( next ) ) ) continue; } if (!_projection) { pCurrent = Document(next); } else { pCurrent = documentFromBsonWithDeps(next, _dependencies); if (debug && !_dependencies.empty()) { // Make sure we behave the same as Projection. Projection doesn't have a // way to specify "no fields needed" so we skip the test in that case. MutableDocument byAggo(pCurrent); MutableDocument byProj(Document(_projection->transform(next))); if (_dependencies["_id"].getType() == Object) { // We handle subfields of _id identically to other fields. // Projection doesn't handle them correctly. byAggo.remove("_id"); byProj.remove("_id"); } if (Document::compare(byAggo.peek(), byProj.peek()) != 0) { PRINT(next); PRINT(_dependencies); PRINT(_projection->getSpec()); PRINT(byAggo.peek()); PRINT(byProj.peek()); verify(false); } } } } hasCurrent = true; cursor()->advance(); return; } // If we got here, there aren't any more documents. // The CursorWithContext (and its read lock) must be released, see SERVER-6123. dispose(); pCurrent = Document(); hasCurrent = false; }