/**
         * A template used by many tests below.
         * Fill out numObj objects, sort them in the order provided by 'direction'.
         * If extAllowed is true, sorting will use use external sorting if available.
         * If limit is not zero, we limit the output of the sort stage to 'limit' results.
         */
        void sortAndCheck(int direction) {
            WorkingSet* ws = new WorkingSet();
            MockStage* ms = new MockStage(ws);

            // Insert a mix of the various types of data.
            insertVarietyOfObjects(ms);

            SortStageParams params;
            params.pattern = BSON("foo" << direction);

            // Must fetch so we can look at the doc as a BSONObj.
            PlanExecutor runner(ws, new FetchStage(ws, new SortStage(params, ws, ms), NULL));

            // Look at pairs of objects to make sure that the sort order is pairwise (and therefore
            // totally) correct.
            BSONObj last;
            ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&last, NULL));

            // Count 'last'.
            int count = 1;

            BSONObj current;
            while (Runner::RUNNER_ADVANCED == runner.getNext(&current, NULL)) {
                int cmp = sgn(current.woSortOrder(last, params.pattern));
                // The next object should be equal to the previous or oriented according to the sort
                // pattern.
                ASSERT(cmp == 0 || cmp == 1);
                ++count;
                last = current;
            }

            // No limit, should get all objects back.
            ASSERT_EQUALS(numObj(), count);
        }
Example #2
0
        void run() {
            Client::WriteContext ctx(&_txn, ns());
            
            Database* db = ctx.ctx().db();
            Collection* coll = db->getCollection(&_txn, ns());
            if (!coll) {
                coll = db->createCollection(&_txn, ns());
            }
            fillData();

            // The data we're going to later invalidate.
            set<DiskLoc> locs;
            getLocs(&locs, coll);

            // Build the mock scan stage which feeds the data.
            WorkingSet ws;
            auto_ptr<MockStage> ms(new MockStage(&ws));
            insertVarietyOfObjects(ms.get(), coll);

            SortStageParams params;
            params.collection = coll;
            params.pattern = BSON("foo" << 1);
            params.limit = limit();
            auto_ptr<SortStage> ss(new SortStage(&_txn, params, &ws, ms.get()));

            const int firstRead = 10;

            // Have sort read in data from the mock stage.
            for (int i = 0; i < firstRead; ++i) {
                WorkingSetID id = WorkingSet::INVALID_ID;
                PlanStage::StageState status = ss->work(&id);
                ASSERT_NOT_EQUALS(PlanStage::ADVANCED, status);
            }

            // We should have read in the first 'firstRead' locs.  Invalidate the first.
            ss->saveState();
            set<DiskLoc>::iterator it = locs.begin();
            ss->invalidate(*it++, INVALIDATION_DELETION);
            ss->restoreState(&_txn);

            // Read the rest of the data from the mock stage.
            while (!ms->isEOF()) {
                WorkingSetID id = WorkingSet::INVALID_ID;
                ss->work(&id);
            }

            // Release to prevent double-deletion.
            ms.release();

            // Let's just invalidate everything now.
            ss->saveState();
            while (it != locs.end()) {
                ss->invalidate(*it++, INVALIDATION_DELETION);
            }
            ss->restoreState(&_txn);

            // Invalidation of data in the sort stage fetches it but passes it through.
            int count = 0;
            while (!ss->isEOF()) {
                WorkingSetID id = WorkingSet::INVALID_ID;
                PlanStage::StageState status = ss->work(&id);
                if (PlanStage::ADVANCED != status) { continue; }
                WorkingSetMember* member = ws.get(id);
                ASSERT(member->hasObj());
                ASSERT(!member->hasLoc());
                ++count;
            }
            ctx.commit();

            // Returns all docs.
            ASSERT_EQUALS(limit() ? limit() : numObj(), count);
        }
        void run() {
            Client::WriteContext ctx(ns());
            fillData();

            // The data we're going to later invalidate.
            set<DiskLoc> locs;
            getLocs(&locs);

            // Build the mock stage which feeds the data.
            WorkingSet ws;
            auto_ptr<MockStage> ms(new MockStage(&ws));
            insertVarietyOfObjects(ms.get());

            SortStageParams params;
            params.pattern = BSON("foo" << 1);
            auto_ptr<SortStage> ss(new SortStage(params, &ws, ms.get()));

            const int firstRead = 10;

            // Have sort read in data from the mock stage.
            for (int i = 0; i < firstRead; ++i) {
                WorkingSetID id;
                PlanStage::StageState status = ss->work(&id);
                ASSERT_NOT_EQUALS(PlanStage::ADVANCED, status);
            }

            // We should have read in the first 'firstRead' locs.  Invalidate the first.
            ss->prepareToYield();
            set<DiskLoc>::iterator it = locs.begin();
            ss->invalidate(*it++);
            ss->recoverFromYield();

            // Read the rest of the data from the mock stage.
            while (!ms->isEOF()) {
                WorkingSetID id;
                ss->work(&id);
            }

            // Release to prevent double-deletion.
            ms.release();

            // Let's just invalidate everything now.
            ss->prepareToYield();
            while (it != locs.end()) {
                ss->invalidate(*it++);
            }
            ss->recoverFromYield();

            // The sort should still work.
            int count = 0;
            while (!ss->isEOF()) {
                WorkingSetID id;
                PlanStage::StageState status = ss->work(&id);
                if (PlanStage::ADVANCED != status) { continue; }
                WorkingSetMember* member = ws.get(id);
                ASSERT(member->hasObj());
                ASSERT(!member->hasLoc());
                ++count;
            }

            // We've invalidated everything, but only 2/3 of our data had a DiskLoc to be
            // invalidated.  We get the rest as-is.
            ASSERT_EQUALS(count, numObj());
        }
        void run() {
            Client::WriteContext ctx(ns());
            Database* db = ctx.ctx().db();
            Collection* coll = db->getCollection(ns());
            if (!coll) {
                coll = db->createCollection(ns());
            }
            fillData();

            // The data we're going to later invalidate.
            set<DiskLoc> locs;
            getLocs(&locs, coll);

            // Build the mock scan stage which feeds the data.
            WorkingSet ws;
            auto_ptr<MockStage> ms(new MockStage(&ws));
            insertVarietyOfObjects(ms.get(), coll);

            SortStageParams params;
            params.pattern = BSON("foo" << 1);
            params.limit = limit();
            auto_ptr<SortStage> ss(new SortStage(params, &ws, ms.get()));

            const int firstRead = 10;

            // Have sort read in data from the mock stage.
            for (int i = 0; i < firstRead; ++i) {
                WorkingSetID id;
                PlanStage::StageState status = ss->work(&id);
                ASSERT_NOT_EQUALS(PlanStage::ADVANCED, status);
            }

            // We should have read in the first 'firstRead' locs.  Invalidate the first.
            ss->prepareToYield();
            set<DiskLoc>::iterator it = locs.begin();
            ss->invalidate(*it++);
            ss->recoverFromYield();

            // Read the rest of the data from the mock stage.
            while (!ms->isEOF()) {
                WorkingSetID id;
                ss->work(&id);
            }

            // Release to prevent double-deletion.
            ms.release();

            // Let's just invalidate everything now.
            ss->prepareToYield();
            while (it != locs.end()) {
                ss->invalidate(*it++);
            }
            ss->recoverFromYield();

            // After invalidating all our data, we have nothing left to sort.
            int count = 0;
            while (!ss->isEOF()) {
                WorkingSetID id;
                PlanStage::StageState status = ss->work(&id);
                if (PlanStage::ADVANCED != status) { continue; }
                WorkingSetMember* member = ws.get(id);
                ASSERT(member->hasObj());
                ASSERT(!member->hasLoc());
                ++count;
            }

            // Therefore, we expect an empty result set from running the sort stage to completion.
            ASSERT_EQUALS(0, count);
        }