Example #1
0
    void run() {
        // Insert a ton of documents with a: 1
        for (size_t i = 0; i < 1000; ++i) {
            insert(BSON("a" << 1));
        }

        // Insert a ton of other documents with a: 2
        for (size_t i = 0; i < 1000; ++i) {
            insert(BSON("a" << 2));
        }

        // Make an index on a:1
        addIndex(BSON("a" << 1));

        AutoGetCollectionForRead ctx(&_txn, ns());
        Collection* coll = ctx.getCollection();

        // Set up the distinct stage.
        std::vector<IndexDescriptor*> indexes;
        coll->getIndexCatalog()->findIndexesByKeyPattern(&_txn, BSON("a" << 1), false, &indexes);
        ASSERT_EQ(indexes.size(), 1U);

        DistinctParams params;
        params.descriptor = indexes[0];
        params.direction = 1;
        // Distinct-ing over the 0-th field of the keypattern.
        params.fieldNo = 0;
        // We'll look at all values in the bounds.
        params.bounds.isSimpleRange = false;
        OrderedIntervalList oil("a");
        oil.intervals.push_back(IndexBoundsBuilder::allValues());
        params.bounds.fields.push_back(oil);

        WorkingSet ws;
        DistinctScan distinct(&_txn, params, &ws);

        WorkingSetID wsid;
        // Get our first result.
        int firstResultWorks = 0;
        while (PlanStage::ADVANCED != distinct.work(&wsid)) {
            ++firstResultWorks;
        }
        // 5 is a bogus number.  There's some amount of setup done by the first few calls but
        // we should return the first result relatively promptly.
        ASSERT_LESS_THAN(firstResultWorks, 5);
        ASSERT_EQUALS(1, getIntFieldDotted(ws, wsid, "a"));

        // Getting our second result should be very quick as we just skip
        // over the first result.
        int secondResultWorks = 0;
        while (PlanStage::ADVANCED != distinct.work(&wsid)) {
            ++secondResultWorks;
        }
        ASSERT_EQUALS(2, getIntFieldDotted(ws, wsid, "a"));
        // This is 0 because we don't have to loop for several values; we just skip over
        // all the 'a' values.
        ASSERT_EQUALS(0, secondResultWorks);

        ASSERT_EQUALS(PlanStage::IS_EOF, distinct.work(&wsid));
    }
Example #2
0
    void run() {
        // Insert a ton of documents with a: [1, 2, 3]
        for (size_t i = 0; i < 1000; ++i) {
            insert(BSON("a" << BSON_ARRAY(1 << 2 << 3)));
        }

        // Insert a ton of other documents with a: [4, 5, 6]
        for (size_t i = 0; i < 1000; ++i) {
            insert(BSON("a" << BSON_ARRAY(4 << 5 << 6)));
        }

        // Make an index on a:1
        addIndex(BSON("a" << 1));

        AutoGetCollectionForRead ctx(&_txn, ns());
        Collection* coll = ctx.getCollection();

        // Set up the distinct stage.
        std::vector<IndexDescriptor*> indexes;
        coll->getIndexCatalog()->findIndexesByKeyPattern(&_txn, BSON("a" << 1), false, &indexes);
        verify(indexes.size() == 1);

        DistinctParams params;
        params.descriptor = indexes[0];
        ASSERT_TRUE(params.descriptor->isMultikey(&_txn));

        verify(params.descriptor);
        params.direction = 1;
        // Distinct-ing over the 0-th field of the keypattern.
        params.fieldNo = 0;
        // We'll look at all values in the bounds.
        params.bounds.isSimpleRange = false;
        OrderedIntervalList oil("a");
        oil.intervals.push_back(IndexBoundsBuilder::allValues());
        params.bounds.fields.push_back(oil);

        WorkingSet ws;
        DistinctScan distinct(&_txn, params, &ws);

        // We should see each number in the range [1, 6] exactly once.
        std::set<int> seen;

        WorkingSetID wsid;
        PlanStage::StageState state;
        while (PlanStage::IS_EOF != (state = distinct.work(&wsid))) {
            if (PlanStage::ADVANCED == state) {
                // Check int value.
                int currentNumber = getIntFieldDotted(ws, wsid, "a");
                ASSERT_GREATER_THAN_OR_EQUALS(currentNumber, 1);
                ASSERT_LESS_THAN_OR_EQUALS(currentNumber, 6);

                // Should see this number only once.
                ASSERT_TRUE(seen.find(currentNumber) == seen.end());
                seen.insert(currentNumber);
            }
        }

        ASSERT_EQUALS(6U, seen.size());
    }
Example #3
0
    // static
    OrderedIntervalList IndexBoundsBuilder::allValuesForField(const BSONElement& elt) {
        // ARGH, BSONValue would make this shorter.
        BSONObjBuilder bob;
        if (-1 == elt.number()) {
            // Index should go from MaxKey to MinKey as it's descending.
            bob.appendMaxKey("");
            bob.appendMinKey("");
        }
        else {
            // Index goes from MinKey to MaxKey as it's ascending.
            bob.appendMinKey("");
            bob.appendMaxKey("");
        }

        OrderedIntervalList oil(elt.fieldName());
        oil.intervals.push_back(makeRangeInterval(bob.obj(), true, true));
        return oil;
    }
Example #4
0
    IndexScan* createIndexScan(BSONObj startKey,
                               BSONObj endKey,
                               bool startInclusive,
                               bool endInclusive,
                               int direction = 1) {
        IndexCatalog* catalog = _coll->getIndexCatalog();
        std::vector<IndexDescriptor*> indexes;
        catalog->findIndexesByKeyPattern(&_opCtx, BSON("x" << 1), false, &indexes);
        ASSERT_EQ(indexes.size(), 1U);

        IndexScanParams params(&_opCtx, *indexes[0]);
        params.direction = direction;

        OrderedIntervalList oil("x");
        BSONObjBuilder bob;
        bob.appendAs(startKey.firstElement(), "");
        bob.appendAs(endKey.firstElement(), "");
        oil.intervals.push_back(Interval(bob.obj(), startInclusive, endInclusive));
        params.bounds.fields.push_back(oil);

        MatchExpression* filter = NULL;
        return new IndexScan(&_opCtx, params, &_ws, filter);
    }
Example #5
0
    IndexScan* createIndexScan(BSONObj startKey,
                               BSONObj endKey,
                               bool startInclusive,
                               bool endInclusive,
                               int direction = 1) {
        IndexCatalog* catalog = _coll->getIndexCatalog();
        IndexDescriptor* descriptor = catalog->findIndexByKeyPattern(&_txn, BSON("x" << 1));
        invariant(descriptor);

        IndexScanParams params;
        params.descriptor = descriptor;
        params.direction = direction;

        OrderedIntervalList oil("x");
        BSONObjBuilder bob;
        bob.appendAs(startKey.firstElement(), "");
        bob.appendAs(endKey.firstElement(), "");
        oil.intervals.push_back(Interval(bob.obj(), startInclusive, endInclusive));
        params.bounds.fields.push_back(oil);

        MatchExpression* filter = NULL;
        return new IndexScan(&_txn, params, &_ws, filter);
    }