diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java index e79f093162..af2b1dd9d3 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/index/SpringMetamodelIndex.java @@ -29,24 +29,29 @@ public class SpringMetamodelIndex { private final ConcurrentMap projectRootElements; + private final ConcurrentMap docUriToDocument; public SpringMetamodelIndex() { projectRootElements = new ConcurrentHashMap<>(); + docUriToDocument = new ConcurrentHashMap<>(); } public void updateElements(String projectName, String docURI, SpringIndexElement[] elements) { ProjectElement project = this.projectRootElements.computeIfAbsent(projectName, name -> new ProjectElement(name)); project.removeDocument(docURI); - + if (elements != null && elements.length > 0) { DocumentElement document = new DocumentElement(docURI); for (SpringIndexElement bean : elements) { document.addChild(bean); } - + project.addChild(document); - } - + docUriToDocument.put(docURI, document); + } else { + docUriToDocument.remove(docURI); + } + } public void removeElements(String projectName, String docURI) { @@ -54,10 +59,18 @@ public void removeElements(String projectName, String docURI) { if (project != null) { project.removeDocument(docURI); } + docUriToDocument.remove(docURI); } public void removeProject(String projectName) { - projectRootElements.remove(projectName); + this.projectRootElements.computeIfPresent(projectName, (name, project) -> { + for (SpringIndexElement child : project.getChildren()) { + if (child instanceof DocumentElement) { + docUriToDocument.remove(((DocumentElement) child).getDocURI()); + } + } + return null; + }); } public Collection getProjects() { @@ -65,11 +78,18 @@ public Collection getProjects() { } public DocumentElement getDocument(String docURI) { + DocumentElement cached = docUriToDocument.get(docURI); + if (cached != null) { + return cached; + } + // Fallback to full traversal if not in cache (e.g. for pre-existing elements) List rootNodes = new ArrayList(this.projectRootElements.values()); List documents = getNodesOfType(DocumentElement.class, rootNodes, document -> document.getDocURI().equals(docURI)); if (documents.size() == 1) { - return documents.get(0); + DocumentElement doc = documents.get(0); + docUriToDocument.putIfAbsent(docURI, doc); + return doc; } else { return null; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/commands/SpringIndexCommands.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/commands/SpringIndexCommands.java index d4d8ff1182..3981a58c9d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/commands/SpringIndexCommands.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/commands/SpringIndexCommands.java @@ -59,7 +59,7 @@ public SpringIndexCommands(SimpleLanguageServer server, SpringMetamodelIndex spr this.modulithService = modulithService; this.stereotypeCatalogRegistry = stereotypeCatalogRegistry; this.sourceLinks = sourceLinks; - this.messageWorkerThreadPool = Executors.newCachedThreadPool(); + this.messageWorkerThreadPool = Executors.newFixedThreadPool(4); server.onCommand(SPRING_STRUCTURE_CMD, params -> { return CompletableFuture.supplyAsync(() -> { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java index 78e870bbad..9b77d68692 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/CompositeASTVisitor.java @@ -71,14 +71,18 @@ public boolean visit(MethodDeclaration node) { @Override public void endVisit(MethodDeclaration node) { for (ASTVisitor astVisitor : visitors) { - astVisitor.endVisit(node); + if (astVisitor != null) { + astVisitor.endVisit(node); + } } } @Override public void endVisit(CompilationUnit node) { for (ASTVisitor astVisitor : visitors) { - astVisitor.endVisit(node); + if (astVisitor != null) { + astVisitor.endVisit(node); + } } } @@ -141,7 +145,9 @@ private boolean delegateVisit(ASTNode node, Function visitF } boolean result = false; for (ASTVisitor visitor : visitors) { - result |= visitFn.apply(visitor); + if (visitor != null) { + result |= visitFn.apply(visitor); + } } return result; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java index ef37fbcf20..986f68c856 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java @@ -83,7 +83,7 @@ public final class CompilationUnitCache implements DocumentContentProvider { private final ReentrantReadWriteLock environmentCacheLock = new ReentrantReadWriteLock(true); private CompletableFuture debounceClassFileChanges = CompletableFuture.completedFuture(null); - private final Executor createCuExecutorThreadPool = Executors.newCachedThreadPool(); + private final Executor createCuExecutorThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public CompilationUnitCache(JavaProjectFinder projectFinder, SimpleLanguageServer server, ProjectObserver projectObserver) { this.projectFinder = projectFinder; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/modulith/ModulithService.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/modulith/ModulithService.java index 8865db400c..60e407e04c 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/modulith/ModulithService.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/modulith/ModulithService.java @@ -111,7 +111,7 @@ public ModulithService( this.springIndexer = springIndexer; this.springIndex = springIndex; this.reconciler = reconciler; - this.executor = Executors.newCachedThreadPool(); + this.executor = Executors.newFixedThreadPool(4); this.autoTrackingProjects = false; this.projectListener = new ProjectObserver.Listener() {