diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java index ac877d93ebb..fedd1586c86 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -100,6 +102,11 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett FIND_RESOURCES_CACHE_SIZE); private HashMap>> findPathInProjectCache = new HashMap<>(); + private final ReentrantReadWriteLock findContainersForLocationURICacheLock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock findFilesForLocationURICacheLock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock findPathInProjectCacheLock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock findPathInFoldertCacheLock = new ReentrantReadWriteLock(); + //String pathStr, URI baseURI -> URI private static class MappedURIKey { URI baseURI; @@ -149,6 +156,9 @@ public boolean equals(Object obj) { private LRUCache fileSystemLocationCache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE); // Caches the result of new File(pathname).exists() private LRUCache pathExistsCache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE); + private final ReentrantReadWriteLock mappedURICacheLock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock fileSystemLocationCacheLock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock pathExistsCacheLock = new ReentrantReadWriteLock(); /** @since 8.2 */ protected EFSExtensionProvider efsProvider = null; @@ -792,8 +802,9 @@ private IResource findFileForLocationURI(URI uri, IProject preferredProject, boo } IResource sourceFile = null; - IResource[] resources = workspaceRootFindFilesForLocationURICache.computeIfAbsent(uri, - key -> ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(key)); + IResource[] resources = threadSafeComputeIfAbsent(uri, workspaceRootFindFilesForLocationURICache, + key -> ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(key), + findFilesForLocationURICacheLock); for (IResource rc : resources) { if (!checkExistence || rc.isAccessible()) { if (rc.getProject().equals(preferredProject)) { @@ -815,8 +826,9 @@ private IResource findFileForLocationURI(URI uri, IProject preferredProject, boo private IResource findContainerForLocationURI(URI uri, IProject preferredProject, boolean checkExistence) { IResource resource = null; - IResource[] resources = workspaceRootFindContainersForLocationURICache.computeIfAbsent(uri, - key -> ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(key)); + IResource[] resources = threadSafeComputeIfAbsent(uri, workspaceRootFindContainersForLocationURICache, + (key) -> ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(key), + findContainersForLocationURICacheLock); for (IResource rc : resources) { if ((rc instanceof IProject || rc instanceof IFolder) && (!checkExistence || rc.isAccessible())) { // treat IWorkspaceRoot as non-workspace path if (rc.getProject().equals(preferredProject)) { @@ -1011,7 +1023,7 @@ private static URI resolvePathFromBaseLocation(String pathStr0, IPath baseLocati * @return {@link URI} of the resource */ private URI determineMappedURI(String pathStr, URI baseURI) { - return mappedURICache.computeIfAbsent(new MappedURIKey(baseURI, pathStr), key -> { + return threadSafeComputeIfAbsent(new MappedURIKey(baseURI, pathStr), mappedURICache, key -> { URI uri = null; if (baseURI == null) { @@ -1040,16 +1052,17 @@ private URI determineMappedURI(String pathStr, URI baseURI) { uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr); } return uri; - }); + }, mappedURICacheLock); } /** * Find all resources in the project which might be represented by relative path passed. */ private List findPathInProject(IPath path, IProject project) { - LRUCache> cache = findPathInProjectCache.computeIfAbsent(project, - key -> new LRUCache<>(FIND_RESOURCES_CACHE_SIZE)); - return cache.computeIfAbsent(path, key -> findPathInFolder(path, project)); + LRUCache> cache = threadSafeComputeIfAbsent(project, findPathInProjectCache, + key -> new LRUCache>(FIND_RESOURCES_CACHE_SIZE), findPathInProjectCacheLock); + return threadSafeComputeIfAbsent(path, cache, key -> findPathInFolder(path, project), + findPathInFoldertCacheLock); } /** @@ -1157,8 +1170,7 @@ private IResource findBestFitInWorkspace(String parsedName) { private IPath getFilesystemLocation(URI uri) { if (uri == null) return null; - - return fileSystemLocationCache.computeIfAbsent(uri, (k) -> { + return threadSafeComputeIfAbsent(uri, fileSystemLocationCache, (k) -> { String pathStr = efsProvider.getMappedPath(uri); URI resUri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr); @@ -1175,7 +1187,7 @@ private IPath getFilesystemLocation(URI uri) { } } return null; - }); + }, fileSystemLocationCacheLock); } /** @@ -1256,9 +1268,9 @@ private ICLanguageSettingEntry resolvePathEntryInFilesystem(AbstractOptionParser IPath location = getFilesystemLocation(uri); if (location != null) { String loc = location.toString(); - boolean exists = pathExistsCache.computeIfAbsent(location, (s) -> { + boolean exists = threadSafeComputeIfAbsent(location, pathExistsCache, (s) -> { return new File(loc).exists(); - }); + }, pathExistsCacheLock); if (exists) { return optionParser.createEntry(loc, loc, flag); } @@ -1415,4 +1427,22 @@ public boolean equals(Object obj) { return true; } + private static V threadSafeComputeIfAbsent(K key, HashMap cacheMap, + Function mappingFunction, ReentrantReadWriteLock rwLock) { + rwLock.readLock().lock(); + V value = cacheMap.get(key); + rwLock.readLock().unlock(); + if (value != null) { + return value; + } + + rwLock.writeLock().lock(); + value = cacheMap.get(key); + if (value == null) { + value = cacheMap.computeIfAbsent(key, mappingFunction); + } + rwLock.writeLock().unlock(); + + return value; + } }