mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-321510 [Gradle|Sync] fix: convert and transfer the Gradle build environment once per model fetch action
Extracted GradleExecutorServiceUtil GitOrigin-RevId: 1654459bbba7d4edcb4401c6e572f3a35ede2f39
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c8af8fea88
commit
97b95edbec
+24
-35
@@ -2,7 +2,7 @@
|
||||
package com.intellij.gradle.toolingExtension.impl.modelAction;
|
||||
|
||||
import com.intellij.gradle.toolingExtension.impl.modelSerialization.ModelConverter;
|
||||
import io.opentelemetry.context.Context;
|
||||
import com.intellij.gradle.toolingExtension.impl.util.GradleExecutorServiceUtil;
|
||||
import org.gradle.tooling.BuildController;
|
||||
import org.gradle.tooling.internal.gradle.DefaultBuildIdentifier;
|
||||
import org.gradle.tooling.model.BuildIdentifier;
|
||||
@@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.model.DefaultBuild;
|
||||
import org.jetbrains.plugins.gradle.model.DefaultBuildController;
|
||||
import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider.GradleModelConsumer;
|
||||
import org.jetbrains.plugins.gradle.tooling.serialization.internal.adapter.InternalBuildEnvironment;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
@@ -56,6 +57,7 @@ public class GradleDaemonModelHolder {
|
||||
private final @NotNull BlockingQueue<Future<DefaultBuild>> myConvertedRootBuild = new LinkedBlockingQueue<>();
|
||||
private final @NotNull BlockingQueue<Future<Collection<DefaultBuild>>> myConvertedNestedBuilds = new LinkedBlockingQueue<>();
|
||||
private final @NotNull BlockingQueue<Future<ConvertedModel>> myConvertedModelQueue = new LinkedBlockingQueue<>();
|
||||
private final @NotNull BlockingQueue<Future<BuildEnvironment>> myConvertedBuildEnvironment = new LinkedBlockingQueue<>();
|
||||
|
||||
public GradleDaemonModelHolder(
|
||||
@NotNull ExecutorService converterExecutor,
|
||||
@@ -68,8 +70,15 @@ public class GradleDaemonModelHolder {
|
||||
myRootGradleBuild = rootGradleBuild;
|
||||
myNestedGradleBuilds = nestedGradleBuilds;
|
||||
myBuildEnvironment = buildEnvironment;
|
||||
submitTask(converterExecutor, myConvertedRootBuild, () -> DefaultBuild.convertGradleBuild(rootGradleBuild));
|
||||
submitTask(converterExecutor, myConvertedNestedBuilds, () -> convertNestedGradleBuilds(nestedGradleBuilds));
|
||||
GradleExecutorServiceUtil.submitTask(converterExecutor, myConvertedRootBuild, () -> {
|
||||
return DefaultBuild.convertGradleBuild(rootGradleBuild);
|
||||
});
|
||||
GradleExecutorServiceUtil.submitTask(converterExecutor, myConvertedNestedBuilds, () -> {
|
||||
return convertNestedGradleBuilds(nestedGradleBuilds);
|
||||
});
|
||||
GradleExecutorServiceUtil.submitTask(converterExecutor, myConvertedBuildEnvironment, () -> {
|
||||
return InternalBuildEnvironment.convertBuildEnvironment(myBuildEnvironment);
|
||||
});
|
||||
}
|
||||
|
||||
public @NotNull Collection<? extends GradleBuild> getGradleBuilds() {
|
||||
@@ -96,7 +105,7 @@ public class GradleDaemonModelHolder {
|
||||
}
|
||||
|
||||
private void consumeModel(@NotNull Object model, @NotNull GradleModelId modelId) {
|
||||
submitTask(converterExecutor, myConvertedModelQueue, () -> {
|
||||
GradleExecutorServiceUtil.submitTask(converterExecutor, myConvertedModelQueue, () -> {
|
||||
Object convertedModel = myModelConverter.convert(model);
|
||||
return new ConvertedModel(modelId, convertedModel);
|
||||
});
|
||||
@@ -104,54 +113,34 @@ public class GradleDaemonModelHolder {
|
||||
};
|
||||
}
|
||||
|
||||
private static <T> void submitTask(
|
||||
@NotNull ExecutorService executor,
|
||||
@NotNull BlockingQueue<Future<T>> queue,
|
||||
@NotNull Callable<T> task
|
||||
) {
|
||||
Future<T> convertedModelFuture = Context.current()
|
||||
.wrap(executor)
|
||||
.submit(task);
|
||||
queue.add(convertedModelFuture);
|
||||
}
|
||||
|
||||
public @NotNull GradleModelHolderState pollPendingState() {
|
||||
DefaultBuild rootBuild = pollPendingConvertedRootBuild();
|
||||
Collection<DefaultBuild> nestedBuilds = pollPendingConvertedNestedBuilds();
|
||||
Map<GradleModelId, Object> models = pollAllPendingConvertedModels();
|
||||
return new GradleModelHolderState(rootBuild, nestedBuilds, myBuildEnvironment, models);
|
||||
BuildEnvironment buildEnvironment = pollPendingBuildEnvironment();
|
||||
return new GradleModelHolderState(rootBuild, nestedBuilds, buildEnvironment, models);
|
||||
}
|
||||
|
||||
private @Nullable DefaultBuild pollPendingConvertedRootBuild() {
|
||||
return poolPendingModel(myConvertedRootBuild);
|
||||
return GradleExecutorServiceUtil.poolPendingResult(myConvertedRootBuild);
|
||||
}
|
||||
|
||||
private @NotNull Collection<DefaultBuild> pollPendingConvertedNestedBuilds() {
|
||||
Collection<DefaultBuild> builds = poolPendingModel(myConvertedNestedBuilds);
|
||||
Collection<DefaultBuild> builds = GradleExecutorServiceUtil.poolPendingResult(myConvertedNestedBuilds);
|
||||
return builds == null ? Collections.emptyList() : builds;
|
||||
}
|
||||
|
||||
private @NotNull Map<GradleModelId, Object> pollAllPendingConvertedModels() {
|
||||
Map<GradleModelId, Object> models = new LinkedHashMap<>();
|
||||
ConvertedModel model = poolPendingModel(myConvertedModelQueue);
|
||||
while (model != null) {
|
||||
models.put(model.myId, model.myModel);
|
||||
model = poolPendingModel(myConvertedModelQueue);
|
||||
List<ConvertedModel> models = GradleExecutorServiceUtil.pollAllPendingResults(myConvertedModelQueue);
|
||||
Map<GradleModelId, Object> modelMap = new LinkedHashMap<>();
|
||||
for (ConvertedModel convertedModel : models) {
|
||||
modelMap.put(convertedModel.myId, convertedModel.myModel);
|
||||
}
|
||||
return models;
|
||||
return modelMap;
|
||||
}
|
||||
|
||||
private static <T> @Nullable T poolPendingModel(@NotNull BlockingQueue<Future<T>> modelQueue) {
|
||||
try {
|
||||
Future<T> future = modelQueue.poll();
|
||||
if (future == null) {
|
||||
return null;
|
||||
}
|
||||
return future.get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException ignored) {
|
||||
return null;
|
||||
}
|
||||
private @Nullable BuildEnvironment pollPendingBuildEnvironment() {
|
||||
return GradleExecutorServiceUtil.poolPendingResult(myConvertedBuildEnvironment);
|
||||
}
|
||||
|
||||
private static @NotNull Collection<DefaultBuild> convertNestedGradleBuilds(
|
||||
|
||||
+2
-29
@@ -3,6 +3,7 @@ package com.intellij.gradle.toolingExtension.impl.modelAction;
|
||||
|
||||
import com.intellij.gradle.toolingExtension.impl.telemetry.GradleOpenTelemetry;
|
||||
import com.intellij.gradle.toolingExtension.impl.telemetry.GradleTracingContext;
|
||||
import com.intellij.gradle.toolingExtension.impl.util.GradleExecutorServiceUtil;
|
||||
import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase;
|
||||
import com.intellij.gradle.toolingExtension.util.GradleVersionUtil;
|
||||
import com.intellij.openapi.externalSystem.model.ExternalSystemException;
|
||||
@@ -27,9 +28,6 @@ import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider.GradleModel
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -83,7 +81,7 @@ public class GradleModelFetchAction implements BuildAction<GradleModelHolderStat
|
||||
@Override
|
||||
public @NotNull GradleModelHolderState execute(@NotNull BuildController controller) {
|
||||
configureAdditionalTypes(controller);
|
||||
return withConverterExecutor(converterExecutor -> {
|
||||
return GradleExecutorServiceUtil.withSingleThreadExecutor("idea-tooling-model-converter", converterExecutor -> {
|
||||
return withOpenTelemetry(telemetry -> {
|
||||
return telemetry.callWithSpan("ProjectImportAction", __ -> {
|
||||
return doExecute(controller, converterExecutor, telemetry);
|
||||
@@ -92,22 +90,6 @@ public class GradleModelFetchAction implements BuildAction<GradleModelHolderStat
|
||||
});
|
||||
}
|
||||
|
||||
private static <T> T withConverterExecutor(@NotNull Function<ExecutorService, T> action) {
|
||||
ExecutorService converterExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory());
|
||||
try {
|
||||
return action.apply(converterExecutor);
|
||||
}
|
||||
finally {
|
||||
converterExecutor.shutdown();
|
||||
try {
|
||||
converterExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GradleModelHolderState withOpenTelemetry(@NotNull Function<GradleOpenTelemetry, GradleModelHolderState> action) {
|
||||
GradleTracingContext tracingContext = myTracingContext;
|
||||
if (tracingContext == null) {
|
||||
@@ -303,13 +285,4 @@ public class GradleModelFetchAction implements BuildAction<GradleModelHolderStat
|
||||
}
|
||||
return modelProviders.tailMap(GradleModelFetchPhase.PROJECT_LOADED_PHASE, false);
|
||||
}
|
||||
|
||||
// Use this static class as a simple ThreadFactory to prevent a memory leak when passing an anonymous ThreadFactory object to
|
||||
// Executors.newSingleThreadExecutor. Memory leak will occur on the Gradle Daemon otherwise.
|
||||
private static final class SimpleThreadFactory implements ThreadFactory {
|
||||
@Override
|
||||
public Thread newThread(@NotNull Runnable runnable) {
|
||||
return new Thread(runnable, "idea-tooling-model-converter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.gradle.toolingExtension.impl.util;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class GradleExecutorServiceUtil {
|
||||
|
||||
public static <T> T withSingleThreadExecutor(@NotNull String name, @NotNull Function<ExecutorService, T> action) {
|
||||
ExecutorService executorService = Executors.newSingleThreadExecutor(new SimpleThreadFactory(name));
|
||||
try {
|
||||
return action.apply(executorService);
|
||||
}
|
||||
finally {
|
||||
executorService.shutdown();
|
||||
try {
|
||||
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void submitTask(
|
||||
@NotNull ExecutorService executor,
|
||||
@NotNull BlockingQueue<Future<T>> queue,
|
||||
@NotNull Callable<T> task
|
||||
) {
|
||||
Future<T> taskResult = Context.current()
|
||||
.wrap(executor)
|
||||
.submit(task);
|
||||
queue.add(taskResult);
|
||||
}
|
||||
|
||||
public static <T> @NotNull List<T> pollAllPendingResults(@NotNull BlockingQueue<Future<T>> queue) {
|
||||
List<T> results = new ArrayList<>();
|
||||
T result = poolPendingResult(queue);
|
||||
while (result != null) {
|
||||
results.add(result);
|
||||
result = poolPendingResult(queue);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public static <T> @Nullable T poolPendingResult(@NotNull BlockingQueue<Future<T>> queue) {
|
||||
try {
|
||||
Future<T> future = queue.poll();
|
||||
if (future == null) {
|
||||
return null;
|
||||
}
|
||||
return future.get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Use this static class as a simple ThreadFactory to prevent a memory leak when passing an anonymous ThreadFactory object to
|
||||
// Executors.newSingleThreadExecutor. Memory leak will occur on the Gradle Daemon otherwise.
|
||||
private static final class SimpleThreadFactory implements ThreadFactory {
|
||||
|
||||
private final String myName;
|
||||
|
||||
private SimpleThreadFactory(@NotNull String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(@NotNull Runnable runnable) {
|
||||
return new Thread(runnable, myName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user