void run() { // Various variables we'll need. dbtests::WriteContextForTests ctx(&_opCtx, nss.ns()); Collection* coll = ctx.getCollection(); ASSERT(coll); const int targetDocIndex = 0; const BSONObj query = BSON("foo" << BSON("$gte" << targetDocIndex)); const auto ws = make_unique<WorkingSet>(); const unique_ptr<CanonicalQuery> cq(canonicalize(query)); // Get the RecordIds that would be returned by an in-order scan. vector<RecordId> recordIds; getRecordIds(coll, CollectionScanParams::FORWARD, &recordIds); // Configure a QueuedDataStage to pass the first object in the collection back in a // RID_AND_OBJ state. auto qds = make_unique<QueuedDataStage>(&_opCtx, ws.get()); WorkingSetID id = ws->allocate(); WorkingSetMember* member = ws->get(id); member->recordId = recordIds[targetDocIndex]; const BSONObj oldDoc = BSON("_id" << targetDocIndex << "foo" << targetDocIndex); member->obj = Snapshotted<BSONObj>(SnapshotId(), oldDoc); ws->transitionToRecordIdAndObj(id); qds->pushBack(id); // Configure the delete. auto deleteParams = std::make_unique<DeleteStageParams>(); deleteParams->returnDeleted = true; deleteParams->canonicalQuery = cq.get(); const auto deleteStage = make_unique<DeleteStage>( &_opCtx, std::move(deleteParams), ws.get(), coll, qds.release()); const DeleteStats* stats = static_cast<const DeleteStats*>(deleteStage->getSpecificStats()); // Should return advanced. id = WorkingSet::INVALID_ID; PlanStage::StageState state = deleteStage->work(&id); ASSERT_EQUALS(PlanStage::ADVANCED, state); // Make sure the returned value is what we expect it to be. // Should give us back a valid id. ASSERT_TRUE(WorkingSet::INVALID_ID != id); WorkingSetMember* resultMember = ws->get(id); // With an owned copy of the object, with no RecordId. ASSERT_TRUE(resultMember->hasOwnedObj()); ASSERT_FALSE(resultMember->hasRecordId()); ASSERT_EQUALS(resultMember->getState(), WorkingSetMember::OWNED_OBJ); ASSERT_TRUE(resultMember->obj.value().isOwned()); // Should be the old value. ASSERT_BSONOBJ_EQ(resultMember->obj.value(), oldDoc); // Should have done the delete. ASSERT_EQUALS(stats->docsDeleted, 1U); // That should be it. id = WorkingSet::INVALID_ID; ASSERT_EQUALS(PlanStage::IS_EOF, deleteStage->work(&id)); }
// static void WorkingSetCommon::getStatusMemberObject(const WorkingSet& ws, WorkingSetID wsid, BSONObj* objOut) { invariant(objOut); // Validate ID and working set member. if (WorkingSet::INVALID_ID == wsid) { return; } WorkingSetMember* member = ws.get(wsid); if (!member->hasOwnedObj()) { return; } BSONObj obj = member->obj.value(); if (!isValidStatusMemberObject(obj)) { return; } *objOut = obj; }
void run() { // Populate the collection. for (int i = 0; i < 50; ++i) { insert(BSON("_id" << i << "foo" << i)); } ASSERT_EQUALS(50U, count(BSONObj())); // Various variables we'll need. dbtests::WriteContextForTests ctx(&_opCtx, nss.ns()); OpDebug* opDebug = &CurOp::get(_opCtx)->debug(); Collection* coll = ctx.getCollection(); ASSERT(coll); UpdateRequest request(nss); const CollatorInterface* collator = nullptr; UpdateDriver driver(new ExpressionContext(&_opCtx, collator)); const int targetDocIndex = 10; const BSONObj query = BSON("foo" << BSON("$gte" << targetDocIndex)); const auto ws = make_unique<WorkingSet>(); const unique_ptr<CanonicalQuery> cq(canonicalize(query)); // Get the RecordIds that would be returned by an in-order scan. vector<RecordId> recordIds; getRecordIds(coll, CollectionScanParams::FORWARD, &recordIds); // Populate the request. request.setQuery(query); request.setUpdates(fromjson("{$set: {x: 0}}")); request.setSort(BSONObj()); request.setMulti(false); request.setReturnDocs(UpdateRequest::RETURN_NEW); const std::map<StringData, std::unique_ptr<ExpressionWithPlaceholder>> arrayFilters; ASSERT_DOES_NOT_THROW(driver.parse(request.getUpdates(), arrayFilters, request.isMulti())); // Configure a QueuedDataStage to pass the first object in the collection back in a // RID_AND_OBJ state. auto qds = make_unique<QueuedDataStage>(&_opCtx, ws.get()); WorkingSetID id = ws->allocate(); WorkingSetMember* member = ws->get(id); member->recordId = recordIds[targetDocIndex]; const BSONObj oldDoc = BSON("_id" << targetDocIndex << "foo" << targetDocIndex); member->obj = Snapshotted<BSONObj>(SnapshotId(), oldDoc); ws->transitionToRecordIdAndObj(id); qds->pushBack(id); // Configure the update. UpdateStageParams updateParams(&request, &driver, opDebug); updateParams.canonicalQuery = cq.get(); auto updateStage = make_unique<UpdateStage>(&_opCtx, updateParams, ws.get(), coll, qds.release()); // Should return advanced. id = WorkingSet::INVALID_ID; PlanStage::StageState state = updateStage->work(&id); ASSERT_EQUALS(PlanStage::ADVANCED, state); // Make sure the returned value is what we expect it to be. // Should give us back a valid id. ASSERT_TRUE(WorkingSet::INVALID_ID != id); WorkingSetMember* resultMember = ws->get(id); // With an owned copy of the object, with no RecordId. ASSERT_TRUE(resultMember->hasOwnedObj()); ASSERT_FALSE(resultMember->hasRecordId()); ASSERT_EQUALS(resultMember->getState(), WorkingSetMember::OWNED_OBJ); ASSERT_TRUE(resultMember->obj.value().isOwned()); // Should be the new value. BSONObj newDoc = BSON("_id" << targetDocIndex << "foo" << targetDocIndex << "x" << 0); ASSERT_BSONOBJ_EQ(resultMember->obj.value(), newDoc); // Should have done the update. vector<BSONObj> objs; getCollContents(coll, &objs); ASSERT_BSONOBJ_EQ(objs[targetDocIndex], newDoc); // That should be it. id = WorkingSet::INVALID_ID; ASSERT_EQUALS(PlanStage::IS_EOF, updateStage->work(&id)); }
void run() { // Populate the collection. for (int i = 0; i < 50; ++i) { insert(BSON("_id" << i << "foo" << i)); } ASSERT_EQUALS(50U, count(BSONObj())); // Various variables we'll need. OldClientWriteContext ctx(&_txn, nss.ns()); OpDebug* opDebug = &CurOp::get(_txn)->debug(); Collection* coll = ctx.getCollection(); UpdateLifecycleImpl updateLifecycle(false, nss); UpdateRequest request(nss); UpdateDriver driver((UpdateDriver::Options())); const int targetDocIndex = 10; const BSONObj query = BSON("foo" << BSON("$gte" << targetDocIndex)); const unique_ptr<WorkingSet> ws(stdx::make_unique<WorkingSet>()); const unique_ptr<CanonicalQuery> cq(canonicalize(query)); // Get the RecordIds that would be returned by an in-order scan. vector<RecordId> locs; getLocs(coll, CollectionScanParams::FORWARD, &locs); // Populate the request. request.setQuery(query); request.setUpdates(fromjson("{$set: {x: 0}}")); request.setSort(BSONObj()); request.setMulti(false); request.setReturnDocs(UpdateRequest::RETURN_NEW); request.setLifecycle(&updateLifecycle); ASSERT_OK(driver.parse(request.getUpdates(), request.isMulti())); // Configure a QueuedDataStage to pass the first object in the collection back in a // LOC_AND_OBJ state. std::unique_ptr<QueuedDataStage> qds(stdx::make_unique<QueuedDataStage>(ws.get())); WorkingSetID id = ws->allocate(); WorkingSetMember* member = ws->get(id); member->loc = locs[targetDocIndex]; const BSONObj oldDoc = BSON("_id" << targetDocIndex << "foo" << targetDocIndex); member->obj = Snapshotted<BSONObj>(SnapshotId(), oldDoc); ws->transitionToLocAndObj(id); qds->pushBack(id); // Configure the update. UpdateStageParams updateParams(&request, &driver, opDebug); updateParams.canonicalQuery = cq.get(); unique_ptr<UpdateStage> updateStage( stdx::make_unique<UpdateStage>(&_txn, updateParams, ws.get(), coll, qds.release())); // Should return advanced. id = WorkingSet::INVALID_ID; PlanStage::StageState state = updateStage->work(&id); ASSERT_EQUALS(PlanStage::ADVANCED, state); // Make sure the returned value is what we expect it to be. // Should give us back a valid id. ASSERT_TRUE(WorkingSet::INVALID_ID != id); WorkingSetMember* resultMember = ws->get(id); // With an owned copy of the object, with no RecordId. ASSERT_TRUE(resultMember->hasOwnedObj()); ASSERT_FALSE(resultMember->hasLoc()); ASSERT_EQUALS(resultMember->getState(), WorkingSetMember::OWNED_OBJ); ASSERT_TRUE(resultMember->obj.value().isOwned()); // Should be the new value. BSONObj newDoc = BSON("_id" << targetDocIndex << "foo" << targetDocIndex << "x" << 0); ASSERT_EQUALS(resultMember->obj.value(), newDoc); // Should have done the update. vector<BSONObj> objs; getCollContents(coll, &objs); ASSERT_EQUALS(objs[targetDocIndex], newDoc); // That should be it. id = WorkingSet::INVALID_ID; ASSERT_EQUALS(PlanStage::IS_EOF, updateStage->work(&id)); }