Asynchronizing PsiSearchHelper

This commit is contained in:
Dmitry Lomov
2012-11-12 14:26:30 +01:00
parent f0228498c2
commit eeadbb3098
21 changed files with 349 additions and 58 deletions
+14 -1
View File
@@ -87,6 +87,20 @@
<option name="WHILE_BRACE_FORCE" value="1" />
<option name="FOR_BRACE_FORCE" value="1" />
<option name="FIELD_ANNOTATION_WRAP" value="0" />
<AndroidXmlCodeStyleSettings>
<option name="LAYOUT_SETTINGS">
<value />
</option>
<option name="MANIFEST_SETTINGS">
<value />
</option>
<option name="VALUE_RESOURCE_FILE_SETTINGS">
<value />
</option>
<option name="OTHER_SETTINGS">
<value />
</option>
</AndroidXmlCodeStyleSettings>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
@@ -259,7 +273,6 @@
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
</codeStyleSettings>
<codeStyleSettings language="SQL">
<option name="KEEP_LINE_BREAKS" value="false" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
</codeStyleSettings>
<codeStyleSettings language="XML">
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="sass-stdlib">
<CLASSES />
<JAVADOC />
<SOURCES>
<root url="file://$APPLICATION_HOME_DIR$/plugins/sass/lib/stubs/sass_functions.scss" />
</SOURCES>
</library>
</component>
@@ -37,6 +37,5 @@ public abstract class AsyncFutureFactory {
return result;
}
public abstract <V> AsyncFutureResult<V> createAsyncFutureResult();
}
@@ -0,0 +1,60 @@
/*
* Copyright 2000-2012 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.concurrency;
/**
* Author: dmitrylomov
*/
public abstract class DoWhile {
private AsyncFutureResult<Boolean> myResult;
public DoWhile() {
}
public AsyncFutureResult<Boolean> getResult() {
if (myResult == null) {
myResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
body().addConsumer(SameThreadExecutor.INSTANCE, new MyConsumer());
}
return myResult;
}
protected abstract AsyncFuture<Boolean> body();
protected abstract boolean condition();
private class MyConsumer extends DefaultResultConsumer<Boolean> {
public MyConsumer() {
super(DoWhile.this.myResult);
}
@Override
public void onSuccess(Boolean value) {
if (!value.booleanValue()) {
myResult.set(false);
}
else {
if(!condition()) {
myResult.set(true);
}
else {
body().addConsumer(SameThreadExecutor.INSTANCE, this);
}
}
}
}
}
@@ -0,0 +1,32 @@
package com.intellij.concurrency;
import java.util.Iterator;
/**
* Author: dmitrylomov
*/
public abstract class Iterate<T> extends DoWhile {
private final Iterator<T> myIterator;
private boolean myIsDone;
public Iterate(Iterable<T> iterable) {
myIterator = iterable.iterator();
myIsDone = false;
}
@Override
protected final AsyncFuture<Boolean> body() {
if (!myIterator.hasNext()) {
myIsDone = true;
return AsyncFutureFactory.wrap(true);
}
return process(myIterator.next());
}
protected abstract AsyncFuture<Boolean> process(T t);
@Override
protected boolean condition() {
return !myIsDone;
}
}
@@ -15,6 +15,10 @@
*/
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import com.intellij.concurrency.AsyncFutureFactory;
import com.intellij.concurrency.AsyncFutureResult;
import com.intellij.concurrency.FinallyFuture;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -76,5 +80,27 @@ public abstract class AbstractQuery<Result> implements Query<Result> {
}
}
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<Result> consumer) {
assertNotProcessing();
myIsProcessing = true;
return new FinallyFuture<Boolean>(processResultsAsync(consumer), new Runnable() {
@Override
public void run() {
myIsProcessing = false;
}
});
}
protected abstract boolean processResults(@NotNull Processor<Result> consumer);
protected AsyncFuture<Boolean> processResultsAsync(@NotNull Processor<Result> consumer) {
final AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
try {
result.set(processResults(consumer));
} catch (Throwable t) {
result.setException(t);
}
return result;
}
}
@@ -16,6 +16,9 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import com.intellij.concurrency.AsyncFutureFactory;
import com.intellij.concurrency.AsyncFutureResult;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -46,6 +49,17 @@ public class ArrayQuery<T> implements Query<T> {
return ContainerUtil.process(myArray, consumer);
}
public AsyncFuture<Boolean> forEachAsync(@NotNull final Processor<T> consumer) {
final AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
try {
result.set(forEach(consumer));
} catch (Throwable t){
result.setException(t);
}
return result;
}
public T[] toArray(final T[] a) {
return myArray;
}
@@ -16,6 +16,9 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import com.intellij.concurrency.AsyncFutureFactory;
import com.intellij.concurrency.AsyncFutureResult;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -49,6 +52,17 @@ public class CollectionQuery<T> implements Query<T> {
return ContainerUtil.process(myCollection, consumer);
}
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<T> consumer) {
AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
try {
result.set(forEach(consumer));
} catch (Throwable t) {
result.setException(t);
}
return result;
}
@Override
public T[] toArray(final T[] a) {
return findAll().toArray(a);
@@ -15,6 +15,8 @@
*/
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import com.intellij.concurrency.AsyncFutureFactory;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -40,6 +42,11 @@ public class EmptyQuery<R> implements Query<R> {
return true;
}
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<R> consumer) {
return AsyncFutureFactory.wrap(true);
}
public R[] toArray(final R[] a) {
return findAll().toArray(a);
}
@@ -16,6 +16,7 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import com.intellij.openapi.util.Condition;
import org.jetbrains.annotations.NotNull;
@@ -43,17 +44,15 @@ public class FilteredQuery<T> implements Query<T> {
@Override
public boolean forEach(@NotNull final Processor<T> consumer) {
myOriginal.forEach(new Processor<T>() {
@Override
public boolean process(final T t) {
return !myFilter.value(t) || consumer.process(t);
}
});
myOriginal.forEach(new MyProcessor(consumer));
return true;
}
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<T> consumer) {
return myOriginal.forEachAsync(new MyProcessor(consumer));
}
@NotNull
public Collection<T> findAll() {
CommonProcessors.CollectProcessor<T> processor = new CommonProcessors.CollectProcessor<T>();
@@ -70,4 +69,19 @@ public class FilteredQuery<T> implements Query<T> {
public Iterator<T> iterator() {
return findAll().iterator();
}
private class MyProcessor implements Processor<T> {
private final Processor<T> myConsumer;
public MyProcessor(Processor<T> consumer) {
myConsumer = consumer;
}
public boolean process(final T t) {
if (!myFilter.value(t)) return true;
if (!myConsumer.process(t)) return false;
return true;
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -51,16 +52,12 @@ public class InstanceofQuery<T> implements Query<T> {
}
public boolean forEach(@NotNull final Processor<T> consumer) {
return myDelegate.forEach(new Processor() {
public boolean process(Object o) {
for (Class aClass : myClasses) {
if (aClass.isInstance(o)) {
return consumer.process(((T)o));
}
}
return true;
}
});
return myDelegate.forEach(new MyProcessor(consumer));
}
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<T> consumer) {
return myDelegate.forEachAsync(new MyProcessor(consumer));
}
public T[] toArray(T[] a) {
@@ -71,4 +68,21 @@ public class InstanceofQuery<T> implements Query<T> {
public Iterator<T> iterator() {
return new UnmodifiableIterator<T>(findAll().iterator());
}
private class MyProcessor<T> implements Processor<T> {
private final Processor<T> myConsumer;
public MyProcessor(Processor<T> consumer) {
myConsumer = consumer;
}
public boolean process(T o) {
for (Class aClass : myClasses) {
if (aClass.isInstance(o)) {
return myConsumer.process(((T)o));
}
}
return true;
}
}
}
@@ -19,6 +19,7 @@
*/
package com.intellij.util;
import com.intellij.concurrency.*;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -52,6 +53,27 @@ public class MergeQuery<T> implements Query<T>{
return processSubQuery(consumer, myQuery1) && processSubQuery(consumer, myQuery2);
}
public AsyncFuture<Boolean> forEachAsync(@NotNull final Processor<T> consumer) {
final AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
final AsyncFuture<Boolean> fq = processSubQueryAsync(consumer, myQuery1);
fq.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result) {
@Override
public void onSuccess(Boolean value) {
if (!value.booleanValue()) {
result.set(false);
}
else {
final AsyncFuture<Boolean> fq2 = processSubQueryAsync(consumer, myQuery2);
fq2.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result));
}
}
});
return result;
}
private <V extends T> boolean processSubQuery(final Processor<T> consumer, Query<V> query1) {
return query1.forEach(new Processor<V>() {
public boolean process(final V t) {
@@ -60,6 +82,14 @@ public class MergeQuery<T> implements Query<T>{
});
}
private <V extends T> AsyncFuture<Boolean> processSubQueryAsync(final Processor<T> consumer, Query<V> query1) {
return query1.forEachAsync(new Processor<V>() {
public boolean process(final V t) {
return consumer.process(t);
}
});
}
public T[] toArray(final T[] a) {
final Collection<T> results = findAll();
return results.toArray(a);
@@ -15,6 +15,7 @@
*/
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,5 +47,7 @@ public interface Query<Result> extends Iterable<Result> {
*/
boolean forEach(@NotNull Processor<Result> consumer);
AsyncFuture<Boolean> forEachAsync(@NotNull Processor<Result> consumer);
Result[] toArray(Result[] a);
}
@@ -16,6 +16,7 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
@@ -54,14 +55,20 @@ public class UniqueResultsQuery<T, M> implements Query<T> {
return process(consumer, Collections.synchronizedSet(new THashSet<M>(myHashingStrategy)));
}
private boolean process(final Processor<T> consumer, final Set<M> processedElements) {
return myOriginal.forEach(new Processor<T>() {
public boolean process(final T t) {
return !processedElements.add(myMapper.fun(t)) || consumer.process(t);
}
});
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<T> consumer) {
return processAsync(consumer, Collections.synchronizedSet(new THashSet<M>(myHashingStrategy)));
}
private boolean process(final Processor<T> consumer, final Set<M> processedElements) {
return myOriginal.forEach(new MyProcessor(processedElements, consumer));
}
private AsyncFuture<Boolean> processAsync(final Processor<T> consumer, final Set<M> processedElements) {
return myOriginal.forEachAsync(new MyProcessor(processedElements, consumer));
}
@NotNull
public Collection<T> findAll() {
if (myMapper == Function.ID) {
@@ -84,4 +91,18 @@ public class UniqueResultsQuery<T, M> implements Query<T> {
public Iterator<T> iterator() {
return findAll().iterator();
}
private class MyProcessor implements Processor<T> {
private final Set<M> myProcessedElements;
private final Processor<T> myConsumer;
public MyProcessor(Set<M> processedElements, Processor<T> consumer) {
myProcessedElements = processedElements;
myConsumer = consumer;
}
public boolean process(final T t) {
return !myProcessedElements.add(myMapper.fun(t)) || myConsumer.process(t);
}
}
}
@@ -135,7 +135,12 @@ public class CoreApplicationEnvironment {
ProgressIndicatorProvider.ourInstance = createProgressIndicatorProvider();
myApplication.registerService(JobLauncher.class, new JobLauncher() {
myApplication.registerService(JobLauncher.class, createJobLauncher());
}
protected JobLauncher createJobLauncher() {
return new JobLauncher() {
@Override
public <T> boolean invokeConcurrentlyUnderProgress(@NotNull List<T> things,
ProgressIndicator progress,
@@ -195,8 +200,7 @@ public class CoreApplicationEnvironment {
});
return null;
}
});
};
}
protected ProgressIndicatorProvider createProgressIndicatorProvider() {
@@ -1,5 +1,6 @@
package com.intellij.psi.search;
import com.intellij.concurrency.AsyncFuture;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiReference;
import com.intellij.util.AbstractQuery;
@@ -18,6 +19,11 @@ public class SearchRequestQuery extends AbstractQuery<PsiReference> {
myRequests = requests;
}
@Override
protected AsyncFuture<Boolean> processResultsAsync(@NotNull Processor<PsiReference> consumer) {
return PsiSearchHelper.SERVICE.getInstance(myProject).processRequestsAsync(myRequests, consumer);
}
@Override
protected boolean processResults(@NotNull Processor<PsiReference> consumer) {
return PsiSearchHelper.SERVICE.getInstance(myProject).processRequests(myRequests, consumer);
@@ -275,7 +275,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
});
final AsyncFutureResult<Boolean> ourResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
completed.addConsumer(SameThreadExecutor.INSTANCE, new ResultConsumer<Boolean>() {
completed.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(ourResult) {
@Override
public void onSuccess(Boolean value) {
if (pceThrown.get())
@@ -510,42 +510,72 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
}
@Override
public AsyncFuture<Boolean> processRequestsAsync(@NotNull SearchRequestCollector request, @NotNull Processor<PsiReference> processor) {
throw new UnsupportedOperationException("Not implemented");
public boolean processRequests(@NotNull SearchRequestCollector request, @NotNull Processor<PsiReference> processor) {
return AsyncUtil.get(processRequestsAsync(request, processor));
}
@Override
public boolean processRequests(@NotNull SearchRequestCollector collector, @NotNull Processor<PsiReference> processor) {
Map<SearchRequestCollector, Processor<PsiReference>> collectors = ContainerUtil.newHashMap();
public AsyncFuture<Boolean> processRequestsAsync(@NotNull SearchRequestCollector collector, @NotNull Processor<PsiReference> processor) {
final Map<SearchRequestCollector, Processor<PsiReference>> collectors = ContainerUtil.newHashMap();
collectors.put(collector, processor);
appendCollectorsFromQueryRequests(collectors);
ProgressIndicator progress = ProgressIndicatorProvider.getGlobalProgressIndicator();
do {
MultiMap<Set<IdIndexEntry>, RequestWithProcessor> globals = new MultiMap<Set<IdIndexEntry>, RequestWithProcessor>();
List<Computable<Boolean>> customs = ContainerUtil.newArrayList();
Set<RequestWithProcessor> locals = ContainerUtil.newLinkedHashSet();
distributePrimitives(collectors, locals, globals, customs);
final ProgressIndicator progress = ProgressIndicatorProvider.getGlobalProgressIndicator();
final DoWhile doWhile = new DoWhile() {
if (!processGlobalRequestsOptimized(globals, progress)) {
return false;
@Override
protected AsyncFuture<Boolean> body() {
final AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
MultiMap<Set<IdIndexEntry>, RequestWithProcessor> globals = new MultiMap<Set<IdIndexEntry>, RequestWithProcessor>();
final List<Computable<Boolean>> customs = ContainerUtil.newArrayList();
final Set<RequestWithProcessor> locals = ContainerUtil.newLinkedHashSet();
distributePrimitives(collectors, locals, globals, customs);
processGlobalRequestsOptimizedAsync(globals, progress)
.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result) {
@Override
public void onSuccess(Boolean value) {
if (!value.booleanValue()) {
result.set(value);
}
else {
final Iterate<RequestWithProcessor> iterate = new Iterate<RequestWithProcessor>(locals) {
@Override
protected AsyncFuture<Boolean> process(RequestWithProcessor local) {
return processSingleRequestAsync(local.request, local.refProcessor);
}
};
iterate.getResult()
.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result) {
@Override
public void onSuccess(Boolean value) {
if (!value.booleanValue()) {
result.set(false);
return;
}
for (Computable<Boolean> custom : customs) {
if (!custom.compute()) {
result.set(false);
return;
}
}
result.set(true);
}
});
}
}
});
return result;
}
for (RequestWithProcessor local : locals) {
if (!processSingleRequest(local.request, local.refProcessor)) {
return false;
}
@Override
protected boolean condition() {
return appendCollectorsFromQueryRequests(collectors);
}
};
for (Computable<Boolean> custom : customs) {
if (!custom.compute()) {
return false;
}
}
} while (appendCollectorsFromQueryRequests(collectors));
return true;
return doWhile.getResult();
}
private static boolean appendCollectorsFromQueryRequests(Map<SearchRequestCollector, Processor<PsiReference>> collectors) {
@@ -563,11 +593,6 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
return changed;
}
private boolean processGlobalRequestsOptimized(MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles,
final ProgressIndicator progress) {
return AsyncUtil.get(processGlobalRequestsOptimizedAsync(singles, progress));
}
private AsyncFuture<Boolean> processGlobalRequestsOptimizedAsync(MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles,
final ProgressIndicator progress) {
if (singles.isEmpty()) {