2021-07-08 22:04:11 +00:00
|
|
|
use futures::Future;
|
2021-07-06 18:56:36 +00:00
|
|
|
pub use futures::future::BoxFuture;
|
|
|
|
|
|
|
|
pub use std::future::ready;
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
use super::ActorId;
|
|
|
|
use super::schemas::internal_protocol::*;
|
|
|
|
use super::error::Error;
|
2021-07-08 22:04:11 +00:00
|
|
|
use super::error::error;
|
2021-07-03 07:03:52 +00:00
|
|
|
|
|
|
|
use preserves::value::Domain;
|
|
|
|
use preserves::value::IOValue;
|
|
|
|
use preserves::value::Map;
|
|
|
|
use preserves::value::NestedValue;
|
|
|
|
|
|
|
|
use std::boxed::Box;
|
|
|
|
use std::collections::hash_map::HashMap;
|
|
|
|
use std::sync::Arc;
|
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
|
|
|
|
|
|
use tokio::select;
|
|
|
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender, UnboundedReceiver};
|
|
|
|
use tokio_util::sync::CancellationToken;
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
use tracing;
|
|
|
|
use tracing::Instrument;
|
|
|
|
|
|
|
|
pub type Assertion = super::schemas::dataspace::_Any;
|
|
|
|
pub use super::schemas::internal_protocol::Handle;
|
|
|
|
pub use super::schemas::internal_protocol::Oid;
|
2021-07-03 07:03:52 +00:00
|
|
|
|
|
|
|
pub type ActorResult = Result<(), Error>;
|
|
|
|
pub type ActorHandle = tokio::task::JoinHandle<ActorResult>;
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
pub trait Entity: Send {
|
2021-07-03 07:03:52 +00:00
|
|
|
fn assert(&mut self, _t: &mut Activation, _a: Assertion, _h: Handle) -> ActorResult {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn retract(&mut self, _t: &mut Activation, _h: Handle) -> ActorResult {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn message(&mut self, _t: &mut Activation, _m: Assertion) -> ActorResult {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn sync(&mut self, t: &mut Activation, peer: Arc<Ref>) -> ActorResult {
|
2021-07-08 22:04:11 +00:00
|
|
|
t.message(&peer, Assertion::new(true));
|
2021-07-03 07:03:52 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2021-07-06 18:56:36 +00:00
|
|
|
fn turn_end(&mut self, _t: &mut Activation) -> ActorResult {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn exit_hook(&mut self, _t: &mut Activation, _exit_status: &ActorResult) -> BoxFuture<ActorResult> {
|
|
|
|
Box::pin(ready(Ok(())))
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type OutboundAssertions = Map<Handle, Arc<Ref>>;
|
|
|
|
|
|
|
|
// This is what other implementations call a "Turn", renamed here to
|
|
|
|
// avoid conflicts with schemas::internal_protocol::Turn.
|
|
|
|
pub struct Activation<'activation> {
|
2021-07-06 18:56:36 +00:00
|
|
|
pub actor: &'activation mut Actor,
|
2021-07-03 07:03:52 +00:00
|
|
|
queues: HashMap<ActorId, Vec<(Arc<Ref>, Event)>>,
|
2021-07-06 18:56:36 +00:00
|
|
|
turn_end_revisit_flag: bool,
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
#[derive(Debug)]
|
2021-07-03 07:03:52 +00:00
|
|
|
enum SystemMessage {
|
|
|
|
Release,
|
|
|
|
ReleaseOid(Oid),
|
|
|
|
Turn(Turn),
|
|
|
|
Crash(Error),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Mailbox {
|
|
|
|
pub actor_id: ActorId,
|
|
|
|
pub mailbox_id: u64,
|
|
|
|
tx: UnboundedSender<SystemMessage>,
|
2021-07-06 18:56:36 +00:00
|
|
|
queue_depth: Arc<AtomicUsize>,
|
|
|
|
mailbox_count: Arc<AtomicUsize>,
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Actor {
|
2021-07-06 18:56:36 +00:00
|
|
|
actor_id: ActorId,
|
|
|
|
tx: UnboundedSender<SystemMessage>,
|
2021-07-03 07:03:52 +00:00
|
|
|
rx: UnboundedReceiver<SystemMessage>,
|
2021-07-06 18:56:36 +00:00
|
|
|
queue_depth: Arc<AtomicUsize>,
|
|
|
|
mailbox_count: Arc<AtomicUsize>,
|
|
|
|
outbound_assertions: OutboundAssertions,
|
|
|
|
oid_map: Map<Oid, Box<dyn Entity + Send>>,
|
|
|
|
next_task_id: u64,
|
|
|
|
linked_tasks: Map<u64, CancellationToken>,
|
|
|
|
exit_hooks: Vec<Oid>,
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
#[derive(PartialEq, Eq, Hash, PartialOrd, Ord)]
|
2021-07-03 07:03:52 +00:00
|
|
|
pub struct Ref {
|
|
|
|
pub relay: Mailbox,
|
|
|
|
pub target: Oid,
|
|
|
|
/* TODO: attenuation */
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
preserves_schema::support::lazy_static! {
|
|
|
|
pub static ref INERT_REF: Arc<Ref> = {
|
|
|
|
struct InertEntity;
|
|
|
|
impl crate::actor::Entity for InertEntity {}
|
|
|
|
let mut ac = Actor::new();
|
|
|
|
let e = ac.create(InertEntity);
|
|
|
|
ac.boot(tracing::info_span!(parent: None, "INERT_REF"),
|
|
|
|
|t| Box::pin(ready(Ok(t.actor.shutdown()))));
|
|
|
|
e
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
impl<'activation> Activation<'activation> {
|
|
|
|
pub fn for_actor(actor: &'activation mut Actor) -> Self {
|
|
|
|
Activation {
|
2021-07-06 18:56:36 +00:00
|
|
|
actor,
|
2021-07-03 07:03:52 +00:00
|
|
|
queues: HashMap::new(),
|
2021-07-06 18:56:36 +00:00
|
|
|
turn_end_revisit_flag: false,
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
pub fn assert<M>(&mut self, r: &Arc<Ref>, a: M) -> Handle where M: Into<Assertion> {
|
2021-07-03 07:03:52 +00:00
|
|
|
let handle = crate::next_handle();
|
2021-07-08 22:04:11 +00:00
|
|
|
self.queue_for(r).push((Arc::clone(r), Event::Assert(Box::new(
|
2021-07-03 07:03:52 +00:00
|
|
|
Assert { assertion: Assertion(a.into()), handle: handle.clone() }))));
|
2021-07-08 22:04:11 +00:00
|
|
|
self.actor.outbound_assertions.insert(handle.clone(), Arc::clone(r));
|
2021-07-03 07:03:52 +00:00
|
|
|
handle
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn retract(&mut self, handle: Handle) {
|
2021-07-06 18:56:36 +00:00
|
|
|
if let Some(r) = self.actor.outbound_assertions.remove(&handle) {
|
2021-07-03 07:03:52 +00:00
|
|
|
self.retract_known_ref(r, handle)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn retract_known_ref(&mut self, r: Arc<Ref>, handle: Handle) {
|
|
|
|
self.queue_for(&r).push((r, Event::Retract(Box::new(Retract { handle }))));
|
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
pub fn message<M>(&mut self, r: &Arc<Ref>, m: M) where M: Into<Assertion> {
|
|
|
|
self.queue_for(r).push((Arc::clone(r), Event::Message(Box::new(
|
2021-07-03 07:03:52 +00:00
|
|
|
Message { body: Assertion(m.into()) }))))
|
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
pub fn sync(&mut self, r: &Arc<Ref>, peer: Arc<Ref>) {
|
|
|
|
self.queue_for(r).push((Arc::clone(r), Event::Sync(Box::new(Sync { peer }))));
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
pub fn set_turn_end_flag(&mut self) {
|
|
|
|
self.turn_end_revisit_flag = true;
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
fn queue_for(&mut self, r: &Arc<Ref>) -> &mut Vec<(Arc<Ref>, Event)> {
|
|
|
|
self.queues.entry(r.relay.actor_id).or_default()
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
fn deliver(&mut self) {
|
2021-07-03 07:03:52 +00:00
|
|
|
for (_actor_id, turn) in std::mem::take(&mut self.queues).into_iter() {
|
|
|
|
if turn.len() == 0 { continue; }
|
|
|
|
let first_ref = Arc::clone(&turn[0].0);
|
|
|
|
let target = &first_ref.relay;
|
|
|
|
target.send(Turn(turn.into_iter().map(
|
|
|
|
|(r, e)| TurnEvent { oid: r.target.clone(), event: e }).collect()));
|
|
|
|
}
|
|
|
|
}
|
2021-07-06 18:56:36 +00:00
|
|
|
|
|
|
|
fn with_oid<R,
|
|
|
|
Ff: FnOnce(&mut Self) -> R,
|
|
|
|
Fs: FnOnce(&mut Self, &mut Box<dyn Entity + Send>) -> R>(
|
|
|
|
&mut self,
|
|
|
|
oid: &Oid,
|
|
|
|
kf: Ff,
|
|
|
|
ks: Fs,
|
|
|
|
) -> R {
|
|
|
|
match self.actor.oid_map.remove_entry(&oid) {
|
|
|
|
None => kf(self),
|
|
|
|
Some((k, mut e)) => {
|
|
|
|
let result = ks(self, &mut e);
|
|
|
|
self.actor.oid_map.insert(k, e);
|
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'activation> Drop for Activation<'activation> {
|
|
|
|
fn drop(&mut self) {
|
2021-07-08 22:04:11 +00:00
|
|
|
if self.turn_end_revisit_flag {
|
|
|
|
panic!("turn_end_revisit_flag is set");
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
self.deliver()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Mailbox {
|
|
|
|
pub fn send(&self, t: Turn) {
|
|
|
|
let _ = self.tx.send(SystemMessage::Turn(t));
|
|
|
|
self.queue_depth.fetch_add(1, Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for Mailbox {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
write!(f, "#<Mailbox {}:{}>", self.actor_id, self.mailbox_id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::hash::Hash for Mailbox {
|
|
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
self.mailbox_id.hash(state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for Mailbox {}
|
|
|
|
impl PartialEq for Mailbox {
|
|
|
|
fn eq(&self, other: &Mailbox) -> bool {
|
|
|
|
self.mailbox_id == other.mailbox_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for Mailbox {
|
|
|
|
fn cmp(&self, other: &Mailbox) -> std::cmp::Ordering {
|
|
|
|
return self.mailbox_id.cmp(&other.mailbox_id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for Mailbox {
|
|
|
|
fn partial_cmp(&self, other: &Mailbox) -> Option<std::cmp::Ordering> {
|
|
|
|
return Some(self.cmp(&other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Clone for Mailbox {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
let Mailbox { actor_id, tx, queue_depth, mailbox_count, .. } = self;
|
2021-07-06 18:56:36 +00:00
|
|
|
let _old_refcount = mailbox_count.fetch_add(1, Ordering::SeqCst);
|
|
|
|
let new_mailbox = Mailbox {
|
2021-07-03 07:03:52 +00:00
|
|
|
actor_id: *actor_id,
|
|
|
|
mailbox_id: crate::next_mailbox_id(),
|
|
|
|
tx: tx.clone(),
|
|
|
|
queue_depth: Arc::clone(queue_depth),
|
|
|
|
mailbox_count: Arc::clone(mailbox_count),
|
2021-07-06 18:56:36 +00:00
|
|
|
};
|
2021-07-08 22:04:11 +00:00
|
|
|
// tracing::trace!(old_mailbox = debug(&self),
|
|
|
|
// new_mailbox = debug(&new_mailbox),
|
|
|
|
// new_mailbox_refcount = debug(_old_refcount + 1));
|
2021-07-06 18:56:36 +00:00
|
|
|
new_mailbox
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Mailbox {
|
|
|
|
fn drop(&mut self) {
|
2021-07-06 18:56:36 +00:00
|
|
|
let old_mailbox_refcount = self.mailbox_count.fetch_sub(1, Ordering::SeqCst);
|
|
|
|
let new_mailbox_refcount = old_mailbox_refcount - 1;
|
2021-07-08 22:04:11 +00:00
|
|
|
// tracing::trace!(mailbox = debug(&self),
|
|
|
|
// new_mailbox_refcount);
|
2021-07-06 18:56:36 +00:00
|
|
|
if new_mailbox_refcount == 0 {
|
2021-07-03 07:03:52 +00:00
|
|
|
let _ = self.tx.send(SystemMessage::Release);
|
|
|
|
()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Actor {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
let (tx, rx) = unbounded_channel();
|
2021-07-06 18:56:36 +00:00
|
|
|
let actor_id = crate::next_actor_id();
|
2021-07-08 22:04:11 +00:00
|
|
|
// tracing::trace!(id = actor_id, "Actor::new");
|
2021-07-03 07:03:52 +00:00
|
|
|
Actor {
|
2021-07-06 18:56:36 +00:00
|
|
|
actor_id,
|
|
|
|
tx,
|
2021-07-03 07:03:52 +00:00
|
|
|
rx,
|
2021-07-06 18:56:36 +00:00
|
|
|
queue_depth: Arc::new(AtomicUsize::new(0)),
|
|
|
|
mailbox_count: Arc::new(AtomicUsize::new(0)),
|
2021-07-03 07:03:52 +00:00
|
|
|
outbound_assertions: Map::new(),
|
|
|
|
oid_map: Map::new(),
|
|
|
|
next_task_id: 0,
|
|
|
|
linked_tasks: Map::new(),
|
2021-07-06 18:56:36 +00:00
|
|
|
exit_hooks: Vec::new(),
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
pub fn create_and_start<E: Entity + Send + 'static>(name: tracing::Span, e: E) -> Arc<Ref> {
|
|
|
|
Self::create_and_start_rec(name, e, |_, _, _| ())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn create_and_start_rec<E: Entity + Send + 'static,
|
|
|
|
F: FnOnce(&mut Self, &mut E, &Arc<Ref>) -> ()>(
|
|
|
|
name: tracing::Span,
|
|
|
|
e: E,
|
|
|
|
f: F,
|
|
|
|
) -> Arc<Ref> {
|
|
|
|
let mut ac = Self::new();
|
|
|
|
let r = ac.create_rec(e, f);
|
|
|
|
ac.start(name);
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
pub fn id(&self) -> ActorId {
|
2021-07-06 18:56:36 +00:00
|
|
|
self.actor_id
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mailbox(&mut self) -> Mailbox {
|
|
|
|
let _old_refcount = self.mailbox_count.fetch_add(1, Ordering::SeqCst);
|
|
|
|
let new_mailbox = Mailbox {
|
|
|
|
actor_id: self.actor_id,
|
|
|
|
mailbox_id: crate::next_mailbox_id(),
|
|
|
|
tx: self.tx.clone(),
|
|
|
|
queue_depth: Arc::clone(&self.queue_depth),
|
|
|
|
mailbox_count: Arc::clone(&self.mailbox_count),
|
|
|
|
};
|
2021-07-08 22:04:11 +00:00
|
|
|
// tracing::trace!(new_mailbox = debug(&new_mailbox),
|
|
|
|
// new_mailbox_refcount = debug(_old_refcount + 1));
|
2021-07-06 18:56:36 +00:00
|
|
|
new_mailbox
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn shutdown(&mut self) {
|
|
|
|
let _ = self.tx.send(SystemMessage::Release);
|
|
|
|
()
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn create<E: Entity + Send + 'static>(&mut self, e: E) -> Arc<Ref> {
|
2021-07-08 22:04:11 +00:00
|
|
|
self.create_rec(e, |_, _, _| ())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn create_rec<E: Entity + Send + 'static,
|
|
|
|
F: FnOnce(&mut Self, &mut E, &Arc<Ref>) -> ()>(
|
|
|
|
&mut self,
|
|
|
|
mut e: E,
|
|
|
|
f: F,
|
|
|
|
) -> Arc<Ref> {
|
|
|
|
let oid = crate::next_oid();
|
|
|
|
let r = Arc::new(Ref { relay: self.mailbox(), target: oid.clone() });
|
|
|
|
f(self, &mut e, &r);
|
|
|
|
self.oid_map.insert(oid, Box::new(e));
|
|
|
|
r
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
pub fn boot<F: 'static + Send + for<'a> FnOnce(&'a mut Activation) -> BoxFuture<'a, ActorResult>>(
|
2021-07-03 07:03:52 +00:00
|
|
|
mut self,
|
|
|
|
name: tracing::Span,
|
|
|
|
boot: F,
|
|
|
|
) -> ActorHandle {
|
2021-07-08 22:04:11 +00:00
|
|
|
name.record("actor_id", &self.id());
|
2021-07-03 07:03:52 +00:00
|
|
|
tokio::spawn(async move {
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::trace!("start");
|
2021-07-06 18:56:36 +00:00
|
|
|
let result = self.run(boot).await;
|
|
|
|
{
|
|
|
|
let mut t = Activation::for_actor(&mut self);
|
|
|
|
for oid in std::mem::take(&mut t.actor.exit_hooks) {
|
|
|
|
match t.actor.oid_map.remove_entry(&oid) {
|
|
|
|
None => (),
|
|
|
|
Some((k, mut e)) => {
|
|
|
|
if let Err(err) = e.exit_hook(&mut t, &result).await {
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::error!(err = debug(err),
|
|
|
|
oid = debug(oid),
|
|
|
|
"error in exit hook");
|
2021-07-06 18:56:36 +00:00
|
|
|
}
|
|
|
|
t.actor.oid_map.insert(k, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
match &result {
|
2021-07-08 22:04:11 +00:00
|
|
|
Ok(()) => {
|
|
|
|
tracing::trace!("normal stop");
|
|
|
|
()
|
|
|
|
}
|
|
|
|
Err(e) => tracing::error!("error stop: {}", e),
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
result
|
|
|
|
}.instrument(name))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn start(self, name: tracing::Span) -> ActorHandle {
|
2021-07-06 18:56:36 +00:00
|
|
|
self.boot(name, |_ac| Box::pin(ready(Ok(()))))
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
async fn run<F: 'static + Send + for<'a> FnOnce(&'a mut Activation) -> BoxFuture<'a, ActorResult>>(
|
2021-07-06 18:56:36 +00:00
|
|
|
&mut self,
|
|
|
|
boot: F,
|
|
|
|
) -> ActorResult {
|
2021-07-08 22:04:11 +00:00
|
|
|
let _id = self.id();
|
|
|
|
// tracing::trace!(_id, "boot");
|
|
|
|
boot(&mut Activation::for_actor(self)).await?;
|
|
|
|
// tracing::trace!(_id, "run");
|
2021-07-03 07:03:52 +00:00
|
|
|
loop {
|
|
|
|
match self.rx.recv().await {
|
|
|
|
None =>
|
2021-07-08 22:04:11 +00:00
|
|
|
Err(error("Unexpected channel close", _Any::new(false)))?,
|
2021-07-03 07:03:52 +00:00
|
|
|
Some(m) => {
|
2021-07-08 22:04:11 +00:00
|
|
|
let should_stop = self.handle(m).await?;
|
|
|
|
if should_stop {
|
2021-07-03 07:03:52 +00:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
// We would have a loop calling try_recv until it answers "no more at
|
|
|
|
// present" here, to avoid decrementing queue_depth for every message
|
|
|
|
// (instead zeroing it on queue empty - it only needs to be approximate),
|
|
|
|
// but try_recv has been removed from mpsc at the time of writing. See
|
2021-07-08 22:04:11 +00:00
|
|
|
// https://github.com/tokio-rs/tokio/issues/3350 . (***)
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
pub fn add_exit_hook(&mut self, oid: &Oid) {
|
|
|
|
self.exit_hooks.push(oid.clone())
|
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
async fn handle(&mut self, m: SystemMessage) -> Result<bool, Error> {
|
2021-07-03 07:03:52 +00:00
|
|
|
match m {
|
2021-07-08 22:04:11 +00:00
|
|
|
SystemMessage::Release => {
|
|
|
|
tracing::trace!("SystemMessage::Release");
|
|
|
|
Ok(true)
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
SystemMessage::ReleaseOid(oid) => {
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::trace!("SystemMessage::ReleaseOid({:?})", &oid);
|
2021-07-03 07:03:52 +00:00
|
|
|
self.oid_map.remove(&oid);
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
SystemMessage::Turn(Turn(events)) => {
|
2021-07-06 18:56:36 +00:00
|
|
|
let mut t = Activation::for_actor(self);
|
|
|
|
let mut revisit_oids = Vec::new();
|
2021-07-03 07:03:52 +00:00
|
|
|
for TurnEvent { oid, event } in events.into_iter() {
|
2021-07-06 18:56:36 +00:00
|
|
|
t.with_oid(&oid, |_| Ok(()), |t, e| match event {
|
|
|
|
Event::Assert(b) => {
|
|
|
|
let Assert { assertion: Assertion(assertion), handle } = *b;
|
|
|
|
e.assert(t, assertion, handle)
|
|
|
|
}
|
|
|
|
Event::Retract(b) => {
|
|
|
|
let Retract { handle } = *b;
|
|
|
|
e.retract(t, handle)
|
|
|
|
}
|
|
|
|
Event::Message(b) => {
|
|
|
|
let Message { body: Assertion(body) } = *b;
|
|
|
|
e.message(t, body)
|
|
|
|
}
|
|
|
|
Event::Sync(b) => {
|
|
|
|
let Sync { peer } = *b;
|
|
|
|
e.sync(t, peer)
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
2021-07-06 18:56:36 +00:00
|
|
|
})?;
|
|
|
|
if t.turn_end_revisit_flag {
|
|
|
|
t.turn_end_revisit_flag = false;
|
|
|
|
revisit_oids.push(oid);
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-08 22:04:11 +00:00
|
|
|
for oid in revisit_oids.into_iter() {
|
2021-07-06 18:56:36 +00:00
|
|
|
t.with_oid(&oid, |_| Ok(()), |t, e| e.turn_end(t))?;
|
|
|
|
}
|
2021-07-08 22:04:11 +00:00
|
|
|
t.actor.queue_depth.fetch_sub(1, Ordering::Relaxed); // see (***) in this file
|
2021-07-03 07:03:52 +00:00
|
|
|
Ok(false)
|
|
|
|
}
|
2021-07-08 22:04:11 +00:00
|
|
|
SystemMessage::Crash(e) => {
|
|
|
|
tracing::trace!("SystemMessage::Crash({:?})", &e);
|
2021-07-03 07:03:52 +00:00
|
|
|
Err(e)?
|
2021-07-08 22:04:11 +00:00
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
pub fn linked_task<F: futures::Future<Output = ActorResult> + Send + 'static>(
|
2021-07-03 07:03:52 +00:00
|
|
|
&mut self,
|
|
|
|
name: tracing::Span,
|
|
|
|
boot: F,
|
2021-07-08 22:04:11 +00:00
|
|
|
) {
|
2021-07-06 18:56:36 +00:00
|
|
|
let mailbox = self.mailbox();
|
2021-07-03 07:03:52 +00:00
|
|
|
let token = CancellationToken::new();
|
|
|
|
let task_id = self.next_task_id;
|
|
|
|
self.next_task_id += 1;
|
2021-07-08 22:04:11 +00:00
|
|
|
name.record("task_id", &task_id);
|
|
|
|
{
|
2021-07-03 07:03:52 +00:00
|
|
|
let token = token.clone();
|
|
|
|
tokio::spawn(async move {
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::trace!(task_id, "linked task start");
|
2021-07-03 07:03:52 +00:00
|
|
|
select! {
|
2021-07-06 18:56:36 +00:00
|
|
|
_ = token.cancelled() => {
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::trace!(task_id, "linked task cancelled");
|
2021-07-06 18:56:36 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
result = boot => {
|
|
|
|
match &result {
|
2021-07-08 22:04:11 +00:00
|
|
|
Ok(()) => {
|
|
|
|
tracing::trace!(task_id, "linked task normal stop");
|
|
|
|
()
|
|
|
|
}
|
2021-07-06 18:56:36 +00:00
|
|
|
Err(e) => {
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::error!(task_id, "linked task error: {}", e);
|
2021-07-06 18:56:36 +00:00
|
|
|
let _ = mailbox.tx.send(SystemMessage::Crash(e.clone()));
|
|
|
|
()
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
2021-07-06 18:56:36 +00:00
|
|
|
result
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-08 22:04:11 +00:00
|
|
|
}.instrument(name));
|
|
|
|
}
|
2021-07-03 07:03:52 +00:00
|
|
|
self.linked_tasks.insert(task_id, token);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Actor {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
for (_task_id, token) in std::mem::take(&mut self.linked_tasks).into_iter() {
|
|
|
|
token.cancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
let to_clear = std::mem::take(&mut self.outbound_assertions);
|
|
|
|
let mut t = Activation::for_actor(self);
|
|
|
|
for (handle, r) in to_clear.into_iter() {
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::trace!(h = debug(&handle), "retract on termination");
|
2021-07-03 07:03:52 +00:00
|
|
|
t.retract_known_ref(r, handle);
|
|
|
|
}
|
2021-07-08 22:04:11 +00:00
|
|
|
tracing::trace!("Actor::drop");
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
impl Ref {
|
|
|
|
pub fn external_event(&self, event: Event) {
|
|
|
|
self.relay.send(Turn(vec![TurnEvent { oid: self.target.clone(), event }]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 22:04:11 +00:00
|
|
|
impl std::fmt::Debug for Ref {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
write!(f, "⌜{}:{}⌝", self.relay.actor_id, self.target.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 07:03:52 +00:00
|
|
|
impl Drop for Ref {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
let _ = self.relay.tx.send(SystemMessage::ReleaseOid(self.target.clone()));
|
|
|
|
()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
impl Domain for Ref {}
|
|
|
|
|
|
|
|
impl std::convert::TryFrom<&IOValue> for Ref {
|
|
|
|
type Error = preserves_schema::support::ParseError;
|
|
|
|
fn try_from(_v: &IOValue) -> Result<Self, Self::Error> {
|
|
|
|
panic!("Attempted to serialize Ref via IOValue");
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-06 18:56:36 +00:00
|
|
|
impl std::convert::From<&Ref> for IOValue {
|
|
|
|
fn from(_v: &Ref) -> IOValue {
|
|
|
|
panic!("Attempted to deserialize Ref via IOValue");
|
2021-07-03 07:03:52 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-08 22:04:11 +00:00
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! name {
|
|
|
|
() => {tracing::info_span!(actor_id = tracing::field::Empty,
|
|
|
|
task_id = tracing::field::Empty,
|
|
|
|
oid = tracing::field::Empty)};
|
|
|
|
($($item:tt)*) => {tracing::info_span!($($item)*,
|
|
|
|
actor_id = tracing::field::Empty,
|
|
|
|
task_id = tracing::field::Empty,
|
|
|
|
oid = tracing::field::Empty)}
|
|
|
|
}
|