Use StripedLockConcurrentHashMap instead of LockPoolSynchronizedMap in UserDataHolder

This commit is contained in:
Alexey Kudravtsev
2010-08-09 14:44:18 +04:00
parent d47d570bb0
commit a84b5f1407
9 changed files with 1341 additions and 40 deletions
@@ -47,9 +47,6 @@ class ConstantExpressionVisitor extends JavaElementVisitor implements PsiConstan
myResult = null;
element.accept(this);
store(element, myResult);
//for (PsiElement child : element.getChildren()) {
// store(child, null); //erase garbage
//}
return myResult;
}
private static final Key<Object> VALUE = Key.create("VALUE");
@@ -21,18 +21,19 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.util.containers.LockPoolSynchronizedMap;
import com.intellij.util.containers.StripedLockConcurrentHashMap;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* @author nik
*/
public class OrderRootsCache {
private final LockPoolSynchronizedMap<CacheKey, VirtualFilePointerContainer> myRoots = new LockPoolSynchronizedMap<CacheKey, VirtualFilePointerContainer>();
private final Map<CacheKey, VirtualFilePointerContainer> myRoots = new StripedLockConcurrentHashMap<CacheKey, VirtualFilePointerContainer>();
private final Disposable myParentDisposable;
public OrderRootsCache(Disposable parentDisposable) {
@@ -19,10 +19,8 @@ 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;
@@ -31,7 +29,6 @@ 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
@@ -75,10 +72,6 @@ public abstract class Language extends UserDataHolderBase {
}
}
protected ConcurrentMap<Key, Object> createDataMap() {
return new ConcurrentHashMap<Key, Object>();
}
/**
* @return collection of all languages registered so far.
*/
@@ -16,7 +16,7 @@
package com.intellij.openapi.util;
import com.intellij.util.containers.LockPoolSynchronizedMap;
import com.intellij.util.containers.StripedLockConcurrentHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
@@ -60,12 +60,13 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
}
public void copyUserDataTo(UserDataHolderBase other) {
if (myUserMap == null) {
ConcurrentMap<Key, Object> map = myUserMap;
if (map == null) {
other.myUserMap = null;
}
else {
ConcurrentMap<Key, Object> fresh = createDataMap();
fresh.putAll(myUserMap);
ConcurrentMap<Key, Object> fresh = createDataMap(2);
fresh.putAll(map);
other.myUserMap = fresh;
}
}
@@ -86,8 +87,8 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
}
}
protected ConcurrentMap<Key, Object> createDataMap() {
return new LockPoolSynchronizedMap<Key, Object>(2, 0.9f);
protected ConcurrentMap<Key, Object> createDataMap(int initialCapacity) {
return new StripedLockConcurrentHashMap<Key, Object>(initialCapacity);
}
public <T> T getCopyableUserData(Key<T> key) {
@@ -108,7 +109,7 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
Map<Key, Object> copyMap = getUserData(COPYABLE_USER_MAP_KEY);
if (copyMap == null) {
if (value == null) return;
copyMap = new LockPoolSynchronizedMap<Key, Object>(1, 0.9f);
copyMap = createDataMap(1);
putUserData(COPYABLE_USER_MAP_KEY, copyMap);
}
@@ -130,7 +131,7 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
synchronized (MAP_LOCK) {
map = myUserMap;
if (map == null) {
myUserMap = map = createDataMap();
myUserMap = map = createDataMap(2);
}
}
}
@@ -138,18 +139,28 @@ public class UserDataHolderBase implements UserDataHolderEx, Cloneable {
}
public <T> boolean replace(@NotNull Key<T> key, @Nullable T oldValue, @Nullable T newValue) {
return getOrCreateMap().replace(key, oldValue, newValue);
ConcurrentMap<Key, Object> map = getOrCreateMap();
if (oldValue == null) {
return newValue == null || map.putIfAbsent(key, newValue) == null;
}
if (newValue == null) {
return map.remove(key, oldValue);
}
return map.replace(key, oldValue, newValue);
}
@NotNull
public <T> T putUserDataIfAbsent(@NotNull final Key<T> key, @NotNull final T value) {
return (T)getOrCreateMap().putIfAbsent(key, value);
T prev = (T)getOrCreateMap().putIfAbsent(key, value);
return prev == null ? value : prev;
}
public void copyCopyableDataTo(UserDataHolderBase clone) {
Map<Key, Object> copyableMap = getUserData(COPYABLE_USER_MAP_KEY);
if (copyableMap != null) {
copyableMap = ((LockPoolSynchronizedMap)copyableMap).clone();
ConcurrentMap<Key, Object> copy = createDataMap(copyableMap.size());
copy.putAll(copyableMap);
copyableMap = copy;
}
clone.putUserData(COPYABLE_USER_MAP_KEY, copyableMap);
}
@@ -22,7 +22,6 @@ package com.intellij.util.containers;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.concurrency.JBLock;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import gnu.trove.THashMap;
import java.util.Collection;
@@ -31,21 +30,11 @@ import java.util.Set;
import java.util.concurrent.ConcurrentMap;
public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements ConcurrentMap<K, V> {
private static final int NUM_LOCKS = 256;
private static final JBReentrantReadWriteLock[] ourLocks = new JBReentrantReadWriteLock[NUM_LOCKS];
private static int ourLockAllocationCounter = 0;
private final JBLock r;
private final JBLock w;
static {
for (int i = 0; i < ourLocks.length; i++) {
ourLocks[i] = LockFactory.createReadWriteLock();
}
}
{
final JBReentrantReadWriteLock mutex = allocateLock();
final JBReentrantReadWriteLock mutex = StripedJBReentrantReadWriteLocks.getInstance().allocateLock();
r = mutex.readLock();
w = mutex.writeLock();
}
@@ -60,11 +49,6 @@ public class LockPoolSynchronizedMap<K, V> extends THashMap<K, V> implements Con
super(initialCapacity, loadFactor);
}
private static JBReentrantReadWriteLock allocateLock() {
ourLockAllocationCounter = (ourLockAllocationCounter + 1) % NUM_LOCKS;
return ourLocks[ourLockAllocationCounter];
}
public int size() {
r.lock();
try {
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.containers;
import com.intellij.util.concurrency.JBReentrantReadWriteLock;
import com.intellij.util.concurrency.LockFactory;
import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
public final class StripedJBReentrantReadWriteLocks extends StripedLockHolder<JBReentrantReadWriteLock> {
@NotNull
@Override
protected JBReentrantReadWriteLock create() {
return LockFactory.createReadWriteLock();
}
private static final StripedJBReentrantReadWriteLocks INSTANCE = new StripedJBReentrantReadWriteLocks();
public static StripedJBReentrantReadWriteLocks getInstance() {
return INSTANCE;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.containers;
import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
public abstract class StripedLockHolder<T> {
private static final int NUM_LOCKS = 256;
private final Object[] ourLocks = new Object[NUM_LOCKS];
private int ourLockAllocationCounter = 0;
protected StripedLockHolder() {
for (int i = 0; i < ourLocks.length; i++) {
ourLocks[i] = create();
}
}
@NotNull
protected abstract T create();
@NotNull
public T allocateLock() {
ourLockAllocationCounter = (ourLockAllocationCounter + 1) % NUM_LOCKS;
return (T)ourLocks[ourLockAllocationCounter];
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.containers;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.locks.ReentrantLock;
/**
* User: cdr
*/
public final class StripedReentrantLocks extends StripedLockHolder<ReentrantLock> {
@NotNull
@Override
protected ReentrantLock create() {
return new ReentrantLock();
}
private static final StripedReentrantLocks INSTANCE = new StripedReentrantLocks();
public static StripedReentrantLocks getInstance() {
return INSTANCE;
}
}