From 510c3cd479dbdb2c46fb0785b4b8ba435e6bfbcd Mon Sep 17 00:00:00 2001 From: Grigorii Kirgizov Date: Wed, 6 Nov 2019 12:13:08 +0300 Subject: [PATCH] MPSCR-5: Clear all logicals from current StateFrameStack observer on incremental session teardown. --- .../mps/logic/reactor/core/LogicalObserver.kt | 9 +++++++++ .../core/internal/EvaluationSessionImpl.kt | 6 ++++-- .../core/internal/ProcessingStateImpl.kt | 11 +++++++++-- .../logic/reactor/core/internal/StateFrame.kt | 8 +++----- .../reactor/core/internal/StateFrameStack.kt | 17 +++++++++++------ 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/LogicalObserver.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/LogicalObserver.kt index e13a1fc5..384cb6af 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/LogicalObserver.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/LogicalObserver.kt @@ -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().toHashSet().size <= 1 && + parentObservers.map { it.second }.filterIsInstance().toHashSet().size <= 1 +} + + diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/EvaluationSessionImpl.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/EvaluationSessionImpl.kt index b200fd5a..3cb36dbc 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/EvaluationSessionImpl.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/EvaluationSessionImpl.kt @@ -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 } diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ProcessingStateImpl.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ProcessingStateImpl.kt index 20fb019a..304b8fcb 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ProcessingStateImpl.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/ProcessingStateImpl.kt @@ -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. diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrame.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrame.kt index a357177c..0fd1d9b8 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrame.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrame.kt @@ -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> = + observers.keys().asSequence().map { it.wrapped } + override fun valueUpdated(logical: Logical<*>) { observers[Id(logical)]?.let { list -> for (observer in list) { diff --git a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrameStack.kt b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrameStack.kt index 266bd0f1..7fad74f4 100644 --- a/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrameStack.kt +++ b/reactor/Core/src/jetbrains/mps/logic/reactor/core/internal/StateFrameStack.kt @@ -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) {