xref: /DragonReach/src/manager/unit_manager/mod.rs (revision ea330323f68db57353801959d67cbd8e0031aa18)
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 impl RunningTableManager {
40     pub fn running_table(&self) -> &HashMap<usize, Child> {
41         &self.running_table
42     }
43 
44     pub fn mut_running_table(&mut self) -> &mut HashMap<usize, Child> {
45         &mut self.running_table
46     }
47 }
48 
49 pub struct UnitManager;
50 
51 unsafe impl Sync for UnitManager {}
52 
53 impl UnitManager {
54     /// 插入一条path到unit_id的映射
55     pub fn insert_into_path_table(path: &str, unit: usize) {
56         let mut hasher = DefaultHasher::new();
57         path.hash(&mut hasher);
58         let hash = hasher.finish();
59         PATH_TO_UNIT_MAP.write().unwrap().insert(hash, unit);
60     }
61 
62     // 判断当前是否已经有了对应path的Unit
63     pub fn contains_path(path: &str) -> bool {
64         let mut hasher = DefaultHasher::new();
65         path.hash(&mut hasher);
66         let hash = hasher.finish();
67         PATH_TO_UNIT_MAP.read().unwrap().contains_key(&hash)
68     }
69 
70     // 通过path获取到Unit
71     pub fn get_unit_with_path(path: &str) -> Option<Arc<Mutex<dyn Unit>>> {
72         let mut hasher = DefaultHasher::new();
73         path.hash(&mut hasher);
74         let hash = hasher.finish();
75         let map = PATH_TO_UNIT_MAP.read().unwrap();
76         let id = match map.get(&hash) {
77             Some(id) => id,
78             None => {
79                 return None;
80             }
81         };
82 
83         let map = ID_TO_UNIT_MAP.read().unwrap();
84         let ret = map.get(id).cloned();
85         ret
86     }
87 
88     // 通过unit_id获取Unit
89     pub fn get_unit_with_id(id: &usize) -> Option<Arc<Mutex<dyn Unit>>> {
90         let map = ID_TO_UNIT_MAP.read().unwrap();
91         let ret = map.get(&id).cloned();
92         ret
93     }
94 
95     // 通过id获取到path
96     pub fn get_id_with_path(path: &str) -> Option<usize> {
97         let mut hasher = DefaultHasher::new();
98         path.hash(&mut hasher);
99         let hash = hasher.finish();
100         PATH_TO_UNIT_MAP.read().unwrap().get(&hash).cloned()
101     }
102 
103     // 判断该Unit是否正在运行中
104     pub fn is_running_unit(id: &usize) -> bool {
105         RUNNING_TABLE.read().unwrap().running_table.contains_key(id)
106             || !FLAG_RUNNING
107                 .read()
108                 .unwrap()
109                 .iter()
110                 .filter(|x| **x == *id)
111                 .collect::<Vec<_>>()
112                 .is_empty()
113     }
114 
115     // 向运行表中添加运行的Unit
116     pub fn push_running(unit_id: usize, p: Child) {
117         RUNNING_TABLE
118             .write()
119             .unwrap()
120             .running_table
121             .insert(unit_id, p);
122     }
123 
124     // 删除运行表中的Unit
125     pub fn remove_running(id: usize) {
126         let mut table = RUNNING_TABLE.write().unwrap();
127         table.running_table.remove(&id);
128     }
129 
130     // 向id到Unit映射表中插入数据
131     pub fn insert_unit_with_id(id: usize, unit: Arc<Mutex<dyn Unit>>) {
132         let mut map = ID_TO_UNIT_MAP.write().unwrap();
133         if !map.contains_key(&id) {
134             map.insert(id, unit);
135         }
136     }
137 
138     // 判断当前DragonReach是否拥有目标id的Unit
139     pub fn contains_id(id: &usize) -> bool {
140         ID_TO_UNIT_MAP.read().unwrap().contains_key(id)
141     }
142 
143     // 弹出一个处于IDLE状态的Service
144     pub fn pop_a_idle_service() -> Option<Arc<Mutex<dyn Unit>>> {
145         let id = IDLE_SERVIEC_DEQUE.lock().unwrap().pop_front();
146         match id {
147             Some(id) => {
148                 return Self::get_unit_with_id(&id);
149             }
150             None => {
151                 return None;
152             }
153         }
154     }
155 
156     // 添加IDLE状态的Service,将在后续调度
157     pub fn push_a_idle_service(id: usize) {
158         if !Self::contains_id(&id) {
159             return;
160         }
161         IDLE_SERVIEC_DEQUE.lock().unwrap().push_back(id);
162     }
163 
164     // 将该Unit标记为运行状态,并且后续不会对其进行运行检查
165     pub fn push_flag_running(id: usize) {
166         let mut t = FLAG_RUNNING.write().unwrap();
167         if t.contains(&id) {
168             return;
169         }
170         t.push(id);
171     }
172 
173     // 当前运行的Unit数
174     pub fn running_count() -> usize {
175         return RUNNING_TABLE.read().unwrap().running_table.len();
176     }
177 
178     // 向Cmd运行表中添加
179     pub fn push_cmd_proc(proc: Child) {
180         CMD_PROCESS_TABLE
181             .write()
182             .unwrap()
183             .insert(proc.id(), Mutex::new(proc));
184     }
185 
186     // 删除对应cmd的进程
187     pub fn remove_cmd_proc(id: u32) {
188         CMD_PROCESS_TABLE.write().unwrap().remove(&id);
189     }
190 
191     // 弹出指定id的cmd进程
192     pub fn pop_cmd_proc(id: u32) -> Option<Mutex<Child>> {
193         CMD_PROCESS_TABLE.write().unwrap().remove(&id)
194     }
195 
196     // 初始化各Unit的依赖关系,此方法只需在解析完系统Unit文件后调用一次
197     pub fn init_units_dependencies() {
198         let manager = ID_TO_UNIT_MAP.write().unwrap();
199 
200         // 处理before段,将before段的Unit添加此Unit为After
201         for (id, unit) in manager.iter() {
202             let mut unit = unit.lock().unwrap();
203             let before = unit.mut_unit_base().unit_part().before();
204             for rid in before {
205                 let req = UnitManager::get_unit_with_id(rid).unwrap();
206                 let mut req = req.lock().unwrap();
207                 req.mut_unit_base().mut_unit_part().push_after_unit(*id);
208             }
209         }
210 
211         for (id, unit) in manager.iter() {
212             let mut unit = unit.lock().unwrap();
213 
214             // 处理binds_to段
215             let binds_to = unit.mut_unit_base().unit_part().binds_to();
216             for rid in binds_to {
217                 let req = UnitManager::get_unit_with_id(rid).unwrap();
218                 let mut req = req.lock().unwrap();
219                 req.mut_unit_base().mut_unit_part().push_be_binded_by(*id);
220             }
221 
222             // 处理part_of段
223             let part_of = unit.mut_unit_base().unit_part().part_of();
224             for rid in part_of {
225                 let req = UnitManager::get_unit_with_id(rid).unwrap();
226                 let mut req = req.lock().unwrap();
227                 req.mut_unit_base().mut_unit_part().push_be_binded_by(*id);
228             }
229         }
230     }
231 
232     /// ## 杀死Unit进程
233     pub fn kill_running(id: usize) {
234         if Self::is_running_unit(&id) {
235             let mut running_manager = RUNNING_TABLE.write().unwrap();
236             let unit = running_manager.running_table.get_mut(&id).unwrap();
237             let _ = unit.kill();
238             println!("kill:{}", id);
239             running_manager.running_table.remove(&id);
240         }
241     }
242 }
243