Exemplo n.º 1
0
    PlanStage::StageState FetchStage::fetchCompleted(WorkingSetID* out) {
        WorkingSetMember* member = _ws->get(_idBeingPagedIn);

        // The DiskLoc we're waiting to page in was invalidated (forced fetch).  Test for
        // matching and maybe pass it up.
        if (member->state == WorkingSetMember::OWNED_OBJ) {
            WorkingSetID memberID = _idBeingPagedIn;
            _idBeingPagedIn = WorkingSet::INVALID_ID;
            return returnIfMatches(member, memberID, out);
        }

        // Assume that the caller has fetched appropriately.
        // TODO: Do we want to double-check the runner?  Not sure how reliable likelyInMemory is
        // on all platforms.
        verify(member->hasLoc());
        verify(!member->hasObj());

        // Make the (unowned) object.
        Record* record = member->loc.rec();
        const char* data = record->dataNoThrowing();
        member->obj = BSONObj(data);

        // Don't need index data anymore as we have an obj.
        member->keyData.clear();
        member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
        verify(!member->obj.isOwned());

        // Return the obj if it passes our filter.
        WorkingSetID memberID = _idBeingPagedIn;
        _idBeingPagedIn = WorkingSet::INVALID_ID;
        return returnIfMatches(member, memberID, out);
    }
Exemplo n.º 2
0
    PlanStage::StageState FetchStage::work(WorkingSetID* out) {
        ++_commonStats.works;

        if (isEOF()) { return PlanStage::IS_EOF; }

        // If we asked our parent for a page-in last time work(...) was called, finish the fetch.
        if (WorkingSet::INVALID_ID != _idBeingPagedIn) {
            cout << "fetch completed, id being paged on " << _idBeingPagedIn << endl;
            return fetchCompleted(out);
        }

        // If we're here, we're not waiting for a DiskLoc to be fetched.  Get another to-be-fetched
        // result from our child.
        WorkingSetID id;
        StageState status = _child->work(&id);

        if (PlanStage::ADVANCED == status) {
            WorkingSetMember* member = _ws->get(id);

            // If there's an obj there, there is no fetching to perform.
            if (member->hasObj()) {
                ++_specificStats.alreadyHasObj;
                return returnIfMatches(member, id, out);
            }

            // We need a valid loc to fetch from and this is the only state that has one.
            verify(WorkingSetMember::LOC_AND_IDX == member->state);
            verify(member->hasLoc());

            Record* record = member->loc.rec();
            const char* data = record->dataNoThrowing();

            if (!recordInMemory(data)) {
                // member->loc points to a record that's NOT in memory.  Pass a fetch request up.
                verify(WorkingSet::INVALID_ID == _idBeingPagedIn);
                _idBeingPagedIn = id;
                *out = id;
                ++_commonStats.needFetch;
                return PlanStage::NEED_FETCH;
            }
            else {
                // Don't need index data anymore as we have an obj.
                member->keyData.clear();
                member->obj = BSONObj(data);
                member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
                return returnIfMatches(member, id, out);
            }
        }
        else {
            if (PlanStage::NEED_FETCH == status) {
                *out = id;
                ++_commonStats.needFetch;
            }
            else if (PlanStage::NEED_TIME == status) {
                ++_commonStats.needTime;
            }
            return status;
        }
    }
Exemplo n.º 3
0
    PlanStage::StageState FetchStage::work(WorkingSetID* out) {
        ++_commonStats.works;

        // Adds the amount of time taken by work() to executionTimeMillis.
        ScopedTimer timer(&_commonStats.executionTimeMillis);

        if (isEOF()) { return PlanStage::IS_EOF; }

        // If we're here, we're not waiting for a DiskLoc to be fetched.  Get another to-be-fetched
        // result from our child.
        WorkingSetID id = WorkingSet::INVALID_ID;
        StageState status = _child->work(&id);

        if (PlanStage::ADVANCED == status) {
            WorkingSetMember* member = _ws->get(id);

            // If there's an obj there, there is no fetching to perform.
            if (member->hasObj()) {
                ++_specificStats.alreadyHasObj;
            }
            else {
                // We need a valid loc to fetch from and this is the only state that has one.
                verify(WorkingSetMember::LOC_AND_IDX == member->state);
                verify(member->hasLoc());

                // Don't need index data anymore as we have an obj.
                member->keyData.clear();
                member->obj = _collection->docFor(member->loc);
                member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
            }

            ++_specificStats.docsExamined;

            return returnIfMatches(member, id, out);
        }
        else if (PlanStage::FAILURE == status) {
            *out = id;
            // If a stage fails, it may create a status WSM to indicate why it
            // failed, in which case 'id' is valid.  If ID is invalid, we
            // create our own error message.
            if (WorkingSet::INVALID_ID == id) {
                mongoutils::str::stream ss;
                ss << "fetch stage failed to read in results from child";
                Status status(ErrorCodes::InternalError, ss);
                *out = WorkingSetCommon::allocateStatusMember( _ws, status);
            }
            return status;
        }
        else {
            if (PlanStage::NEED_TIME == status) {
                ++_commonStats.needTime;
            }
            return status;
        }
    }
