From b65739ec34529f2e3e69dcdf3851017d7cd04530 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 30 Mar 2017 17:54:30 +0200 Subject: [PATCH] extract TimedIconCache to simplify RunManagerImpl (cherry picked from commit c24404edc0d38ec8f64118b6a5937d2853fc2f63) --- .../execution/impl/RunManagerImpl.java | 71 ++-------- .../intellij/execution/impl/TimedIconCache.kt | 124 ++++++++++++++++++ 2 files changed, 133 insertions(+), 62 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/execution/impl/TimedIconCache.kt diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java index 3d9a45cc4cef..17558894a5f2 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunManagerImpl.java @@ -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 myIdToIcon = new HashMap<>(); - private final Map myIconCheckTimes = new HashMap<>(); - private final Map myIconCalcTime = Collections.synchronizedMap(new HashMap()); + 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 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); diff --git a/platform/lang-impl/src/com/intellij/execution/impl/TimedIconCache.kt b/platform/lang-impl/src/com/intellij/execution/impl/TimedIconCache.kt new file mode 100644 index 000000000000..affe03d34be4 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/impl/TimedIconCache.kt @@ -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() + private val iconCheckTimes = ObjectLongHashMap() + private val iconCalcTime = ObjectLongHashMap() + + 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) + } + } + } + } +} \ No newline at end of file