make FileTypeAssocTable thread-safe to avoid crashes accessing them from background

GitOrigin-RevId: a26c1fc6570229197fbcccc2b60f40e7fa1947ec
This commit is contained in:
Alexey Kudravtsev
2021-03-22 13:01:49 +00:00
committed by intellij-monorepo-bot
parent 32c292c8e9
commit 463c805fc2
2 changed files with 34 additions and 14 deletions
@@ -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<T> {
@@ -29,15 +30,11 @@ public final class FileTypeAssocTable<T> {
@NotNull Map<? extends CharSequence, ? extends T> exactFileNameAnyCaseMappings,
@NotNull Map<String, ? extends T> hashBangMap,
@NotNull List<? extends Pair<FileNameMatcher, T>> 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<T> {
myMatchingMappings.add(Pair.create(matcher, type));
return null;
}
else {
Pair<FileNameMatcher, T> old = myMatchingMappings.get(i);
myMatchingMappings.set(i, Pair.create(matcher, type));
return Pair.getSecond(old);
}
Pair<FileNameMatcher, T> 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<T> {
Map<String, T> getInternalRawHashBangPatterns() {
return CollectionFactory.createSmallMemoryFootprintMap(myHashBangMap);
}
private static @NotNull <T> Map<CharSequence, T> createCharSequenceConcurrentMap(@NotNull Map<? extends CharSequence, ? extends T> source) {
// todo convert to ConcurrentCollectionFactory when it's available in the classpath
Map<CharSequence, T> map = CollectionFactory.createCharSequenceMap(false, source.size(), 0.5f);
map.putAll(source);
return Collections.synchronizedMap(map);
}
}
@@ -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<T> {
static @NotNull HashingStrategy<String> caseInsensitive() {
return CaseInsensitiveStringHashingStrategy.INSTANCE;
}
static @NotNull HashingStrategy<CharSequence> caseInsensitiveCharSequence() {
return CaseInsensitiveCharSequenceHashingStrategy.INSTANCE;
}
}
class CaseInsensitiveCharSequenceHashingStrategy implements HashingStrategy<CharSequence> {
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<T> implements HashingStrategy<T> {
static final HashingStrategy<?> INSTANCE = new CanonicalHashingStrategy<>();