1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright (c) Sean Lawlor
//
// This source code is licensed under both the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree.

//! Supervision management logic
//!
//! Supervision is a special notion of "ownership" over actors by a parent (supervisor).
//! Supervisors are responsible for the lifecycle of a child actor such that they get notified
//! when a child actor starts, stops, or panics (when possible). The supervisor can then decide
//! how to handle the event. Should it restart the actor, leave it dead, potentially die itself
//! notifying the supervisor's supervisor? That's up to the implementation of the [super::Actor]
//!
//! This is currently an initial implementation of [Erlang supervisors](https://www.erlang.org/doc/man/supervisor.html)
//! which will be expanded upon as the library develops. Next in line is likely supervision strategies
//! for automatic restart routines.

use std::sync::{
    atomic::{AtomicU64, Ordering},
    Arc, RwLock,
};

use dashmap::DashMap;

use super::{actor_cell::ActorCell, messages::SupervisionEvent};
use crate::ActorId;

/// A supervision tree
#[derive(Default)]
pub struct SupervisionTree {
    children: DashMap<ActorId, (u64, ActorCell)>,
    supervisor: Arc<RwLock<Option<ActorCell>>>,
    monitors: DashMap<ActorId, ActorCell>,
    monitored: DashMap<ActorId, ActorCell>,
    start_order: AtomicU64,
}

impl SupervisionTree {
    /// Push a child into the tere
    pub fn insert_child(&self, child: ActorCell) {
        let start_order = self.start_order.fetch_add(1, Ordering::Relaxed);
        self.children.insert(child.get_id(), (start_order, child));
    }

    /// Remove a specific actor from the supervision tree (e.g. actor died)
    pub fn remove_child(&self, child: ActorId) {
        match self.children.entry(child) {
            dashmap::mapref::entry::Entry::Occupied(item) => {
                item.remove();
            }
            dashmap::mapref::entry::Entry::Vacant(_) => {}
        }
    }

    /// Push a parent into the tere
    pub fn set_supervisor(&self, parent: ActorCell) {
        *(self.supervisor.write().unwrap()) = Some(parent);
    }

    /// Remove a specific actor from the supervision tree (e.g. actor died)
    pub fn clear_supervisor(&self) {
        *(self.supervisor.write().unwrap()) = None;
    }

    /// Set a monitor of this supervision tree
    pub fn set_monitor(&self, monitor: ActorCell) {
        self.monitors.insert(monitor.get_id(), monitor);
    }

    /// Mark that this actor is monitoring some other actors
    pub fn mark_monitored(&self, who: ActorCell) {
        self.monitored.insert(who.get_id(), who);
    }

    /// Mark that this actor is no longer monitoring some other actors
    pub fn unmark_monitored(&self, who: ActorId) {
        self.monitored.remove(&who);
    }

    /// Remove a specific monitor from the supervision tree
    pub fn remove_monitor(&self, monitor: ActorId) {
        self.monitors.remove(&monitor);
    }

    /// Get the [ActorCell]s of the monitored actors this actor monitors
    pub fn monitored_actors(&self) -> Vec<ActorCell> {
        self.monitored.iter().map(|a| a.value().clone()).collect()
    }

    /// Terminate all your supervised children and unlink them
    /// from the supervision tree since the supervisor is shutting down
    /// and can't deal with superivison events anyways
    pub fn terminate_all_children(&self) {
        let cells = self
            .children
            .iter()
            .map(|r| r.1.clone())
            .collect::<Vec<_>>();
        // wipe local children to prevent double-link problems
        self.children.clear();

        for cell in cells {
            cell.terminate();
            cell.clear_supervisor();
        }
    }

    /// Determine if the specified actor is a parent of this actor
    pub fn is_child_of(&self, id: ActorId) -> bool {
        if let Some(parent) = &*(self.supervisor.read().unwrap()) {
            parent.get_id() == id
        } else {
            false
        }
    }

    /// Send a notification to the supervisor and monitors.
    ///
    /// CAVEAT: Monitors get notified first, in order to save an unnecessary
    /// clone if there are no monitors.
    pub fn notify_supervisor_and_monitors(&self, evt: SupervisionEvent) {
        for monitor in self.monitors.iter() {
            let _ = monitor.value().send_supervisor_evt(evt.clone_no_data());
        }
        if let Some(parent) = &*(self.supervisor.read().unwrap()) {
            let _ = parent.send_supervisor_evt(evt);
        }
    }

    /// Retrieve the number of supervised children
    #[cfg(test)]
    pub fn get_num_children(&self) -> usize {
        self.children.len()
    }

    /// Retrieve the number of supervised children
    #[cfg(test)]
    pub fn get_num_parents(&self) -> usize {
        usize::from(self.supervisor.read().unwrap().is_some())
    }
}