diff --git a/platform/platform-api/src/com/intellij/lang/Language.java b/platform/platform-api/src/com/intellij/lang/Language.java index 5a88fc98aee0..2e14d4956875 100644 --- a/platform/platform-api/src/com/intellij/lang/Language.java +++ b/platform/platform-api/src/com/intellij/lang/Language.java @@ -19,8 +19,10 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ConcurrentHashMap; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -29,6 +31,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.concurrent.ConcurrentMap; /** * The base class for all programming language support implementations. Specific language implementations should inherit from this class @@ -72,6 +75,10 @@ public abstract class Language extends UserDataHolderBase { } } + protected ConcurrentMap createDataMap() { + return new ConcurrentHashMap(); + } + /** * @return collection of all languages registered so far. */ diff --git a/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java b/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java index 775c76af7c9f..a2e36feb613a 100644 --- a/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java +++ b/platform/util/src/com/intellij/openapi/util/UserDataHolderBase.java @@ -6,13 +6,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; +import java.util.concurrent.ConcurrentMap; public class UserDataHolderBase implements UserDataHolderEx, Cloneable { private static final Object MAP_LOCK = new Object(); private static final Object COPYABLE_MAP_LOCK = new Object(); private static final Key> COPYABLE_USER_MAP_KEY = Key.create("COPYABLE_USER_MAP_KEY"); - private volatile LockPoolSynchronizedMap myUserMap = null; + private volatile ConcurrentMap myUserMap = null; protected Object clone() { try { @@ -28,7 +29,7 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable { } public String getUserDataString() { - final Map userMap = myUserMap; + final ConcurrentMap userMap = myUserMap; if (userMap == null) { return ""; } @@ -46,7 +47,7 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable { other.myUserMap = null; } else { - LockPoolSynchronizedMap fresh = createMap(); + ConcurrentMap fresh = createDataMap(); fresh.putAll(myUserMap); other.myUserMap = fresh; } @@ -58,7 +59,7 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable { } public void putUserData(Key key, T value) { - LockPoolSynchronizedMap map = getOrCreateMap(); + Map map = getOrCreateMap(); if (value == null) { map.remove(key); @@ -68,7 +69,7 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable { } } - private static LockPoolSynchronizedMap createMap() { + protected ConcurrentMap createDataMap() { return new LockPoolSynchronizedMap(2, 0.9f); } @@ -107,11 +108,11 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable { } - private LockPoolSynchronizedMap getOrCreateMap() { + private ConcurrentMap getOrCreateMap() { if (myUserMap == null) { synchronized (MAP_LOCK) { if (myUserMap == null) { - myUserMap = createMap(); + myUserMap = createDataMap(); } } } diff --git a/platform/util/src/com/intellij/util/containers/LockPoolSynchronizedMap.java b/platform/util/src/com/intellij/util/containers/LockPoolSynchronizedMap.java index 85102c95a31c..a0d1f1094a52 100644 --- a/platform/util/src/com/intellij/util/containers/LockPoolSynchronizedMap.java +++ b/platform/util/src/com/intellij/util/containers/LockPoolSynchronizedMap.java @@ -28,8 +28,9 @@ import gnu.trove.THashMap; import java.util.Collection; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentMap; -public class LockPoolSynchronizedMap extends THashMap { +public class LockPoolSynchronizedMap extends THashMap implements ConcurrentMap { private static final int NUM_LOCKS = 256; private static final JBReentrantReadWriteLock[] ourLocks = new JBReentrantReadWriteLock[NUM_LOCKS]; private static int ourLockAllocationCounter = 0; @@ -211,6 +212,24 @@ public class LockPoolSynchronizedMap extends THashMap { } } + public V replace(K key, V newValue) { + w.lock(); + try { + V prev = get(key); + + if (newValue == null) { + remove(key); + } + else { + put(key, newValue); + } + return prev; + } + finally { + w.unlock(); + } + } + public V putIfAbsent(K key, V value) { w.lock(); try { @@ -228,4 +247,17 @@ public class LockPoolSynchronizedMap extends THashMap { } } + public boolean remove(Object key, Object oldValue) { + w.lock(); + try { + if (!Comparing.equal(oldValue, get(key))) { + return false; + } + return super.remove(key) != null; + } + finally { + w.unlock(); + } + } + }