Skip to content

Never resolve the target platform from PDELabelProvider - #2417

Draft
vogella wants to merge 1 commit into
eclipse-pde:masterfrom
vogella:label-provider-no-target-resolution
Draft

Never resolve the target platform from PDELabelProvider#2417
vogella wants to merge 1 commit into
eclipse-pde:masterfrom
vogella:label-provider-no-target-resolution

Conversation

@vogella

@vogella vogella commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Opening the Dependencies page of a manifest editor could freeze the UI thread for over a minute.
RequiresSection.initialize() sets the viewer input, and every row asks PDELabelProvider for a decoration, which calls PluginReference.isResolved() and ends up resolving the entire target platform.
With an m2e Maven location that means a full MavenExecutionContext plus a bnd wrap of every transitive artifact, all on main, which holds both the PluginModelManager entry table monitor and the MavenTargetLocation monitor while doing it, so background jobs queue up behind the frozen editor.

The label provider now checks the existing PluginModelManager.isInitialized() before any registry lookup.
While the models are unknown it returns the plain, undecorated label and schedules initialization through the new PluginModelManager.initializeInBackground(Runnable); when that finishes it fires a LabelProviderChangedEvent, so every viewer sharing the provider repaints with the resolved state and unresolved imports get their error overlay as before.
The editor opens immediately instead of blocking, and the same guard covers the ten other paths through PDELabelProvider that could reach the entry table, not just the one in the trace below.

"main" #1 prio=6 elapsed=75.24s runnable
   java.lang.Thread.State: RUNNABLE
	at java.util.zip.ZipFile.<init>(java.base@21/ZipFile.java:254)
	at aQute.bnd.osgi.Jar.buildFromZip(Jar.java:304)
	at aQute.bnd.osgi.Jar.<init>(Jar.java:142)
	at org.eclipse.m2e.pde.target.shared.MavenBundleWrapper.getCachedJar(MavenBundleWrapper.java:303)
	at org.eclipse.m2e.pde.target.shared.MavenBundleWrapper.getWrappedNode(MavenBundleWrapper.java:227)
	at org.eclipse.m2e.pde.target.shared.MavenBundleWrapper.getWrappedNode(MavenBundleWrapper.java:214)
	at org.eclipse.m2e.pde.target.shared.MavenBundleWrapper.getWrappedNode(MavenBundleWrapper.java:214)
	at org.eclipse.m2e.pde.target.shared.MavenBundleWrapper.getWrappedArtifact(MavenBundleWrapper.java:157)
	at org.eclipse.m2e.pde.target.MavenTargetBundle.lambda$2(MavenTargetBundle.java:158)
	at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:462)
	at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:342)
	at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:281)
	at org.eclipse.m2e.pde.target.MavenTargetBundle.getWrappedArtifact(MavenTargetBundle.java:154)
	at org.eclipse.m2e.pde.target.MavenTargetBundle.generateOrOverrideManifest(MavenTargetBundle.java:133)
	at org.eclipse.m2e.pde.target.MavenTargetBundle.<init>(MavenTargetBundle.java:114)
	at org.eclipse.m2e.pde.target.MavenTargetLocation.addBundleForArtifact(MavenTargetLocation.java:394)
	at org.eclipse.m2e.pde.target.MavenTargetLocation.resolveDependency(MavenTargetLocation.java:281)
	at org.eclipse.m2e.pde.target.MavenTargetLocation.resolveArtifacts(MavenTargetLocation.java:182)
	- locked <a org.eclipse.m2e.pde.target.MavenTargetLocation>
	at org.eclipse.m2e.pde.target.MavenTargetLocation.resolveBundles(MavenTargetLocation.java:169)
	at org.eclipse.pde.internal.core.target.AbstractBundleContainer.resolve(AbstractBundleContainer.java:96)
	at org.eclipse.pde.internal.core.target.TargetDefinition.resolve(TargetDefinition.java:379)
	at org.eclipse.pde.internal.core.TargetPlatformHelper.getWorkspaceTargetResolved(TargetPlatformHelper.java:558)
	at org.eclipse.pde.internal.core.PluginModelManager.getExternalBundles(PluginModelManager.java:563)
	at org.eclipse.pde.internal.core.PluginModelManager.initializeTable(PluginModelManager.java:486)
	at org.eclipse.pde.internal.core.PluginModelManager.getEntryTable(PluginModelManager.java:436)
	at org.eclipse.pde.internal.core.PluginModelManager.findEntry(PluginModelManager.java:911)
	- locked <fEntriesSynchronizer>
	at org.eclipse.pde.core.plugin.PluginRegistry.findEntry(PluginRegistry.java:95)
	at org.eclipse.pde.core.plugin.PluginRegistry.selectModels(PluginRegistry.java:443)
	at org.eclipse.pde.core.plugin.PluginRegistry.findModels(PluginRegistry.java:427)
	at org.eclipse.pde.core.plugin.PluginRegistry.findModel(PluginRegistry.java:387)
	at org.eclipse.pde.internal.core.plugin.ImportObject.findModel(ImportObject.java:92)
	at org.eclipse.pde.internal.core.plugin.PluginReference.getPlugin(PluginReference.java:45)
	at org.eclipse.pde.internal.core.plugin.PluginReference.isResolved(PluginReference.java:64)
	at org.eclipse.pde.internal.ui.PDELabelProvider.getObjectImage(PDELabelProvider.java:647)
	at org.eclipse.pde.internal.ui.PDELabelProvider.getImage(PDELabelProvider.java:454)
	at org.eclipse.pde.internal.ui.util.SharedLabelProvider.getColumnImage(SharedLabelProvider.java:227)
	at org.eclipse.jface.viewers.TableColumnViewerLabelProvider.update(TableColumnViewerLabelProvider.java:72)
	at org.eclipse.jface.viewers.ViewerColumn.refresh(ViewerColumn.java:149)
	at org.eclipse.jface.viewers.AbstractTableViewer.doUpdateItem(AbstractTableViewer.java:393)
	at org.eclipse.jface.viewers.StructuredViewer.updateItem(StructuredViewer.java:2112)
	at org.eclipse.jface.viewers.AbstractTableViewer.createItem(AbstractTableViewer.java:285)
	at org.eclipse.jface.viewers.AbstractTableViewer.internalRefreshAll(AbstractTableViewer.java:732)
	at org.eclipse.jface.viewers.AbstractTableViewer.internalRefresh(AbstractTableViewer.java:622)
	at org.eclipse.jface.viewers.AbstractTableViewer.inputChanged(AbstractTableViewer.java:567)
	at org.eclipse.jface.viewers.ContentViewer.setInput(ContentViewer.java:279)
	at org.eclipse.jface.viewers.StructuredViewer.setInput(StructuredViewer.java:1640)
	at org.eclipse.pde.internal.ui.editor.plugin.RequiresSection.initialize(RequiresSection.java:550)
	at org.eclipse.pde.internal.ui.editor.plugin.RequiresSection.createClient(RequiresSection.java:161)

