Skip to content

Commit 1cec1fc

Browse files
committed
Implement a thread safe solution for computeIfAbsent
1 parent 7d47221 commit 1cec1fc

File tree

1 file changed

+51
-27
lines changed

1 file changed

+51
-27
lines changed

build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/language/settings/providers/AbstractLanguageSettingsOutputScanner.java

+51-27
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
import java.net.URISyntaxException;
2020
import java.util.ArrayList;
2121
import java.util.Arrays;
22-
import java.util.Collections;
2322
import java.util.HashMap;
2423
import java.util.HashSet;
2524
import java.util.LinkedHashSet;
2625
import java.util.List;
2726
import java.util.Map;
2827
import java.util.Set;
28+
import java.util.concurrent.locks.ReentrantReadWriteLock;
29+
import java.util.function.Function;
2930
import java.util.regex.Matcher;
3031
import java.util.regex.Pattern;
3132

@@ -95,12 +96,16 @@ public abstract class AbstractLanguageSettingsOutputScanner extends LanguageSett
9596

9697
private static final int FIND_RESOURCES_CACHE_SIZE = 100;
9798

98-
private Map<URI, IResource[]> workspaceRootFindContainersForLocationURICache = Collections
99-
.synchronizedMap(new LRUCache<>(FIND_RESOURCES_CACHE_SIZE));
100-
private Map<URI, IResource[]> workspaceRootFindFilesForLocationURICache = Collections
101-
.synchronizedMap(new LRUCache<>(FIND_RESOURCES_CACHE_SIZE));
102-
private Map<IProject, LRUCache<IPath, List<IResource>>> findPathInProjectCache = Collections
103-
.synchronizedMap(new HashMap<>());
99+
private LRUCache<URI, IResource[]> workspaceRootFindContainersForLocationURICache = new LRUCache<>(
100+
FIND_RESOURCES_CACHE_SIZE);
101+
private LRUCache<URI, IResource[]> workspaceRootFindFilesForLocationURICache = new LRUCache<>(
102+
FIND_RESOURCES_CACHE_SIZE);
103+
private HashMap<IProject, LRUCache<IPath, List<IResource>>> findPathInProjectCache = new HashMap<>();
104+
105+
private final ReentrantReadWriteLock findContainersForLocationURICacheLock = new ReentrantReadWriteLock();
106+
private final ReentrantReadWriteLock findFilesForLocationURICacheLock = new ReentrantReadWriteLock();
107+
private final ReentrantReadWriteLock findPathInProjectCacheLock = new ReentrantReadWriteLock();
108+
private final ReentrantReadWriteLock findPathInFoldertCacheLock = new ReentrantReadWriteLock();
104109

105110
//String pathStr, URI baseURI -> URI
106111
private static class MappedURIKey {
@@ -146,14 +151,14 @@ public boolean equals(Object obj) {
146151
}
147152

148153
// Caches the result of determineMappedURI
149-
private Map<MappedURIKey, URI> mappedURICache = Collections
150-
.synchronizedMap(new LRUCache<>(FIND_RESOURCES_CACHE_SIZE));
154+
private LRUCache<MappedURIKey, URI> mappedURICache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE);
151155
// Caches the result of getFilesystemLocation
152-
private Map<URI, IPath> fileSystemLocationCache = Collections
153-
.synchronizedMap(new LRUCache<>(FIND_RESOURCES_CACHE_SIZE));
156+
private LRUCache<URI, IPath> fileSystemLocationCache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE);
154157
// Caches the result of new File(pathname).exists()
155-
private Map<IPath, Boolean> pathExistsCache = Collections
156-
.synchronizedMap(new LRUCache<>(FIND_RESOURCES_CACHE_SIZE));
158+
private LRUCache<IPath, Boolean> pathExistsCache = new LRUCache<>(FIND_RESOURCES_CACHE_SIZE);
159+
private final ReentrantReadWriteLock mappedURICacheLock = new ReentrantReadWriteLock();
160+
private final ReentrantReadWriteLock fileSystemLocationCacheLock = new ReentrantReadWriteLock();
161+
private final ReentrantReadWriteLock pathExistsCacheLock = new ReentrantReadWriteLock();
157162

158163
/** @since 8.2 */
159164
protected EFSExtensionProvider efsProvider = null;
@@ -797,8 +802,9 @@ private IResource findFileForLocationURI(URI uri, IProject preferredProject, boo
797802
}
798803
IResource sourceFile = null;
799804

