xref: /DragonReach/src/manager/unit_manager/mod.rs (revision 76992bdb7f9f450492cb23e443efb1a716e86958)
1 use std::hash::{Hash, Hasher};
2 use std::{
3     collections::hash_map::DefaultHasher,
4     collections::vec_deque::VecDeque,
5     print, println,
6     process::Child,
7     sync::{Arc, Mutex, RwLock},
8     vec::Vec,
9 };
10 
11 use crate::unit::Unit;
12 use hashbrown::HashMap;
13 use lazy_static::lazy_static;
14 
15 lazy_static! {
16     // 对于启动后即使退出亦认为其为运行状态的特殊注册类Service,对于这类进程做一个标记
17     static ref FLAG_RUNNING: RwLock<Vec<usize>> = RwLock::new(Vec::new());
18 
19     // 任务等待队列,IDLE类型的service入队等待其它任务完成再执行
20     static ref IDLE_SERVIEC_DEQUE: Mutex<VecDeque<usize>> = Mutex::new(VecDeque::new());
21 
22     // id到unit的映射表,全局的Unit管理表
23     static ref ID_TO_UNIT_MAP: RwLock<HashMap<usize,Arc<Mutex<dyn Unit>>>> = RwLock::new(HashMap::new());
24 
25     // 辅助表,通过服务名映射其id
26     static ref PATH_TO_UNIT_MAP: RwLock<HashMap<u64,usize>> = RwLock::new(HashMap::new());
27 
28     // 全局运行中的Unit表
29     pub(super) static ref RUNNING_TABLE: RwLock<RunningTableManager> = RwLock::new(RunningTableManager { running_table: HashMap::new() });
30 
31     // CMD进程表,用于处理Unit的CMD派生进程(ExecStartPre等命令派生进程)
32     pub(super) static ref CMD_PROCESS_TABLE: RwLock<HashMap<u32,Mutex<Child>>> = RwLock::new(HashMap::new());
33 }
34 
35 pub struct RunningTableManager {
36     running_table: HashMap<usize, Child>,
37 }
38 
39 #[allow(dead_code)]
40 impl RunningTableManager {
41     pub fn running_table(&self) -> &HashMap<usize, Child> {
42         &self.running_table
43     }
44 
45     pub fn mut_running_table(&mut self) -> &mut HashMap<usize, Child> {
46         &mut self.running_table
47     }
48 }
49 
50 pub struct UnitManager;
51 
52 unsafe impl Sync for UnitManager {}
53 
54 #[allow(dead_code)]
55 impl UnitManager {
56     /// 插入一条path到unit_id的映射
57     pub fn insert_into_path_table(path: &str, unit: usize) {
58         let mut hasher = DefaultHasher::new();
59         path.hash(&mut hasher);
60         let hash = hasher.finish();
61         PATH_TO_UNIT_MAP.write().unwrap().insert(hash, unit);
62     }
63 
64     // 判断当前是否已经有了对应path的Unit
65     pub fn contains_path(path: &str) -> bool {
66         let mut hasher = DefaultHasher::new();
67         path.hash(&mut hasher);
68         let hash = hasher.finish();
69         PATH_TO_UNIT_MAP.read().unwrap().contains_key(&hash)
70     }
71 
72     // 通过path获取到Unit
73     pub fn get_unit_with_path(path: &str) -> Option<Arc<Mutex<dyn Unit>>> {
74         let mut hasher = DefaultHasher::new();
75         path.hash(&mut hasher);
76         let hash = hasher.finish();
77         let map = PATH_TO_UNIT_MAP.read().unwrap();
78         let id = match map.get(&hash) {
79             Some(id) => id,
80             None => {
81                 return None;
82             }
83         };
84 
85         let map = ID_TO_UNIT_MAP.read().unwrap();
86         let ret = map.get(id).cloned();
87         ret
88     }
89 
90     // 通过unit_id获取Unit
91     pub fn get_unit_with_id(id: &usize) -> Option<Arc<Mutex<dyn Unit>>> {
92         let map = ID_TO_UNIT_MAP.read().unwrap();
93         let ret = map.get(&id).cloned();
94         ret
95     }
96 
97     // 通过id获取到path
98     pub fn get_id_with_path(path: &str) -> Option<usize> {
99         let mut hasher = DefaultHasher::new();
100         path.hash(&mut hasher);
101         let hash = hasher.finish();
102         PATH_TO_UNIT_MAP.read().unwrap().get(&hash).cloned()
103     }
104 
105     // 判断该Unit是否正在运行中
106     pub fn is_running_unit(id: &usize) -> bool {
107         RUNNING_TABLE.read().unwrap().running_table.contains_key(id)
108             || !FLAG_RUNNING
109                 .read()
110                 .unwrap()
111                 .iter()
112                 .filter(|x| **x == *id)
113                 .collect::<Vec<_>>()
114                 .is_empty()
115     }
116 
117     // 向运行表中添加运行的Unit
118     pub fn push_running(unit_id: usize, p: Child) {
119         RUNNING_TABLE
120             .write()
121             .unwrap()
122             .running_table
123             .insert(unit_id, p);
124     }
125 
126     // 删除运行表中的Unit
127     pub fn remove_running(id: usize) {
128         let mut table = RUNNING_TABLE.write().unwrap();
129         table.running_table.remove(&id);
130     }
131 
132     // 向id到Unit映射表中插入数据
133     pub fn insert_unit_with_id(id: usize, unit: Arc<Mutex<dyn Unit>>) {
134         let mut map = ID_TO_UNIT_MAP.write().unwrap();
135         if !map.contains_key(&id) {
136             map.insert(id, unit);
137         }
138     }
139 
140     // 判断当前DragonReach是否拥有目标id的Unit
141     pub fn contains_id(id: &usize) -> bool {
142         ID_TO_UNIT_MAP.read().unwrap().contains_key(id)
143     }
144 
145     // 弹出一个处于IDLE状态的Service
146     pub fn pop_a_idle_service() -> Option<Arc<Mutex<dyn Unit>>> {
147         let id = IDLE_SERVIEC_DEQUE.lock().unwrap().pop_front();
148         match id {
149             Some(id) => {
150                 return Self::get_unit_with_id(&id);
151             }
152             None => {
153                 return None;
154             }
155         }
156     }
157 
158     // 添加IDLE状态的Service,将在后续调度
159     pub fn push_a_idle_service(id: usize) {
160         if !Self::contains_id(&id) {
161             return;
162         }
163         IDLE_SERVIEC_DEQUE.lock().unwrap().push_back(id);
164     }
165 
166     // 将该Unit标记为运行状态,并且后续不会对其进行运行检查
167     pub fn push_flag_running(id: usize) {
168         let mut t = FLAG_RUNNING.write().unwrap();
169         if t.contains(&id) {
170             return;
171         }
172         t.push(id);
173     }
174 
175     // 当前运行的Unit数
176     pub fn running_count() -> usize {
177         return RUNNING_TABLE.read().unwrap().running_table.len();
178     }
179 
180     // 向Cmd运行表中添加
181     pub fn push_cmd_proc(proc: Child) {
182         CMD_PROCESS_TABLE
183             .write()
184             .unwrap()
185             .insert(proc.id(), Mutex::new(proc));
186     }
187 
188     // 删除对应cmd的进程
189     pub fn remove_cmd_proc(id: u32) {
190         CMD_PROCESS_TABLE.write().unwrap().remove(&id);
191     }
192 
193     // 弹出指定id的cmd进程
194     pub fn pop_cmd_proc(id: u32) -> Option<Mutex<Child>> {
195         CMD_PROCESS_TABLE.write().unwrap().remove(&id)
196     }
197 
198     // 初始化各Unit的依赖关系,此方法只需在解析完系统Unit文件后调用一次
199     pub fn init_units_dependencies() {
200         let manager = ID_TO_UNIT_MAP.write().unwrap();
201 
202         // 处理before段,将before段的Unit添加此Unit为After
203         for (id, unit) in manager.iter() {
204             let mut unit = unit.lock().unwrap();
205             let before = unit.mut_unit_base().unit_part().before();
206             for rid in before {
207                 let req = UnitManager::get_unit_with_id(rid).unwrap();
208                 let mut req = req.lock().unwrap();
209                 req.mut_unit_base().mut_unit_part().push_after_unit(*id);
210             }
211         }
212 
213         for (id, unit) in manager.iter() {
214             let mut unit = unit.lock().unwrap();
215 
216             // 处理binds_to段
217             let binds_to = unit.mut_unit_base().unit_part().binds_to();
218             for rid in binds_to {
219                 let req = UnitManager::get_unit_with_id(rid).unwrap();
220                 let mut req = req.lock().unwrap();
221                 req.mut_unit_base().mut_unit_part().push_be_binded_by(*id);
222             }
223 
224             // 处理part_of段
225             let part_of = unit.mut_unit_base().unit_part().part_of();
226             for rid in part_of {
227                 let req = UnitManager::get_unit_with_id(rid).unwrap();
228                 let mut req = req.lock().unwrap();
229                 req.mut_unit_base().mut_unit_part().push_be_binded_by(*id);
230             }
231         }
232     }
233 
234     /// ## 杀死Unit进程
235     pub fn kill_running(id: usize) {
236         if Self::is_running_unit(&id) {
237             let mut running_manager = RUNNING_TABLE.write().unwrap();
238             let unit = running_manager.running_table.get_mut(&id).unwrap();
239             let _ = unit.kill();
240             println!("kill:{}", id);
241             running_manager.running_table.remove(&id);
242         }
243     }
244 }
245