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

Reduce Megolm blocking and add cancellation #3035

Merged
merged 4 commits into from
Jan 24, 2023

Conversation

clarkf
Copy link
Contributor

@clarkf clarkf commented Jan 8, 2023

This was originally intended to help with element-hq/element-web#21612, but ended up addressing #1255 as well.

The input delay was addressed by adding a setTimeout to the cpu-bound portion of the code. That should allow rendering code and event handlers to preempt key preparation periodically. Should help somewhat, but probably not a full solution. Ideally, setImmediate should be used or approximated, but it's basically not supported in any browser, so 0ms timeouts it is.

That allowed for cancellation to be addressed. There are multiple ways this could have been achieved, and I wasn't able to find a clear precedent. I opted for passing around stateful closures. It had the most minimal impact on the API that I could come up with.

I've tried my best to follow the contribution guidelines and code style documentation, but this is my first (substantial) contribution. Any and all feedback welcome!

Checklist

  • Tests written for new code (and old code if feasible)
  • Linter and other CI checks pass
  • Sign-off given on the changes (see CONTRIBUTING.md)

Notes: Introduces a backwards-compatible API change. MegolmEncrypter#prepareToEncrypt's return type has changed from void to () => void.


Here's what your changelog entry will look like:

✨ Features

  • Introduces a backwards-compatible API change. MegolmEncrypter#prepareToEncrypt's return type has changed from void to () => void. (#3035). Contributed by @clarkf.

@clarkf clarkf requested a review from a team as a code owner January 8, 2023 23:09
@github-actions github-actions bot added the Z-Community-PR Issue is solved by a community member's PR label Jan 8, 2023
@robintown robintown self-assigned this Jan 12, 2023
@robintown robintown removed the request for review from florianduros January 16, 2023 03:22
@robintown robintown removed their assignment Jan 16, 2023
Copy link
Member

@robintown robintown left a comment

Choose a reason for hiding this comment

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

The changes look pretty straightforward, thanks.

For the record, you're actually free to use setImmediate here, since any time the js-sdk gets used in a browser, it invariably gets run through Babel which has polyfills for that.

*/
public prepareToEncrypt(room: Room): void {
public prepareToEncrypt(room: Room): Stop {
Copy link
Member

Choose a reason for hiding this comment

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

I would prefer to just write out () => void instead of Stop, since the doc comments already describe well enough what the return value does, and when the types are this simple, aliases tend to only add confusion.

src/crypto/algorithms/megolm.ts Show resolved Hide resolved
// Yield prior to checking each device so that we don't block
// updating/rendering for too long.
// See https://github.com/vector-im/element-web/issues/21612
await sleep(0);
Copy link
Member

Choose a reason for hiding this comment

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

While I see how this would unblock the event loop and fix the linked issue, I also want to make sure this won't create a performance regression in encryptMessage. It's quite possible that there will be a lot of devices processed here, and the HTML spec claims that after 5 nested calls, any further setTimeout calls are clamped to a minimum delay, which could add up.

Perhaps it would be more appropriate for the function to only yield on cancelable operations?

Suggested change
await sleep(0);
if (isCancelled !== undefined) await sleep(0);

Copy link
Contributor Author

@clarkf clarkf Jan 16, 2023

Choose a reason for hiding this comment

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

Interesting, I'd never heard about the minimum delay!

Swapping to setImmediate, since it's polyfilled, which should obviate the problem. Seems core-js provides a MessageChannel-based implementation, only falling back to setTimeout on browsers that aren't targeted.

Also added the conditional!

Adds an async/promise-based version of `setImmediate`. Note that, despite being
poorly adopted, `setImmediate` is polyfilled, and should be more performant
than `sleep(0)`.

Signed-off-by: Clark Fischer <[email protected]>
Currently, calling `Client#prepareToEncrypt` in a megolm room has the potential
to block for multiple seconds while it crunches numbers.

Sleeping for 0 seconds (approximating `setImmediate`) allows the engine to
process other events, updates, or re-renders in between checks.

See
- element-hq/element-web#21612
- element-hq/element-web#11836

Signed-off-by: Clark Fischer <[email protected]>
NOTE: This commit introduces a backwards-compatible API change.

Adds the ability to cancel `MegolmEncryption#prepareToEncrypt` by returning
a cancellation function. The bulk of the processing happens in
`getDevicesInRoom`, which now accepts a 'getter' that allows the caller to
indicate cancellation.

See matrix-org#1255
Closes matrix-org#1255

Signed-off-by: Clark Fischer <[email protected]>
Copy link
Member

@robintown robintown left a comment

Choose a reason for hiding this comment

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

Sorry for the wait, this looks good to land now 👍

@robintown robintown enabled auto-merge January 24, 2023 17:20
@robintown robintown merged commit 70656e9 into matrix-org:develop Jan 24, 2023
@clarkf clarkf deleted the megolm-cancellation branch January 24, 2023 18:58
@clarkf clarkf mentioned this pull request Jan 25, 2023
3 tasks
su-ex added a commit to SchildiChat/matrix-js-sdk that referenced this pull request Feb 28, 2023
* Element-R: implement encryption of outgoing events ([\matrix-org#3122](matrix-org#3122)).
* Poll model - page /relations results ([\matrix-org#3073](matrix-org#3073)). Contributed by @kerryarchibald.
* Poll model - validate end events ([\matrix-org#3072](matrix-org#3072)). Contributed by @kerryarchibald.
* Handle optional last_known_event_id property in m.predecessor ([\matrix-org#3119](matrix-org#3119)). Contributed by @andybalaam.
* Add support for stable identifier for fixed MAC in SAS verification ([\matrix-org#3101](matrix-org#3101)).
* Provide eventId as well as roomId from Room.findPredecessor ([\matrix-org#3095](matrix-org#3095)). Contributed by @andybalaam.
* MSC3946 Dynamic room predecessors ([\matrix-org#3042](matrix-org#3042)). Contributed by @andybalaam.
* Poll model ([\matrix-org#3036](matrix-org#3036)). Contributed by @kerryarchibald.
* Remove video tracks on video mute without renegotiating ([\matrix-org#3091](matrix-org#3091)).
* Introduces a backwards-compatible API change. `MegolmEncrypter#prepareToEncrypt`'s return type has changed from `void` to `() => void`. ([\matrix-org#3035](matrix-org#3035)). Contributed by @clarkf.
* Stop the ICE disconnected timer on call terminate ([\matrix-org#3147](matrix-org#3147)).
* Clear notifications when we can infer read status from receipts ([\matrix-org#3139](matrix-org#3139)). Fixes element-hq/element-web#23991.
* Messages sent out of order after one message fails ([\matrix-org#3131](matrix-org#3131)). Fixes element-hq/element-web#22885 and element-hq/element-web#18942. Contributed by @justjanne.
* Element-R: fix a bug which prevented encryption working after a reload ([\matrix-org#3126](matrix-org#3126)).
* Element-R: Fix invite processing ([\matrix-org#3121](matrix-org#3121)).
* Don't throw with no `opponentDeviceInfo` ([\matrix-org#3107](matrix-org#3107)).
* Remove flaky megolm test ([\matrix-org#3098](matrix-org#3098)). Contributed by @clarkf.
* Fix "verifyLinks" functionality of getRoomUpgradeHistory ([\matrix-org#3089](matrix-org#3089)). Contributed by @andybalaam.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-Enhancement Z-Community-PR Issue is solved by a community member's PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants