MPSCR-5: Clear all logicals from current StateFrameStack observer on incremental session teardown.

This commit is contained in:
Grigorii Kirgizov 2019-11-06 12:13:08 +03:00
parent daa1bdceb6
commit 510c3cd479
5 changed files with 36 additions and 15 deletions

View File

@ -17,6 +17,7 @@
package jetbrains.mps.logic.reactor.core
import jetbrains.mps.logic.reactor.core.internal.LogicalImpl
import jetbrains.mps.logic.reactor.core.internal.StateFrameStack
import jetbrains.mps.logic.reactor.logical.Logical
/**
@ -41,3 +42,11 @@ fun Logical<*>.removeObserver(observer: LogicalObserver) {
(this as LogicalImpl<*>).valueObservers.removeAll { p -> p.second == observer }
(this as LogicalImpl<*>).parentObservers.removeAll { p -> p.second == observer }
}
// Helps ensuring absence of memory leak of StateFrameStack through variable's internal arrays of observers
internal fun checkForwardingObserverUniqueInstance(logical: Logical<*>): Boolean = with(logical as LogicalImpl<*>) {
valueObservers.map { it.second }.filterIsInstance<StateFrameStack>().toHashSet().size <= 1 &&
parentObservers.map { it.second }.filterIsInstance<StateFrameStack>().toHashSet().size <= 1
}

View File

@ -146,9 +146,11 @@ internal class EvaluationSessionImpl private constructor (
}
return object : EvaluationResult {
override fun token(): SessionToken = session.controller.state.snapshot()
private val token = session.controller.state.endSession()
override fun storeView(): StoreView? = session.controller.storeView()
override fun token(): SessionToken = token
override fun storeView(): StoreView = token.journalView.storeView
override fun feedback(): EvaluationFeedback? = failure
}

View File

@ -204,8 +204,15 @@ internal class ProcessingStateImpl(private var dispatchingFront: Dispatcher.Disp
fun launchQueue(controller: Controller): FeedbackStatus =
execQueue.run(controller, this)
fun snapshot(): SessionToken =
SessionTokenImpl(view(), ruleOrdering.ruleTags, dispatchingFront.state())
/**
* Clears state unneeded between incremental sessions
* and returns [SessionToken] with session results.
*/
fun endSession(): SessionToken {
val histView = view()
resetStore() // clear observers
return SessionTokenImpl(histView, ruleOrdering.ruleTags, dispatchingFront.state())
}
/**
* Called to update the state with the currently active constraint occurrence.

View File

@ -43,11 +43,6 @@ internal class StateFrame constructor() : LogicalObserver
this.observers = prototype.observers
}
fun destroy() {
// TODO remove observers
}
fun addForwardingObserver(logical: Logical<*>, observer: LogicalObserver) {
val logicalId = Id(logical)
this.observers = observers.assoc(logicalId,
@ -64,6 +59,9 @@ internal class StateFrame constructor() : LogicalObserver
fun isObserving(logical: Logical<*>) =
observers[Id(logical)] != null
fun observed(): Sequence<Logical<*>> =
observers.keys().asSequence().map { it.wrapped }
override fun valueUpdated(logical: Logical<*>) {
observers[Id(logical)]?.let { list ->
for (observer in list) {

View File

@ -16,10 +16,7 @@
package jetbrains.mps.logic.reactor.core.internal
import jetbrains.mps.logic.reactor.core.LogicalObserver
import jetbrains.mps.logic.reactor.core.ProcessingState
import jetbrains.mps.logic.reactor.core.addObserver
import jetbrains.mps.logic.reactor.core.removeObserver
import jetbrains.mps.logic.reactor.core.*
import jetbrains.mps.logic.reactor.logical.Logical
import java.util.*
@ -42,12 +39,19 @@ internal open class StateFrameStack() : ProcessingState, LogicalObserver
return newFrame
}
fun reset() = reset(stateFrames.last)
fun reset() {
// Clear logicals from this forwarding observer on full reset
currentFrame().observed().forEach {
it.removeObserver(this)
}
reset(stateFrames.last)
}
fun reset(frame: StateFrame) {
val it = stateFrames.iterator()
while (it.hasNext()) {
if (frame === it.next()) { // referential equality
val next = it.next()
if (frame === next) { // referential equality
return
}
it.remove()
@ -60,6 +64,7 @@ internal open class StateFrameStack() : ProcessingState, LogicalObserver
logical.addObserver(this)
}
currentFrame().addForwardingObserver(logical, observer)
// assert(checkForwardingObserverUniqueInstance(logical))
}
override fun removeForwardingObserver(logical: Logical<*>, observer: LogicalObserver) {