summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2015-06-15 13:07:33 -0400
committerDavid Storch <david.storch@10gen.com>2015-06-17 12:37:10 -0400
commitf3ca2d0ba8fa13959f5dc6b36805aa137c25089e (patch)
tree11b6a6162b95b719592b66fd6c3bb5d9abe0ff20
parent17678f50406d674fb2b3a6bcdcd00f72ae8eacc1 (diff)
downloadmongo-f3ca2d0ba8fa13959f5dc6b36805aa137c25089e.tar.gz
SERVER-18926 avoid iterating the entire working set when preparing for a WiredTiger snapshot change
Improves performance for query plans with a blocking stage when using the WiredTiger storage engine. In particular, this should benefit full text search and geoNear queries.
-rw-r--r--src/mongo/db/exec/collection_scan.cpp4
-rw-r--r--src/mongo/db/exec/distinct_scan.cpp1
-rw-r--r--src/mongo/db/exec/fetch.cpp2
-rw-r--r--src/mongo/db/exec/fetch.h2
-rw-r--r--src/mongo/db/exec/idhack.cpp2
-rw-r--r--src/mongo/db/exec/index_scan.cpp1
-rw-r--r--src/mongo/db/exec/multi_iterator.cpp4
-rw-r--r--src/mongo/db/exec/oplogstart.cpp2
-rw-r--r--src/mongo/db/exec/text.cpp2
-rw-r--r--src/mongo/db/exec/working_set.cpp80
-rw-r--r--src/mongo/db/exec/working_set.h96
-rw-r--r--src/mongo/db/exec/working_set_common.cpp26
-rw-r--r--src/mongo/db/exec/working_set_common.h11
-rw-r--r--src/mongo/db/exec/working_set_test.cpp100
-rw-r--r--src/mongo/db/query/query_solution.h3
-rw-r--r--src/mongo/dbtests/query_stage_fetch.cpp2
-rw-r--r--src/mongo/dbtests/query_stage_sort.cpp2
17 files changed, 88 insertions, 252 deletions
diff --git a/src/mongo/db/exec/collection_scan.cpp b/src/mongo/db/exec/collection_scan.cpp
index 0d857506950..e278f97f517 100644
--- a/src/mongo/db/exec/collection_scan.cpp
+++ b/src/mongo/db/exec/collection_scan.cpp
@@ -68,7 +68,7 @@ namespace mongo {
// for anything other than passing up NEED_FETCH. We use the loc and owned obj state, but
// the loc isn't really pointing at any obj. The obj field of the WSM should never be used.
WorkingSetMember* member = _workingSet->get(_wsidForFetch);
- member->state = WorkingSetMember::LOC_AND_OWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
}
PlanStage::StageState CollectionScan::work(WorkingSetID* out) {
@@ -148,7 +148,7 @@ namespace mongo {
member->loc = curr;
member->obj = Snapshotted<BSONObj>(_txn->recoveryUnit()->getSnapshotId(),
_iter->dataFor(member->loc).releaseToBson());
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
// Advance the iterator.
invariant(_iter->getNext() == curr);
diff --git a/src/mongo/db/exec/distinct_scan.cpp b/src/mongo/db/exec/distinct_scan.cpp
index a0b4e4e0271..9b0586b13b3 100644
--- a/src/mongo/db/exec/distinct_scan.cpp
+++ b/src/mongo/db/exec/distinct_scan.cpp
@@ -154,6 +154,7 @@ namespace mongo {
member->loc = loc;
member->keyData.push_back(IndexKeyDatum(_descriptor->keyPattern(), ownedKeyObj));
member->state = WorkingSetMember::LOC_AND_IDX;
+ _workingSet->flagNewIdxId(id);
*out = id;
++_commonStats.advanced;
diff --git a/src/mongo/db/exec/fetch.cpp b/src/mongo/db/exec/fetch.cpp
index 9d78111ea35..2e0addefb94 100644
--- a/src/mongo/db/exec/fetch.cpp
+++ b/src/mongo/db/exec/fetch.cpp
@@ -125,7 +125,7 @@ namespace mongo {
// as well as an unowned object
member->obj = _collection->docFor(_txn, member->loc);
member->keyData.clear();
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
}
return returnIfMatches(member, id, out);
diff --git a/src/mongo/db/exec/fetch.h b/src/mongo/db/exec/fetch.h
index 53ed3952a06..3d0962a3508 100644
--- a/src/mongo/db/exec/fetch.h
+++ b/src/mongo/db/exec/fetch.h
@@ -40,7 +40,7 @@ namespace mongo {
/**
* This stage turns a RecordId into a BSONObj.
*
- * In WorkingSetMember terms, it transitions from LOC_AND_IDX to LOC_AND_UNOWNED_OBJ by reading
+ * In WorkingSetMember terms, it transitions from LOC_AND_IDX to LOC_AND_OBJ by reading
* the record at the provided loc. Returns verbatim any data that already has an object.
*
* Preconditions: Valid RecordId.
diff --git a/src/mongo/db/exec/idhack.cpp b/src/mongo/db/exec/idhack.cpp
index acf6ebc4122..79bc3aeefd9 100644
--- a/src/mongo/db/exec/idhack.cpp
+++ b/src/mongo/db/exec/idhack.cpp
@@ -135,7 +135,7 @@ namespace mongo {
WorkingSetID id = _workingSet->allocate();
WorkingSetMember* member = _workingSet->get(id);
member->loc = loc;
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
// We may need to request a yield while we fetch the document.
std::auto_ptr<RecordFetcher> fetcher(_collection->documentNeedsFetch(_txn, loc));
diff --git a/src/mongo/db/exec/index_scan.cpp b/src/mongo/db/exec/index_scan.cpp
index 3b0d5f9bec4..536c3bfa55c 100644
--- a/src/mongo/db/exec/index_scan.cpp
+++ b/src/mongo/db/exec/index_scan.cpp
@@ -241,6 +241,7 @@ namespace mongo {
member->loc = loc;
member->keyData.push_back(IndexKeyDatum(_keyPattern, keyObj));
member->state = WorkingSetMember::LOC_AND_IDX;
+ _workingSet->flagNewIdxId(id);
if (_params.addKeyMetadata) {
BSONObjBuilder bob;
diff --git a/src/mongo/db/exec/multi_iterator.cpp b/src/mongo/db/exec/multi_iterator.cpp
index 20f2c3a734b..f7782ac937b 100644
--- a/src/mongo/db/exec/multi_iterator.cpp
+++ b/src/mongo/db/exec/multi_iterator.cpp
@@ -48,7 +48,7 @@ namespace mongo {
// for anything other than passing up NEED_FETCH. We use the loc and owned obj state, but
// the loc isn't really pointing at any obj. The obj field of the WSM should never be used.
WorkingSetMember* member = _ws->get(_wsidForFetch);
- member->state = WorkingSetMember::LOC_AND_OWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
}
void MultiIteratorStage::addIterator(RecordIterator* it) {
@@ -84,7 +84,7 @@ namespace mongo {
WorkingSetMember* member = _ws->get(*out);
member->loc = next;
member->obj = _collection->docFor(_txn, next);
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
return PlanStage::ADVANCED;
}
diff --git a/src/mongo/db/exec/oplogstart.cpp b/src/mongo/db/exec/oplogstart.cpp
index 80f18ebea5d..56668b4b4fd 100644
--- a/src/mongo/db/exec/oplogstart.cpp
+++ b/src/mongo/db/exec/oplogstart.cpp
@@ -95,7 +95,7 @@ namespace mongo {
WorkingSetMember* member = _workingSet->get(id);
member->loc = loc;
member->obj = _collection->docFor(_txn, member->loc);
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
*out = id;
return PlanStage::ADVANCED;
}
diff --git a/src/mongo/db/exec/text.cpp b/src/mongo/db/exec/text.cpp
index 08fc4055480..52d660471cb 100644
--- a/src/mongo/db/exec/text.cpp
+++ b/src/mongo/db/exec/text.cpp
@@ -293,7 +293,7 @@ namespace mongo {
wsm->obj = _params.index->getCollection()->docFor(_txn, wsm->loc);
doc = wsm->obj.value();
wsm->keyData.clear();
- wsm->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ wsm->state = WorkingSetMember::LOC_AND_OBJ;
}
// Filter for phrases and negated terms
diff --git a/src/mongo/db/exec/working_set.cpp b/src/mongo/db/exec/working_set.cpp
index cbe7217b1b6..22799aaf202 100644
--- a/src/mongo/db/exec/working_set.cpp
+++ b/src/mongo/db/exec/working_set.cpp
@@ -82,7 +82,7 @@ namespace mongo {
_flagged.insert(i);
}
- const unordered_set<WorkingSetID>& WorkingSet::getFlagged() const {
+ const std::unordered_set<WorkingSetID>& WorkingSet::getFlagged() const {
return _flagged;
}
@@ -104,69 +104,15 @@ namespace mongo {
_flagged.clear();
}
- //
- // Iteration
- //
-
- WorkingSet::iterator::iterator(WorkingSet* ws, size_t index)
- : _ws(ws),
- _index(index) {
- // If we're currently not pointing at an allocated member, then we have
- // to advance to the first one, unless we're already at the end.
- if (_index < _ws->_data.size() && isFree()) {
- advance();
- }
- }
-
- void WorkingSet::iterator::advance() {
- // Move forward at least once in the data list.
- _index++;
-
- // While we haven't hit the end and the current member is not in use. (Skips ahead until
- // we find the next allocated member.)
- while (_index < _ws->_data.size() && isFree()) {
- _index++;
- }
- }
-
- bool WorkingSet::iterator::isFree() const {
- return _ws->_data[_index].nextFreeOrSelf != _index;
- }
-
- void WorkingSet::iterator::free() {
- dassert(!isFree());
- _ws->free(_index);
- }
-
- void WorkingSet::iterator::operator++() {
- dassert(_index < _ws->_data.size());
- advance();
- }
-
- bool WorkingSet::iterator::operator==(const WorkingSet::iterator& other) const {
- return (_index == other._index);
- }
-
- bool WorkingSet::iterator::operator!=(const WorkingSet::iterator& other) const {
- return (_index != other._index);
- }
-
- WorkingSetMember& WorkingSet::iterator::operator*() {
- dassert(_index < _ws->_data.size() && !isFree());
- return *_ws->_data[_index].member;
+ void WorkingSet::flagNewIdxId(const WorkingSetID& id) {
+ _idxIds.push_back(id);
}
- WorkingSetMember* WorkingSet::iterator::operator->() {
- dassert(_index < _ws->_data.size() && !isFree());
- return _ws->_data[_index].member;
- }
-
- WorkingSet::iterator WorkingSet::begin() {
- return WorkingSet::iterator(this, 0);
- }
-
- WorkingSet::iterator WorkingSet::end() {
- return WorkingSet::iterator(this, _data.size());
+ std::vector<WorkingSetID> WorkingSet::getAndClearIdxIds() {
+ std::vector<WorkingSetID> out;
+ // Clear '_idxIds' by swapping it into the vector to be returned.
+ _idxIds.swap(out);
+ return out;
}
//
@@ -188,19 +134,15 @@ namespace mongo {
}
bool WorkingSetMember::hasLoc() const {
- return state == LOC_AND_IDX || state == LOC_AND_UNOWNED_OBJ || state == LOC_AND_OWNED_OBJ;
+ return state == LOC_AND_IDX || state == LOC_AND_OBJ;
}
bool WorkingSetMember::hasObj() const {
- return hasOwnedObj() || hasUnownedObj();
+ return hasOwnedObj() || (state == LOC_AND_OBJ);
}
bool WorkingSetMember::hasOwnedObj() const {
- return state == OWNED_OBJ || state == LOC_AND_OWNED_OBJ;
- }
-
- bool WorkingSetMember::hasUnownedObj() const {
- return state == LOC_AND_UNOWNED_OBJ;
+ return state == OWNED_OBJ;
}
bool WorkingSetMember::hasComputed(const WorkingSetComputedDataType type) const {
diff --git a/src/mongo/db/exec/working_set.h b/src/mongo/db/exec/working_set.h
index e725529188a..62773d188f2 100644
--- a/src/mongo/db/exec/working_set.h
+++ b/src/mongo/db/exec/working_set.h
@@ -29,6 +29,7 @@
#pragma once
#include <boost/scoped_ptr.hpp>
+#include <unordered_set>
#include <vector>
#include "mongo/base/disallow_copying.h"
@@ -80,6 +81,13 @@ namespace mongo {
}
/**
+ * Returns true iff WorkingSetMember with id 'i' is free.
+ */
+ bool isFree(const WorkingSetID& i) const {
+ return _data[i].nextFreeOrSelf != i;
+ }
+
+ /**
* Deallocate the i-th query result and release its resources.
*/
void free(const WorkingSetID& i);
@@ -110,56 +118,31 @@ namespace mongo {
void clear();
//
- // Iteration
+ // Used with the WT storage engine to prepare the working set for snapshot changes.
//
/**
- * Forward iterates over the list of working set members, skipping any entries
- * that are on the free list.
+ * Adds 'id' to the set of ids returned by getIdxIds().
+ *
+ * Whenever a stage transitions a working set member into the LOC_AND_IDX state, it is
+ * responsible for flagging it as such by calling this method.
*/
- class iterator {
- public:
- iterator(WorkingSet* ws, size_t index);
-
- void operator++();
-
- bool operator==(const WorkingSet::iterator& other) const;
- bool operator!=(const WorkingSet::iterator& other) const;
-
- WorkingSetMember& operator*();
-
- WorkingSetMember* operator->();
-
- /**
- * Free the WSM we are currently pointing to. Does not advance the iterator.
- *
- * It is invalid to dereference the iterator after calling free until the iterator is
- * next incremented.
- */
- void free();
-
- private:
- /**
- * Move the iterator forward to the next allocated WSM.
- */
- void advance();
+ void flagNewIdxId(const WorkingSetID& id);
- /**
- * Returns true if the MemberHolder currently pointed at by the iterator is free, and
- * false if it contains an allocated working set member.
- */
- bool isFree() const;
-
- // The working set we're iterating over. Not owned here.
- WorkingSet* _ws;
-
- // The index of the member we're currently pointing at.
- size_t _index;
- };
-
- WorkingSet::iterator begin();
-
- WorkingSet::iterator end();
+ /**
+ * Returns the list of working set ids that have transitioned into the LOC_AND_IDX state
+ * since the last yield. The members corresponding to these ids may have since transitioned
+ * out of the LOC_AND_IDX state or been freed, so these cases must be handled by the
+ * caller.
+ *
+ * Execution stages are responsible for adding to this list via the flagNewIdxId() method
+ * when they put a member into the LOC_AND_IDX state. Stages are not responsible for
+ * clearing working set ids from this list when the member transitions out of LOC_AND_IDX.
+ *
+ * As a side effect, calling this method clears the list of flagged ids kept by the working
+ * set.
+ */
+ std::vector<WorkingSetID> getAndClearIdxIds();
private:
struct MemberHolder {
@@ -183,7 +166,11 @@ namespace mongo {
WorkingSetID _freeList;
// An insert-only set of WorkingSetIDs that have been flagged for review.
- unordered_set<WorkingSetID> _flagged;
+ std::unordered_set<WorkingSetID> _flagged;
+
+ // Contains all working set members that have transitioned into the LOC_AND_IDX state since
+ // the last snapshot change.
+ std::vector<WorkingSetID> _idxIds;
};
/**
@@ -245,7 +232,7 @@ namespace mongo {
*
* Index scan stages return a WorkingSetMember in the LOC_AND_IDX state.
*
- * Collection scan stages the LOC_AND_UNOWNED_OBJ state.
+ * Collection scan stages return a WorkingSetMember in the LOC_AND_OBJ state.
*
* A WorkingSetMember may have any of the data above.
*/
@@ -267,19 +254,13 @@ namespace mongo {
// Data is from 1 or more indices.
LOC_AND_IDX,
- // Data is from a collection scan, or data is from an index scan and was fetched.
- LOC_AND_UNOWNED_OBJ,
+ // Data is from a collection scan, or data is from an index scan and was fetched. The
+ // BSONObj might be owned or unowned.
+ LOC_AND_OBJ,
// RecordId has been invalidated, or the obj doesn't correspond to an on-disk document
- // anymore (e.g. is a computed expression).
+ // anymore (e.g. is a computed expression). The BSONObj must be owned.
OWNED_OBJ,
-
- // Due to a yield, RecordId is no longer protected by the storage engine's transaction
- // and may have been invalidated. The object is either identical to the object keyed
- // by RecordId, or is an old version of the document stored at RecordId.
- //
- // Only used by doc-level locking storage engines (not used by MMAP v1).
- LOC_AND_OWNED_OBJ,
};
//
@@ -294,7 +275,6 @@ namespace mongo {
bool hasLoc() const;
bool hasObj() const;
bool hasOwnedObj() const;
- bool hasUnownedObj() const;
//
// Computed data
diff --git a/src/mongo/db/exec/working_set_common.cpp b/src/mongo/db/exec/working_set_common.cpp
index 05f9163f040..ec634b601c6 100644
--- a/src/mongo/db/exec/working_set_common.cpp
+++ b/src/mongo/db/exec/working_set_common.cpp
@@ -59,14 +59,13 @@ namespace mongo {
invariant(collection);
dassert(supportsDocLocking());
- for (WorkingSet::iterator it = workingSet->begin(); it != workingSet->end(); ++it) {
- if (WorkingSetMember::LOC_AND_OWNED_OBJ == it->state) {
- // Already in our desired state.
+ for (auto id : workingSet->getAndClearIdxIds()) {
+ if (workingSet->isFree(id)) {
continue;
}
- // We can't do anything without a RecordId.
- if (!it->hasLoc()) {
+ WorkingSetMember* member = workingSet->get(id);
+ if (WorkingSetMember::LOC_AND_IDX != member->state) {
continue;
}
@@ -77,15 +76,20 @@ namespace mongo {
// and starts to delete the matching documents, including D. The working set members for
// D created by the two rejected are still present, but their RecordIds no longer refer
// to a valid document.
- it->obj.reset();
- if (!collection->findDoc(txn, it->loc, &it->obj)) {
+ member->obj.reset();
+ if (!collection->findDoc(txn, member->loc, &member->obj)) {
// Leftover working set members pointing to old docs can be safely freed.
- it.free();
+ workingSet->free(id);
continue;
}
- it->obj.setValue(it->obj.value().getOwned() );
- it->state = WorkingSetMember::LOC_AND_OWNED_OBJ;
+ // We rely on the assumption that doc-locking storage engines always return owned BSON.
+ // This assumption may become invalid in future versions but must remain valid on the
+ // 3.0 branch.
+ invariant(member->obj.value().isOwned());
+
+ member->keyData.clear();
+ member->state = WorkingSetMember::LOC_AND_OBJ;
}
}
@@ -107,7 +111,7 @@ namespace mongo {
invariant(member->hasLoc());
member->obj = collection->docFor(txn, member->loc);
member->keyData.clear();
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
}
// static
diff --git a/src/mongo/db/exec/working_set_common.h b/src/mongo/db/exec/working_set_common.h
index 96ccb333c0a..721eb0d0ec6 100644
--- a/src/mongo/db/exec/working_set_common.h
+++ b/src/mongo/db/exec/working_set_common.h
@@ -44,13 +44,18 @@ namespace mongo {
const Collection* collection);
/**
- * Iterates over 'workingSet'. For all valid working set members, if the member has a
- * RecordId but does not have an owned obj, then puts the member in "loc with owned
- * obj" state.
+ * Iterates over 'workingSet' members that have transitioned to the LOC_AND_IDX state since
+ * the last yield. For all members still in the LOC_AND_IDX state, fetches the associated
+ * document and puts the member in "loc with unowned obj" state.
*
* This "force-fetching" is called on saveState() for storage-engines that support document-
* level locking. This ensures that all WS members are still valid, even after the
* OperationContext becomes invalid due to a yield.
+ *
+ * Note that although we use the "loc and unowned obj" state, document-level locking storage
+ * engines are assumed to be returning owned BSON. This is an assumption that may not be
+ * valid for future versions, but must remain valid on the v3.0 branch. Therefore, it is ok
+ * to have a "loc and unowned obj" survive a yield.
*/
static void forceFetchAllLocs(OperationContext* txn,
WorkingSet* workingSet,
diff --git a/src/mongo/db/exec/working_set_test.cpp b/src/mongo/db/exec/working_set_test.cpp
index bc0c7b04230..e2b645a49d2 100644
--- a/src/mongo/db/exec/working_set_test.cpp
+++ b/src/mongo/db/exec/working_set_test.cpp
@@ -75,7 +75,7 @@ namespace {
// Our state is that of a valid object. The getFieldDotted shouldn't throw; there's
// something to call getFieldDotted on, but there's no field there.
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
ASSERT_TRUE(member->getFieldDotted("foo", &elt));
member->state = WorkingSetMember::OWNED_OBJ;
@@ -87,7 +87,7 @@ namespace {
BSONObj obj = BSON(fieldName << 5);
// Not truthful since the loc is bogus, but the loc isn't accessed anyway...
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member->state = WorkingSetMember::LOC_AND_OBJ;
member->obj = Snapshotted<BSONObj>(SnapshotId(), BSONObj(obj.objdata()));
ASSERT_TRUE(obj.isOwned());
ASSERT_FALSE(member->obj.value().isOwned());
@@ -149,100 +149,4 @@ namespace {
ASSERT_FALSE(member->getFieldDotted("y", &elt));
}
- //
- // WorkingSet::iterator tests
- //
-
- TEST(WorkingSetIteratorTest, BasicIteratorTest) {
- WorkingSet ws;
-
- WorkingSetID id1 = ws.allocate();
- WorkingSetMember* member1 = ws.get(id1);
- member1->state = WorkingSetMember::LOC_AND_IDX;
- member1->keyData.push_back(IndexKeyDatum(BSON("a" << 1), BSON("" << 3)));
-
- WorkingSetID id2 = ws.allocate();
- WorkingSetMember* member2 = ws.get(id2);
- member2->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
- member2->obj = Snapshotted<BSONObj>(SnapshotId(), BSON("a" << 3));
-
- int counter = 0;
- for (WorkingSet::iterator it = ws.begin(); it != ws.end(); ++it) {
- ASSERT(it->state == WorkingSetMember::LOC_AND_IDX ||
- it->state == WorkingSetMember::LOC_AND_UNOWNED_OBJ);
- counter++;
- }
- ASSERT_EQ(counter, 2);
- }
-
- TEST(WorkingSetIteratorTest, EmptyWorkingSet) {
- WorkingSet ws;
-
- int counter = 0;
- for (WorkingSet::iterator it = ws.begin(); it != ws.end(); ++it) {
- counter++;
- }
- ASSERT_EQ(counter, 0);
- }
-
- TEST(WorkingSetIteratorTest, EmptyWorkingSetDueToFree) {
- WorkingSet ws;
-
- WorkingSetID id = ws.allocate();
- ws.free(id);
-
- int counter = 0;
- for (WorkingSet::iterator it = ws.begin(); it != ws.end(); ++it) {
- counter++;
- }
- ASSERT_EQ(counter, 0);
- }
-
- TEST(WorkingSetIteratorTest, MixedFreeAndInUse) {
- WorkingSet ws;
-
- WorkingSetID id1 = ws.allocate();
- WorkingSetID id2 = ws.allocate();
- WorkingSetID id3 = ws.allocate();
-
- WorkingSetMember* member = ws.get(id2);
- member->state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
- member->obj = Snapshotted<BSONObj>(SnapshotId(), BSON("a" << 3));
-
- ws.free(id1);
- ws.free(id3);
-
- int counter = 0;
- for (WorkingSet::iterator it = ws.begin(); it != ws.end(); ++it) {
- ASSERT(it->state == WorkingSetMember::LOC_AND_UNOWNED_OBJ);
- counter++;
- }
- ASSERT_EQ(counter, 1);
- }
-
- TEST(WorkingSetIteratorTest, FreeWhileIterating) {
- WorkingSet ws;
-
- ws.allocate();
- ws.allocate();
- ws.allocate();
-
- // Free the last two members during iteration.
- int counter = 0;
- for (WorkingSet::iterator it = ws.begin(); it != ws.end(); ++it) {
- if (counter > 0) {
- it.free();
- }
- counter++;
- }
- ASSERT_EQ(counter, 3);
-
- // Verify that only one item remains in the working set.
- counter = 0;
- for (WorkingSet::iterator it = ws.begin(); it != ws.end(); ++it) {
- counter++;
- }
- ASSERT_EQ(counter, 1);
- }
-
} // namespace
diff --git a/src/mongo/db/query/query_solution.h b/src/mongo/db/query/query_solution.h
index 6a49beb6edc..06ebc45f1af 100644
--- a/src/mongo/db/query/query_solution.h
+++ b/src/mongo/db/query/query_solution.h
@@ -225,8 +225,7 @@ namespace mongo {
virtual void appendToString(mongoutils::str::stream* ss, int indent) const;
- // Text's return is LOC_AND_UNOWNED_OBJ or LOC_AND_OWNED_OBJ so it's fetched and has all
- // fields.
+ // Text's return is LOC_AND_OBJ so it's fetched and has all fields.
bool fetched() const { return true; }
bool hasField(const std::string& field) const { return true; }
bool sortedByDiskLoc() const { return false; }
diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp
index b58c9572125..248fbf14511 100644
--- a/src/mongo/dbtests/query_stage_fetch.cpp
+++ b/src/mongo/dbtests/query_stage_fetch.cpp
@@ -114,7 +114,7 @@ namespace QueryStageFetch {
// Mock data.
{
WorkingSetMember mockMember;
- mockMember.state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ mockMember.state = WorkingSetMember::LOC_AND_OBJ;
mockMember.loc = *locs.begin();
mockMember.obj = coll->docFor(&_txn, mockMember.loc);
// Points into our DB.
diff --git a/src/mongo/dbtests/query_stage_sort.cpp b/src/mongo/dbtests/query_stage_sort.cpp
index eca4c36d4d8..dc3d109386e 100644
--- a/src/mongo/dbtests/query_stage_sort.cpp
+++ b/src/mongo/dbtests/query_stage_sort.cpp
@@ -92,7 +92,7 @@ namespace QueryStageSortTests {
// Insert some owned obj data.
WorkingSetMember member;
member.loc = *it;
- member.state = WorkingSetMember::LOC_AND_UNOWNED_OBJ;
+ member.state = WorkingSetMember::LOC_AND_OBJ;
member.obj = coll->docFor(&_txn, *it);
ms->pushBack(member);
}