Skip to content

Commit

Permalink
fix: Quarkus Tools significantly increases startup time for Intellij (#…
Browse files Browse the repository at this point in the history
…739)

* fix: Quarkus Tools significantly increases startup time for Intellij

Fixes #733

Signed-off-by: Jeff MAURY <jmaury@redhat.com>
  • Loading branch information
jeffmaury authored Feb 22, 2023
1 parent 07cd66c commit 3d7a464
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 47 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ tasks.withType(Test) {
environment 'GRADLE_RELEASE_REPOSITORY','https://services.gradle.org/distributions'
systemProperty 'idea.log.leaked.projects.in.tests', 'false'
systemProperty 'idea.maven.test.mirror', 'https://repo1.maven.org/maven2'
systemProperty 'com.redhat.devtools.intellij.telemetry.mode', 'disabled'
}

tasks.withType(Copy) {
Expand Down Expand Up @@ -175,7 +176,7 @@ task copyDeps(type: Copy) {
}

runIde {
systemProperties['com.redhat.devtools.intellij.telemetry.mode'] = 'debug'
systemProperties['com.redhat.devtools.intellij.telemetry.mode'] = 'disabled'
systemProperties['com.redhat.devtools.intellij.quarkus.trace'] = 'true'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.intellij.openapi.roots.OrderEnumerator;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.RootPolicy;
import com.intellij.openapi.roots.impl.OrderEntryUtil;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
Expand Down Expand Up @@ -84,7 +85,8 @@ public static void ensureQuarkusLibrary(Module module) {
QuarkusModuleComponent component = module.getComponent(QuarkusModuleComponent.class);
Integer previousHash = component.getHash();
Integer actualHash = computeHash(module);
if ((actualHash != null && !actualHash.equals(previousHash)) ||
var qlib = OrderEntryUtil.findLibraryOrderEntry(ModuleRootManager.getInstance(module), QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME);
if (qlib == null || (actualHash != null && !actualHash.equals(previousHash)) ||
!QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_VERSION.equals(component.getVersion())){
ModuleRootModificationUtil.updateModel(module, model -> {
LibraryTable table = model.getModuleLibraryTable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
public class QuarkusPostStartupActivity implements StartupActivity, DumbAware {
@Override
public void runActivity(@NotNull Project project) {
for (Module module : ModuleManager.getInstance(project).getModules()) {
QuarkusModuleUtil.ensureQuarkusLibrary(module);
}
QuarkusProjectService.getInstance(project);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,19 @@
******************************************************************************/
package com.redhat.devtools.intellij.quarkus;

import com.intellij.ProjectTopics;
import com.intellij.json.JsonFileType;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.ModuleListener;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.impl.libraries.LibraryEx;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
Expand All @@ -30,6 +35,7 @@
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.messages.Topic;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.PropertiesManager;
Expand All @@ -46,19 +52,35 @@
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class QuarkusProjectService implements LibraryTable.Listener, BulkFileListener {
public class QuarkusProjectService implements LibraryTable.Listener, BulkFileListener, ModuleListener, Disposable {
private static final Logger LOGGER = LoggerFactory.getLogger(QuarkusProjectService.class);

private final Project project;

private final Map<Module, MutablePair<VirtualFile, Boolean>> schemas = new ConcurrentHashMap<>();

private final ExecutorService executor;

private Set<Module> modulesBeingEnsured = new HashSet<>();

@Override
public void dispose() {
executor.shutdown();
}

public interface Listener {
void libraryUpdated(Library library);
void sourceUpdated(List<Pair<Module, VirtualFile>> sources);
Expand All @@ -74,16 +96,67 @@ public static QuarkusProjectService getInstance(Project project) {

public QuarkusProjectService(Project project) {
this.project = project;
if (ApplicationManager.getApplication().isUnitTestMode()) {
this.executor = ConcurrencyUtil.newSameThreadExecutorService();
} else {
this.executor = new ThreadPoolExecutor(0, 1,
1L, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(),
r -> new Thread(r, "Quarkus lib pool " + project.getName()));
}
LibraryTablesRegistrar.getInstance().getLibraryTable(project).addListener(this, project);
connection = ApplicationManager.getApplication().getMessageBus().connect(project);
connection.subscribe(VirtualFileManager.VFS_CHANGES, this);
project.getMessageBus().connect().subscribe(ProjectTopics.MODULES, this);
processModules();
}

private CompletableFuture<Void> checkQuarkusLibrary(Module module, boolean sync) {
if (modulesBeingEnsured.add(module)) {
if (sync) {
QuarkusModuleUtil.ensureQuarkusLibrary(module);
modulesBeingEnsured.remove(module);
return CompletableFuture.completedFuture(null);
} else {
return CompletableFuture.runAsync(() -> {
QuarkusModuleUtil.ensureQuarkusLibrary(module);
modulesBeingEnsured.remove(module);
}, executor);
}
}
return CompletableFuture.completedFuture(null);
}

public CompletableFuture<Void> processModules() {
return CompletableFuture.runAsync(() -> {
for (var module : ModuleManager.getInstance(project).getModules()) {
LOGGER.info("Calling ensure from processModules");
checkQuarkusLibrary(module, true);
}
}, executor);
}

private CompletableFuture<Void> processModule(Module module) {
return checkQuarkusLibrary(module, false);
}

private void handleLibraryUpdate(Library library) {
project.getMessageBus().syncPublisher(TOPIC).libraryUpdated(library);
schemas.forEach((module, pair) -> {
pair.setRight(Boolean.FALSE);
LOGGER.info("handleLibraryUpdate called " + library.getName());
if (library instanceof LibraryEx && ((LibraryEx) library).getModule() != null) {
var module = ((LibraryEx) library).getModule();
processModule(module).thenRun(() -> {
var pair = schemas.get(module);
if (pair != null) {
pair.setRight(Boolean.FALSE);
}
});
} else {
processModules().thenRun(() -> {
project.getMessageBus().syncPublisher(TOPIC).libraryUpdated(library);
schemas.forEach((module, pair) -> {
pair.setRight(Boolean.FALSE);
});
});
}
}

@Override
Expand Down Expand Up @@ -165,4 +238,19 @@ private VirtualFile computeSchema(Module module, VirtualFile schemaFile) {
}
return null;
}

private void moduleChanged(Module module) {
LOGGER.info("Calling ensure from moduleChanged for module " + module.getName());
checkQuarkusLibrary(module, false);
}

@Override
public void moduleAdded(@NotNull Project project, @NotNull Module module) {
moduleChanged(module);
}

@Override
public void moduleRemoved(@NotNull Project project, @NotNull Module module) {
moduleChanged(module);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,5 @@ public void preProcess(Module module, MavenProject mavenProject, MavenProjectCha

@Override
public void process(IdeModifiableModelsProvider modifiableModelsProvider, Module module, MavenRootModelAdapter rootModel, MavenProjectsTree mavenModel, MavenProject mavenProject, MavenProjectChanges changes, Map<MavenProject, String> mavenProjectToModuleName, List<MavenProjectsProcessorTask> postTasks) {
postTasks.add(new QuarkusMavenProjectsProcessTask(module));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import com.intellij.openapi.components.State;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleComponent;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -52,7 +51,6 @@ public QuarkusModuleComponent(Module module) {

@Override
public void moduleAdded() {
QuarkusModuleUtil.ensureQuarkusLibrary(module);
}

@Nullable
Expand Down Expand Up @@ -82,7 +80,7 @@ public void setHash(Integer hash) {
}

public Integer getVersion() {
return state != null ? state.getHash() : null;
return state != null ? state.getVersion() : null;
}

public void setVersion(Integer version) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.redhat.devtools.intellij.quarkus.QuarkusProjectService;
import com.redhat.devtools.intellij.quarkus.gradle.AbstractGradleToolDelegate;
import org.gradle.tooling.GradleConnector;
import org.gradle.tooling.ProjectConnection;
Expand Down Expand Up @@ -74,6 +75,7 @@ protected void importProject() {
for(Module m : ModuleManager.getInstance(myProject).getModules()) {
setupJdkForModule(m.getName());
}
QuarkusProjectService.getInstance(myProject).processModules();
}

@Parameterized.Parameters(name = "{index}: with Gradle-{0}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.core.ls.PsiUtilsLSImpl;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;
import com.redhat.devtools.intellij.quarkus.QuarkusProjectService;
import org.apache.commons.io.FileUtils;
import org.jetbrains.idea.maven.MavenImportingTestCase;

Expand Down Expand Up @@ -81,8 +82,8 @@ protected List<Module> createMavenModules(List<File> projectDirs) throws Excepti
Module[] modules = ModuleManager.getInstance(myTestFixture.getProject()).getModules();
for(Module module : modules) {
setupJdkForModule(module.getName());
QuarkusModuleUtil.ensureQuarkusLibrary(module);
}
QuarkusProjectService.getInstance(myTestFixture.getProject()).processModules();
return Arrays.asList(modules).stream().skip(1).collect(Collectors.toList());
}
protected Module createMavenModule(File projectDir) throws Exception {
Expand Down

0 comments on commit 3d7a464

Please sign in to comment.