Skip to content

Commit

Permalink
perf: Improve performance of Quarkus deployment jar support
Browse files Browse the repository at this point in the history
Fixes #1143

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Oct 13, 2023
1 parent 7d107b0 commit 3e9071c
Show file tree
Hide file tree
Showing 12 changed files with 481 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,10 @@ public interface Listener {

private final Project project;

private final List<RunnableProgress> preprocessors;

public ClasspathResourceChangedManager(Project project) {
this.project = project;
this.preprocessors = new ArrayList<>();
// Send source files changed in debounce mode
this.resourceChangedNotifier = new ClasspathResourceChangedNotifier(project, preprocessors);
this.resourceChangedNotifier = new ClasspathResourceChangedNotifier(project);
listener = new ClasspathResourceChangedListener(this);
projectConnection = project.getMessageBus().connect();
// Track end of Java libraries update
Expand Down Expand Up @@ -105,13 +102,4 @@ Project getProject() {
ClasspathResourceChangedNotifier getResourceChangedNotifier() {
return resourceChangedNotifier;
}

/**
* Add a preprocessor to update classpatch when a library changed before sending the {@link Listener#librariesChanged()} event.
*
* @param preprocessor the preprocessor to add.
*/
public void addPreprocessor(RunnableProgress preprocessor) {
preprocessors.add(preprocessor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
package com.redhat.devtools.intellij.lsp4mp4ij.classpath;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
Expand All @@ -27,10 +25,10 @@
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.HashSet;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

/**
* Source file change notifier with a debounce mode.
Expand All @@ -46,12 +44,10 @@ public class ClasspathResourceChangedNotifier implements Disposable {

private final Set<Pair<VirtualFile, Module>> sourceFiles;
private boolean librariesChanged;
private final List<RunnableProgress> processBeforeLibrariesChanged;
private boolean disposed;

public ClasspathResourceChangedNotifier(Project project, List<RunnableProgress> preprocessors) {
public ClasspathResourceChangedNotifier(Project project) {
this.project = project;
this.processBeforeLibrariesChanged = preprocessors;
sourceFiles = new HashSet<>();
}

Expand Down Expand Up @@ -107,11 +103,7 @@ private void notifyChanges() {
}
if (librariesChanged) {
// Java Libraries has changed
if (processBeforeLibrariesChanged.isEmpty() || ApplicationManager.getApplication().isUnitTestMode()) {
// No preprocessor or Test context, send directly the librariesChanged event.
for (var runnable : processBeforeLibrariesChanged) {
runnable.run(new EmptyProgressIndicator());
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
// Send the libraries changed event
project.getMessageBus().syncPublisher(ClasspathResourceChangedManager.TOPIC).librariesChanged();
librariesChanged = false;
Expand All @@ -125,9 +117,6 @@ public void run(@NotNull ProgressIndicator progressIndicator) {
// Execute preprocessor
progressIndicator.setIndeterminate(false);
progressIndicator.checkCanceled();
for (var runnable : processBeforeLibrariesChanged) {
runnable.run(progressIndicator);
}
} finally {
// Send the libraries changed event
project.getMessageBus().syncPublisher(ClasspathResourceChangedManager.TOPIC).librariesChanged();
Expand All @@ -152,7 +141,7 @@ public void dispose() {
this.disposed = true;
if (debounceTask != null) {
debounceTask.cancel();
debounceTask =null;
debounceTask = null;
}
if (debounceTimer != null) {
debounceTimer.cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
Expand All @@ -65,7 +66,7 @@ public static boolean isQuarkusExtensionWithDeploymentArtifact(Library library)
if (library != null) {
VirtualFile[] files = library.getFiles(OrderRootType.CLASSES);

for(int i=0; !result && i < files.length;++i) {
for (int i = 0; !result && i < files.length; ++i) {
if (files[i].isDirectory()) {
result = ToolDelegate.getDeploymentJarId(VfsUtilCore.virtualToIoFile(files[i])) != null;
}
Expand All @@ -77,7 +78,7 @@ public static boolean isQuarkusExtensionWithDeploymentArtifact(Library library)
/**
* Check if the Quarkus library needs to be recomputed and update it if required.
*
* @param module the module to check
* @param module the module to check
* @param progressIndicator
*/
public static void ensureQuarkusLibrary(Module module, ProgressIndicator progressIndicator) {
Expand All @@ -95,20 +96,28 @@ public static void ensureQuarkusLibrary(Module module, ProgressIndicator progres
Integer actualHash = computeHash(module);
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())){
!QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_VERSION.equals(component.getVersion())) {
ModuleRootModificationUtil.updateModel(module, model -> {
LibraryTable table = model.getModuleLibraryTable();
Library library = table.getLibraryByName(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME);
while (library != null) {
table.removeLibrary(library);
TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "removeLibrary");
try {
TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "removeLibrary");
} catch (Exception e) {

}
library = table.getLibraryByName(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME);
}
progressIndicator.checkCanceled();
progressIndicator.setText("Collecting Quarkus deployment dependencies...");
progressIndicator.setText("Adding in ''" + module.getName() + "'' Quarkus deployment dependencies to classpath...");
List<VirtualFile>[] files = toolDelegate.getDeploymentFiles(module, progressIndicator);
LOGGER.info("Adding library to " + module.getName() + " previousHash=" + previousHash + " newHash=" + actualHash);
TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "addLibrary").send();
try {
TelemetryService.instance().action(TelemetryService.MODEL_PREFIX + "addLibrary").send();
} catch (Exception e) {

}
addLibrary(model, files, module);
});
component.setHash(actualHash);
Expand All @@ -120,7 +129,7 @@ public static void ensureQuarkusLibrary(Module module, ProgressIndicator progres
}

private static void addLibrary(ModifiableRootModel model, List<VirtualFile>[] files, Module module) {
LibraryEx library = (LibraryEx)model.getModuleLibraryTable().createLibrary(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME);
LibraryEx library = (LibraryEx) model.getModuleLibraryTable().createLibrary(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME);
LibraryEx.ModifiableModelEx libraryModel = library.getModifiableModel();

for (VirtualFile rootFile : files[ToolDelegate.BINARY]) {
Expand All @@ -145,14 +154,14 @@ private static Integer computeHash(Module module) {
@Override
public Set<String> visitLibraryOrderEntry(@NotNull LibraryOrderEntry libraryOrderEntry, Set<String> value) {
if (!isQuarkusDeploymentLibrary(libraryOrderEntry) && isQuarkusExtensionWithDeploymentArtifact(libraryOrderEntry.getLibrary())) {
for(VirtualFile file : libraryOrderEntry.getFiles(OrderRootType.CLASSES)) {
for (VirtualFile file : libraryOrderEntry.getFiles(OrderRootType.CLASSES)) {
value.add(file.getPath());
}
}
return value;
}
}, new HashSet<>());
return files.isEmpty()?null:files.hashCode();
return files.isEmpty() ? null : files.hashCode();
}

/**
Expand All @@ -174,7 +183,7 @@ public Boolean visitLibraryOrderEntry(@NotNull LibraryOrderEntry libraryOrderEnt
}

public static boolean isQuarkusLibrary(@NotNull LibraryOrderEntry libraryOrderEntry) {
return libraryOrderEntry.getLibraryName() != null &&
return libraryOrderEntry.getLibraryName() != null &&
libraryOrderEntry.getLibraryName().contains(QuarkusConstants.QUARKUS_CORE_PREFIX);
}

Expand Down Expand Up @@ -204,9 +213,9 @@ public static boolean checkQuarkusVersion(Module module, Predicate<Matcher> pred
.findFirst();
if (quarkusCoreJar.isPresent()) {
Matcher quarkusCoreArtifactMatcher = QUARKUS_CORE_PATTERN.matcher(quarkusCoreJar.get().getName());
if(quarkusCoreArtifactMatcher.matches()) {
if (quarkusCoreArtifactMatcher.matches()) {
String quarkusVersion = quarkusCoreArtifactMatcher.group(1);
LOGGER.debug("Detected Quarkus version = " + quarkusVersion);
LOGGER.debug("Detected Quarkus version = " + quarkusVersion);
Matcher quarkusVersionMatcher = QUARKUS_STANDARD_VERSIONING.matcher(quarkusVersion);
return predicate.test(quarkusVersionMatcher);
} else {
Expand All @@ -219,7 +228,7 @@ public static boolean checkQuarkusVersion(Module module, Predicate<Matcher> pred

public static Set<String> getModulesURIs(Project project) {
Set<String> uris = new HashSet<>();
for(Module module : ModuleManager.getInstance(project).getModules()) {
for (Module module : ModuleManager.getInstance(project).getModules()) {
uris.add(PsiUtilsLSImpl.getProjectURI(module));
}
return uris;
Expand Down
Loading

0 comments on commit 3e9071c

Please sign in to comment.