From 463c805fc2fdca3b4a77101ca3166eaf6c1369f4 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 22 Mar 2021 13:33:22 +0100 Subject: [PATCH] make FileTypeAssocTable thread-safe to avoid crashes accessing them from background GitOrigin-RevId: a26c1fc6570229197fbcccc2b60f40e7fa1947ec --- .../fileTypes/impl/FileTypeAssocTable.java | 30 ++++++++++--------- .../util/containers/HashingStrategy.java | 18 +++++++++++ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/jps/model-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeAssocTable.java b/jps/model-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeAssocTable.java index 82a941a400da..c01d09766fdd 100644 --- a/jps/model-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeAssocTable.java +++ b/jps/model-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeAssocTable.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public final class FileTypeAssocTable { @@ -29,15 +30,11 @@ public final class FileTypeAssocTable { @NotNull Map exactFileNameAnyCaseMappings, @NotNull Map hashBangMap, @NotNull List> matchingMappings) { - myExtensionMappings = CollectionFactory.createCharSequenceMap(false, Math.max(10, extensionMappings.size()), 0.5f); - myExtensionMappings.putAll(extensionMappings); - myExactFileNameMappings = CollectionFactory.createCharSequenceMap(true, Math.max(10, exactFileNameMappings.size()), 0.5f); - myExactFileNameMappings.putAll(exactFileNameMappings); - myExactFileNameAnyCaseMappings = CollectionFactory.createCharSequenceMap(false, Math.max(10, exactFileNameAnyCaseMappings.size()), 0.5f); - myExactFileNameAnyCaseMappings.putAll(exactFileNameAnyCaseMappings); - myHashBangMap = CollectionFactory.createSmallMemoryFootprintMap(Math.max(10, hashBangMap.size()), 0.5f); - myHashBangMap.putAll(hashBangMap); - myMatchingMappings = new ArrayList<>(matchingMappings); + myExtensionMappings = createCharSequenceConcurrentMap(extensionMappings); + myExactFileNameMappings = new ConcurrentHashMap<>(exactFileNameMappings); + myExactFileNameAnyCaseMappings = createCharSequenceConcurrentMap(exactFileNameAnyCaseMappings); + myHashBangMap = new ConcurrentHashMap<>(hashBangMap); + myMatchingMappings = Collections.synchronizedList(new ArrayList<>(matchingMappings)); } public FileTypeAssocTable() { @@ -75,11 +72,9 @@ public final class FileTypeAssocTable { myMatchingMappings.add(Pair.create(matcher, type)); return null; } - else { - Pair old = myMatchingMappings.get(i); - myMatchingMappings.set(i, Pair.create(matcher, type)); - return Pair.getSecond(old); - } + Pair old = myMatchingMappings.get(i); + myMatchingMappings.set(i, Pair.create(matcher, type)); + return Pair.getSecond(old); } void addHashBangPattern(@NotNull String hashBang, @NotNull T type) { @@ -289,4 +284,11 @@ public final class FileTypeAssocTable { Map getInternalRawHashBangPatterns() { return CollectionFactory.createSmallMemoryFootprintMap(myHashBangMap); } + + private static @NotNull Map createCharSequenceConcurrentMap(@NotNull Map source) { + // todo convert to ConcurrentCollectionFactory when it's available in the classpath + Map map = CollectionFactory.createCharSequenceMap(false, source.size(), 0.5f); + map.putAll(source); + return Collections.synchronizedMap(map); + } } diff --git a/platform/util/src/com/intellij/util/containers/HashingStrategy.java b/platform/util/src/com/intellij/util/containers/HashingStrategy.java index 2b878794ac64..0b7372696548 100644 --- a/platform/util/src/com/intellij/util/containers/HashingStrategy.java +++ b/platform/util/src/com/intellij/util/containers/HashingStrategy.java @@ -1,6 +1,7 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.util.containers; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.Strings; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -26,8 +27,25 @@ public interface HashingStrategy { static @NotNull HashingStrategy caseInsensitive() { return CaseInsensitiveStringHashingStrategy.INSTANCE; } + static @NotNull HashingStrategy caseInsensitiveCharSequence() { + return CaseInsensitiveCharSequenceHashingStrategy.INSTANCE; + } } +class CaseInsensitiveCharSequenceHashingStrategy implements HashingStrategy { + static final CaseInsensitiveCharSequenceHashingStrategy INSTANCE = new CaseInsensitiveCharSequenceHashingStrategy(); + + @Override + public int hashCode(CharSequence object) { + return Strings.stringHashCodeInsensitive(object); + } + + @Override + public boolean equals(CharSequence s1, CharSequence s2) { + return StringUtil.equalsIgnoreCase(s1, s2); + } +}; + final class CanonicalHashingStrategy implements HashingStrategy { static final HashingStrategy INSTANCE = new CanonicalHashingStrategy<>();