1use eva_common::prelude::*;
2use parking_lot::Mutex;
3use std::collections::hash_map::Entry;
4use std::collections::HashMap;
5use uuid::Uuid;
6
7pub struct Actt {
9 pending_by_oid: HashMap<OID, Mutex<HashMap<Uuid, PendingAction>>>,
10 pending_by_uuid: Mutex<HashMap<Uuid, PendingAction>>,
11}
12
13impl Actt {
14 pub fn new(oids: &[&OID]) -> Self {
18 let mut pending_by_oid = HashMap::new();
19 for oid in oids {
20 pending_by_oid.insert((*oid).clone(), <_>::default());
21 }
22 Self {
23 pending_by_oid,
24 pending_by_uuid: <_>::default(),
25 }
26 }
27 #[inline]
29 pub fn register(&mut self, oid: &OID) {
30 self.pending_by_oid.insert(oid.clone(), <_>::default());
31 }
32 #[inline]
34 pub fn unregister(&mut self, oid: &OID) {
35 self.pending_by_oid.remove(oid);
36 }
37 pub fn append(&self, oid: &OID, uuid: Uuid) -> EResult<()> {
43 if let Some(actions) = self.pending_by_oid.get(oid) {
44 let mut a = actions.lock();
45 let mut a_uuid = self.pending_by_uuid.lock();
46 if let Entry::Vacant(o) = a.entry(uuid) {
47 o.insert(PendingAction::new());
48 a_uuid.insert(uuid, PendingAction::new());
49 Ok(())
50 } else {
51 Err(Error::core("duplicate action UUID"))
52 }
53 } else {
54 Err(Error::core(format!(
55 "{} is not in PENDING_ACTIONS map",
56 oid
57 )))
58 }
59 }
60 pub fn remove(&self, oid: &OID, uuid: &Uuid) -> EResult<bool> {
73 if let Some(actions) = self.pending_by_oid.get(oid) {
74 let mut a = actions.lock();
75 let mut a_uuid = self.pending_by_uuid.lock();
76 if let Some(v) = a.remove(uuid) {
77 if let Some(v_u) = a_uuid.remove(uuid) {
78 Ok(v.is_active() && v_u.is_active())
79 } else {
80 Ok(v.is_active())
81 }
82 } else {
83 Err(Error::not_found("action not found in PENDING_ACTIONS map"))
84 }
85 } else {
86 Err(Error::core(format!(
87 "{} is not in PENDING_ACTIONS map",
88 oid
89 )))
90 }
91 }
92 pub fn is_active(&self, oid: &OID, uuid: &Uuid) -> EResult<bool> {
98 if let Some(actions) = self.pending_by_oid.get(oid) {
99 let a = actions.lock();
100 let a_uuid = self.pending_by_uuid.lock();
101 if let Some(v) = a.get(uuid) {
102 if let Some(v_u) = a_uuid.get(uuid) {
103 Ok(v.is_active() && v_u.is_active())
104 } else {
105 Ok(v.is_active())
106 }
107 } else {
108 Err(Error::not_found("action not found in PENDING_ACTIONS map"))
109 }
110 } else {
111 Err(Error::core(format!(
112 "{} is not in PENDING_ACTIONS map",
113 oid
114 )))
115 }
116 }
117 pub fn mark_terminated(&self, uuid: &Uuid) -> EResult<()> {
123 let mut a_uuid = self.pending_by_uuid.lock();
124 if let Some(v_u) = a_uuid.get_mut(uuid) {
125 v_u.cancel();
126 Ok(())
127 } else {
128 Err(Error::not_found(format!("action {} not found", uuid)))
129 }
130 }
131 pub fn mark_killed(&self, oid: &OID) -> EResult<()> {
137 if let Some(actions) = self.pending_by_oid.get(oid) {
138 for a in actions.lock().values_mut() {
139 a.cancel();
140 }
141 Ok(())
142 } else {
143 Err(Error::core(format!(
144 "{} is not in PENDING_ACTIONS map",
145 oid
146 )))
147 }
148 }
149}
150
151struct PendingAction {
152 active: bool,
153}
154
155impl PendingAction {
156 #[inline]
157 fn new() -> Self {
158 Self { active: true }
159 }
160 #[inline]
161 fn is_active(&self) -> bool {
162 self.active
163 }
164 #[inline]
165 fn cancel(&mut self) {
166 self.active = false;
167 }
168}