Skip to content

Commit 3e78918

Browse files
authored
[#1207] cache IResource in EnablementTester (#1208)
Cache resource for URI because each call of LSPEclipseUtils.findResourceFor(URI) takes ~300 microseconds. And it gets called a lot of times. fixes #1207
1 parent 2cc8e57 commit 3e78918

4 files changed

Lines changed: 99 additions & 20 deletions

File tree

org.eclipse.lsp4e/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
22
Bundle-ManifestVersion: 2
33
Bundle-Name: Language Server Protocol client for Eclipse IDE (Incubation)
44
Bundle-SymbolicName: org.eclipse.lsp4e;singleton:=true
5-
Bundle-Version: 0.18.17.qualifier
5+
Bundle-Version: 0.18.18.qualifier
66
Bundle-RequiredExecutionEnvironment: JavaSE-17
77
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.12.0",
88
org.eclipse.equinox.common;bundle-version="3.8.0",

org.eclipse.lsp4e/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111
<artifactId>org.eclipse.lsp4e</artifactId>
1212
<packaging>eclipse-plugin</packaging>
13-
<version>0.18.17-SNAPSHOT</version>
13+
<version>0.18.18-SNAPSHOT</version>
1414

1515
<build>
1616
<plugins>

org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
import org.eclipse.jface.viewers.ISelectionProvider;
9595
import org.eclipse.lsp4e.internal.ArrayUtil;
9696
import org.eclipse.lsp4e.internal.DocumentInputStream;
97+
import org.eclipse.lsp4e.internal.ResourceForUriCache;
9798
import org.eclipse.lsp4e.refactoring.CreateFileChange;
9899
import org.eclipse.lsp4e.refactoring.DeleteExternalFile;
99100
import org.eclipse.lsp4e.refactoring.LSPTextChange;
@@ -458,24 +459,7 @@ public static IResource findResourceFor(@Nullable String uri) {
458459

459460
@Nullable
460461
public static IResource findResourceFor(@Nullable URI uri) {
461-
if (uri == null) {
462-
return null;
463-
}
464-
if (FILE_SCHEME.equals(uri.getScheme())) {
465-
IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
466-
467-
IFile[] files = wsRoot.findFilesForLocationURI(uri);
468-
if (files.length > 0) {
469-
IFile file = findMostNested(files);
470-
if(file!=null) {
471-
return file;
472-
}
473-
}
474-
475-
return ArrayUtil.findFirst(wsRoot.findContainersForLocationURI(uri));
476-
} else {
477-
return Adapters.adapt(uri, IResource.class, true);
478-
}
462+
return ResourceForUriCache.get(uri);
479463
}
480464

481465
public static @Nullable IFile findMostNested(IFile[] files) {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Contributors to the Eclipse Foundation.
3+
* This program and the accompanying materials are made
4+
* available under the terms of the Eclipse Public License 2.0
5+
* which is available at https://www.eclipse.org/legal/epl-2.0/
6+
*
7+
* SPDX-License-Identifier: EPL-2.0
8+
*
9+
* Contributors:
10+
* See git history
11+
*******************************************************************************/
12+
13+
package org.eclipse.lsp4e.internal;
14+
15+
import java.net.URI;
16+
17+
import org.eclipse.core.resources.IFile;
18+
import org.eclipse.core.resources.IResource;
19+
import org.eclipse.core.resources.IWorkspaceRoot;
20+
import org.eclipse.core.resources.ResourcesPlugin;
21+
import org.eclipse.core.runtime.Adapters;
22+
import org.eclipse.jdt.annotation.Nullable;
23+
import org.eclipse.lsp4e.LSPEclipseUtils;
24+
25+
import com.google.common.cache.Cache;
26+
import com.google.common.cache.CacheBuilder;
27+
28+
/**
29+
* <p>NOTE: In case a resource has been moved or deleted the entry will not be removed automatically.
30+
* It's up to the caller to check if the resource is accessible.
31+
*
32+
* <p>The cache is limited to 100 resource elements. It uses least-recently-used eviction if limit exceeds.
33+
* The cache will try to evict entries that haven't been used recently.
34+
* Therefore entries can be removed before the limit exceeds.
35+
*/
36+
public final class ResourceForUriCache {
37+
private static final String FILE_SCHEME = "file"; //$NON-NLS-1$
38+
private static final Cache<URI, IResource> cache = CacheBuilder.newBuilder().maximumSize(100).build();
39+
40+
private ResourceForUriCache() {
41+
// this class shouldn't be instantiated
42+
}
43+
44+
/**
45+
* <p>Returns the cached IResource for the given URI. Tries to determine the IResource
46+
* if it's not already in the cache. Returns NULL if the IResource could not be determined,
47+
* e.g. the URI points to a file outside the workspace.
48+
*
49+
* <p>NOTE: In case a resource has been moved or deleted the entry will not be removed automatically.
50+
* It's up to the caller to check if the resource is accessible.
51+
* @param uri
52+
* @return IResource or NULL
53+
*/
54+
@Nullable
55+
public static IResource get(@Nullable URI uri) {
56+
// Note: The load method in CacheLoader/LoadingCache cannot be applied here because
57+
// the load method has to return a non-null value.
58+
// But it cannot be guaranteed that there can be a IResource fetched for the given URI.
59+
URI localURI = uri;
60+
IResource resource = null;
61+
if (localURI != null) {
62+
resource = cache.getIfPresent(localURI);
63+
if (resource != null) {
64+
return resource;
65+
}
66+
resource = findResourceFor(localURI);
67+
if (resource != null) {
68+
cache.put(localURI, resource);
69+
}
70+
}
71+
return resource;
72+
}
73+
74+
@Nullable
75+
private static IResource findResourceFor(URI uri) {
76+
if (FILE_SCHEME.equals(uri.getScheme())) {
77+
IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
78+
79+
IFile[] files = wsRoot.findFilesForLocationURI(uri);
80+
if (files.length > 0) {
81+
IFile file = LSPEclipseUtils.findMostNested(files);
82+
if(file!=null) {
83+
return file;
84+
}
85+
}
86+
87+
return ArrayUtil.findFirst(wsRoot.findContainersForLocationURI(uri));
88+
} else {
89+
return Adapters.adapt(uri, IResource.class, true);
90+
}
91+
}
92+
93+
}
94+
95+

0 commit comments

Comments
 (0)