Value DocumentSourceCursor::serialize(bool explain) const { // we never parse a documentSourceCursor, so we only serialize for explain if (!explain) return Value(); Lock::DBRead lk(ns); Client::Context ctx(ns, storageGlobalParams.dbpath, /*doVersion=*/false); ClientCursorPin pin(_cursorId); ClientCursor* cursor = pin.c(); uassert(17135, "Cursor deleted. Was the collection or database dropped?", cursor); cursor->c()->recoverFromYield(); return Value(DOC(getSourceName() << DOC("query" << Value(_query) << "sort" << (!_sort.isEmpty() ? Value(_sort) : Value()) << "limit" << (_limit ? Value(_limit->getLimit()) : Value()) << "fields" << (_projection ? Value(_projection->getSpec()) : Value()) << "indexOnly" << canUseCoveredIndex(cursor) << "cursorType" << cursor->c()->toString() ))); // TODO get more plan information }
void DocumentSourceCursor::findNext() { if ( !_cursorWithContext ) { pCurrent.reset(); 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 BSONObj documentObj; if (canUseCoveredIndex()) { // Can't have a Chunk Manager if we are here documentObj = cursor()->c()->keyFieldsOnly()->hydrate(cursor()->currKey()); } else { documentObj = cursor()->current(); // check to see if this is a new object we don't own yet // because of a chunk migration if ( chunkMgr() && ! chunkMgr()->belongsToMe(documentObj) ) continue; if (_projection) { documentObj = _projection->transform(documentObj); } } pCurrent = Document::createFromBsonObj( &documentObj, NULL /* LATER pDependencies.get()*/); 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.reset(); }
void DocumentSourceCursor::yieldSometimes() { try { // SERVER-5752 may make this try unnecessary // if we are index only we don't need the recored bool cursorOk = cursor()->yieldSometimes(canUseCoveredIndex() ? ClientCursor::DontNeed : ClientCursor::WillNeed); uassert( 16028, "collection or database disappeared when cursor yielded", cursorOk ); } catch(SendStaleConfigException& e){ // We want to ignore this because the migrated documents will be filtered out of the // cursor anyway and, we don't want to restart the aggregation after every migration. log() << "Config changed during aggregation - command will resume" << endl; // useful for debugging but off by default to avoid looking like a scary error. LOG(1) << "aggregation stale config exception: " << e.what() << endl; } }
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; }