From f599e00d0a176058e40d40a176e7fc5468c7d2b8 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Thu, 20 Aug 2026 12:53:51 +0200 Subject: [PATCH] Avoid a second tree lookup in Workspace.getResourceInfo getResourceInfo walked the element tree twice for every read access: once through ElementTree.includes and again through ElementTree.getElementData. The single-slot lookupCache that is meant to make the second walk free compares keys by identity and is shared by all threads, so under concurrent access (builders, indexers) it gets replaced between the two calls and the second walk runs for real. Add the internal ElementTree.getElementDataOrNull, which does one lookup and returns null when the element is absent, and use it for the non-mutable path. This removes one full tree walk plus one monitor acquisition from the hottest resource access path. Behavior is unchanged: a missing element and an element with null data both already resulted in null. --- .../core/internal/resources/Workspace.java | 10 +++++----- .../core/internal/watson/ElementTree.java | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java index 690cb8fe72e..16d458a404e 100644 --- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java +++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Workspace.java @@ -1870,14 +1870,14 @@ public ResourceInfo getResourceInfo(IPath path, boolean phantom, boolean mutable Assert.isNotNull(info, "Tree root info must never be null"); //$NON-NLS-1$ return info; } - ResourceInfo result = null; - if (!tree.includes(path)) { - return null; - } + ResourceInfo result; if (mutable) { + if (!tree.includes(path)) { + return null; + } result = (ResourceInfo) tree.openElementData(path); } else { - result = (ResourceInfo) tree.getElementData(path); + result = (ResourceInfo) tree.getElementDataOrNull(path); } if (result != null && (!phantom && result.isSet(M_PHANTOM))) { return null; diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/watson/ElementTree.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/watson/ElementTree.java index a0820ade654..a7b59d26c85 100644 --- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/watson/ElementTree.java +++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/watson/ElementTree.java @@ -384,6 +384,26 @@ public DeltaDataTree getDataTree() { return tree; } + /** + * Returns the element data for the given element identifier, or + * null if the element is not present in this tree. + *

+ * Unlike {@link #includes(IPath)} followed by {@link #getElementData(IPath)} + * this performs at most one tree lookup. + */ + public Object getElementDataOrNull(IPath key) { + if (key.isRoot()) { + return null; + } + synchronized (this) { + DataTreeLookup lookup = lookupCache; // Grab it in case it's replaced concurrently. + if (lookup == null || lookup.key != key) { + lookupCache = lookup = tree.lookup(key); + } + return lookup.isPresent ? lookup.data : null; + } + } + /** * Returns the element data for the given element identifier. * The given element must be present in this tree.