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

Avoid race conditions with VFS and VFS versions #2789

Merged
merged 2 commits into from
Apr 16, 2022
Merged

Conversation

wz1000
Copy link
Collaborator

@wz1000 wz1000 commented Mar 19, 2022

We need to take VFS snapshots as soon as we get a change notification.

Consider the following interleaving of events:

  1. Change Notification A (updates LSP VFS)
  2. Restart Shake Session (A changed) initiated
  3. Change Notification B (updates LSP VFS)
  4. Restart Shake Session (A changed) takes VFS snapshot and possibly performs more computation
  5. Restart Shake Session (B changed)

In particular, between step 3 and 5, we took a snapshot for a previous build,
but this snapshot included changes from a newer VFS state that the build should
not have seen.

To fix this, we need to take snapshots as soon as a notification handler is
called, before forking any threads. This works because LSP calls all handlers
in a single threaded fashion and these handlers block message processing. It
is essential to do this on the LSP handler thread rather than the reactor thread
that GHCIDE sets up in order to maintin the property.

@wz1000 wz1000 changed the title Avoid race conditions with VFS and VFS version Avoid race conditions with VFS and VFS versions Mar 19, 2022
@wz1000 wz1000 force-pushed the wip/file-versions2 branch 3 times, most recently from 2c023e1 to 6c6d130 Compare March 19, 2022 15:11
Copy link
Collaborator

@pepeiborra pepeiborra left a comment

Choose a reason for hiding this comment

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

Nice

@wz1000 wz1000 added the merge me Label to trigger pull request merge label Mar 19, 2022
Copy link
Collaborator

@fendor fendor left a comment

Choose a reason for hiding this comment

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

Awesome, thank you!

@michaelpj
Copy link
Collaborator

I'm wondering what we could do to make this easier. Would it be helpful to have the ability to install a callback which gets called whenever the VFS gets modified?

@wz1000
Copy link
Collaborator Author

wz1000 commented Mar 20, 2022

The DidChange etc LSP notification handlers are the callback.

@michaelpj
Copy link
Collaborator

The DidChange etc LSP notification handlers are the callback.

Sure, but you have to know that, and you have to deal with all of them. You can't just say "please tell me when the VFS changes". So we're failing to provide a usable abstraction!

@wz1000
Copy link
Collaborator Author

wz1000 commented Mar 20, 2022

Earlier on IRC I suggested we could pass the VFS value along with the notification handlers that cause it to be changed, and this could be extended to the other kinds of state that lsp manages, including sending changed configuration values on configuration change events etc.

Alternatively, I don't think it would be too bad of an idea to remove this state on the lsp side entirely, relying on users to maintain and update their own VFS data using functions provided by lsp.

@michaelpj
Copy link
Collaborator

Earlier on IRC I suggested we could pass the VFS value along with the notification handlers that cause it to be changed, and this could be extended to the other kinds of state that lsp manages, including sending changed configuration values on configuration change events etc.

My problem with this is that handlers already run in LspM which is supposed to exactly provide you with access to these things! So it's quite confusing to provide it in two ways. And it rather suggests that the approach getting it via LspM isn't fit for purpose.

Alternatively, I don't think it would be too bad of an idea to remove this state on the lsp side entirely, relying on users to maintain and update their own VFS data using functions provided by lsp.

I feel like you're just going to end up saying that lsp shouldn't provide a server implementation at all. That might be right! Maybe it shouldn't. We could just provide the pieces.


Okay, one more idea: what if we had a "big lock" on the LSP server state. You could take the big lock if you're going to do something long-running that relies on having a consistent view of the state. The cost would be that it would block anything else from progressing, but that might just be fine.

@wz1000 wz1000 enabled auto-merge (rebase) March 20, 2022 23:25
@wz1000 wz1000 disabled auto-merge April 1, 2022 12:38
We need to take VFS snapshots as soon as we get a change notification.

Consider the following interleaving of events:

1. Change Notification A (updates LSP VFS)
2. Restart Shake Session (A changed) initiated
3. Change Notification B (updates LSP VFS)
4. Restart Shake Session (A changed) takes VFS snapshot and possibly performs more computation
5. Restart Shake Session (B changed)

In particular, between step 3 and 5, we took a snapshot for a previous build,
but this snapshot included changes from a newer VFS state that the build should
not have seen.

To fix this, we need to take snapshots as soon as a notification handler is
called, before forking any threads. This works because LSP calls all handlers
in a single threaded fashion and these handlers block message processing. It
is essential to this on the LSP handler thread rather than the reactor thread
that GHCIDE sets up in order to maintin the property.
@mergify mergify bot merged commit 3c24c20 into master Apr 16, 2022
sloorush pushed a commit to sloorush/haskell-language-server that referenced this pull request May 21, 2022
* Avoid race conditions with VFS and VFS version

We need to take VFS snapshots as soon as we get a change notification.

Consider the following interleaving of events:

1. Change Notification A (updates LSP VFS)
2. Restart Shake Session (A changed) initiated
3. Change Notification B (updates LSP VFS)
4. Restart Shake Session (A changed) takes VFS snapshot and possibly performs more computation
5. Restart Shake Session (B changed)

In particular, between step 3 and 5, we took a snapshot for a previous build,
but this snapshot included changes from a newer VFS state that the build should
not have seen.

To fix this, we need to take snapshots as soon as a notification handler is
called, before forking any threads. This works because LSP calls all handlers
in a single threaded fashion and these handlers block message processing. It
is essential to this on the LSP handler thread rather than the reactor thread
that GHCIDE sets up in order to maintin the property.

* Disable flaky test 'add missing module (non workspace)'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge me Label to trigger pull request merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants