mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
vcs: sanitize BackgroundTaskQueue
This commit is contained in:
committed by
Aleksey Pivovarov
parent
5c4046a522
commit
d2f4eeec33
@@ -325,16 +325,16 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
|
||||
@NotNull
|
||||
public Future<?> runProcessWithProgressAsynchronously(@NotNull final Task.Backgroundable task,
|
||||
@NotNull final ProgressIndicator progressIndicator,
|
||||
@Nullable final Runnable continuation) {
|
||||
@NotNull final ProgressIndicator progressIndicator,
|
||||
@Nullable final Runnable continuation) {
|
||||
return runProcessWithProgressAsynchronously(task, progressIndicator, continuation, ModalityState.NON_MODAL);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Future<?> runProcessWithProgressAsynchronously(@NotNull final Task.Backgroundable task,
|
||||
@NotNull final ProgressIndicator progressIndicator,
|
||||
@Nullable final Runnable continuation,
|
||||
@NotNull final ModalityState modalityState) {
|
||||
@NotNull final ProgressIndicator progressIndicator,
|
||||
@Nullable final Runnable continuation,
|
||||
@NotNull final ModalityState modalityState) {
|
||||
if (progressIndicator instanceof Disposable) {
|
||||
Disposer.register(ApplicationManager.getApplication(), (Disposable)progressIndicator);
|
||||
}
|
||||
@@ -371,7 +371,7 @@ public class CoreProgressManager extends ProgressManager implements Disposable {
|
||||
return ApplicationManager.getApplication().executeOnPooledThread(action);
|
||||
}
|
||||
|
||||
protected boolean runProcessWithProgressSynchronously(@NotNull final Task task, @Nullable final JComponent parentComponent) {
|
||||
public boolean runProcessWithProgressSynchronously(@NotNull final Task task, @Nullable final JComponent parentComponent) {
|
||||
final Ref<Exception> exceptionRef = new Ref<Exception>();
|
||||
TaskContainer taskContainer = new TaskContainer(task) {
|
||||
@Override
|
||||
|
||||
@@ -15,45 +15,14 @@
|
||||
*/
|
||||
package com.intellij.openapi.progress;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class RunBackgroundable {
|
||||
private RunBackgroundable() {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void run(@NotNull final Task task) {
|
||||
final ProgressManager pm = ProgressManager.getInstance();
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
pm.run(task);
|
||||
} else {
|
||||
runIfBackgroundThread(task, pm.getProgressIndicator(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void runIfBackgroundThread(final Task task, final ProgressIndicator pi, @Nullable final Runnable pooledContinuation) {
|
||||
boolean canceled = true;
|
||||
try {
|
||||
task.run(pi);
|
||||
canceled = pi != null && pi.isCanceled();
|
||||
} catch (ProcessCanceledException e) {
|
||||
//
|
||||
} finally {
|
||||
if (pooledContinuation != null) {
|
||||
pooledContinuation.run();
|
||||
}
|
||||
}
|
||||
|
||||
final boolean finalCanceled = canceled;
|
||||
UIUtil.invokeLaterIfNeeded(() -> {
|
||||
if (finalCanceled) {
|
||||
task.onCancel();
|
||||
}
|
||||
else {
|
||||
task.onSuccess();
|
||||
}
|
||||
});
|
||||
ProgressManager.getInstance().run(task);
|
||||
}
|
||||
}
|
||||
|
||||
+61
-104
@@ -19,17 +19,12 @@ package com.intellij.openapi.progress;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
|
||||
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import com.intellij.util.PlusMinus;
|
||||
import com.intellij.util.concurrency.QueueProcessor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -39,42 +34,44 @@ import org.jetbrains.annotations.TestOnly;
|
||||
* Runs backgroundable tasks one by one.
|
||||
* To add a task to the queue use {@link #run(com.intellij.openapi.progress.Task.Backgroundable)}
|
||||
* BackgroundTaskQueue may have a title - this title will be used if the task which is currently running doesn't have a title.
|
||||
*
|
||||
* @author yole
|
||||
* @author Kirill Likhodedov
|
||||
*/
|
||||
@SomeQueue
|
||||
public class BackgroundTaskQueue {
|
||||
private final static String ourMonitorFlag = "monitor.background.queue.load";
|
||||
private static final Logger LOG = Logger.getInstance(BackgroundTaskQueue.class.getName());
|
||||
//private final Project myProject;
|
||||
private final QueueProcessor<Pair<Task.Backgroundable, Getter<ProgressIndicator>>> myProcessor;
|
||||
private Boolean myForcedTestMode;
|
||||
private final PlusMinus<String> myMonitor;
|
||||
@NotNull private final String myTitle;
|
||||
@NotNull private final QueueProcessor<TaskData> myProcessor;
|
||||
|
||||
private boolean myForceAsyncInTests = false;
|
||||
|
||||
public BackgroundTaskQueue(@Nullable Project project, @NotNull String title) {
|
||||
this(project, title, null);
|
||||
}
|
||||
myTitle = title;
|
||||
|
||||
public BackgroundTaskQueue(@Nullable final Project project, @NotNull String title, final Boolean forcedHeadlessMode) {
|
||||
myMonitor = Boolean.TRUE.equals(Boolean.getBoolean(ourMonitorFlag)) ? new BackgroundTasksMonitor(title) : new PlusMinus.Empty<String>();
|
||||
final boolean headless = forcedHeadlessMode != null ? forcedHeadlessMode : ApplicationManager.getApplication().isHeadlessEnvironment();
|
||||
Condition disposeCondition = project != null ? project.getDisposed() : ApplicationManager.getApplication().getDisposed();
|
||||
|
||||
final QueueProcessor.ThreadToUse threadToUse = headless ? QueueProcessor.ThreadToUse.POOLED : QueueProcessor.ThreadToUse.AWT;
|
||||
final PairConsumer<Pair<Task.Backgroundable, Getter<ProgressIndicator>>, Runnable> consumer
|
||||
= headless ? new BackgroundableHeadlessRunner() : new BackgroundableUnderProgressRunner(title, project, myMonitor);
|
||||
myProcessor = new QueueProcessor<TaskData>((data, continuation) -> {
|
||||
Task.Backgroundable task = data.task;
|
||||
ProgressIndicator indicator = data.indicator;
|
||||
ModalityState modalityState = data.modalityState;
|
||||
|
||||
myProcessor = new QueueProcessor<Pair<Task.Backgroundable, Getter<ProgressIndicator>>>(consumer, true,
|
||||
threadToUse, new Condition<Object>() {
|
||||
@Override public boolean value(Object o) {
|
||||
if (project == null) return ApplicationManager.getApplication().isDisposed();
|
||||
if (project.isDefault()) {
|
||||
return project.isDisposed();
|
||||
} else {
|
||||
return !ApplicationManager.getApplication().isUnitTestMode() && !project.isOpen() || project.isDisposed();
|
||||
}
|
||||
if (StringUtil.isEmptyOrSpaces(task.getTitle())) {
|
||||
task.setTitle(myTitle);
|
||||
}
|
||||
|
||||
boolean synchronous = (task.isHeadless() && !myForceAsyncInTests) ||
|
||||
(task.isConditionalModal() && !task.shouldStartInBackground());
|
||||
|
||||
ProgressManagerImpl pm = (ProgressManagerImpl)ProgressManager.getInstance();
|
||||
if (synchronous) {
|
||||
try {
|
||||
pm.runProcessWithProgressSynchronously(task, null);
|
||||
}
|
||||
});
|
||||
finally {
|
||||
continuation.run();
|
||||
}
|
||||
}
|
||||
else {
|
||||
pm.runProcessWithProgressAsynchronously(task, indicator, continuation, modalityState);
|
||||
}
|
||||
}, true, QueueProcessor.ThreadToUse.AWT, disposeCondition);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@@ -84,91 +81,51 @@ public class BackgroundTaskQueue {
|
||||
public boolean isEmpty() {
|
||||
return myProcessor.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
public void waitForTasksToFinish() {
|
||||
myProcessor.waitFor();
|
||||
}
|
||||
|
||||
public void run(Task.Backgroundable task) {
|
||||
public void run(@NotNull Task.Backgroundable task) {
|
||||
run(task, null, null);
|
||||
}
|
||||
|
||||
public void run(Task.Backgroundable task, final ModalityState state, final Getter<ProgressIndicator> pi) {
|
||||
myMonitor.plus(task.getTitle());
|
||||
if (isTestMode()) { // test tasks are executed in this thread without the progress manager
|
||||
RunBackgroundable.runIfBackgroundThread(task, new EmptyProgressIndicator(), null);
|
||||
} else {
|
||||
myProcessor.add(Pair.create(task, pi), state);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BackgroundableHeadlessRunner implements PairConsumer<Pair<Task.Backgroundable, Getter<ProgressIndicator>>, Runnable> {
|
||||
@Override
|
||||
public void consume(Pair<Task.Backgroundable, Getter<ProgressIndicator>> pair, Runnable runnable) {
|
||||
final Task.Backgroundable backgroundable = pair.getFirst();
|
||||
// synchronously
|
||||
ProgressManager.getInstance().run(backgroundable);
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private static class BackgroundableUnderProgressRunner implements PairConsumer<Pair<Task.Backgroundable, Getter<ProgressIndicator>>, Runnable> {
|
||||
private final String myTitle;
|
||||
private final Project myProject;
|
||||
private final PlusMinus<String> myMonitor;
|
||||
|
||||
public BackgroundableUnderProgressRunner(String title, final Project project, PlusMinus<String> monitor) {
|
||||
myTitle = title;
|
||||
myProject = project;
|
||||
myMonitor = monitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(final Pair<Task.Backgroundable, Getter<ProgressIndicator>> pair, final Runnable runnable) {
|
||||
myMonitor.minus(pair.getFirst().getTitle());
|
||||
final Task.Backgroundable backgroundable = pair.getFirst();
|
||||
final ProgressIndicator[] pi = new ProgressIndicator[1];
|
||||
final boolean taskTitleIsEmpty = StringUtil.isEmptyOrSpaces(backgroundable.getTitle());
|
||||
|
||||
final Runnable wrappedTask = () -> {
|
||||
// calls task's run and onCancel() or onSuccess(); call continuation after task.run()
|
||||
RunBackgroundable.runIfBackgroundThread(backgroundable,
|
||||
pi[0] == null ? ProgressManager.getInstance().getProgressIndicator() : pi[0], runnable);
|
||||
};
|
||||
|
||||
final ProgressManager pm = ProgressManager.getInstance();
|
||||
if (backgroundable.isConditionalModal() && ! backgroundable.shouldStartInBackground()) {
|
||||
pm.runProcessWithProgressSynchronously(wrappedTask, taskTitleIsEmpty ? myTitle : backgroundable.getTitle(),
|
||||
backgroundable.isCancellable(), myProject);
|
||||
} else {
|
||||
if (pair.getSecond() != null) {
|
||||
pi[0] = pair.getSecond().get();
|
||||
}
|
||||
if (pi[0] == null) {
|
||||
if (taskTitleIsEmpty) {
|
||||
backgroundable.setTitle(myTitle);
|
||||
}
|
||||
pi[0] = new BackgroundableProcessIndicator(backgroundable);
|
||||
}
|
||||
|
||||
((ProgressManagerImpl)ProgressManager.getInstance()).runProcessWithProgressAsynchronously(backgroundable, pi[0], runnable);
|
||||
public void run(@NotNull Task.Backgroundable task, @Nullable ModalityState modalityState, @Nullable ProgressIndicator indicator) {
|
||||
if (modalityState == null) modalityState = ModalityState.NON_MODAL;
|
||||
if (indicator == null) {
|
||||
if (ApplicationManager.getApplication().isHeadlessEnvironment()) {
|
||||
indicator = new EmptyProgressIndicator();
|
||||
}
|
||||
else {
|
||||
indicator = new BackgroundableProcessIndicator(task);
|
||||
}
|
||||
}
|
||||
myProcessor.add(new TaskData(task, modalityState, indicator), modalityState);
|
||||
}
|
||||
|
||||
public boolean isTestMode() {
|
||||
if (myForcedTestMode != null) return myForcedTestMode;
|
||||
return ApplicationManager.getApplication().isUnitTestMode();
|
||||
private static class TaskData {
|
||||
@NotNull public final Task.Backgroundable task;
|
||||
@NotNull public final ModalityState modalityState;
|
||||
@NotNull public final ProgressIndicator indicator;
|
||||
|
||||
public TaskData(@NotNull Task.Backgroundable task, @NotNull ModalityState modalityState, @NotNull ProgressIndicator indicator) {
|
||||
this.task = task;
|
||||
this.modalityState = modalityState;
|
||||
this.indicator = indicator;
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public void setForcedTestMode(Boolean forcedTestMode, Disposable parentDisposable) {
|
||||
myForcedTestMode = forcedTestMode;
|
||||
Disposer.register(parentDisposable, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
myForcedTestMode = null;
|
||||
}
|
||||
});
|
||||
public void setForceAsyncInTests(boolean value, @Nullable Disposable disposable) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
myForceAsyncInTests = value;
|
||||
if (disposable != null) {
|
||||
Disposer.register(disposable, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
myForceAsyncInTests = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.openapi.progress;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.PlusMinus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 4/13/11
|
||||
* Time: 5:32 PM
|
||||
*/
|
||||
public class BackgroundTasksMonitor implements PlusMinus<String> {
|
||||
private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.BackgroundTasksMonitor");
|
||||
private static final long ourStatInterval = 300000;
|
||||
private long myRecentTime;
|
||||
private final Map<String, Integer> myMap;
|
||||
private final Map<String, Integer> myMaxMap;
|
||||
private final Object myLock;
|
||||
private final String myQueueTitle;
|
||||
|
||||
public BackgroundTasksMonitor(final String queueTitle) {
|
||||
myQueueTitle = queueTitle;
|
||||
myMap = new HashMap<String, Integer>();
|
||||
myMaxMap = new HashMap<String, Integer>();
|
||||
myLock = new Object();
|
||||
myRecentTime = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void plus(String title) {
|
||||
synchronized (myLock) {
|
||||
final Integer previous = myMap.get(title);
|
||||
final int newVal = previous == null ? 1 : (previous + 1);
|
||||
myMap.put(title, newVal);
|
||||
final Integer max = myMaxMap.get(title);
|
||||
if (max == null || max < newVal) {
|
||||
myMaxMap.put(title, newVal);
|
||||
}
|
||||
reportStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void minus(String title) {
|
||||
synchronized (myLock) {
|
||||
final Integer integer = myMap.get(title);
|
||||
assert integer != null;
|
||||
if (integer == 1) {
|
||||
myMap.remove(title);
|
||||
} else {
|
||||
myMap.put(title, integer - 1);
|
||||
}
|
||||
reportStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
private void reportStatistics() {
|
||||
final long time = System.currentTimeMillis();
|
||||
if (time - ourStatInterval < myRecentTime) return;
|
||||
final StringBuilder sb = new StringBuilder("BackgroundTaskQueue '" + myQueueTitle + "' usage statistics\n");
|
||||
sb.append("----------------------------------------------------\n");
|
||||
sb.append("Current Values:");
|
||||
for (Map.Entry<String, Integer> entry : myMap.entrySet()) {
|
||||
sb.append(entry.getKey()).append(": ").append(entry.getValue());
|
||||
}
|
||||
sb.append("\nMaximum Values:");
|
||||
for (Map.Entry<String, Integer> entry : myMaxMap.entrySet()) {
|
||||
sb.append('\n').append(entry.getKey()).append(": ").append(entry.getValue());
|
||||
}
|
||||
sb.append("----------------------------------------------------\n");
|
||||
LOG.info(sb.toString());
|
||||
myRecentTime = time;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -71,7 +71,7 @@ public class ProgressManagerImpl extends CoreProgressManager implements Disposab
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean runProcessWithProgressSynchronously(@NotNull final Task task, @Nullable final JComponent parentComponent) {
|
||||
public boolean runProcessWithProgressSynchronously(@NotNull final Task task, @Nullable final JComponent parentComponent) {
|
||||
final long start = System.currentTimeMillis();
|
||||
final boolean result = super.runProcessWithProgressSynchronously(task, parentComponent);
|
||||
if (result) {
|
||||
|
||||
@@ -248,7 +248,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider {
|
||||
}
|
||||
}
|
||||
};
|
||||
myDataLoaderQueue.run(backgroundable, null, () -> myRefresher.getProgress().createProgressIndicator(backgroundable));
|
||||
myDataLoaderQueue.run(backgroundable, null, myRefresher.getProgress().createProgressIndicator(backgroundable));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user