From 352676217d73604e41ff4f76199f471e925b5435 Mon Sep 17 00:00:00 2001 From: Alexander Kuznetsov Date: Tue, 25 Mar 2025 01:14:01 +0100 Subject: [PATCH] [rd][debugger] IJPL-177087 Ultimate attempt to fix project leak Don't delete entities manually; instead, link them to the session entity (and hope all with be deleted with it) GitOrigin-RevId: 170916f28532ef6161013eacfbc9ef706e1c7c15 --- .../impl/backend/BackendXDebugSessionApi.kt | 10 ++++---- .../impl/backend/BackendXExecutionStackApi.kt | 4 ++-- .../impl/rhizome/XDebuggerEntities.kt | 23 ++++++++++++------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebugSessionApi.kt b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebugSessionApi.kt index 38808c9f34b5..8a565e5b9dab 100644 --- a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebugSessionApi.kt +++ b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXDebugSessionApi.kt @@ -140,7 +140,7 @@ internal class BackendXDebugSessionApi : XDebugSessionApi { return channelFlow { withEntities(sessionEntity) { session.getCurrentSuspendContextFlow().asEntityFlow { suspendContext -> - XSuspendContextEntity.new(this, suspendContext) + XSuspendContextEntity.new(this, suspendContext, sessionEntity) }.collect { contextAndId -> if (contextAndId == null) { send(null) @@ -159,7 +159,7 @@ internal class BackendXDebugSessionApi : XDebugSessionApi { return channelFlow { withEntities(sessionEntity) { session.getCurrentExecutionStackFlow().asEntityFlow { executionStack -> - XExecutionStackEntity.new(this, executionStack) + XExecutionStackEntity.new(this, executionStack, sessionEntity) }.collect { stackAndId -> val (executionStack, id) = stackAndId ?: run { send(null) @@ -177,7 +177,7 @@ internal class BackendXDebugSessionApi : XDebugSessionApi { return channelFlow { withEntities(sessionEntity) { session.getCurrentStackFrameFlow().asEntityFlow { stackFrame -> - XStackFrameEntity.new(this, stackFrame) + XStackFrameEntity.new(this, stackFrame, sessionEntity) }.collect { frameAndId -> if (frameAndId == null) { send(null) @@ -221,10 +221,10 @@ internal class BackendXDebugSessionApi : XDebugSessionApi { suspendContextEntity.obj.computeExecutionStacks(object : XSuspendContext.XExecutionStackContainer { override fun addExecutionStack(executionStacks: List, last: Boolean) { channel.trySend(this@channelFlow.async { - withEntities(suspendContextEntity) { + withEntities(suspendContextEntity, suspendContextEntity.sessionEntity) { val stackEntities = executionStacks.map { stack -> change { - XExecutionStackEntity.new(this, stack) + XExecutionStackEntity.new(this, stack, suspendContextEntity.sessionEntity) } } change { diff --git a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXExecutionStackApi.kt b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXExecutionStackApi.kt index 0350aa6771c1..38dee44ca9bc 100644 --- a/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXExecutionStackApi.kt +++ b/platform/xdebugger-impl/backend/src/com/intellij/platform/debugger/impl/backend/BackendXExecutionStackApi.kt @@ -53,10 +53,10 @@ internal class BackendXExecutionStackApi : XExecutionStackApi { executionStack.computeStackFrames(firstFrameIndex, object : XExecutionStack.XStackFrameContainer { override fun addStackFrames(stackFrames: List, last: Boolean) { channel.trySend(this@channelFlow.async { - withEntities(executionStackEntity) { + withEntities(executionStackEntity, executionStackEntity.sessionEntity) { val frameEntities = stackFrames.map { frame -> change { - XStackFrameEntity.new(this, frame) + XStackFrameEntity.new(this, frame, executionStackEntity.sessionEntity) } } change { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt index 448ccc3b75a4..637117c9d828 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/rhizome/XDebuggerEntities.kt @@ -14,12 +14,10 @@ import com.intellij.xdebugger.impl.rpc.XValueId import com.jetbrains.rhizomedb.* import fleet.kernel.change import fleet.util.UID -import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.withContext import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import org.jetbrains.annotations.ApiStatus @@ -193,15 +191,23 @@ interface XDebuggerEntity : Entity { val obj: T get() = this[ObjAttr] as T + val sessionEntity: XDebugSessionEntity + get() = this[SessionEntityAttr] + companion object : Mixin>(XDebuggerEntity::class.java.name, "com.intellij.xdebugger.impl.rhizome") { val IdAttr: Attributes>.Required = requiredTransient("id", Indexing.UNIQUE) private val ObjAttr: Attributes>.Required = requiredTransient("obj") + // TODO[IJPL-177087] remove entities from DB in more appropriate time, don't wait until session ended + // (ideally, make withEntityFlow work) + private val SessionEntityAttr: Required = requiredRef("session", RefFlags.CASCADE_DELETE_BY) + @ApiStatus.Internal - fun , ET : EntityType> ET.new(changeScope: ChangeScope, obj: Any): E = with(changeScope) { + fun , ET : EntityType> ET.new(changeScope: ChangeScope, obj: Any, sessionEntity: XDebugSessionEntity): E = with(changeScope) { new { it[IdAttr] = UID.random() it[ObjAttr] = obj + it[SessionEntityAttr] = sessionEntity } } @@ -232,11 +238,12 @@ fun , ET : EntityType> Flow.asEntityFlow( awaitCancellation() } finally { - withContext(NonCancellable) { - change { - valueEntity.delete() - } - } + // TODO[IJPL-177087] not needed at the moment?, because of cascade deletion linked to the session entity + //withContext(NonCancellable) { + // change { + // valueEntity.delete() + // } + //} } } }