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