From 71a2974d101afed283adbcc6d5a9b449ff8b2b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Kubitz?= Date: Mon, 4 Mar 2024 16:09:25 +0100 Subject: [PATCH 1/2] version bumps --- .../bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF | 2 +- ua/org.eclipse.help.base/META-INF/MANIFEST.MF | 2 +- ua/org.eclipse.help.base/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF index 606b38f567a..cff283ec254 100644 --- a/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF +++ b/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.core.resources; singleton:=true -Bundle-Version: 3.20.100.qualifier +Bundle-Version: 3.20.200.qualifier Bundle-Activator: org.eclipse.core.resources.ResourcesPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/ua/org.eclipse.help.base/META-INF/MANIFEST.MF b/ua/org.eclipse.help.base/META-INF/MANIFEST.MF index 935e52c066f..dd0d5344ea6 100644 --- a/ua/org.eclipse.help.base/META-INF/MANIFEST.MF +++ b/ua/org.eclipse.help.base/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %help_base_plugin_name Bundle-SymbolicName: org.eclipse.help.base; singleton:=true -Bundle-Version: 4.4.300.qualifier +Bundle-Version: 4.4.400.qualifier Bundle-Activator: org.eclipse.help.internal.base.HelpBasePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/ua/org.eclipse.help.base/pom.xml b/ua/org.eclipse.help.base/pom.xml index 8ede6519c01..26472ca4baa 100644 --- a/ua/org.eclipse.help.base/pom.xml +++ b/ua/org.eclipse.help.base/pom.xml @@ -18,7 +18,7 @@ org.eclipse.help org.eclipse.help.base - 4.4.300-SNAPSHOT + 4.4.400-SNAPSHOT eclipse-plugin true From 35c416961826c52a243bb00da351feabd8249cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Kubitz?= Date: Thu, 29 Feb 2024 18:49:53 +0100 Subject: [PATCH 2/2] ResourcesPlugin: Multithreaded lazy start Reads all projects in parallel. As this was done during ResourcePlugin.start() it had to be deferred as multithreaded classloading during BundleActivator#start(BundleContext) is not supported. All that happens while splash screen still shown. --- .../core/internal/resources/SaveManager.java | 102 +++++++++++------- .../core/resources/ResourcesPlugin.java | 37 +++++-- 2 files changed, 91 insertions(+), 48 deletions(-) diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java index d6d0535c5b6..810a679484c 100644 --- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java +++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/SaveManager.java @@ -49,6 +49,7 @@ import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinWorkerThread; import java.util.stream.Collectors; @@ -888,15 +889,64 @@ protected void restoreMarkers(IResource resource, boolean generateDeltas, IProgr } return; } - IProject[] projects = ((IWorkspaceRoot) resource).getProjects(IContainer.INCLUDE_HIDDEN); - for (IProject project : projects) - if (project.isAccessible()) - markerManager.restore(project, generateDeltas, monitor); + forEachProjectInParallel(monitor, project -> { + if (project.isAccessible()) { + markerManager.restore(project, generateDeltas, null); + } + }); if (Policy.DEBUG_RESTORE_MARKERS) { Policy.debug("Restore Markers for workspace: " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ } } + @FunctionalInterface + public interface CoreConsumer { + /** + * Performs this operation on the given argument. + * + * @param t the input argument + */ + void accept(T t) throws CoreException; + } + + private void forEachProjectInParallel(IProgressMonitor m, CoreConsumer consumer) throws CoreException { + IProject[] projects = workspace.getRoot().getProjects(IContainer.INCLUDE_HIDDEN); + if (projects.length == 0) { + return; + } + SubMonitor subMointor = SubMonitor.convert(m, projects.length); + IStatus[] stats; + // Never use a shared ForkJoinPool.commonPool() as it may be busy with other tasks, which might deadlock. + // Also use a custom ForkJoinWorkerThreadFactory, to prevent issues with a + // potential SecurityManager, since the threads created by it get no permissions. + // See https://github.com/eclipse-platform/eclipse.platform/issues/294 + ExecutorService executor = new ForkJoinPool(ForkJoinPool.getCommonPoolParallelism(), + pool -> new ForkJoinWorkerThread(pool) { + // anonymous subclass to access protected constructor + }, null, false); + try { + stats = executor.submit(() -> Arrays.stream(projects).parallel().map(project -> { + subMointor.split(1); + try { + consumer.accept(project); + } catch (CoreException e) { + return new ResourceStatus(IResourceStatus.FAILED_READ_METADATA, project.getFullPath(), + "Error with project " + project.getName(), e); //$NON-NLS-1$ + } + return null; + }).filter(Objects::nonNull).toArray(IStatus[]::new)).get(); + } catch (InterruptedException | ExecutionException e) { + List notExecuted = executor.shutdownNow(); + throw new CoreException(Status.error("Error with " + notExecuted.size() + " projects left", e)); //$NON-NLS-1$//$NON-NLS-2$ + } finally { + executor.shutdown(); + } + if (stats.length > 0) { + throw new CoreException(new MultiStatus(ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, stats, + "Error with " + stats.length + " projects", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + protected void restoreMasterTable() throws CoreException { long start = System.currentTimeMillis(); masterTable.clear(); @@ -926,15 +976,14 @@ protected void restoreMetaInfo(MultiStatus problems, IProgressMonitor monitor) { if (Policy.DEBUG_RESTORE_METAINFO) Policy.debug("Restore workspace metainfo: starting..."); //$NON-NLS-1$ long start = System.currentTimeMillis(); - IProject[] roots = workspace.getRoot().getProjects(IContainer.INCLUDE_HIDDEN); - for (IProject root : roots) { - //fatal to throw exceptions during startup - try { + try { + forEachProjectInParallel(monitor, root -> { restoreMetaInfo((Project) root, monitor); - } catch (CoreException e) { - String message = NLS.bind(Messages.resources_readMeta, root.getName()); - problems.merge(new ResourceStatus(IResourceStatus.FAILED_READ_METADATA, root.getFullPath(), message, e)); - } + }); + } catch (CoreException e) { + // fatal to throw exceptions during startup + problems.merge(new ResourceStatus(IResourceStatus.FAILED_READ_METADATA, workspace.getRoot().getFullPath(), + "Could not read metadata", e)); //$NON-NLS-1$ } if (Policy.DEBUG_RESTORE_METAINFO) Policy.debug("Restore workspace metainfo: " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -1778,34 +1827,7 @@ public void visitAndSave(final IResource root) throws CoreException { // recurse over the projects in the workspace if we were given the workspace root if (root.getType() == IResource.PROJECT) return; - IProject[] projects = ((IWorkspaceRoot) root).getProjects(IContainer.INCLUDE_HIDDEN); - // Never use a shared ForkJoinPool.commonPool() as it may be busy with other tasks, which might deadlock. - // Also use a custom ForkJoinWorkerThreadFactory, to prevent issues with a - // potential SecurityManager, since the threads created by it get no permissions. - // See https://github.com/eclipse-platform/eclipse.platform/issues/294 - ForkJoinPool forkJoinPool = new ForkJoinPool(ForkJoinPool.getCommonPoolParallelism(), - pool -> new ForkJoinWorkerThread(pool) { - // anonymous subclass to access protected constructor - }, null, false); - IStatus[] stats; - try { - stats = forkJoinPool.submit(() -> Arrays.stream(projects).parallel().map(project -> { - try { - visitAndSave(project); - } catch (CoreException e) { - return e.getStatus(); - } - return null; - }).filter(Objects::nonNull).toArray(IStatus[]::new)).get(); - } catch (InterruptedException | ExecutionException e) { - throw new CoreException(Status.error(Messages.resources_saveProblem, e)); - } finally { - forkJoinPool.shutdown(); - } - if (stats.length > 0) { - throw new CoreException(new MultiStatus(ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, stats, - Messages.resources_saveProblem, null)); - } + forEachProjectInParallel(null, this::visitAndSave); } /** diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/ResourcesPlugin.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/ResourcesPlugin.java index 48a48f6b134..89a9f5b22ce 100644 --- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/ResourcesPlugin.java +++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/ResourcesPlugin.java @@ -27,13 +27,21 @@ import org.eclipse.core.internal.resources.Workspace; import org.eclipse.core.internal.utils.Messages; import org.eclipse.core.internal.utils.Policy; -import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.osgi.service.datalocation.Location; import org.eclipse.osgi.service.debug.DebugOptions; import org.eclipse.osgi.service.debug.DebugOptionsListener; -import org.osgi.framework.*; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; @@ -419,7 +427,7 @@ public final class ResourcesPlugin extends Plugin { * @see #getSystemEncoding() */ public static String getEncoding() { - ResourcesPlugin resourcesPlugin = plugin; + ResourcesPlugin resourcesPlugin = getPlugin(); if (resourcesPlugin == null) { return getSystemEncoding(); } @@ -475,7 +483,21 @@ private static String getSystemEncoding() { * @return the single instance of this plug-in runtime class */ public static ResourcesPlugin getPlugin() { - return plugin; + if (plugin == null) { + return null; + } + return plugin.initialized(); + } + + private ResourcesPlugin initialized() { + ServiceTracker t = instanceLocationTracker; + if (t != null && t.size() == 0) { + synchronized (t) { + // lazy initialize + t.open(); + } + } + return this; } /** @@ -491,10 +513,8 @@ public static ResourcesPlugin getPlugin() { * class. */ public static IWorkspace getWorkspace() { - ResourcesPlugin resourcesPlugin = plugin; + ResourcesPlugin resourcesPlugin = getPlugin(); if (resourcesPlugin == null) { - // this happens when the resource plugin is shut down already... or never - // started! throw new IllegalStateException(Messages.resources_workspaceClosedStatic); } Workspace workspace = resourcesPlugin.workspaceInitCustomizer.workspace; @@ -520,6 +540,7 @@ public void stop(BundleContext context) throws Exception { // save the preferences for this plug-in getPlugin().savePluginPreferences(); plugin = null; + instanceLocationTracker = null; } /** @@ -542,7 +563,7 @@ public void start(BundleContext context) throws Exception { workspaceInitCustomizer); plugin = this; // must before open the tracker, as this can cause the registration of the // workspace and this might trigger code that calls the static method then. - instanceLocationTracker.open(); + new Thread(this::initialized, "Async ResourcesPlugin start").start(); //$NON-NLS-1$ } private final class WorkspaceInitCustomizer implements ServiceTrackerCustomizer {