Exemplo n.º 4
0
    PlanStage::StageState CollectionScan::work(WorkingSetID* out) {
        ++_commonStats.works;

        // Adds the amount of time taken by work() to executionTimeMillis.
        ScopedTimer timer(&_commonStats.executionTimeMillis);

        if (_isDead) { return PlanStage::DEAD; }

        // Do some init if we haven't already.
        if (NULL == _iter) {
            if ( _params.collection == NULL ) {
                _isDead = true;
                return PlanStage::DEAD;
            }

            if (_lastSeenLoc.isNull()) {
                _iter.reset( _params.collection->getIterator( _txn,
                                                              _params.start,
                                                              _params.direction ) );
            }
            else {
                invariant(_params.tailable);

                _iter.reset( _params.collection->getIterator( _txn,
                                                              _lastSeenLoc,
                                                              _params.direction ) );

                // Advance _iter past where we were last time. If it returns something else, mark us
                // as dead since we want to signal an error rather than silently dropping data from
                // the stream. This is related to the _lastSeenLock handling in invalidate.
                if (_iter->getNext() != _lastSeenLoc) {
                    _isDead = true;
                    return PlanStage::DEAD;
                }
            }

            ++_commonStats.needTime;
            return PlanStage::NEED_TIME;
        }

        // Should we try getNext() on the underlying _iter?
        if (isEOF())
            return PlanStage::IS_EOF;

        const DiskLoc curr = _iter->curr();
        if (curr.isNull()) {
            // We just hit EOF
            if (_params.tailable)
                _iter.reset(); // pick up where we left off on the next call to work()
            return PlanStage::IS_EOF;
        }

        _lastSeenLoc = curr;

        // See if the record we're about to access is in memory. If not, pass a fetch request up.
        // Note that curr() does not touch the record (on MMAPv1 which is the only place we use
        // NEED_FETCH) so we are able to yield before touching the record, as long as we do so
        // before calling getNext().
        {
            std::auto_ptr<RecordFetcher> fetcher(
                _params.collection->documentNeedsFetch(_txn, curr));
            if (NULL != fetcher.get()) {
                WorkingSetMember* member = _workingSet->get(_wsidForFetch);
                member->loc = curr;
                // Pass the RecordFetcher off to the WSM.
                member->setFetcher(fetcher.release());
                *out = _wsidForFetch;
                _commonStats.needFetch++;
                return NEED_FETCH;
            }
        }

        WorkingSetID id = _workingSet->allocate();
        WorkingSetMember* member = _workingSet->get(id);
        member->loc = curr;
        member->obj = _iter->dataFor(member->loc).releaseToBson();
        member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;

        // Advance the iterator.
        invariant(_iter->getNext() == curr);

        return returnIfMatches(member, id, out);
    }
Exemplo n.º 5
0
    PlanStage::StageState CollectionScan::work(WorkingSetID* out) {
        ++_commonStats.works;

        // Adds the amount of time taken by work() to executionTimeMillis.
        ScopedTimer timer(&_commonStats.executionTimeMillis);

        if (_isDead) { return PlanStage::DEAD; }

        // Do some init if we haven't already.
        if (NULL == _iter) {
            if ( _params.collection == NULL ) {
                _isDead = true;
                return PlanStage::DEAD;
            }

            if (_lastSeenLoc.isNull()) {
                _iter.reset( _params.collection->getIterator( _txn,
                                                              _params.start,
                                                              _params.direction ) );
            }
            else {
                invariant(_params.tailable);

                _iter.reset( _params.collection->getIterator( _txn,
                                                              _lastSeenLoc,
                                                              _params.direction ) );

                // Advance _iter past where we were last time. If it returns something else, mark us
                // as dead since we want to signal an error rather than silently dropping data from
                // the stream. This is related to the _lastSeenLock handling in invalidate.
                if (_iter->getNext() != _lastSeenLoc) {
                    _isDead = true;
                    return PlanStage::DEAD;
                }
            }

            ++_commonStats.needTime;
            return PlanStage::NEED_TIME;
        }

        // Should we try getNext() on the underlying _iter?
        if (isEOF())
            return PlanStage::IS_EOF;

        // See if the record we're about to access is in memory. If not, pass a fetch request up.
        // Note that curr() returns the same thing as getNext() will, except without advancing the
        // iterator or touching the DiskLoc. This means that we can use curr() to check whether we
        // need to fetch on the DiskLoc prior to touching it with getNext().
        DiskLoc curr = _iter->curr();
        if (!curr.isNull()) {
            std::auto_ptr<RecordFetcher> fetcher(
                _params.collection->documentNeedsFetch(_txn, curr));
            if (NULL != fetcher.get()) {
                WorkingSetMember* member = _workingSet->get(_wsidForFetch);
                member->loc = curr;
                // Pass the RecordFetcher off to the WSM.
                member->setFetcher(fetcher.release());
                *out = _wsidForFetch;
                _commonStats.needFetch++;
                return NEED_FETCH;
            }
        }

        // What we'll return to the user.
        DiskLoc nextLoc;

        // See if _iter gives us anything new.
        nextLoc = _iter->getNext();
        if (nextLoc.isNull()) {
            if (_params.tailable)
                _iter.reset(); // pick up where we left off on the next call to work()
            return PlanStage::IS_EOF;
        }

        _lastSeenLoc = nextLoc;

        WorkingSetID id = _workingSet->allocate();
        WorkingSetMember* member = _workingSet->get(id);
        member->loc = nextLoc;
        member->obj = _iter->dataFor(member->loc).releaseToBson();
        member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;

        return returnIfMatches(member, id, out);
    }