fix(plugin-mongodb): stop large collections hanging on open and make Stop cancel the query - #1999
Merged
Merged
Conversation
…Stop cancel the query Claude-Session: https://claude.ai/code/session_01DSrwXNZ4S4jQXftgC6E2hv
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported in chat: opening a MongoDB collection with ~4.6M documents hangs on "Executing…" forever at page size 20, while Compass shows the first page instantly.
What was actually wrong
The obvious theory (the row count blocks the grid) is contradicted by the code.
toolbarState.setExecuting(false)fires the moment the browse query returns, before phase 2 is even launched, so a stuck spinner proves thefind({}).limit(20)itself never returned. The count was already deferred and already used the O(1) metadata read. The screenshot also rules out a restored filter: the Filters button renders a filled icon and a(N)count when filters are applied, and it shows neither.Two defects made any non-instant MongoDB operation an unrecoverable hang:
estimatedDocumentCountpassednilopts, so the configuredmaxTimeMSnever reached the server on the one call that runs on every table open. Views and time-series collections have no metadata count, so the server falls back to executing the pipeline as a full scan, unbounded.mongoc_cursor_nextcalls, so it could not touch a blocking count or the firstcursor_nextwhere an unindexed sort's scan happens.The most likely trigger for this specific report is a sort on a non-
_idfield with no index. Per MongoDB's docs asort+limit: 20uses top-k, which buffers only 20 documents, so it never trips the 100MB guard and raises no error at all while still reading all 4.6M documents. It is indistinguishable from a count scan. I could not confirm which trigger fired without the reporter's database, so the fix targets the class: no MongoDB operation can hang past a bound, and every hang is cancellable and explicable.Changes
Plugin (ships on a
plugin-mongodb-v*republish, not with the app release)estimatedDocumentCountnow builds opts and carriesmaxTimeMS.COUNT_MAX_TIME_MS_CAP); user-initiated counts use the configured timeout.countDocumentsgetshint: "_id_"(MongoDB's documented mitigation), retried without the hint only on a bad-hint error, never on a timeout.findruns inside a mongoc session whose lsid is copied under lock, so cancel sendskillSessionsfrom a separate control client. The connection's own queue is blocked inside the C call and cannot send anything. Degrades cleanly when the deployment has no session support.executeUserQuerybounds the server-side limit instead of requestingPluginRowLimits.emergencyMax(5,000,000) and trimming client-side. It asks forrowCap + 1so truncation stays detectable.streamRows/streamFindhonourskipandlimit, which were silently dropped.iterateCursorStreaminggained the truncation capiterateCursoralready had.App (ships with the app release)
fetchExactRowCountrequirement onPluginDatabaseDriverwith a default implementation: additive, so nocurrentPluginKitVersionbump and norelease-all-plugins.shrun. Already-built plugins keep loading.?.Verification
--strictclean on every changed file. The two force-unwrap hits inMongoDBConnection.swiftare pre-existing onmain(lines 241-242 there) and untouched.swiftc -parse.TableProTests/PluginTestSources/so the tests exercise the shipping code, not a copy. Worth knowing:BsonDocumentFlattenerTests.swiftdeclares a private duplicate of the type it tests, so it validates a copy.Notes for review
defaultExportQuery(find({}), no limit). The streaming export path receivesbaseQueryForMore, a query-tab concept, so honouring its limit is a fix rather than a regression.~4,600,000text itself tappable. Splitting a localized format string to make one number clickable breaks translations and RTL.https://claude.ai/code/session_01DSrwXNZ4S4jQXftgC6E2hv