本文整理汇总了C++中WorkingSetMember::hasObj方法的典型用法代码示例。如果您正苦于以下问题:C++ WorkingSetMember::hasObj方法的具体用法?C++ WorkingSetMember::hasObj怎么用?C++ WorkingSetMember::hasObj使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类WorkingSetMember
的用法示例。
在下文中一共展示了WorkingSetMember::hasObj方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: allocateIterator
virtual ElementIterator* allocateIterator(const ElementPath* path) const {
WorkingSetMember* member = _ws->get(_id);
if (!member->hasObj()) {
// Try to look in the key.
BSONObjIterator keyPatternIt(_keyPattern);
BSONObjIterator keyDataIt(_key);
while (keyPatternIt.more()) {
BSONElement keyPatternElt = keyPatternIt.next();
verify(keyDataIt.more());
BSONElement keyDataElt = keyDataIt.next();
if (path->fieldRef().equalsDottedField(keyPatternElt.fieldName())) {
if (Array == keyDataElt.type()) {
return new SimpleArrayElementIterator(keyDataElt, true);
} else {
return new SingleElementElementIterator(keyDataElt);
}
}
}
}
// Go to the raw document, fetching if needed.
return new BSONElementIterator(path, getObj());
}
示例2: fetchCompleted
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);
}
示例3: workBackwardsScan
PlanStage::StageState OplogStart::workBackwardsScan(WorkingSetID* out) {
PlanStage::StageState state = child()->work(out);
// EOF. Just start from the beginning, which is where we've hit.
if (PlanStage::IS_EOF == state) {
_done = true;
return state;
}
if (PlanStage::ADVANCED != state) {
return state;
}
WorkingSetMember* member = _workingSet->get(*out);
verify(member->hasObj());
verify(member->hasRecordId());
if (!_filter->matchesBSON(member->obj.value())) {
_done = true;
// RecordId is returned in *out.
return PlanStage::ADVANCED;
} else {
_workingSet->free(*out);
return PlanStage::NEED_TIME;
}
}
示例4: work
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;
}
}
示例5: doWork
PlanStage::StageState ShardFilterStage::doWork(WorkingSetID* out) {
// If we've returned as many results as we're limited to, isEOF will be true.
if (isEOF()) {
return PlanStage::IS_EOF;
}
StageState status = child()->work(out);
if (PlanStage::ADVANCED == status) {
// If we're sharded make sure that we don't return data that is not owned by us,
// including pending documents from in-progress migrations and orphaned documents from
// aborted migrations
if (_metadata->isSharded()) {
ShardKeyPattern shardKeyPattern(_metadata->getKeyPattern());
WorkingSetMember* member = _ws->get(*out);
WorkingSetMatchableDocument matchable(member);
BSONObj shardKey = shardKeyPattern.extractShardKeyFromMatchable(matchable);
if (shardKey.isEmpty()) {
// We can't find a shard key for this document - this should never happen with
// a non-fetched result unless our query planning is screwed up
if (!member->hasObj()) {
Status status(ErrorCodes::InternalError,
"shard key not found after a covered stage, "
"query planning has failed");
// Fail loudly and cleanly in production, fatally in debug
error() << redact(status);
dassert(false);
_ws->free(*out);
*out = WorkingSetCommon::allocateStatusMember(_ws, status);
return PlanStage::FAILURE;
}
// Skip this document with a warning - no shard key should not be possible
// unless manually inserting data into a shard
warning() << "no shard key found in document " << redact(member->obj.value()) << " "
<< "for shard key pattern " << _metadata->getKeyPattern() << ", "
<< "document may have been inserted manually into shard";
}
if (!_metadata->keyBelongsToMe(shardKey)) {
_ws->free(*out);
++_specificStats.chunkSkips;
return PlanStage::NEED_TIME;
}
}
// If we're here either we have shard state and our doc passed, or we have no shard
// state. Either way, we advance.
return status;
}
return status;
}
示例6: work
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;
}
}
示例7: getNext
Runner::RunnerState MultiPlanRunner::getNext(BSONObj* objOut, DiskLoc* dlOut) {
if (_killed) { return Runner::RUNNER_DEAD; }
if (_failure) { return Runner::RUNNER_ERROR; }
// If we haven't picked the best plan yet...
if (NULL == _bestPlan) {
if (!pickBestPlan(NULL)) {
verify(_failure || _killed);
if (_killed) { return Runner::RUNNER_DEAD; }
if (_failure) { return Runner::RUNNER_ERROR; }
}
}
if (!_alreadyProduced.empty()) {
WorkingSetID id = _alreadyProduced.front();
_alreadyProduced.pop_front();
WorkingSetMember* member = _bestPlan->getWorkingSet()->get(id);
// Note that this copies code from PlanExecutor.
if (NULL != objOut) {
if (WorkingSetMember::LOC_AND_IDX == member->state) {
if (1 != member->keyData.size()) {
_bestPlan->getWorkingSet()->free(id);
return Runner::RUNNER_ERROR;
}
*objOut = member->keyData[0].keyData;
}
else if (member->hasObj()) {
*objOut = member->obj;
}
else {
// TODO: Checking the WSM for covered fields goes here.
_bestPlan->getWorkingSet()->free(id);
return Runner::RUNNER_ERROR;
}
}
if (NULL != dlOut) {
if (member->hasLoc()) {
*dlOut = member->loc;
}
else {
_bestPlan->getWorkingSet()->free(id);
return Runner::RUNNER_ERROR;
}
}
_bestPlan->getWorkingSet()->free(id);
return Runner::RUNNER_ADVANCED;
}
return _bestPlan->getNext(objOut, dlOut);
}
示例8: run
void run() {
OldClientWriteContext ctx(&_txn, nss.ns());
addIndex(BSON("b" << 1 << "a" << 1));
addIndex(BSON("c" << 1 << "a" << 1));
BSONObj query = fromjson("{a: 1, $or: [{b: 2}, {c: 3}]}");
// Two of these documents match.
insert(BSON("_id" << 1 << "a" << 1 << "b" << 2));
insert(BSON("_id" << 2 << "a" << 2 << "b" << 2));
insert(BSON("_id" << 3 << "a" << 1 << "c" << 3));
insert(BSON("_id" << 4 << "a" << 1 << "c" << 4));
auto qr = stdx::make_unique<QueryRequest>(nss);
qr->setFilter(query);
auto cq = unittest::assertGet(CanonicalQuery::canonicalize(
txn(), std::move(qr), ExtensionsCallbackDisallowExtensions()));
Collection* collection = ctx.getCollection();
// Get planner params.
QueryPlannerParams plannerParams;
fillOutPlannerParams(&_txn, collection, cq.get(), &plannerParams);
WorkingSet ws;
std::unique_ptr<SubplanStage> subplan(
new SubplanStage(&_txn, collection, &ws, plannerParams, cq.get()));
// Plan selection should succeed due to falling back on regular planning.
PlanYieldPolicy yieldPolicy(PlanExecutor::YIELD_MANUAL, _clock);
ASSERT_OK(subplan->pickBestPlan(&yieldPolicy));
// Work the stage until it produces all results.
size_t numResults = 0;
PlanStage::StageState stageState = PlanStage::NEED_TIME;
while (stageState != PlanStage::IS_EOF) {
WorkingSetID id = WorkingSet::INVALID_ID;
stageState = subplan->work(&id);
ASSERT_NE(stageState, PlanStage::DEAD);
ASSERT_NE(stageState, PlanStage::FAILURE);
if (stageState == PlanStage::ADVANCED) {
++numResults;
WorkingSetMember* member = ws.get(id);
ASSERT(member->hasObj());
ASSERT(member->obj.value() == BSON("_id" << 1 << "a" << 1 << "b" << 2) ||
member->obj.value() == BSON("_id" << 3 << "a" << 1 << "c" << 3));
}
}
ASSERT_EQ(numResults, 2U);
}
示例9: getCollContents
/**
* Returns a vector of all of the documents currently in 'collection'.
*
* Uses a forward collection scan stage to get the docs, and populates 'out' with
* the results.
*/
void getCollContents(Collection* collection, vector<BSONObj>* out) {
WorkingSet ws;
CollectionScanParams params;
params.direction = CollectionScanParams::FORWARD;
params.tailable = false;
unique_ptr<CollectionScan> scan(new CollectionScan(&_opCtx, collection, params, &ws, NULL));
while (!scan->isEOF()) {
WorkingSetID id = WorkingSet::INVALID_ID;
PlanStage::StageState state = scan->work(&id);
if (PlanStage::ADVANCED == state) {
WorkingSetMember* member = ws.get(id);
verify(member->hasObj());
out->push_back(member->obj.value().getOwned());
}
}
}
示例10: getIntFieldDotted
/**
* Returns the projected value from the working set that would
* be returned in the 'values' field of the distinct command result.
* Limited to NumberInt BSON types because this is the only
* BSON type used in this suite of tests.
*/
static int getIntFieldDotted(const WorkingSet& ws, WorkingSetID wsid,
const std::string& field) {
// For some reason (at least under OS X clang), we cannot refer to INVALID_ID
// inside the test assertion macro.
WorkingSetID invalid = WorkingSet::INVALID_ID;
ASSERT_NOT_EQUALS(invalid, wsid);
WorkingSetMember* member = ws.get(wsid);
// Distinct hack execution is always covered.
// Key value is retrieved from working set key data
// instead of RecordId.
ASSERT_FALSE(member->hasObj());
BSONElement keyElt;
ASSERT_TRUE(member->getFieldDotted(field, &keyElt));
ASSERT_TRUE(keyElt.isNumber());
return keyElt.numberInt();
}
示例11: getSortKey
Status SortKeyGenerator::getSortKey(const WorkingSetMember& member, BSONObj* objOut) const {
StatusWith<BSONObj> sortKey = BSONObj();
if (member.hasObj()) {
sortKey = getSortKeyFromObject(member);
} else {
sortKey = getSortKeyFromIndexKey(member);
}
if (!sortKey.isOK()) {
return sortKey.getStatus();
}
if (!_sortHasMeta) {
*objOut = sortKey.getValue();
return Status::OK();
}
BSONObjBuilder mergedKeyBob;
// Merge metadata into the key.
BSONObjIterator it(_rawSortSpec);
BSONObjIterator sortKeyIt(sortKey.getValue());
while (it.more()) {
BSONElement elt = it.next();
if (elt.isNumber()) {
// Merge btree key elt.
mergedKeyBob.append(sortKeyIt.next());
} else if (LiteParsedQuery::isTextScoreMeta(elt)) {
// Add text score metadata
double score = 0.0;
if (member.hasComputed(WSM_COMPUTED_TEXT_SCORE)) {
const TextScoreComputedData* scoreData = static_cast<const TextScoreComputedData*>(
member.getComputed(WSM_COMPUTED_TEXT_SCORE));
score = scoreData->getScore();
}
mergedKeyBob.append("$metaTextScore", score);
}
}
*objOut = mergedKeyBob.obj();
return Status::OK();
}
示例12: doWork
PlanStage::StageState SortStage::doWork(WorkingSetID* out) {
const size_t maxBytes = static_cast<size_t>(internalQueryExecMaxBlockingSortBytes);
if (_memUsage > maxBytes) {
mongoutils::str::stream ss;
ss << "Sort operation used more than the maximum " << maxBytes
<< " bytes of RAM. Add an index, or specify a smaller limit.";
Status status(ErrorCodes::OperationFailed, ss);
*out = WorkingSetCommon::allocateStatusMember(_ws, status);
return PlanStage::FAILURE;
}
if (isEOF()) {
return PlanStage::IS_EOF;
}
// Still reading in results to sort.
if (!_sorted) {
WorkingSetID id = WorkingSet::INVALID_ID;
StageState code = child()->work(&id);
if (PlanStage::ADVANCED == code) {
// Add it into the map for quick invalidation if it has a valid RecordId.
// A RecordId may be invalidated at any time (during a yield). We need to get into
// the WorkingSet as quickly as possible to handle it.
WorkingSetMember* member = _ws->get(id);
// Planner must put a fetch before we get here.
verify(member->hasObj());
// We might be sorting something that was invalidated at some point.
if (member->hasLoc()) {
_wsidByDiskLoc[member->loc] = id;
}
SortableDataItem item;
item.wsid = id;
// We extract the sort key from the WSM's computed data. This must have been generated
// by a SortKeyGeneratorStage descendent in the execution tree.
auto sortKeyComputedData =
static_cast<const SortKeyComputedData*>(member->getComputed(WSM_SORT_KEY));
item.sortKey = sortKeyComputedData->getSortKey();
if (member->hasLoc()) {
// The RecordId breaks ties when sorting two WSMs with the same sort key.
item.loc = member->loc;
}
addToBuffer(item);
return PlanStage::NEED_TIME;
} else if (PlanStage::IS_EOF == code) {
// TODO: We don't need the lock for this. We could ask for a yield and do this work
// unlocked. Also, this is performing a lot of work for one call to work(...)
sortBuffer();
_resultIterator = _data.begin();
_sorted = true;
return PlanStage::NEED_TIME;
} else if (PlanStage::FAILURE == code || PlanStage::DEAD == code) {
*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 << "sort stage failed to read in results to sort from child";
Status status(ErrorCodes::InternalError, ss);
*out = WorkingSetCommon::allocateStatusMember(_ws, status);
}
return code;
} else if (PlanStage::NEED_YIELD == code) {
*out = id;
}
return code;
}
// Returning results.
verify(_resultIterator != _data.end());
verify(_sorted);
*out = _resultIterator->wsid;
_resultIterator++;
// If we're returning something, take it out of our DL -> WSID map so that future
// calls to invalidate don't cause us to take action for a DL we're done with.
WorkingSetMember* member = _ws->get(*out);
if (member->hasLoc()) {
_wsidByDiskLoc.erase(member->loc);
}
return PlanStage::ADVANCED;
}
示例13: getNext
Runner::RunnerState MultiPlanRunner::getNext(BSONObj* objOut, DiskLoc* dlOut) {
if (_killed) { return Runner::RUNNER_DEAD; }
if (_failure) { return Runner::RUNNER_ERROR; }
// If we haven't picked the best plan yet...
if (NULL == _bestPlan) {
if (!pickBestPlan(NULL, objOut)) {
verify(_failure || _killed);
if (_killed) { return Runner::RUNNER_DEAD; }
if (_failure) { return Runner::RUNNER_ERROR; }
}
}
// Look for an already produced result that provides the data the caller wants.
while (!_alreadyProduced.empty()) {
WorkingSetID id = _alreadyProduced.front();
_alreadyProduced.pop_front();
WorkingSetMember* member = _bestPlan->getWorkingSet()->get(id);
// Note that this copies code from PlanExecutor.
if (NULL != objOut) {
if (WorkingSetMember::LOC_AND_IDX == member->state) {
if (1 != member->keyData.size()) {
_bestPlan->getWorkingSet()->free(id);
// If the caller needs the key data and the WSM doesn't have it, drop the
// result and carry on.
continue;
}
*objOut = member->keyData[0].keyData;
}
else if (member->hasObj()) {
*objOut = member->obj;
}
else {
// If the caller needs an object and the WSM doesn't have it, drop and
// try the next result.
_bestPlan->getWorkingSet()->free(id);
continue;
}
}
if (NULL != dlOut) {
if (member->hasLoc()) {
*dlOut = member->loc;
}
else {
// If the caller needs a DiskLoc and the WSM doesn't have it, drop and carry on.
_bestPlan->getWorkingSet()->free(id);
continue;
}
}
// If we're here, the caller has all the data needed and we've set the out
// parameters. Remove the result from the WorkingSet.
_bestPlan->getWorkingSet()->free(id);
return Runner::RUNNER_ADVANCED;
}
RunnerState state = _bestPlan->getNext(objOut, dlOut);
if (Runner::RUNNER_ERROR == state && (NULL != _backupSolution)) {
QLOG() << "Best plan errored out switching to backup\n";
// Uncache the bad solution if we fall back
// on the backup solution.
//
// XXX: Instead of uncaching we should find a way for the
// cached plan runner to fall back on a different solution
// if the best solution fails. Alternatively we could try to
// defer cache insertion to be after the first produced result.
Database* db = cc().database();
verify(NULL != db);
Collection* collection = db->getCollection(_query->ns());
verify(NULL != collection);
PlanCache* cache = collection->infoCache()->getPlanCache();
cache->remove(*_query);
_bestPlan.reset(_backupPlan);
_backupPlan = NULL;
_bestSolution.reset(_backupSolution);
_backupSolution = NULL;
_alreadyProduced = _backupAlreadyProduced;
return getNext(objOut, dlOut);
}
if (NULL != _backupSolution && Runner::RUNNER_ADVANCED == state) {
QLOG() << "Best plan had a blocking sort, became unblocked, deleting backup plan\n";
delete _backupSolution;
delete _backupPlan;
_backupSolution = NULL;
_backupPlan = NULL;
// TODO: free from WS?
_backupAlreadyProduced.clear();
}
return state;
}
示例14: work
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;
}
// Either retry the last WSM we worked on or get a new one from our child.
WorkingSetID id;
StageState status;
if (_idRetrying == WorkingSet::INVALID_ID) {
status = child()->work(&id);
} else {
status = ADVANCED;
id = _idRetrying;
_idRetrying = WorkingSet::INVALID_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->getState());
verify(member->hasLoc());
try {
if (!_cursor)
_cursor = _collection->getCursor(getOpCtx());
if (auto fetcher = _cursor->fetcherForId(member->loc)) {
// There's something to fetch. Hand the fetcher off to the WSM, and pass up
// a fetch request.
_idRetrying = id;
member->setFetcher(fetcher.release());
*out = id;
_commonStats.needYield++;
return NEED_YIELD;
}
// The doc is already in memory, so go ahead and grab it. Now we have a RecordId
// as well as an unowned object
if (!WorkingSetCommon::fetch(getOpCtx(), _ws, id, _cursor)) {
_ws->free(id);
_commonStats.needTime++;
return NEED_TIME;
}
} catch (const WriteConflictException& wce) {
_idRetrying = id;
*out = WorkingSet::INVALID_ID;
_commonStats.needYield++;
return NEED_YIELD;
}
}
return returnIfMatches(member, id, out);
} else if (PlanStage::FAILURE == status || PlanStage::DEAD == 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;
} else if (PlanStage::NEED_YIELD == status) {
++_commonStats.needYield;
*out = id;
}
return status;
}
示例15: addTerm
PlanStage::StageState TextStage::addTerm(WorkingSetID wsid, WorkingSetID* out) {
WorkingSetMember* wsm = _ws->get(wsid);
invariant(wsm->state == WorkingSetMember::LOC_AND_IDX);
invariant(1 == wsm->keyData.size());
const IndexKeyDatum newKeyData = wsm->keyData.back(); // copy to keep it around.
TextRecordData* textRecordData = &_scores[wsm->loc];
double* documentAggregateScore = &textRecordData->score;
if (WorkingSet::INVALID_ID == textRecordData->wsid) {
// We haven't seen this RecordId before. Keep the working set member around
// (it may be force-fetched on saveState()).
textRecordData->wsid = wsid;
if (_filter) {
// We have not seen this document before and need to apply a filter.
bool shouldKeep;
bool wasDeleted = false;
try {
TextMatchableDocument tdoc(
_txn, newKeyData.indexKeyPattern, newKeyData.keyData, wsm, _recordCursor);
shouldKeep = _filter->matches(&tdoc);
} catch (const WriteConflictException& wce) {
_idRetrying = wsid;
*out = WorkingSet::INVALID_ID;
return NEED_YIELD;
} catch (const TextMatchableDocument::DocumentDeletedException&) {
// We attempted to fetch the document but decided it should be excluded from the
// result set.
shouldKeep = false;
wasDeleted = true;
}
if (!shouldKeep) {
if (wasDeleted || wsm->hasObj()) {
// We had to fetch but we're not going to return it.
++_specificStats.fetches;
}
_ws->free(textRecordData->wsid);
textRecordData->wsid = WorkingSet::INVALID_ID;
*documentAggregateScore = -1;
return NEED_TIME;
}
} else {
// If we're here, we're going to return the doc, and we do a fetch later.
++_specificStats.fetches;
}
} else {
// We already have a working set member for this RecordId. Free the new
// WSM and retrieve the old one.
// Note that since we don't keep all index keys, we could get a score that doesn't match
// the document, but this has always been a problem.
// TODO something to improve the situation.
invariant(wsid != textRecordData->wsid);
_ws->free(wsid);
wsm = _ws->get(textRecordData->wsid);
}
++_specificStats.keysExamined;
if (*documentAggregateScore < 0) {
// We have already rejected this document for not matching the filter.
return NEED_TIME;
}
// Locate score within possibly compound key: {prefix,term,score,suffix}.
BSONObjIterator keyIt(newKeyData.keyData);
for (unsigned i = 0; i < _params.spec.numExtraBefore(); i++) {
keyIt.next();
}
keyIt.next(); // Skip past 'term'.
BSONElement scoreElement = keyIt.next();
double documentTermScore = scoreElement.number();
// Aggregate relevance score, term keys.
*documentAggregateScore += documentTermScore;
return NEED_TIME;
}