From c8fbf968b9a0abfbbd198ceaced09780aa5e04f6 Mon Sep 17 00:00:00 2001 From: Liudmila Kornilova Date: Thu, 21 Mar 2024 12:30:25 +0100 Subject: [PATCH] IDEA-345401 Report cancellation reason of health checks GitOrigin-RevId: e16029e99152fd5f680a9069626de271afcbb60b --- ...ndexableFilesFilterHealthCheckCollector.kt | 8 +- .../ProjectIndexableFilesFilter.kt | 31 ++++++-- .../ProjectIndexableFilesFilterHealthCheck.kt | 76 +++++++++++-------- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/IndexableFilesFilterHealthCheckCollector.kt b/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/IndexableFilesFilterHealthCheckCollector.kt index 775181838163..cc09c7dbce9b 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/IndexableFilesFilterHealthCheckCollector.kt +++ b/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/IndexableFilesFilterHealthCheckCollector.kt @@ -11,7 +11,7 @@ import com.intellij.openapi.project.Project */ internal object IndexableFilesFilterHealthCheckCollector : CounterUsagesCollector() { private val GROUP = EventLogGroup("indexable.files.filter", - 8, + 9, "FUS", "Collects statistics of ProjectIndexableFilesFilterHealthCheck. " + "See more here: https://youtrack.jetbrains.com/articles/IJPL-A-300/indexable.files.filter") @@ -23,6 +23,7 @@ internal object IndexableFilesFilterHealthCheckCollector : CounterUsagesCollecto private val successfulAttemptNumberInProjectField = EventFields.Int("successful_attempt_number_in_project", "Finished (not-cancelled) health check attempt number in a given project. First is 1.") private val durationMsFiled = EventFields.Int("duration_ms", "Health check duration in milliseconds") private val cancelledAttemptNumberInProjectField = EventFields.Int("cancelled_attempt_number_in_project", "Cancelled health check attempt number in a given project. First is 1.") + private val cancellationReasonField = EventFields.Enum("cancellation_reason", FilterActionCancellationReason::class.java) private val nonIndexableFilesInFilterField = EventFields.Int("non_indexable_files_in_filter_count") private val indexableFilesNotInFilterField = EventFields.Int("indexable_files_not_in_filter_count") @@ -51,6 +52,7 @@ internal object IndexableFilesFilterHealthCheckCollector : CounterUsagesCollecto attemptNumberInProjectField, cancelledAttemptNumberInProjectField, durationMsFiled, + cancellationReasonField, ) fun reportIndexableFilesFilterHealthcheckStarted(project: Project, @@ -86,13 +88,15 @@ internal object IndexableFilesFilterHealthCheckCollector : CounterUsagesCollecto filter: ProjectIndexableFilesFilter, attemptNumber: Int, cancelledAttemptNumber: Int, - durationMs: Int) { + durationMs: Int, + cancellationReason: FilterActionCancellationReason) { indexableFilesFilterHealthCheckCancelled.log( project, filterNameField.with(getFilterName(filter)), attemptNumberInProjectField.with(attemptNumber), cancelledAttemptNumberInProjectField.with(cancelledAttemptNumber), durationMsFiled.with(durationMs), + cancellationReasonField.with(cancellationReason) ) } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilter.kt b/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilter.kt index 51312b9f0c36..234dee90c551 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilter.kt +++ b/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilter.kt @@ -4,6 +4,8 @@ package com.intellij.util.indexing.projectFilter import com.intellij.openapi.project.Project import com.intellij.util.indexing.IdFilter import com.intellij.util.indexing.dependencies.ProjectIndexingDependenciesService +import com.intellij.util.indexing.projectFilter.FilterActionCancellationReason.FILTER_IS_UPDATED +import com.intellij.util.indexing.projectFilter.FilterActionCancellationReason.SCANNING_IS_IN_PROGRESS import java.util.concurrent.atomic.AtomicReference internal abstract class ProjectIndexableFilesFilterFactory { @@ -35,18 +37,29 @@ internal abstract class ProjectIndexableFilesFilter(protected val project: Proje } } - fun runAndCheckThatNoChangesHappened(action: () -> T): T? { + fun runAndCheckThatNoChangesHappened(action: () -> T): T { val (numberOfParallelUpdates, version) = parallelUpdatesCounter.getCounterAndVersion() - if (numberOfParallelUpdates != 0) return null + if (numberOfParallelUpdates != 0) { + throw FilterActionCancelledException(FILTER_IS_UPDATED) + } val res = action() val (numberOfParallelUpdates2, version2) = parallelUpdatesCounter.getCounterAndVersion() - return if (numberOfParallelUpdates2 != 0 || version2 != version) null + return if (numberOfParallelUpdates2 != 0 || version2 != version) { + throw FilterActionCancelledException(FILTER_IS_UPDATED) + } else res } abstract fun getFileStatuses(): Sequence> } +internal class FilterActionCancelledException(val reason: FilterActionCancellationReason) : Exception() + +internal enum class FilterActionCancellationReason { + FILTER_IS_UPDATED, + SCANNING_IS_IN_PROGRESS +} + private class AtomicVersionedCounter { private val counterAndVersion = AtomicReference(0 to 0) @@ -60,10 +73,14 @@ private class AtomicVersionedCounter { fun getCounterAndVersion(): Pair = counterAndVersion.get() } -internal fun runIfScanningScanningIsCompleted(project: Project, action: () -> T): T? { +internal fun runIfScanningScanningIsCompleted(project: Project, action: () -> T): T { val service = project.getService(ProjectIndexingDependenciesService::class.java) - if (!service.isScanningCompleted()) return null + if (!service.isScanningCompleted()) { + throw FilterActionCancelledException(SCANNING_IS_IN_PROGRESS) + } val res = action() - return if (service.isScanningCompleted()) res - else null + if (!service.isScanningCompleted()) { + throw FilterActionCancelledException(SCANNING_IS_IN_PROGRESS) + } + return res } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilterHealthCheck.kt b/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilterHealthCheck.kt index 9d8d69e4e12b..c0a23c326aa5 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilterHealthCheck.kt +++ b/platform/lang-impl/src/com/intellij/util/indexing/projectFilter/ProjectIndexableFilesFilterHealthCheck.kt @@ -100,34 +100,41 @@ class ProjectIndexableFilesFilterHealthCheck(private val project: Project, priva val startTime = System.currentTimeMillis() Observation.awaitConfiguration(project) // wait for project import IDEA-348501 - val res = smartReadAction(project) { - runHealthCheck(project, filter) + val res: HealthCheckResult = smartReadAction(project) { + try { + runHealthCheck(project, filter) + } + catch (e: FilterActionCancelledException) { + HealthCheckCancelled(e.reason) + } } - if (res == null) { - IndexableFilesFilterHealthCheckCollector.reportIndexableFilesFilterHealthcheckCancelled( - project, - filter, - attemptNumber, - cancelledAttemptsCount.incrementAndGet(), - (System.currentTimeMillis() - startTime).toInt()) - return + when (res) { + is HealthCheckFinished -> { + res.nonIndexableFilesInFilter.fix(filter) + res.indexableFilesNotInFilter.fix(filter) + + IndexableFilesFilterHealthCheckCollector.reportIndexableFilesFilterHealthcheck( + project, + filter, + attemptNumber, + successfulAttemptsCount.incrementAndGet(), + (System.currentTimeMillis() - startTime).toInt(), + res.nonIndexableFilesInFilter.size, + res.indexableFilesNotInFilter.size) + + res.nonIndexableFilesInFilter.logMessage() + res.indexableFilesNotInFilter.logMessage() + } + is HealthCheckCancelled -> { + IndexableFilesFilterHealthCheckCollector.reportIndexableFilesFilterHealthcheckCancelled( + project, + filter, + attemptNumber, + cancelledAttemptsCount.incrementAndGet(), + (System.currentTimeMillis() - startTime).toInt(), + res.reason) + } } - val (nonIndexableFilesInFilter, indexableFilesNotInFilter) = res - - nonIndexableFilesInFilter.fix(filter) - indexableFilesNotInFilter.fix(filter) - - IndexableFilesFilterHealthCheckCollector.reportIndexableFilesFilterHealthcheck( - project, - filter, - attemptNumber, - successfulAttemptsCount.incrementAndGet(), - (System.currentTimeMillis() - startTime).toInt(), - nonIndexableFilesInFilter.size, - indexableFilesNotInFilter.size) - - nonIndexableFilesInFilter.logMessage() - indexableFilesNotInFilter.logMessage() } catch (_: ProcessCanceledException) { @@ -137,9 +144,9 @@ class ProjectIndexableFilesFilterHealthCheck(private val project: Project, priva } } - private fun runHealthCheck(project: Project, filter: ProjectIndexableFilesFilter): Pair? { - return runIfScanningScanningIsCompleted(project) { - filter.runAndCheckThatNoChangesHappened { + private fun runHealthCheck(project: Project, filter: ProjectIndexableFilesFilter): HealthCheckResult { + return filter.runAndCheckThatNoChangesHappened { + runIfScanningScanningIsCompleted(project) { // It is possible that scanning will start and finish while we are performing healthcheck, // but then healthcheck will be terminated by the fact that filter was update. // If it was not updated, then we don't care that scanning happened, and we can trust healthcheck result @@ -159,7 +166,7 @@ class ProjectIndexableFilesFilterHealthCheck(private val project: Project, priva */ private fun doRunHealthCheck(project: Project, checkAllExpectedIndexableFiles: Boolean, - fileStatuses: Sequence>): Pair { + fileStatuses: Sequence>): HealthCheckFinished { val nonIndexableFilesInFilter = mutableListOf() val indexableFilesNotInFilter = mutableListOf() @@ -187,8 +194,8 @@ class ProjectIndexableFilesFilterHealthCheck(private val project: Project, priva } } - return NonIndexableFilesInFilterGroup(nonIndexableFilesInFilter) to - IndexableFilesNotInFilterGroup(indexableFilesNotInFilter, shouldBeIndexable) + return HealthCheckFinished(NonIndexableFilesInFilterGroup(nonIndexableFilesInFilter), + IndexableFilesNotInFilterGroup(indexableFilesNotInFilter, shouldBeIndexable)) } private fun getFilesThatShouldBeIndexable(project: Project): IndexableFiles { @@ -314,3 +321,8 @@ private class IndexableFiles { return perProvider.find { it.second.get(fileId) }?.first } } + +sealed interface HealthCheckResult + +private class HealthCheckFinished(val nonIndexableFilesInFilter: NonIndexableFilesInFilterGroup, val indexableFilesNotInFilter: IndexableFilesNotInFilterGroup) : HealthCheckResult +private class HealthCheckCancelled(val reason: FilterActionCancellationReason) : HealthCheckResult