800-
IResource[] resources = workspaceRootFindFilesForLocationURICache.computeIfAbsent(uri,
801-
key -> ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(key));
805+
IResource[] resources = threadSafeComputeIfAbsent(uri, workspaceRootFindFilesForLocationURICache,
806+
key -> ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(key),
807+
findFilesForLocationURICacheLock);
802808
for (IResource rc : resources) {
803809
if (!checkExistence || rc.isAccessible()) {
804810
if (rc.getProject().equals(preferredProject)) {
@@ -820,8 +826,9 @@ private IResource findFileForLocationURI(URI uri, IProject preferredProject, boo
820826
private IResource findContainerForLocationURI(URI uri, IProject preferredProject, boolean checkExistence) {
821827
IResource resource = null;
822828

823-
IResource[] resources = workspaceRootFindContainersForLocationURICache.computeIfAbsent(uri,
824-
key -> ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(key));
829+
IResource[] resources = threadSafeComputeIfAbsent(uri, workspaceRootFindContainersForLocationURICache,
830+
(key) -> ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(key),
831+
findContainersForLocationURICacheLock);
825832
for (IResource rc : resources) {
826833
if ((rc instanceof IProject || rc instanceof IFolder) && (!checkExistence || rc.isAccessible())) { // treat IWorkspaceRoot as non-workspace path
827834
if (rc.getProject().equals(preferredProject)) {
@@ -1016,7 +1023,7 @@ private static URI resolvePathFromBaseLocation(String pathStr0, IPath baseLocati
10161023
* @return {@link URI} of the resource
10171024
*/
10181025
private URI determineMappedURI(String pathStr, URI baseURI) {
1019-
return mappedURICache.computeIfAbsent(new MappedURIKey(baseURI, pathStr), key -> {
1026+
return threadSafeComputeIfAbsent(new MappedURIKey(baseURI, pathStr), mappedURICache, key -> {
10201027
URI uri = null;
10211028

10221029
if (baseURI == null) {
@@ -1045,16 +1052,16 @@ private URI determineMappedURI(String pathStr, URI baseURI) {
10451052
uri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr);
10461053
}
10471054
return uri;
1048-
});
1055+
}, mappedURICacheLock);
10491056
}
10501057

10511058
/**
10521059
* Find all resources in the project which might be represented by relative path passed.
10531060
*/
10541061
private List<IResource> findPathInProject(IPath path, IProject project) {
1055-
LRUCache<IPath, List<IResource>> cache = findPathInProjectCache.computeIfAbsent(project,
1056-
key -> new LRUCache<>(FIND_RESOURCES_CACHE_SIZE));
1057-
return cache.computeIfAbsent(path, key -> findPathInFolder(path, project));
1062+
LRUCache<IPath, List<IResource>> cache = threadSafeComputeIfAbsent(project, findPathInProjectCache,
1063+
key -> new LRUCache<IPath, List<IResource>>(FIND_RESOURCES_CACHE_SIZE), findPathInProjectCacheLock);
1064+
return threadSafeComputeIfAbsent(path, cache, key -> findPathInFolder(path, project), findPathInFoldertCacheLock);
10581065
}
10591066

10601067
/**
@@ -1162,8 +1169,7 @@ private IResource findBestFitInWorkspace(String parsedName) {
11621169
private IPath getFilesystemLocation(URI uri) {
11631170
if (uri == null)
11641171
return null;
1165-
1166-
return fileSystemLocationCache.computeIfAbsent(uri, (k) -> {
1172+
return threadSafeComputeIfAbsent(uri, fileSystemLocationCache, (k) -> {
11671173
String pathStr = efsProvider.getMappedPath(uri);
11681174
URI resUri = org.eclipse.core.filesystem.URIUtil.toURI(pathStr);
11691175

@@ -1180,7 +1186,7 @@ private IPath getFilesystemLocation(URI uri) {
11801186
}
11811187
}
11821188
return null;
1183-
});
1189+
}, fileSystemLocationCacheLock);
11841190
}
11851191

11861192
/**
@@ -1261,9 +1267,9 @@ private ICLanguageSettingEntry resolvePathEntryInFilesystem(AbstractOptionParser
12611267
IPath location = getFilesystemLocation(uri);
12621268
if (location != null) {
12631269
String loc = location.toString();
1264-
boolean exists = pathExistsCache.computeIfAbsent(location, (s) -> {
1270+
boolean exists = threadSafeComputeIfAbsent(location, pathExistsCache, (s) -> {
12651271
return new File(loc).exists();
1266-
});
1272+
}, pathExistsCacheLock);
12671273
if (exists) {
12681274
return optionParser.createEntry(loc, loc, flag);
12691275
}
@@ -1420,4 +1426,22 @@ public boolean equals(Object obj) {
14201426
return true;
14211427
}
14221428

1429+
private static <K, V> V threadSafeComputeIfAbsent(K key, HashMap<K, V> cacheMap,
1430+
Function<? super K, ? extends V> mappingFunction, ReentrantReadWriteLock rwLock) {
1431+
rwLock.readLock().lock();
1432+
V value = cacheMap.get(key);
1433+
rwLock.readLock().unlock();
1434+
if (value != null) {
1435+
return value;
1436+
}
1437+
1438+
rwLock.writeLock().lock();
1439+
value = cacheMap.get(key);
1440+
if (value == null) {
1441+
value = cacheMap.computeIfAbsent(key, mappingFunction);
1442+
}
1443+
rwLock.writeLock().unlock();
1444+
1445+
return value;
1446+
}
14231447
}

0 commit comments

Comments
 (0)