[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
This commit is contained in:
Alexander Kuznetsov
2025-03-25 02:02:28 +00:00
committed by intellij-monorepo-bot
parent 0d2f2cbba4
commit 352676217d
3 changed files with 22 additions and 15 deletions
@@ -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<XExecutionStack>, 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 {
@@ -53,10 +53,10 @@ internal class BackendXExecutionStackApi : XExecutionStackApi {
executionStack.computeStackFrames(firstFrameIndex, object : XExecutionStack.XStackFrameContainer {
override fun addStackFrames(stackFrames: List<XStackFrame>, 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 {
@@ -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<T : Any> : Entity {
val obj: T
get() = this[ObjAttr] as T
val sessionEntity: XDebugSessionEntity
get() = this[SessionEntityAttr]
companion object : Mixin<XDebuggerEntity<*>>(XDebuggerEntity::class.java.name, "com.intellij.xdebugger.impl.rhizome") {
val IdAttr: Attributes<XDebuggerEntity<*>>.Required<UID> = requiredTransient<UID>("id", Indexing.UNIQUE)
private val ObjAttr: Attributes<XDebuggerEntity<*>>.Required<Any> = requiredTransient<Any>("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<XDebugSessionEntity> = requiredRef<XDebugSessionEntity>("session", RefFlags.CASCADE_DELETE_BY)
@ApiStatus.Internal
fun <T : Any, E : XDebuggerEntity<T>, ET : EntityType<E>> ET.new(changeScope: ChangeScope, obj: Any): E = with(changeScope) {
fun <T : Any, E : XDebuggerEntity<T>, ET : EntityType<E>> 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 <T : Any, E : XDebuggerEntity<T>, ET : EntityType<E>> Flow<T?>.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()
// }
//}
}
}
}