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()); } const int N = 50; for (int i = 0; i < N; ++i) { // We insert a:1 c:i for i=0..49 but in reverse order for the heck of it. insert(BSON("a" << 1 << "c" << N - i - 1)); insert(BSON("b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << -1); BSONObj secondIndex = BSON("b" << 1 << "c" << -1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:-1 MergeSortStageParams msparams; msparams.pattern = BSON("c" << -1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMaxKey(1); params.bounds.endKey = objWithMinKey(1); params.bounds.endKeyInclusive = true; // This is the direction along the index. params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); for (int i = 0; i < N; ++i) { BSONObj first, second; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&first, NULL)); ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(N - i - 1, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
void run() { Client::WriteContext ctx(ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { coll = db->createCollection(&txn, ns()); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:1 MergeSortStageParams msparams; msparams.dedup = false; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; ms->addChild(new IndexScan(params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(params, ws, NULL)); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); for (int i = 0; i < N; ++i) { BSONObj first, second; // We inserted N objects but we get 2 * N from the runner because of dups. ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&first, NULL)); ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(i, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
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()); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "c" << i)); insert(BSON("b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:1 MergeSortStageParams msparams; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:51 (EOF) params.descriptor = getIndex(secondIndex, coll); params.bounds.startKey = BSON("" << 51 << "" << MinKey); params.bounds.endKey = BSON("" << 51 << "" << MaxKey); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); // Only getting results from the a:1 index scan. for (int i = 0; i < N; ++i) { BSONObj obj; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["c"].numberInt()); ASSERT_EQUALS(1, obj["a"].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
void run() { Client::WriteContext ctx(&_txn, ns()); Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(&_txn, ns()); if (!coll) { WriteUnitOfWork wuow(&_txn); coll = db->createCollection(&_txn, ns()); wuow.commit(); } WorkingSet* ws = new WorkingSet(); // Sort by foo:1 MergeSortStageParams msparams; msparams.pattern = BSON("foo" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); IndexScanParams params; params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; int numIndices = 20; for (int i = 0; i < numIndices; ++i) { // 'a', 'b', ... string index(1, 'a' + i); insert(BSON(index << 1 << "foo" << i)); BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); } PlanExecutor* rawExec; Status status = PlanExecutor::make(&_txn, ws, new FetchStage(&_txn, ws, ms, NULL, coll), coll, PlanExecutor::YIELD_MANUAL, &rawExec); ASSERT_OK(status); boost::scoped_ptr<PlanExecutor> exec(rawExec); for (int i = 0; i < numIndices; ++i) { BSONObj obj; ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["foo"].numberInt()); string index(1, 'a' + i); ASSERT_EQUALS(1, obj[index].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }
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()); } WorkingSet* ws = new WorkingSet(); // Sort by foo:1 MergeSortStageParams msparams; msparams.pattern = BSON("foo" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); IndexScanParams params; params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; int numIndices = 20; for (int i = 0; i < numIndices; ++i) { // 'a', 'b', ... string index(1, 'a' + i); insert(BSON(index << 1 << "foo" << i)); BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); } ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); for (int i = 0; i < numIndices; ++i) { BSONObj obj; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["foo"].numberInt()); string index(1, 'a' + i); ASSERT_EQUALS(1, obj[index].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
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()); } WorkingSet ws; // Sort by foo:1 MergeSortStageParams msparams; msparams.pattern = BSON("foo" << 1); auto_ptr<MergeSortStage> ms(new MergeSortStage(msparams, &ws, coll)); IndexScanParams params; params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; // Index 'a'+i has foo equal to 'i'. int numIndices = 20; for (int i = 0; i < numIndices; ++i) { // 'a', 'b', ... string index(1, 'a' + i); insert(BSON(index << 1 << "foo" << i)); BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); ms->addChild(new IndexScan(&_txn, params, &ws, NULL)); } set<DiskLoc> locs; getLocs(&locs, coll); set<DiskLoc>::iterator it = locs.begin(); ctx.commit(); // Get 10 results. Should be getting results in order of 'locs'. int count = 0; while (!ms->isEOF() && count < 10) { WorkingSetID id = WorkingSet::INVALID_ID; PlanStage::StageState status = ms->work(&id); if (PlanStage::ADVANCED != status) { continue; } WorkingSetMember* member = ws.get(id); ASSERT_EQUALS(member->loc, *it); BSONElement elt; string index(1, 'a' + count); ASSERT(member->getFieldDotted(index, &elt)); ASSERT_EQUALS(1, elt.numberInt()); ASSERT(member->getFieldDotted("foo", &elt)); ASSERT_EQUALS(count, elt.numberInt()); ++count; ++it; } // Invalidate locs[11]. Should force a fetch. We don't get it back. ms->prepareToYield(); ms->invalidate(*it, INVALIDATION_DELETION); ms->recoverFromYield(&_txn); // Make sure locs[11] was fetched for us. { // TODO: If we have "return upon invalidation" ever triggerable, do the following test. /* WorkingSetID id = WorkingSet::INVALID_ID; PlanStage::StageState status; do { status = ms->work(&id); } while (PlanStage::ADVANCED != status); WorkingSetMember* member = ws.get(id); ASSERT(!member->hasLoc()); ASSERT(member->hasObj()); string index(1, 'a' + count); BSONElement elt; ASSERT_TRUE(member->getFieldDotted(index, &elt)); ASSERT_EQUALS(1, elt.numberInt()); ASSERT(member->getFieldDotted("foo", &elt)); ASSERT_EQUALS(count, elt.numberInt()); */ ++it; ++count; } // And get the rest. while (!ms->isEOF()) { WorkingSetID id = WorkingSet::INVALID_ID; PlanStage::StageState status = ms->work(&id); if (PlanStage::ADVANCED != status) { continue; } WorkingSetMember* member = ws.get(id); ASSERT_EQUALS(member->loc, *it); BSONElement elt; string index(1, 'a' + count); ASSERT_TRUE(member->getFieldDotted(index, &elt)); ASSERT_EQUALS(1, elt.numberInt()); ASSERT(member->getFieldDotted("foo", &elt)); ASSERT_EQUALS(count, elt.numberInt()); ++count; ++it; } }
void run() { Client::WriteContext ctx(&_txn, ns()); Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(&_txn, ns()); if (!coll) { WriteUnitOfWork wuow(&_txn); coll = db->createCollection(&_txn, ns()); wuow.commit(); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:1 MergeSortStageParams msparams; msparams.dedup = false; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); PlanExecutor* rawExec; Status status = PlanExecutor::make(&_txn, ws, new FetchStage(&_txn, ws, ms, NULL, coll), coll, PlanExecutor::YIELD_MANUAL, &rawExec); ASSERT_OK(status); boost::scoped_ptr<PlanExecutor> exec(rawExec); for (int i = 0; i < N; ++i) { BSONObj first, second; // We inserted N objects but we get 2 * N from the runner because of dups. ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&first, NULL)); ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(i, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }