示例#1
0
    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();
    }
示例#2
0
    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;
    }