-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Reuse jdt.ls workspace #2970
Reuse jdt.ls workspace #2970
Conversation
@tsmaeder @akosyakov Take a look please |
This should be solved in the language server itself. The initialize sends the workspace uri and the jdt.ls should internally do the meta data reuse based on the path name. At least the parameter for the meta data should be part of an extended initialize method and not be a program argument as it is closely related to the workspaceroot(s). Doesn't that same issue exist with jdt.ls when used from VS Code? CC @fbricon |
const jarPath = path.resolve(serverPath, jarPaths[0]); | ||
const workspacePath = path.resolve(os.tmpdir(), '_ws_' + new Date().getTime()); | ||
|
||
const uri = await this.workspaceService.getMostRecentlyUsedWorkspace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only by luck returning the expected root. I.e. if another window connected on different workspace in the meantime it will not be what you expect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess if we're reusing, somewhere in user home would be appropriate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@svenefftinge It works as I expect when Theia already started and I just open another window on different workspace. But yes, if i have two windows on different workspaces and Theia start initializing - I got the some value for both instances.
Does Theia already have some way to get current workspace's name or URI?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tsmaeder as an option we can save it in os.homedir() + .theia/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does Theia already have some way to get current workspace's name or URI?
Yes, however each frontend application is the one aware of what its own current workspace is - the backend doesn't know or keep track of this. This way, there can be multiple frontends, each with its own independently-set workspace (it's permitted to re-use a WS between clients), using the same stateless backend.
One way where jdt.ls may differ from other LS we use is that it probably does not permit sharing a workspace between two or more clients. So for that case, we might still need to have different jdt.ls workspaces. However when a given client is reloaded, it would make sense for it to re-use the same jdt.ls workspace as before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we want to eventually share language server instances
Interesting. Would a single jdt.ls instance be able to simultaneously serve two or more LS clients, for the same workspace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it would not: you can't send the initialize message twice, for example. Also, there is no provision for opening multiple communication channels (socket or otherwise). Such multiplexing has to happen outside of the language server.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One way where jdt.ls may differ from other LS we use is that it probably does not permit sharing a workspace between two or more clients.
Actually, I would expect this to be the case for many non-trivial languages servers: there would a some metadata stored and cached by the language server (think symbol index), and if the language server derives from some IDE tool (as jdt.ls), it probably assumes that it's working alone on that metadata.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it would not: you can't send the initialize message twice, for example. Also, there is no provision for opening multiple communication channels (socket or otherwise). Such multiplexing has to happen outside of the language server.
One could start one language server process that accepts many connections and then the language server internally could do all kinds of sharing and caching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could start one language server process that accepts many connections and then the language server internally could do all kinds of sharing and caching.
Yes, one could, but currently, language servers are not written that way.
@svenefftinge I am not sure about jdt.ls doing this itself: for one, it does not know about other instances of jdt.ls running. Also, the concurrency needs depend on the environment: Theia and VSCode have a model where you open an arbitrary folder, whereas Eclipse IDE or Che have a fixed workspace root. |
jdt.ls being an Eclipse application, AFAIK, the only way to define the workspace location is as a command line argument. I don't think you can start the app and then change the workspace location. But I'd be happy to be proven wrong. |
Having thought about this a bit more, I had a couple of thoughts I think might be of interest:
|
Yes. This should work today already. Both clients will be watching the file. The second client will re-read the file when notified by the watcher. This works also if the file is modified outside of a Theia editor.
I see them as separate IDEs sharing the filesystem, with the option to share state / coordinate when it makes sense. Saving the IDE state: the saved state is totally independent for each client, and is saved in the browser's local storage. This is "best effort" since changes in widgets or layout save/restore scheme can make it impossible to restore an arbitrary old saved state. AFAIK, when we detect that the browser window is being closed, local browser storage is the only place we can save the state reliably. Preferences: the intelligence is in the client, the storage in the B-E. Each client's Preferences service watches the preferences files it currently uses. If some preference file is modified, that is shared between clients (same user prefs and/or same workspace prefs), all clients using it will re-read the content and apply the changes, if any. So if two clients use the same workspace, their preferences will stay in sync. |
As I already pointed out in the inline comment, using |
Ok. I just wonder why we should add such an optimization for Theia, only. It seems like the same would be useful for other LSP clients using jdt.ls? |
@svenefftinge that's how vscode-java works, as well as all other clients, if they follow the instructions (item 7) |
Actually, Che (6) does not, since the workspace is always in a fixed location in the container. You cannot different locations in a Che workspace. |
Would it make sense to send the workspace root with the start request for the language server? At this point, the workspace root should be known, no? |
Yes, that would be fine, as well. |
I tested this PR a bit and it does seem to help the performance of restarting a Java workspace. With the example project I used, the Java LS became responsive to my actions after ~20s instead of ~30s (when a jdt.ls data folder is re-used). That's a nice improvement. |
when reusing a workspace, you should expect the server to be responsive within 5sec (tested with https://github.com/spring-projects/spring-boot (and "java.import.gradle.enabled": false) in vscode. |
@fbricon The project I used to test generates a lot of errors, so the results are not meant to be representative. I just tried with spring-boot and it took under 5s to become responsive, even with the ~700 errors due to the fact I did not setup the project. |
It is not possible to send the workspace uri with the start request, because the LS is started as soon as the jsonrpc connection is established on the server |
@AlexTugarev, this seems to be the same pattern as what we discussed about the Python language server needing to know the virtual env path at the moment we launch it. The frontend wants to influence how the language server process is started, but there is no way for it to pass parameters to the backend code that launches the process. I think we should settle on how parameters are sent from the frontend to the backend when starting a language server. I see three possibilities:
|
@simark, I think we should look into 2nd option first. See: @akosyakov, WDYT? |
I would be happy with this. After discussing it with you last time it seemed like you didn't really like that idea, but if you do now I don't mind :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One little detail to iron-out before merge: the folder under which we save the jdt.ls data folders.
@marcdumais-work @AlexTugarev @akosyakov @svenefftinge @tsmaeder |
My previous "blocking" comment is resolved, dismissing previous review
To avoid changing existing extensions I've sent start parameters before starting language server. And each implementation of ls contribution has an ability to provide such params if it is needed. |
@svor good, can you extract changes to the languages extension to a new PR? that we can merge it and use for other languages |
@akosyakov The PR is updated, take a look please. |
@marcdumais-work @AlexTugarev @svenefftinge @tsmaeder please, can you help finish the review? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That works nicely! Thanks!
Warmup time for the Java support is noticeable shorter if an Eclipse workspace directory can be reused.
@@ -125,6 +143,17 @@ export class JavaContribution extends BaseLanguageServerContribution { | |||
}); | |||
} | |||
|
|||
private generateDataFolderSuffix(workspaceUri: string): string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe you could make this method protected, so extenders can change it.
Signed-off-by: Valeriy Svydenko <vsvydenk@redhat.com>
Signed-off-by: Valeriy Svydenko vsvydenk@redhat.com
The PR suggests to reuse jdt.ls' workspace multiple times.
The jdt.ls workspace has schema:
_ws_<opened-theia-workspace-sha1>_<0..n>
If we have 2 opened instances of Theia with same workspace, we'll have 2 jdt.ls' workspaces:
/tmp/_ws_sha1ValueOfTheiaWs_0
/tmp/_ws_sha1ValueOfTheiaWs_1
Related issue: eclipse-che/che#10325