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

Implement streaming for compare view #3771

Merged
merged 2 commits into from
Oct 30, 2024
Merged

Conversation

koesie10
Copy link
Member

This implements streaming for the compare view to avoid a crash when the total JSON.stringified size of the comparison is larger than 1GB (i.e. the Node.js string limit). It does this as follows:

  • All results are chunked into 1,000 results per message. This means we'll send at most 1,000 to and at most 1,000 from results in 1 message (i.e. 2,000 actual results).
  • We'll send a "setup" message to tell the webview that we're starting a streaming result. This also contains a chunk.
  • We'll then send as many "add results" messages as necessary to send all results.
  • We'll send a "complete" message to tell the webview that we're done.

The 1,000 results per message is just a safe estimate where we should never run into the string limit. However, I can't really test this.

@koesie10 koesie10 force-pushed the koesie10/streaming-comparison branch from 571f689 to a69ef15 Compare October 22, 2024 13:19
This avoids a bug where comparisons could potentially overlap if the
user opens a new comparison while the previous one has not yet finished
loading.
@koesie10 koesie10 marked this pull request as ready for review October 22, 2024 13:51
@koesie10 koesie10 requested a review from a team as a code owner October 22, 2024 13:51
Copy link
Contributor

@aeisenberg aeisenberg left a comment

Choose a reason for hiding this comment

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

A handful of simplifications, and a question.

Looks good, but I have not ran this myself.

Comment on lines +261 to +275
if (result.kind === "raw") {
return {
...result,
from: result.from.slice(start, end),
to: result.to.slice(start, end),
};
}

if (result.kind === "interpreted") {
return {
...result,
from: result.from.slice(start, end),
to: result.to.slice(start, end),
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like the bodies of these if statements are the same. Should you combine them?

Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately that's not possible in this case because TypeScript can't determine that automatically from these overlapping types: Returned expression type {kind: "raw" | "interpreted", from: Row[] | Result[], to: Row[] | Result[]} is not assignable to type QueryCompareResult .

Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunate.

Comment on lines +87 to +90
if (msg.result.kind !== "raw") {
throw new Error(
"Streaming comparison: expected raw results, got interpreted results",
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Any danger of getting here if you switch in the middle of rendering a very large comparison result?

Copy link
Member Author

Choose a reason for hiding this comment

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

There shouldn't be: 510a269 adds a check for that race condition by adding an id to every message so that if a different setup message is received, it will ignore all future messages from the previous stream.

Comment on lines +106 to +110
result = {
...prev.result,
from: [...prev.result.from, ...msg.result.from],
to: [...prev.result.to, ...msg.result.to],
};
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like this assignment is the same as the one above. Can you merge the cases?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is split out for the same reason as above: we get a TypeScript error if we don't have this.

Copy link
Contributor

@aeisenberg aeisenberg left a comment

Choose a reason for hiding this comment

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

Given the limitations of the type system, I think this is fine. I'm sure there's some type wizardry we can do to make this cleaner, but it's really not worth the effort.

Comment on lines +261 to +275
if (result.kind === "raw") {
return {
...result,
from: result.from.slice(start, end),
to: result.to.slice(start, end),
};
}

if (result.kind === "interpreted") {
return {
...result,
from: result.from.slice(start, end),
to: result.to.slice(start, end),
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunate.

@koesie10 koesie10 merged commit 625c8a7 into main Oct 30, 2024
27 checks passed
@koesie10 koesie10 deleted the koesie10/streaming-comparison branch October 30, 2024 10:29
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.

2 participants