Handle case of invalidating stale discarding matches (MPSCR-35)
This commit is contained in:
parent
18fc4592f0
commit
efd22872a9
|
|
@ -22,6 +22,7 @@ import jetbrains.mps.logic.reactor.program.IncrementalProgramSpec
|
||||||
import jetbrains.mps.logic.reactor.evaluation.RuleMatch
|
import jetbrains.mps.logic.reactor.evaluation.RuleMatch
|
||||||
import jetbrains.mps.logic.reactor.evaluation.SessionToken
|
import jetbrains.mps.logic.reactor.evaluation.SessionToken
|
||||||
import jetbrains.mps.logic.reactor.program.Rule
|
import jetbrains.mps.logic.reactor.program.Rule
|
||||||
|
import jetbrains.mps.logic.reactor.util.Id
|
||||||
import jetbrains.mps.logic.reactor.util.Profiler
|
import jetbrains.mps.logic.reactor.util.Profiler
|
||||||
import jetbrains.mps.logic.reactor.util.profile
|
import jetbrains.mps.logic.reactor.util.profile
|
||||||
|
|
||||||
|
|
@ -46,7 +47,8 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
|
||||||
val profiler: Profiler? = null)
|
val profiler: Profiler? = null)
|
||||||
: StoreAwareJournalImpl(journal, logicalState)
|
: StoreAwareJournalImpl(journal, logicalState)
|
||||||
{
|
{
|
||||||
private val execQueue: ExecutionQueue = ExecutionQueue(journal.index(), RuleOrdering(ruleIndex))
|
private val journalIndex: MatchJournal.Index = journal.index()
|
||||||
|
private val execQueue: ExecutionQueue = ExecutionQueue(journalIndex, RuleOrdering(ruleIndex))
|
||||||
|
|
||||||
private data class MatchCandidate(val rule: Rule, val occChunk: MatchJournal.OccChunk)
|
private data class MatchCandidate(val rule: Rule, val occChunk: MatchJournal.OccChunk)
|
||||||
|
|
||||||
|
|
@ -208,10 +210,13 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
|
||||||
push()
|
push()
|
||||||
assert(active.alive)
|
assert(active.alive)
|
||||||
|
|
||||||
|
val activationChunk: MatchJournal.OccChunk?
|
||||||
if (!active.stored) {
|
if (!active.stored) {
|
||||||
active.stored = true
|
active.stored = true
|
||||||
logActivation(active)
|
activationChunk = logActivation(active)
|
||||||
active.revive(logicalState)
|
active.revive(logicalState)
|
||||||
|
} else {
|
||||||
|
activationChunk = journalIndex.activatingChunkOf(Id(active))
|
||||||
}
|
}
|
||||||
|
|
||||||
profiler.profile("dispatch_${active.constraint().symbol()}") {
|
profiler.profile("dispatch_${active.constraint().symbol()}") {
|
||||||
|
|
@ -223,6 +228,7 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
|
||||||
val matches = dispatchingFront.matches().toList()
|
val matches = dispatchingFront.matches().toList()
|
||||||
val newCurrentMatches =
|
val newCurrentMatches =
|
||||||
// todo: assert that there can be no future matches on non-principal occurrences?
|
// todo: assert that there can be no future matches on non-principal occurrences?
|
||||||
|
// with that move withPostponedMatches to else-branch
|
||||||
if (isFront() || !active.isPrincipal()) {
|
if (isFront() || !active.isPrincipal()) {
|
||||||
matches
|
matches
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -232,6 +238,13 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
|
||||||
val currentMatches = execQueue.withPostponedMatches(active, newCurrentMatches)
|
val currentMatches = execQueue.withPostponedMatches(active, newCurrentMatches)
|
||||||
|
|
||||||
val outStatus = currentMatches.fold(inStatus) { status, match ->
|
val outStatus = currentMatches.fold(inStatus) { status, match ->
|
||||||
|
if (activationChunk != null && !isFront()) {
|
||||||
|
val discards = match.matchHeadReplaced().contains(active)
|
||||||
|
if (discards) {
|
||||||
|
dropDiscardingMatchesFor(activationChunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: paranoid check. should be isAlive() instead
|
// TODO: paranoid check. should be isAlive() instead
|
||||||
// FIXME: move this check elsewhere
|
// FIXME: move this check elsewhere
|
||||||
if (status.operational && active.stored && match.allStored())
|
if (status.operational && active.stored && match.allStored())
|
||||||
|
|
@ -248,6 +261,12 @@ internal class ConstraintsProcessing(private var dispatchingFront: Dispatcher.Di
|
||||||
return outStatus
|
return outStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun dropDiscardingMatchesFor(ancestor: MatchJournal.OccChunk) =
|
||||||
|
this.dropDescendantsWhile(ancestor) { chunk ->
|
||||||
|
chunk is MatchJournal.MatchChunk
|
||||||
|
&& chunk.match.matchHeadReplaced().contains(ancestor.occ)
|
||||||
|
}
|
||||||
|
|
||||||
private inline fun FeedbackStatus.then(action: (FeedbackStatus) -> FeedbackStatus) : FeedbackStatus =
|
private inline fun FeedbackStatus.then(action: (FeedbackStatus) -> FeedbackStatus) : FeedbackStatus =
|
||||||
if (operational) action(this) else this
|
if (operational) action(this) else this
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,13 @@ interface MatchJournal : MutableIterable<MatchJournal.Chunk> {
|
||||||
*/
|
*/
|
||||||
fun reset(pastPos: Pos)
|
fun reset(pastPos: Pos)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes [Chunk]s among descendants of [ancestor] if they satisfy [dropIf] predicate.
|
||||||
|
* Transitively removes descendants of removed chunks.
|
||||||
|
* Only erases future chunks and leaves journal position intact.
|
||||||
|
*/
|
||||||
|
fun dropDescendantsWhile(ancestor: Chunk, dropIf: (Chunk) -> Boolean)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replay activated and discarded occurrences logged in journal between current and provided positions.
|
* Replay activated and discarded occurrences logged in journal between current and provided positions.
|
||||||
* Advances journal position to specified position.
|
* Advances journal position to specified position.
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,36 @@ internal open class MatchJournalImpl(
|
||||||
if (currentPos() != until) throw IllegalStateException()
|
if (currentPos() != until) throw IllegalStateException()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun dropDescendantsWhile(ancestor: Chunk, dropIf: (Chunk) -> Boolean) {
|
||||||
|
// starts iterating from the Chunk which is next after current
|
||||||
|
// leaves 'current' and 'posPtr' intact
|
||||||
|
val droppedIds = mutableListOf<Int>()
|
||||||
|
val start = current
|
||||||
|
|
||||||
|
while (posPtr.hasNext()) {
|
||||||
|
current = posPtr.next()
|
||||||
|
if (!current.isDescendantOf(ancestor.id)) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dropIf(current)) {
|
||||||
|
droppedIds.add(current.id)
|
||||||
|
// no need to 'resetOccurrences' because journal position is left intact
|
||||||
|
posPtr.remove()
|
||||||
|
} else if (current.justifications.intersects(droppedIds)) {
|
||||||
|
// drop descendants of dropped Chunks
|
||||||
|
posPtr.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rollback to the start
|
||||||
|
while (current != start) {
|
||||||
|
current = posPtr.previous()
|
||||||
|
}
|
||||||
|
// make ptr point right after 'current' in case we changed anything
|
||||||
|
if (posPtr.hasNext()) posPtr.next()
|
||||||
|
}
|
||||||
|
|
||||||
private fun resetOccurrences(occSpecs: Iterable<MatchJournal.Chunk.Entry>) =
|
private fun resetOccurrences(occSpecs: Iterable<MatchJournal.Chunk.Entry>) =
|
||||||
occSpecs.forEach {
|
occSpecs.forEach {
|
||||||
if (it.discarded) {
|
if (it.discarded) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue