summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/pipeline/document_source.h5
-rw-r--r--src/mongo/db/pipeline/document_source_match.cpp7
-rw-r--r--src/mongo/db/pipeline/document_source_skip.cpp15
3 files changed, 24 insertions, 3 deletions
diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h
index bf4c65fa18b..0dd3b7b3154 100644
--- a/src/mongo/db/pipeline/document_source.h
+++ b/src/mongo/db/pipeline/document_source.h
@@ -199,6 +199,11 @@ public:
* this DocumentSource.
*
* All implementers must call pExpCtx->checkForInterrupt().
+ *
+ * For performance reasons, a streaming stage must not keep references to documents across calls
+ * to getNext(). Such stages must retrieve a result from their child and then release it (or
+ * return it) before asking for another result. Failing to do so can result in extra work, since
+ * the Document/Value library must copy data on write when that data has a refcount above one.
*/
virtual GetNextResult getNext() = 0;
diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp
index 494d6589099..3107e8b7677 100644
--- a/src/mongo/db/pipeline/document_source_match.cpp
+++ b/src/mongo/db/pipeline/document_source_match.cpp
@@ -82,6 +82,13 @@ DocumentSource::GetNextResult DocumentSourceMatch::getNext() {
if (_expression->matchesBSON(toMatch)) {
return nextInput;
}
+
+ // For performance reasons, a streaming stage must not keep references to documents across
+ // calls to getNext(). Such stages must retrieve a result from their child and then release
+ // it (or return it) before asking for another result. Failing to do so can result in extra
+ // work, since the Document/Value library must copy data on write when that data has a
+ // refcount above one.
+ nextInput.releaseDocument();
}
return nextInput;
diff --git a/src/mongo/db/pipeline/document_source_skip.cpp b/src/mongo/db/pipeline/document_source_skip.cpp
index ff528f0634e..114a2f7d1b4 100644
--- a/src/mongo/db/pipeline/document_source_skip.cpp
+++ b/src/mongo/db/pipeline/document_source_skip.cpp
@@ -57,11 +57,20 @@ const char* DocumentSourceSkip::getSourceName() const {
DocumentSource::GetNextResult DocumentSourceSkip::getNext() {
pExpCtx->checkForInterrupt();
- auto nextInput = pSource->getNext();
- for (; _nSkippedSoFar < _nToSkip && nextInput.isAdvanced(); nextInput = pSource->getNext()) {
+ while (_nSkippedSoFar < _nToSkip) {
+ // For performance reasons, a streaming stage must not keep references to documents across
+ // calls to getNext(). Such stages must retrieve a result from their child and then release
+ // it (or return it) before asking for another result. Failing to do so can result in extra
+ // work, since the Document/Value library must copy data on write when that data has a
+ // refcount above one.
+ auto nextInput = pSource->getNext();
+ if (!nextInput.isAdvanced()) {
+ return nextInput;
+ }
++_nSkippedSoFar;
}
- return nextInput;
+
+ return pSource->getNext();
}
Value DocumentSourceSkip::serialize(bool explain) const {