extract TimedIconCache to simplify RunManagerImpl

(cherry picked from commit c24404edc0d38ec8f64118b6a5937d2853fc2f63)
This commit is contained in:
Vladimir Krivosheev
2017-04-10 18:19:53 +02:00
parent 0825d5ef78
commit b65739ec34
2 changed files with 133 additions and 62 deletions
@@ -27,20 +27,20 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.UnknownFeaturesCollector;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.IconDeferrer;
import com.intellij.util.EventDispatcher;
import com.intellij.util.IconUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.WeakHashMap;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
@@ -77,9 +77,7 @@ public abstract class RunManagerImpl extends RunManagerEx implements PersistentS
@Nullable private String myLoadedSelectedConfigurationUniqueName = null;
@Nullable private String mySelectedConfigurationId = null;
private final Map<String, Icon> myIdToIcon = new HashMap<>();
private final Map<String, Long> myIconCheckTimes = new HashMap<>();
private final Map<String, Long> myIconCalcTime = Collections.synchronizedMap(new HashMap<String, Long>());
private final TimedIconCache myIconCache = new TimedIconCache();
@NonNls
protected static final String CONFIGURATION = "configuration";
@@ -110,7 +108,7 @@ public abstract class RunManagerImpl extends RunManagerEx implements PersistentS
public void rootsChanged(ModuleRootEvent event) {
RunnerAndConfigurationSettings configuration = getSelectedConfiguration();
if (configuration != null) {
myIconCheckTimes.remove(configuration.getUniqueID());//cache will be expired
myIconCache.remove(configuration.getUniqueID());
}
}
});
@@ -814,9 +812,7 @@ public abstract class RunManagerImpl extends RunManagerEx implements PersistentS
myUnknownElements = null;
myTemplateConfigurationsMap.clear();
myLoadedSelectedConfigurationUniqueName = null;
myIdToIcon.clear();
myIconCheckTimes.clear();
myIconCalcTime.clear();
myIconCache.clear();
myRecentlyUsedTemporaries.clear();
fireRunConfigurationsRemoved(configurations);
}
@@ -1057,53 +1053,9 @@ public abstract class RunManagerImpl extends RunManagerEx implements PersistentS
RunnerAndConfigurationSettings selectedConfiguration = getSelectedConfiguration();
String selectedId = selectedConfiguration != null ? selectedConfiguration.getUniqueID() : "";
if (selectedId.equals(uniqueID)) {
Long lastCheckTime = myIconCheckTimes.get(uniqueID);
Long calcTime = myIconCalcTime.get(uniqueID);
if (calcTime == null || calcTime<150) calcTime = 150L;
if (lastCheckTime == null || System.currentTimeMillis() - lastCheckTime > calcTime*10) {
myIdToIcon.remove(uniqueID);//cache has expired
}
}
Icon icon = myIdToIcon.get(uniqueID);
if (icon == null) {
icon = IconDeferrer.getInstance().deferAutoUpdatable(settings.getConfiguration().getIcon(), myProject.hashCode() ^ settings.hashCode(),
param -> {
if (myProject.isDisposed()) return null;
myIconCalcTime.remove(uniqueID);
long startTime = System.currentTimeMillis();
Icon icon1;
if (DumbService.isDumb(myProject) && !Registry.is("dumb.aware.run.configurations")) {
icon1 =
IconLoader.getDisabledIcon(ProgramRunnerUtil.getRawIcon(settings));
if (settings.isTemporary()) {
icon1 = ProgramRunnerUtil.getTemporaryIcon(icon1);
}
}
else {
try {
DumbService.getInstance(myProject).setAlternativeResolveEnabled(true);
settings.checkSettings();
icon1 = ProgramRunnerUtil.getConfigurationIcon(settings, false);
}
catch (IndexNotReadyException e) {
icon1 = ProgramRunnerUtil.getConfigurationIcon(settings, !Registry.is("dumb.aware.run.configurations"));
}
catch (RuntimeConfigurationException ignored) {
icon1 = ProgramRunnerUtil.getConfigurationIcon(settings, true);
}
finally {
DumbService.getInstance(myProject).setAlternativeResolveEnabled(false);
}
}
myIconCalcTime.put(uniqueID, System.currentTimeMillis() - startTime);
return icon1;
});
myIdToIcon.put(uniqueID, icon);
myIconCheckTimes.put(uniqueID, System.currentTimeMillis());
myIconCache.checkValidity(uniqueID);
}
Icon icon = myIconCache.get(uniqueID, settings, myProject);
if (withLiveIndicator) {
List<RunContentDescriptor> runningDescriptors = ExecutionManagerImpl.getInstance(myProject).getRunningDescriptors(s -> s == settings);
if (runningDescriptors.size() == 1) {
@@ -1239,11 +1191,6 @@ public abstract class RunManagerImpl extends RunManagerEx implements PersistentS
fireBeforeRunTasksUpdated();
}
public final void resetBeforeRunTasks(final RunConfiguration runConfiguration) {
myConfigurationToBeforeTasksMap.remove(runConfiguration);
fireBeforeRunTasksUpdated();
}
@Override
public void addConfiguration(@NotNull RunnerAndConfigurationSettings settings, boolean isShared) {
addConfiguration(settings, isShared, getTemplateBeforeRunTasks(settings.getConfiguration()), false);
@@ -0,0 +1,124 @@
/*
* Copyright 2000-2017 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.execution.impl
import com.intellij.execution.ProgramRunnerUtil
import com.intellij.execution.RunnerAndConfigurationSettings
import com.intellij.execution.configurations.RuntimeConfigurationException
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.IconLoader
import com.intellij.openapi.util.registry.Registry
import com.intellij.ui.IconDeferrer
import com.intellij.util.containers.ObjectLongHashMap
import gnu.trove.THashMap
import java.util.concurrent.locks.ReentrantReadWriteLock
import javax.swing.Icon
import kotlin.concurrent.read
import kotlin.concurrent.write
class TimedIconCache {
private val idToIcon = THashMap<String, Icon>()
private val iconCheckTimes = ObjectLongHashMap<String>()
private val iconCalcTime = ObjectLongHashMap<String>()
private val lock = ReentrantReadWriteLock()
fun remove(id: String) {
lock.write {
iconCheckTimes.remove(id)
}
}
fun get(id: String, settings: RunnerAndConfigurationSettings, project: Project): Icon {
return lock.read { idToIcon.get(id) } ?: IconDeferrer.getInstance().deferAutoUpdatable(settings.configuration.icon, project.hashCode() xor settings.hashCode()) { param ->
if (project.isDisposed) {
return@deferAutoUpdatable null
}
lock.write {
iconCalcTime.remove(id)
}
val startTime = System.currentTimeMillis()
var icon: Icon
if (DumbService.isDumb(project) && !Registry.`is`("dumb.aware.run.configurations")) {
icon = IconLoader.getDisabledIcon(ProgramRunnerUtil.getRawIcon(settings))!!
if (settings.isTemporary) {
icon = ProgramRunnerUtil.getTemporaryIcon(icon)
}
}
else {
try {
DumbService.getInstance(project).isAlternativeResolveEnabled = true
settings.checkSettings()
icon = ProgramRunnerUtil.getConfigurationIcon(settings, false)
}
catch (e: IndexNotReadyException) {
icon = ProgramRunnerUtil.getConfigurationIcon(settings, !Registry.`is`("dumb.aware.run.configurations"))
}
catch (ignored: RuntimeConfigurationException) {
icon = ProgramRunnerUtil.getConfigurationIcon(settings, true)
}
finally {
DumbService.getInstance(project).isAlternativeResolveEnabled = false
}
}
lock.write {
iconCalcTime.put(id, System.currentTimeMillis() - startTime)
set(id, icon)
}
icon
}
}
private fun set(id: String, icon: Icon) {
idToIcon.put(id, icon)
iconCheckTimes.put(id, System.currentTimeMillis())
}
fun clear() {
lock.write {
idToIcon.clear()
iconCheckTimes.clear()
iconCalcTime.clear()
}
}
fun checkValidity(id: String) {
lock.read {
val lastCheckTime = iconCheckTimes.get(id)
var expired = lastCheckTime == -1L
if (!expired) {
var calcTime = iconCalcTime.get(id)
if (calcTime == -1L || calcTime < 150) {
calcTime = 150L
}
expired = (System.currentTimeMillis() - lastCheckTime) > (calcTime * 10)
}
if (expired) {
lock.write {
idToIcon.remove(id)
}
}
}
}
}