org.aiddl.common.scala.execution.Actor.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aiddl-common-scala Show documentation
Show all versions of aiddl-common-scala Show documentation
Provides common types and algorithm implementations for the fast prototyping integrative AI systems with the AIDDL framework.
The newest version!
package org.aiddl.common.scala.execution
import org.aiddl.common.scala.execution.Actor
import org.aiddl.common.scala.execution.clock.Tickable
import org.aiddl.core.scala.function.Function
import org.aiddl.core.scala.representation.{Sym, Term}
import scala.collection.mutable
object Actor {
enum Status {
case Pending
case Active
case Succeeded
case Error(code: Term, msg: String)
case Recalling
case Recalled
case Preempting
case Preempted
def isDone: Boolean = this match {
case Succeeded | Preempted | Recalled | Error(_, _) => true
case _ => false
}
}
type ActionInstanceId = Long
}
trait Actor extends Tickable {
import Actor.Status.*
import Actor.{ActionInstanceId, Status}
protected val actionIdMap: mutable.Map[ActionInstanceId, Term] = new mutable.HashMap[ActionInstanceId, Term]()
private val stateMap: mutable.Map[ActionInstanceId, Status] = new mutable.HashMap[ActionInstanceId, Status]()
private var callbacks: List[(ActionInstanceId, Term, Status) => Unit] = Nil
private var nextFreeId = 0
/** Check if an action is supported
*
* @return `true` if action can be dispatched by this dispatcher, `false` otherwise
*/
def supported(action: Term): Boolean
/** Dispatch an action and return a dispatch ID.
*
* @return If an action was dispatched a dispatch ID is returned wrapped in an Option as `Some(id)`.
* If the action could not be dispatched (e.g., if the dispatcher is busy and does not
* support queueing, or if the action is not supported) `None` is returned.
*/
def dispatch(action: Term): Option[ActionInstanceId]
/** Dispatch an action and wait for result. Returns only when action has `Done` or `Failed` status.
*
* @return If an action was dispatched its ID is returned wrapped in an Option as `Some(id)`.
* If the action could not be dispatched (e.g., if the dispatcher is busy and does not
* support queueing, or if the action is not supported) `None` is returned.
*/
def dispatchBlock(action: Term): Option[ActionInstanceId] = {
this.dispatch(action) match {
case Some(id) => {
while {
!this.status(id).isDone
} do {
tick
Thread.sleep(10)
}
Some(id)
}
case None => None
}
}
/**
* Attempt to cancel action (if supported). Should lead to Recalling state if Pending
* and Preempting state if Active.
*/
def cancel(id: ActionInstanceId) = {}
/** Get the status of a dispatch ID if it exists.
*
* @return If the ID exists, its latest status message is returned wrapped in an `Option`.
* Otherwise, `None` is returned.
*/
def getStatus(id: ActionInstanceId): Option[Status] = this.stateMap.get(id)
/** Get the status of a dispatch ID if it exists.
*
* @return the latest status message.
*/
def status(id: ActionInstanceId): Status = this.stateMap(id)
/**
* Get a new action instance ID
* @return the created ID
*/
protected def nextId: ActionInstanceId = {
val id = nextFreeId
nextFreeId += 1
id
}
/**
* Create a new action instance ID and set its status
* @param status initial status for newly created ID
* @return the created ID
*/
protected def nextIdWithStatus(status: Status): ActionInstanceId = {
val id = this.nextId
this.update(id, status)
id
}
/** Check if dispatcher is idle
*
* @return `true` if dispatcher is idle, `false` otherwise
*/
def idle: Boolean =
stateMap.values.forall( _.isDone )
protected def update(id: ActionInstanceId, s: Status): Unit =
this.stateMap.get(id) match {
case Some(currentState) if s != currentState =>
updateAndCallback(id, s)
case None =>
this.updateAndCallback(id, s)
case _ => {}
}
private def updateAndCallback(id: ActionInstanceId, status: Status): Unit = {
this.stateMap.put(id, status)
callbacks.foreach(f => f(id, this.actionIdMap.getOrElse(id, Sym("UNKNOWN")), status))
}
/** Register a callback function for this dispatcher. For each status change, every registered callback is called
* with the dispatch ID and the new status.
*/
def registerCallback( f: (ActionInstanceId, Term, Status) => Unit ): Unit =
callbacks = f :: callbacks
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy