StatisticsStateCollectorsScheduler - do not use projectOpened

GitOrigin-RevId: 04e0a645ab05c5ebf9241d93803559b0794d6f6a
This commit is contained in:
Vladimir Krivosheev
2022-07-18 07:24:17 +02:00
committed by intellij-monorepo-bot
parent 0bd061fca0
commit 28d91ee7e8
6 changed files with 96 additions and 102 deletions

View File

@@ -15,6 +15,7 @@
<extensions defaultExtensionNs="com.intellij">
<applicationInitializedListener implementation="com.intellij.internal.statistic.updater.StatisticsJobsScheduler"/>
<applicationInitializedListener implementation="com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler"/>
<postStartupActivity implementation="com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler$MyStartupActivity"/>
<projectViewPane implementation="com.intellij.ide.projectView.impl.ProjectViewPane"/>

View File

@@ -1,13 +1,15 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.serviceContainer;
import com.intellij.openapi.Disposable;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CancellationException;
/**
* @see Disposable
*/
public final class AlreadyDisposedException extends IllegalStateException {
public final class AlreadyDisposedException extends CancellationException {
public AlreadyDisposedException(@NotNull String message) {
super(message);
}

View File

@@ -27,5 +27,6 @@
<orderEntry type="module" module-name="intellij.platform.ide.core" />
<orderEntry type="module" module-name="intellij.platform.projectModel" />
<orderEntry type="module" module-name="intellij.platform.analysis" />
<orderEntry type="library" name="kotlinx-coroutines-jdk8" level="project" />
</component>
</module>

View File

@@ -1,102 +1,94 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.internal.statistic.updater;
package com.intellij.internal.statistic.updater
import com.intellij.concurrency.JobScheduler;
import com.intellij.ide.ApplicationInitializedListener;
import com.intellij.ide.lightEdit.LightEdit;
import com.intellij.internal.statistic.service.fus.collectors.FUStateUsagesLogger;
import com.intellij.internal.statistic.utils.StatisticsUploadAssistant;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerListener;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import com.intellij.ide.ApplicationInitializedListener
import com.intellij.ide.lightEdit.LightEdit
import com.intellij.internal.statistic.service.fus.collectors.FUStateUsagesLogger
import com.intellij.internal.statistic.utils.StatisticsUploadAssistant
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.startup.ProjectPostStartupActivity
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
internal class StatisticsStateCollectorsScheduler : ApplicationInitializedListener {
companion object {
private val LOG_APPLICATION_STATES_INITIAL_DELAY = 10.minutes
private val LOG_APPLICATION_STATES_DELAY = 24.hours
private val LOG_APPLICATION_STATE_SMART_MODE_DELAY = 1.minutes
private val LOG_PROJECTS_STATES_INITIAL_DELAY = 5.minutes
private val LOG_PROJECTS_STATES_DELAY = 12.hours
private const val REDUCE_DELAY_FLAG_KEY = "fus.internal.reduce.initial.delay"
final class StatisticsStateCollectorsScheduler implements ApplicationInitializedListener {
public static final int LOG_APPLICATION_STATES_INITIAL_DELAY_IN_MIN = 10;
public static final int LOG_APPLICATION_STATES_DELAY_IN_MIN = 24 * 60;
private static final int LOG_APPLICATION_STATE_SMART_MODE_DELAY_IN_SECONDS = 60;
public static final int LOG_PROJECTS_STATES_INITIAL_DELAY_IN_MIN = 5;
public static final int LOG_PROJECTS_STATES_DELAY_IN_MIN = 12 * 60;
private static final String REDUCE_DELAY_FLAG_KEY = "fus.internal.reduce.initial.delay";
private final Map<Project, Future<?>> persistStatisticsSessionsMap = Collections.synchronizedMap(new HashMap<>());
private final AtomicBoolean allowExecution = new AtomicBoolean(true);
@Override
public void componentsInitialized() {
runStatesLogging();
private val allowExecution = AtomicBoolean(true)
}
private void runStatesLogging() {
override fun componentsInitialized() {
if (!StatisticsUploadAssistant.isSendAllowed()) {
return;
return
}
allowExecution.set(true)
// avoid overlapping logging from periodic scheduler and OneTimeLogger (long indexing case)
JobScheduler.getScheduler().schedule(() -> allowExecution.set(false),
LOG_APPLICATION_STATES_INITIAL_DELAY_IN_MIN, TimeUnit.MINUTES);
JobScheduler.getScheduler().scheduleWithFixedDelay(() -> FUStateUsagesLogger.create().logApplicationStates(),
LOG_APPLICATION_STATES_INITIAL_DELAY_IN_MIN,
LOG_APPLICATION_STATES_DELAY_IN_MIN, TimeUnit.MINUTES);
ApplicationManager.getApplication().getMessageBus().simpleConnect().subscribe(ProjectManager.TOPIC, new ProjectManagerListener() {
@Override
public void projectOpened(@NotNull Project project) {
// Smart mode is not available when LightEdit is active
if (LightEdit.owns(project)) {
return;
}
//wait until initial indexation will be finished
DumbService.getInstance(project).runWhenSmart(() -> {
boolean reduceInitialDelay = Boolean.parseBoolean(System.getProperty(REDUCE_DELAY_FLAG_KEY));
ScheduledFuture<?> future = JobScheduler.getScheduler()
.scheduleWithFixedDelay(() -> FUStateUsagesLogger.create().logProjectStates(project, new EmptyProgressIndicator()),
reduceInitialDelay ? 0 : LOG_PROJECTS_STATES_INITIAL_DELAY_IN_MIN,
LOG_PROJECTS_STATES_DELAY_IN_MIN, TimeUnit.MINUTES);
persistStatisticsSessionsMap.put(project, future);
});
if (allowExecution.get()) {
DumbService.getInstance(project).runWhenSmart(() -> {
// wait until all projects will exit dumb mode
if (ContainerUtil.exists(ProjectManager.getInstance().getOpenProjects(),
p -> !p.isDisposed() && p.isInitialized() && DumbService.getInstance(p).isDumb())) {
return;
}
scheduleLogging();
});
}
ApplicationManager.getApplication().coroutineScope.launch {
delay(LOG_APPLICATION_STATES_INITIAL_DELAY)
allowExecution.set(false)
FUStateUsagesLogger.create().logApplicationStates()
while (true) {
delay(LOG_APPLICATION_STATES_DELAY)
FUStateUsagesLogger.create().logApplicationStates()
}
@Override
public void projectClosed(@NotNull Project project) {
Future<?> future = persistStatisticsSessionsMap.remove(project);
if (future != null) {
future.cancel(true);
}
}
});
}
// check and execute only once because several projects can exit dumb mode at the same time
private void scheduleLogging() {
if (allowExecution.getAndSet(false)) {
JobScheduler.getScheduler().schedule(() -> FUStateUsagesLogger.create().logApplicationStatesOnStartup(),
LOG_APPLICATION_STATE_SMART_MODE_DELAY_IN_SECONDS, TimeUnit.SECONDS);
}
}
}
internal class MyStartupActivity : ProjectPostStartupActivity {
override suspend fun execute(project: Project) {
// smart mode is not available when LightEdit is active
if (LightEdit.owns(project)) {
return
}
// wait until initial indexation will be finished
DumbService.getInstance(project).runWhenSmart {
project.coroutineScope.launch {
val reduceInitialDelay = System.getProperty(REDUCE_DELAY_FLAG_KEY).toBoolean()
if (!reduceInitialDelay) {
delay(LOG_PROJECTS_STATES_INITIAL_DELAY)
}
FUStateUsagesLogger.create().logProjectStates(project, EmptyProgressIndicator())
while (true) {
delay(LOG_PROJECTS_STATES_DELAY)
FUStateUsagesLogger.create().logProjectStates(project, EmptyProgressIndicator())
}
}
}
if (allowExecution.get()) {
DumbService.getInstance(project).runWhenSmart {
// wait until all projects will exit dumb mode
if (ProjectManager.getInstance().openProjects.any { p -> !p.isDisposed && p.isInitialized && DumbService.getInstance(p).isDumb }) {
return@runWhenSmart
}
scheduleLogging(project)
}
}
}
// check and execute only once because several projects can exit dumb mode at the same time
private fun scheduleLogging(project: Project) {
if (allowExecution.getAndSet(false)) {
project.coroutineScope.launch {
delay(LOG_APPLICATION_STATE_SMART_MODE_DELAY)
FUStateUsagesLogger.create().logApplicationStatesOnStartup()
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.internal.statistic.utils;
import com.intellij.internal.statistic.eventLog.*;
@@ -8,7 +8,7 @@ import com.intellij.internal.statistic.eventLog.connection.EventLogUploadSetting
import com.intellij.internal.statistic.eventLog.connection.StatisticsService;
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.Strings;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -31,17 +31,17 @@ public final class StatisticsUploadAssistant {
if (ApplicationManager.getApplication().isHeadlessEnvironment()) {
return isHeadlessStatisticsEnabled();
}
UsageStatisticsPersistenceComponent settings = UsageStatisticsPersistenceComponent.getInstance();
boolean sendOverride = getSendAllowedOverride();
return settings != null && settings.isAllowed() || sendOverride;
UsageStatisticsPersistenceComponent settings = UsageStatisticsPersistenceComponent.getInstance();
return settings != null && settings.isAllowed() || getSendAllowedOverride();
}
public static boolean isCollectAllowed() {
if (ApplicationManager.getApplication().isHeadlessEnvironment()) {
return isHeadlessStatisticsEnabled();
}
final UsageStatisticsPersistenceComponent settings = UsageStatisticsPersistenceComponent.getInstance();
UsageStatisticsPersistenceComponent settings = UsageStatisticsPersistenceComponent.getInstance();
boolean collectOverride = getCollectAllowedOverride();
return (settings != null && settings.isAllowed() || collectOverride) || isLocalStatisticsWithoutReport();
}
@@ -56,10 +56,7 @@ public final class StatisticsUploadAssistant {
public static boolean getCollectAllowedOverride() {
ExternalEventLogSettings externalEventLogSettings = StatisticsEventLogProviderUtil.getExternalEventLogSettings();
if (externalEventLogSettings != null)
return externalEventLogSettings.isCollectAllowedOverride();
else
return false;
return externalEventLogSettings != null && externalEventLogSettings.isCollectAllowedOverride();
}
private static boolean isHeadlessStatisticsEnabled() {
@@ -98,7 +95,7 @@ public final class StatisticsUploadAssistant {
}
public static boolean isTeamcityDetected() {
return StringUtil.isNotEmpty(System.getenv("TEAMCITY_VERSION"));
return Strings.isNotEmpty(System.getenv("TEAMCITY_VERSION"));
}
public static boolean isSuppressStatisticsReport() {

View File

@@ -10,6 +10,7 @@
<extensions defaultExtensionNs="com.intellij">
<applicationInitializedListener implementation="com.intellij.internal.statistic.updater.StatisticsJobsScheduler"/>
<applicationInitializedListener implementation="com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler"/>
<postStartupActivity implementation="com.intellij.internal.statistic.updater.StatisticsStateCollectorsScheduler$MyStartupActivity"/>
<projectViewPane implementation="com.intellij.ide.projectView.impl.ProjectViewPane"/>