Manual check: fresh workspace, a target with an m2e Maven location using dependencyDepth="infinite" and a cold ~/.m2. The manifest editor opens right away with undecorated icons, and the decorations fill in once resolution finishes in the background.

Opening the Dependencies page of a manifest editor could block the UI
thread for over a minute. The call chain is:

  RequiresSection.initialize()
    TableViewer.setInput()
      PDELabelProvider.getImage(ImportObject)
        ImportObject.isResolved() / getPlugin()
          PluginRegistry.findModel(id, range)
            PluginModelManager.findEntry()
              getEntryTable()
                initializeTable()
                  getExternalBundles()
                    TargetPlatformHelper.getWorkspaceTargetResolved()

The last step resolves the whole target platform. With an m2e Maven
location it runs a full MavenExecutionContext and bnd-wraps every
transitive artifact, while the UI thread holds both the entry table
monitor and the Maven location monitor, so every background job that
needs a model queues up behind it.

getEntryTable() is reached from findEntry, findModel, getActiveModels,
getAllModels, getState, getSystemBundleId and isEmpty, so the label
provider had several ways in, not just the one in the stack:

  getObjectImage(ImportObject)     isResolved(), getPlugin()
  getObjectImage(PackageObject)    ImportPackageObject.isResolved()
  getObjectImage(IProductPlugin)   TargetPlatformHelper.getState()
  getObjectImage(IFeatureImport)   FeatureImport.getPlugin()
  getObjectImage(IFeaturePlugin)   FeaturePlugin.getPluginBase()
  getObjectText(IPluginBase)       getSystemBundleInfo()
  getObjectText(ImportObject)      getSystemBundleInfo()
  getObjectText(IPluginImport)     findModel(), full name mode only
  getObjectText(BundleDescription) findModel(), full name mode only
  getObjectText(FeaturePlugin)     getLabel(), full name mode only
  getObjectText(ISiteBundle)       findModel()

All of them are now guarded by arePluginModelsAvailable(), which builds
on the existing PluginModelManager.isInitialized() fast path. While the
models are unknown the plain, undecorated label is returned and
initialization is scheduled through the new
PluginModelManager.initializeInBackground(Runnable). Once it completes
the label provider fires a LabelProviderChangedEvent, so every viewer
sharing it repaints with the resolved state. Unresolved imports still
get the error overlay as soon as the models are there.

getSystemBundleInfo() also stopped assuming that system.bundle resolves;
it returned the plug-in base of a possibly null model.

initializeInBackground() is new but PluginModelManager lives in
org.eclipse.pde.internal.core, so this is not published API. Firing a
PluginModelDelta after initialization was rejected on purpose: it would
make PDERegistryStrategy create the extension registry, FeatureRebuilder
touch all feature projects and PluginsView add every entry one by one.
@github-actions

Copy link
Copy Markdown

Test Results

  129 files  ±0    129 suites  ±0   39m 25s ⏱️ + 3m 7s
3 536 tests +2  3 482 ✅ +2   54 💤 ±0  0 ❌ ±0 
9 411 runs  +6  9 281 ✅ +6  130 💤 ±0  0 ❌ ±0 

Results for commit 3679685. ± Comparison against base commit 4454bcd.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant