mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +07:00
IJPL-164852 Memory leak related to StatisticsEventLoggerProvider prevents dynamic unloading of AIA
Disposable StatisticsFileEventLogger lifecycle was bound to Application and disposed only on application close. This does not allow plugins with own implementation of StatisticsEventLoggerProvider to reload without memory leak. Created Application and Project level coroutine scopes for Statistics. Hold coroutine scope in StatisticsEventLoggerProvider and provide ability to override it. Handle lifecycle of disposable StatisticsFileEventLogger with coroutine instead of Disposer#register. Subscribe to EventLogConfigOptionsService.TOPIC using coroutine scope. Override coroutine scope in some implementations of implementation of StatisticsEventLoggerProvider. GitOrigin-RevId: f4efe2f589602482ab8746d06ad67bc810f973ee
This commit is contained in:
committed by
intellij-monorepo-bot
parent
32413fb37c
commit
ec2f17b852
@@ -166,6 +166,7 @@ a:com.intellij.internal.statistic.eventLog.StatisticsEventLoggerProvider
|
||||
- b:<init>(java.lang.String,I,J,I,Z,Z,Z,I,kotlin.jvm.internal.DefaultConstructorMarker):V
|
||||
- createEventsMergeStrategy():com.intellij.internal.statistic.eventLog.StatisticsEventMergeStrategy
|
||||
- f:getActiveLogFile():com.intellij.internal.statistic.eventLog.EventLogFile
|
||||
- getCoroutineScope():kotlinx.coroutines.CoroutineScope
|
||||
- sf:getEP_NAME():com.intellij.openapi.extensions.ExtensionPointName
|
||||
- f:getLogFilesProvider():com.intellij.internal.statistic.eventLog.EventLogFilesProvider
|
||||
- getLogger():com.intellij.internal.statistic.eventLog.StatisticsEventLogger
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.internal.statistic
|
||||
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface StatisticsServiceScope {
|
||||
companion object {
|
||||
fun getScope(project: Project): CoroutineScope = project.service<StatisticsServiceProjectScope>().scope
|
||||
fun getScope(): CoroutineScope = service<StatisticsServiceApplicationScope>().scope
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Service(Service.Level.APP)
|
||||
class StatisticsServiceApplicationScope(val scope: CoroutineScope)
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Service(Service.Level.PROJECT)
|
||||
class StatisticsServiceProjectScope(val scope: CoroutineScope)
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.internal.statistic.eventLog
|
||||
|
||||
import com.intellij.ide.plugins.ProductLoadingStrategy
|
||||
import com.intellij.idea.AppMode
|
||||
import com.intellij.internal.statistic.StatisticsServiceScope
|
||||
import com.intellij.internal.statistic.eventLog.logger.StatisticsEventLogThrottleWriter
|
||||
import com.intellij.internal.statistic.persistence.UsageStatisticsPersistenceComponent
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
@@ -10,6 +11,7 @@ import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.platform.runtime.product.ProductMode
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
@@ -81,6 +83,7 @@ abstract class StatisticsEventLoggerProvider(val recorderId: String,
|
||||
}
|
||||
}
|
||||
|
||||
open val coroutineScope: CoroutineScope = StatisticsServiceScope.getScope()
|
||||
private val localLogger: StatisticsEventLogger by lazy { createLocalLogger() }
|
||||
private val actualLogger: StatisticsEventLogger by lazy { createLogger() }
|
||||
internal val eventLogSystemLogger: EventLogSystemCollector by lazy { EventLogSystemCollector(this) }
|
||||
@@ -137,14 +140,15 @@ abstract class StatisticsEventLoggerProvider(val recorderId: String,
|
||||
|
||||
val configService = EventLogConfigOptionsService.getInstance()
|
||||
val throttledWriter = StatisticsEventLogThrottleWriter(
|
||||
configService, recorderId, version.toString(), writer
|
||||
configService, recorderId, version.toString(), writer, coroutineScope
|
||||
)
|
||||
|
||||
val logger = StatisticsFileEventLogger(
|
||||
recorderId, config.sessionId, isHeadless, eventLogConfiguration.build, config.bucket.toString(), version.toString(),
|
||||
throttledWriter, UsageStatisticsPersistenceComponent.getInstance(), createEventsMergeStrategy(), ideMode, productMode
|
||||
)
|
||||
Disposer.register(ApplicationManager.getApplication(), logger)
|
||||
|
||||
coroutineScope.coroutineContext.job.invokeOnCompletion { Disposer.dispose(logger) }
|
||||
return logger
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
// 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-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.internal.statistic.eventLog.logger
|
||||
|
||||
import com.intellij.application.subscribe
|
||||
import com.intellij.internal.statistic.eventLog.*
|
||||
import com.intellij.internal.statistic.eventLog.EventLogConfigOptionsService.EventLogThresholdConfigOptionsListener
|
||||
import com.intellij.internal.statistic.utils.EventRateThrottleResult
|
||||
import com.intellij.internal.statistic.utils.EventsIdentityWindowThrottle
|
||||
import com.intellij.internal.statistic.utils.EventsRateWindowThrottle
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.jetbrains.fus.reporting.model.lion3.LogEvent
|
||||
import com.jetbrains.fus.reporting.model.lion3.LogEventAction
|
||||
import com.jetbrains.fus.reporting.model.lion3.LogEventGroup
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
internal class StatisticsEventLogThrottleWriter(configOptionsService: EventLogConfigOptionsService,
|
||||
private val recorderId: String,
|
||||
private val recorderVersion: String,
|
||||
private val delegate: StatisticsEventLogWriter) : StatisticsEventLogWriter {
|
||||
private val delegate: StatisticsEventLogWriter,
|
||||
coroutineScope: CoroutineScope) : StatisticsEventLogWriter {
|
||||
private val ourLock: Any = Object()
|
||||
|
||||
/**
|
||||
@@ -37,7 +40,7 @@ internal class StatisticsEventLogThrottleWriter(configOptionsService: EventLogCo
|
||||
val groupAlertThreshold = getOrDefault(configOptions.groupAlertThreshold, 6000)
|
||||
ourGroupThrottle = EventsIdentityWindowThrottle(groupThreshold, groupAlertThreshold, 60L * 60 * 1000)
|
||||
|
||||
EventLogConfigOptionsService.TOPIC.subscribe(this, object : EventLogThresholdConfigOptionsListener(recorderId) {
|
||||
ApplicationManager.getApplication().messageBus.connect(coroutineScope).subscribe(EventLogConfigOptionsService.TOPIC, object : EventLogThresholdConfigOptionsListener(recorderId) {
|
||||
override fun onThresholdChanged(newValue: Int) {
|
||||
if (newValue > 0) {
|
||||
synchronized(ourLock) {
|
||||
|
||||
Reference in New Issue
Block a user