From b529a826e89ac7d2fdce45b42c5fe7223d4723df Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 6 Feb 2017 12:20:22 +0300 Subject: [PATCH] PY-21180 PyUtil#getParametrizedCachedValue uses ConcurrentHashMap in case multiple read-only threads update the same cache simultaneously --- python/src/com/jetbrains/python/psi/PyUtil.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 3e368553c1fa..dc656f0a5e66 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -846,19 +846,12 @@ public class PyUtil { }); } - private static final Object NULL_VALUE = new Object(); public static T getParameterizedCachedValue(@NotNull PsiElement element, @Nullable P param, @NotNull NullableFunction f) { - final Map cache = CachedValuesManager.getCachedValue(element, new CachedValueProvider>() { - @Nullable - @Override - public Result> compute() { - // TODO should be concurrent map instead - return Result.create(Maps.newHashMap(), PsiModificationTracker.MODIFICATION_COUNT); - } + final Map, Optional> cache = CachedValuesManager.getCachedValue(element, () -> { + // concurrent hash map is a null-hostile collection + return CachedValueProvider.Result.create(Maps.newConcurrentMap(), PsiModificationTracker.MODIFICATION_COUNT); }); - final Object wrapped = cache.computeIfAbsent(param, p -> ObjectUtils.notNull(f.fun(param), NULL_VALUE)); - //noinspection unchecked - return (T)ObjectUtils.nullizeByCondition(wrapped, NULL_VALUE::equals); + return cache.computeIfAbsent(Optional.ofNullable(param), p -> Optional.ofNullable(f.fun(param))).orElse(null); } /**