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
    }
Exemple #2
0
    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();
    }
Exemple #3
0
    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;
    }