mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[rd debugger] IDEA-382185 Preload manager should be empty after scope cancellation
* also preloaded events can be consumed only once GitOrigin-RevId: 280b17ba1226190a40becbe2c9e7054d66fe3161
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f7e71265d1
commit
cd42f126f7
+4
-2
@@ -30,6 +30,8 @@ import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.asPromise
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
@ApiStatus.Internal
|
||||
class FrontendXValue private constructor(
|
||||
@@ -368,9 +370,9 @@ private fun renderAdvancedPresentation(renderer: XValuePresentation.XValueTextRe
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Obsolescent.childCoroutineScope(parentScope: CoroutineScope, name: String): CoroutineScope {
|
||||
internal fun Obsolescent.childCoroutineScope(parentScope: CoroutineScope, name: String, context: CoroutineContext = EmptyCoroutineContext): CoroutineScope {
|
||||
val obsolescent = this
|
||||
val scope = parentScope.childScope(name)
|
||||
val scope = parentScope.childScope(name, context)
|
||||
parentScope.launch(context = Dispatchers.IO, start = CoroutineStart.UNDISPATCHED) {
|
||||
while (!obsolescent.isObsolete) {
|
||||
delay(ConcurrencyUtil.DEFAULT_TIMEOUT_MS)
|
||||
|
||||
+2
-3
@@ -7,7 +7,6 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.debugger.impl.frontend.frame.VariablesPreloadManager
|
||||
import com.intellij.platform.debugger.impl.rpc.*
|
||||
import com.intellij.platform.debugger.impl.shared.XValuesPresentationBuilder
|
||||
import com.intellij.platform.util.coroutines.childScope
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.xdebugger.frame.XCompositeNode
|
||||
import com.intellij.xdebugger.frame.XNamedValue
|
||||
@@ -58,8 +57,8 @@ internal class FrontendXValueContainer(
|
||||
|
||||
override fun computeChildren(node: XCompositeNode) {
|
||||
val childrenManager = getOrCreteChildrenManager(node)
|
||||
val scope = cs.childScope("FrontendXValueContainer#computeChildren", childrenManager)
|
||||
node.childCoroutineScope(parentScope = cs, "FrontendXValueContainer#computeChildren").launch(Dispatchers.EDT) {
|
||||
val scope = node.childCoroutineScope(parentScope = cs, "FrontendXValueContainer#computeChildren", childrenManager)
|
||||
scope.launch(Dispatchers.EDT) {
|
||||
val flow = childrenManager.getChildrenEventsFlow(id)
|
||||
val builder = XValuesPresentationBuilder()
|
||||
flow.collect { event ->
|
||||
|
||||
+15
-14
@@ -3,11 +3,10 @@ package com.intellij.platform.debugger.impl.frontend.frame
|
||||
|
||||
import com.intellij.openapi.diagnostic.fileLogger
|
||||
import com.intellij.platform.debugger.impl.rpc.*
|
||||
import com.intellij.platform.util.coroutines.childScope
|
||||
import com.intellij.util.AwaitCancellationAndInvoke
|
||||
import com.intellij.util.awaitCancellationAndInvoke
|
||||
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.consumeEach
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -29,19 +28,19 @@ class VariablesPreloadManager(
|
||||
treeState: XDebuggerTreeExpandedNode,
|
||||
frameId: XStackFrameId,
|
||||
) {
|
||||
private val cs = parentScope.childScope("VariablesPreloadManager")
|
||||
private val preloadedEvents = ConcurrentHashMap<XContainerId, Channel<XValueComputeChildrenEvent>>()
|
||||
|
||||
init {
|
||||
markToBeLoaded(frameId)
|
||||
cs.launch {
|
||||
val localEvents = hashMapOf<XContainerId, Channel<XValueComputeChildrenEvent>>()
|
||||
markToBeLoaded(frameId, localEvents)
|
||||
parentScope.launch {
|
||||
XValueApi.getInstance().computeExpandedChildren(frameId, treeState).collect { event ->
|
||||
when (event) {
|
||||
is PreloadChildrenEvent.ToBePreloaded -> {
|
||||
markToBeLoaded(event.id)
|
||||
markToBeLoaded(event.id, localEvents)
|
||||
}
|
||||
is PreloadChildrenEvent.ExpandedChildrenEvent -> {
|
||||
val channel = preloadedEvents[event.id] ?: run {
|
||||
val channel = localEvents[event.id] ?: run {
|
||||
fileLogger().error("Preloaded event for ${event.id} was not properly received")
|
||||
return@collect
|
||||
}
|
||||
@@ -50,22 +49,24 @@ class VariablesPreloadManager(
|
||||
}
|
||||
}
|
||||
}
|
||||
parentScope.awaitCancellationAndInvoke {
|
||||
preloadedEvents.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun getChildrenEventsFlow(entityId: XContainerId): Flow<XValueComputeChildrenEvent>? {
|
||||
val eventsChannel = preloadedEvents[entityId] ?: return null
|
||||
// channel can be consumed only once, so we remove it here
|
||||
val eventsChannel = preloadedEvents.remove(entityId) ?: return null
|
||||
return channelFlow {
|
||||
eventsChannel.consumeEach { send(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun markToBeLoaded(id: XContainerId) {
|
||||
val old = preloadedEvents.put(id, Channel(capacity = Channel.UNLIMITED))
|
||||
private fun markToBeLoaded(id: XContainerId, localEvents: MutableMap<XContainerId, Channel<XValueComputeChildrenEvent>>) {
|
||||
val channel = Channel<XValueComputeChildrenEvent>(capacity = Channel.UNLIMITED)
|
||||
val old = localEvents.put(id, channel)
|
||||
assert(old == null) { "Channel for $id was already registered" }
|
||||
}
|
||||
|
||||
internal fun cancel() {
|
||||
cs.cancel()
|
||||
preloadedEvents[id] = channel
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
Reference in New Issue
Block a user