Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve memory leak when using cursor operations like $count in mongodb@4-6 #152

Merged
merged 2 commits into from
Feb 13, 2024

Conversation

ericyhwang
Copy link
Contributor

@ericyhwang ericyhwang commented Feb 12, 2024

Starting in Mongo Node driver mongodb@4, up through the latest version mongodb@6, using cursor.count() results in a memory leak. mongodb@3 doesn't leak in the same situation.

The driver creates an implicit client session, but it doesn't automatically close the session when getting the results back from the server. Those unclosed sessions build up over time, causing a memory leak.

Relevant issues filed against the Mongo Node driver:

sharedb-mongo exposes document counting via a user passing the $count: true property on query objects, and it currently uses cursor.count().

There are a couple ways sharedb-mongo could address the leak:

  • Switch to Collection#countDocuments(), which is the recommended replacement for the deprecated FindCursor#count(). This is better long-term, but it's more work since we have to map things like $limit from using chained cursor calls over to the equivalent property in CountOptions, where appropriate.
  • Explicitly close the cursor. Easy and safe, since the cursor is created inside sharedb-mongo and not exposed externally.

To resolve the leak more quickly, this change opts for the latter, explicitly closing the cursor for the "cursor operations" $count, $explain, and $map.

Thanks to @deongroenewald for the private report and repro case!

This also includes the changes in #153 and #154 - assuming those get merged first, I'll rebase this for a smaller diff.

@coveralls
Copy link

coveralls commented Feb 12, 2024

Coverage Status

coverage: 92.593% (+0.02%) from 92.574%
when pulling 3410c26 on fix-mongo-count-leak
into 5e6fc4c on master.

@alecgibson
Copy link
Contributor

@ericyhwang is this a bug with node-mongodb-native? Have you raised an issue there? Possibly related to https://jira.mongodb.org/projects/NODE/issues/NODE-2882 ?

@alecgibson
Copy link
Contributor

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also need to actively close the cursor if no operation is defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need, the toArray() will exhaust the cursor, so no leak in that case.

As discussed, I'll remove the cursor.close() in the $map case since I added a toArray() there.

…db@4-6

Starting in Mongo Node driver `mongodb@4`, up through the latest version `mongodb@6`, using `cursor.count()` results in a memory leak. `mongodb@3` doesn't leak in the same situation.

The driver creates an implicit client session, but it doesn't automatically close the session when getting the results back from the server. Those unclosed sessions build up over time, causing a memory leak.

sharedb-mongo exposes document counting via a user passing the `$count: true` property on query objects, and it currently uses `cursor.count()`.

There are a couple ways sharedb-mongo could address the leak:
- Switch to `Collection#countDocuments()`, which is the recommended replacement for the deprecated `FindCursor#count()`. This is better long-term, but it's more work since we have to map things like `$limit` from using chained cursor calls over to the equivalent property in CountOptions, where appropriate.
- Explicitly close the cursor. Easy and safe, since the cursor is created inside sharedb-mongo and not exposed externally.

To resolve the leak more quickly, this change opts for the latter, explicitly closing the cursor for the "cursor operations" `$count`, `$explain`, and `$map`.
@ericyhwang
Copy link
Contributor Author

@ericyhwang is this a bug with node-mongodb-native? Have you raised an issue there? Possibly related to https://jira.mongodb.org/projects/NODE/issues/NODE-2882 ?

FindCursor#count() is deprecated, scheduled for removal in the next major driver version.

I'll try and set up a repro for FindCursor#explain() to see if it leaks, though, and if so I'll report it to the Node Mongo driver.

@ericyhwang ericyhwang merged commit 2b3566d into master Feb 13, 2024
32 checks passed
@ericyhwang ericyhwang deleted the fix-mongo-count-leak branch February 13, 2024 17:24
@ericyhwang
Copy link
Contributor Author

BTW, after fighting Jira search for a while, I found issues already filed against the Node driver:

Have edited them into the PR description for posterity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants