mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
deadlock fix
This commit is contained in:
@@ -36,6 +36,7 @@ import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
@@ -374,10 +375,14 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
return Collections.<StubIndexKey>unmodifiableCollection(myIndices.keySet());
|
||||
}
|
||||
|
||||
public <K> void updateIndex(StubIndexKey key, int fileId, Map<K, TIntArrayList> oldValues, Map<K, TIntArrayList> newValues) {
|
||||
public <K> void updateIndex(StubIndexKey key, int fileId, final Map<K, TIntArrayList> oldValues, Map<K, TIntArrayList> newValues) {
|
||||
try {
|
||||
MyIndex<K> index = (MyIndex<K>)myIndices.get(key);
|
||||
index.updateWithMap(fileId, newValues, oldValues.keySet());
|
||||
final MyIndex<K> index = (MyIndex<K>)myIndices.get(key);
|
||||
index.updateWithMap(fileId, newValues, new Callable<Collection<K>>() {
|
||||
public Collection<K> call() throws Exception {
|
||||
return oldValues.keySet();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (StorageException e) {
|
||||
LOG.info(e);
|
||||
@@ -390,14 +395,8 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
|
||||
super(null, null, storage);
|
||||
}
|
||||
|
||||
public void updateWithMap(final int inputId, final Map<K, TIntArrayList> newData, Collection<K> oldKeys) throws StorageException {
|
||||
getWriteLock().lock();
|
||||
try {
|
||||
super.updateWithMap(inputId, newData, oldKeys);
|
||||
}
|
||||
finally {
|
||||
getWriteLock().unlock();
|
||||
}
|
||||
public void updateWithMap(final int inputId, final Map<K, TIntArrayList> newData, Callable<Collection<K>> oldKeysGetter) throws StorageException {
|
||||
super.updateWithMap(inputId, newData, oldKeysGetter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtension<Integer, SerializedStubTree, FileContent> {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubUpdatingIndex");
|
||||
@@ -256,8 +256,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateStubIndices(final Collection<StubIndexKey> indexKeys, final int inputId, final Map<StubIndexKey, Map<Object, TIntArrayList>> oldStubTree,
|
||||
final Map<StubIndexKey, Map<Object, TIntArrayList>> newStubTree) {
|
||||
private static void updateStubIndices(final Collection<StubIndexKey> indexKeys, final int inputId, final Map<StubIndexKey, Map<Object, TIntArrayList>> oldStubTree, final Map<StubIndexKey, Map<Object, TIntArrayList>> newStubTree) {
|
||||
final StubIndexImpl stubIndex = (StubIndexImpl)StubIndex.getInstance();
|
||||
for (StubIndexKey key : indexKeys) {
|
||||
final Map<Object, TIntArrayList> oldMap = oldStubTree.get(key);
|
||||
@@ -290,26 +289,29 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateWithMap(final int inputId, final Map<Integer, SerializedStubTree> newData, Collection<Integer> oldKeys)
|
||||
protected void updateWithMap(final int inputId, final Map<Integer, SerializedStubTree> newData, Callable<Collection<Integer>> oldKeysGetter)
|
||||
throws StorageException {
|
||||
|
||||
checkNameStorage();
|
||||
Map<Integer, SerializedStubTree> oldData = readOldData(inputId);
|
||||
final Map<StubIndexKey, Map<Object, TIntArrayList>> oldStubTree = getStubTree(oldData);
|
||||
final Map<StubIndexKey, Map<Object, TIntArrayList>> newStubTree = getStubTree(newData);
|
||||
|
||||
final Collection<StubIndexKey> affectedIndices = getAffectedIndices(oldStubTree, newStubTree);
|
||||
final StubIndexImpl stubIndex = (StubIndexImpl)StubIndex.getInstance();
|
||||
final Collection<StubIndexKey> allStubIndices = stubIndex.getAllStubIndexKeys();
|
||||
try {
|
||||
// first write-lock affected stub indices to avoid deadlocks
|
||||
for (StubIndexKey key : affectedIndices) {
|
||||
for (StubIndexKey key : allStubIndices) {
|
||||
stubIndex.getWriteLock(key).lock();
|
||||
}
|
||||
|
||||
try {
|
||||
getWriteLock().lock();
|
||||
super.updateWithMap(inputId, newData, oldKeys);
|
||||
updateStubIndices(affectedIndices, inputId, oldStubTree, newStubTree);
|
||||
|
||||
final Map<Integer, SerializedStubTree> oldData = readOldData(inputId);
|
||||
final Map<StubIndexKey, Map<Object, TIntArrayList>> oldStubTree = getStubTree(oldData);
|
||||
|
||||
super.updateWithMap(inputId, newData, oldKeysGetter);
|
||||
|
||||
updateStubIndices(getAffectedIndices(oldStubTree, newStubTree), inputId, oldStubTree, newStubTree);
|
||||
}
|
||||
finally {
|
||||
getWriteLock().unlock();
|
||||
@@ -317,7 +319,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
|
||||
}
|
||||
finally {
|
||||
for (StubIndexKey key : affectedIndices) {
|
||||
for (StubIndexKey key : allStubIndices) {
|
||||
stubIndex.getWriteLock(key).unlock();
|
||||
}
|
||||
}
|
||||
@@ -344,24 +346,17 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
|
||||
return stubTree;
|
||||
}
|
||||
|
||||
/*MUST be called from under the WriteLock*/
|
||||
private Map<Integer, SerializedStubTree> readOldData(final int key) throws StorageException {
|
||||
|
||||
final Map<Integer, SerializedStubTree> result = new HashMap<Integer, SerializedStubTree>();
|
||||
final Lock lock = getReadLock();
|
||||
try {
|
||||
lock.lock();
|
||||
final ValueContainer<SerializedStubTree> valueContainer = getData(key);
|
||||
if (valueContainer.size() != 1) {
|
||||
LOG.assertTrue(valueContainer.size() == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.put(key, valueContainer.getValueIterator().next());
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
final ValueContainer<SerializedStubTree> valueContainer = myStorage.read(key);
|
||||
if (valueContainer.size() != 1) {
|
||||
LOG.assertTrue(valueContainer.size() == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.put(key, valueContainer.getValueIterator().next());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.util.indexing.MapReduceIndex");
|
||||
private final ID<Key, Value> myIndexId;
|
||||
private final DataIndexer<Key, Value, Input> myIndexer;
|
||||
private final IndexStorage<Key, Value> myStorage;
|
||||
protected final IndexStorage<Key, Value> myStorage;
|
||||
private PersistentHashMap<Integer, Collection<Key>> myInputsIndex;
|
||||
|
||||
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
|
||||
@@ -183,56 +184,51 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
|
||||
}
|
||||
|
||||
public final void update(final int inputId, @Nullable Input content) throws StorageException {
|
||||
//final Map<Key, Value> oldData = mapOld(oldContent);
|
||||
assert myInputsIndex != null;
|
||||
|
||||
final Map<Key, Value> data = mapNew(content);
|
||||
|
||||
Collection<Key> oldKeys;
|
||||
try {
|
||||
oldKeys = myInputsIndex.get(inputId);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new StorageException(e);
|
||||
}
|
||||
if (oldKeys == null) {
|
||||
oldKeys = Collections.emptyList();
|
||||
}
|
||||
final Map<Key, Value> data = content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
|
||||
|
||||
updateWithMap(inputId, data, new Callable<Collection<Key>>() {
|
||||
public Collection<Key> call() throws Exception {
|
||||
final Collection<Key> oldKeys = myInputsIndex.get(inputId);
|
||||
return oldKeys == null? Collections.<Key>emptyList() : oldKeys;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void updateWithMap(final int inputId, final Map<Key, Value> newData, Callable<Collection<Key>> oldKeysGetter) throws StorageException {
|
||||
getWriteLock().lock();
|
||||
try {
|
||||
// remove outdated values
|
||||
updateWithMap(inputId, data, oldKeys);
|
||||
try {
|
||||
final Set<Key> newKeys = data.keySet();
|
||||
if (newKeys.size() > 0) {
|
||||
myInputsIndex.put(inputId, newKeys);
|
||||
}
|
||||
else {
|
||||
myInputsIndex.remove(inputId);
|
||||
for (Key key : oldKeysGetter.call()) {
|
||||
myStorage.removeAllValues(key, inputId);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
catch (Exception e) {
|
||||
throw new StorageException(e);
|
||||
}
|
||||
// add new values
|
||||
for (Map.Entry<Key, Value> entry : newData.entrySet()) {
|
||||
myStorage.addValue(entry.getKey(), inputId, entry.getValue());
|
||||
}
|
||||
if (myInputsIndex != null) {
|
||||
try {
|
||||
final Set<Key> newKeys = newData.keySet();
|
||||
if (newKeys.size() > 0) {
|
||||
myInputsIndex.put(inputId, newKeys);
|
||||
}
|
||||
else {
|
||||
myInputsIndex.remove(inputId);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new StorageException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
getWriteLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<Key, Value> mapNew(final Input content) throws StorageException {
|
||||
return content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
|
||||
}
|
||||
|
||||
protected void updateWithMap(final int inputId, final Map<Key, Value> newData, Collection<Key> oldKeys) throws StorageException {
|
||||
for (Key key : oldKeys) {
|
||||
myStorage.removeAllValues(key, inputId);
|
||||
}
|
||||
// add new values
|
||||
for (Key key : newData.keySet()) {
|
||||
final Value newValue = newData.get(key);
|
||||
myStorage.addValue(key, inputId, newValue);
|
||||
}
|
||||
scheduleFlush();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user