diff options
-rw-r--r-- | src/mongo/db/pipeline/document_source.h | 5 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_match.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/pipeline/document_source_skip.cpp | 15 |
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 { |