def make_manager: Consumer_Thread[Any] = { var contexts = Map.empty[Document_ID.Command, Context]
var memory_children = Map.empty[Long, Set[Long]] var memory = Map.empty[Index, Answer]
def find_question(serial: Long): Option[(Document_ID.Command, Question)] =
contexts collectFirst { case (id, context) if context.questions contains serial =>
(id, context.questions(serial))
}
def do_cancel(serial: Long, id: Document_ID.Command): Unit = {
// To save memory, we could try to remove empty contexts at this point.
// However, if a new serial gets attached to the same command_id after we deleted
// its context, its last_serial counter will start at 0 again, and we'll think the
// old serials are actually new
contexts += (id -> (contexts(id) - serial))
}
Consumer_Thread.fork[Any]("Simplifier_Trace.manager", daemon = true)(
consume = { (arg: Any) =>
arg match { case Handle_Results(session, id, results, slot) => var new_context = contexts.getOrElse(id, Context()) var new_serial = new_context.last_serial
for ((serial, result) <- results.iterator if serial > new_context.last_serial) {
result match { case Item(markup, data) =>
memory_children +=
(data.parent -> (memory_children.getOrElse(data.parent, Set.empty) + serial))
markup match {
case Markup.SIMP_TRACE_STEP => val index = Index.of_data(data)
memory.get(index) match { case Some(answer) if data.memory =>
do_reply(session, serial, answer) case _ =>
new_context += Question(data, Answer.step.all)
}
case Markup.SIMP_TRACE_HINT =>
data.props match { case Success(false) =>
results.get(data.parent) match { case Some(Item(Markup.SIMP_TRACE_STEP, _)) =>
new_context += Question(data, Answer.hint_fail.all) case _ =>
// unknown, better send a default reply
do_reply(session, data.serial, Answer.hint_fail.exit)
} case _ =>
}
case Markup.SIMP_TRACE_IGNORE =>
// At this point, we know that the parent of this'IGNORE' entry is a 'STEP'
// entry, and that that 'STEP' entry is about to be replayed. Hence, we need
// to selectively purge the replies which have been memorized, going down from
// the parent to all leaves.
@tailrec def purge(queue: Vector[Long]): Unit =
queue match { case s +: rest => for (case Item(Markup.SIMP_TRACE_STEP, data) <- results.get(s))
memory -= Index.of_data(data) val children = memory_children.getOrElse(s, Set.empty)
memory_children -= s
purge(rest ++ children.toVector) case _ =>
}
purge(Vector(data.parent))
case _ =>
}
case _ =>
}
new_serial = serial
}
new_context = new_context.with_serial(new_serial)
contexts += (id -> new_context)
slot.fulfill(new_context)
case Generate_Trace(results, slot) =>
// Since there are potentially lots of trace messages, we do not cache them here again.
// Instead, everytime the trace is being requested, we re-assemble it based on the
// current results.
val items =
results.iterator.collect { case (_, Item(_, data)) => data }.toList
slot.fulfill(Trace(items))
case Cancel(serial) =>
find_question(serial) match { case Some((id, _)) =>
do_cancel(serial, id) case None =>
}
case Clear_Memory =>
memory_children = Map.empty
memory = Map.empty
case Reply(session, serial, answer) =>
find_question(serial) match { case Some((id, Question(data, _))) => if (data.markup == Markup.SIMP_TRACE_STEP && data.memory) { val index = Index.of_data(data)
memory += (index -> answer)
}
do_cancel(serial, id) case None =>
Output.warning("send_reply: unknown serial " + serial)
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.