venus_core/execute/
reload.rs1use std::collections::HashMap;
7
8use crate::compile::{
9 CellCompiler, CompilationResult, CompiledCell, CompilerConfig, ToolchainManager,
10};
11use crate::error::{Error, Result};
12use crate::graph::{CellId, CellInfo, GraphEngine};
13
14use super::LinearExecutor;
15use super::context::CellContext;
16
17pub struct HotReloader {
26 compiler: CellCompiler,
28 contexts: HashMap<CellId, CellContext>,
30}
31
32impl HotReloader {
33 pub fn new(config: CompilerConfig) -> Result<Self> {
35 let toolchain = ToolchainManager::new()?;
36 let compiler = CellCompiler::new(config, toolchain);
37
38 Ok(Self {
39 compiler,
40 contexts: HashMap::new(),
41 })
42 }
43
44 pub fn with_compiler(compiler: CellCompiler) -> Self {
46 Self {
47 compiler,
48 contexts: HashMap::new(),
49 }
50 }
51
52 pub fn register_context(&mut self, cell_id: CellId, context: CellContext) {
54 self.contexts.insert(cell_id, context);
55 }
56
57 pub fn get_context(&self, cell_id: CellId) -> Option<&CellContext> {
59 self.contexts.get(&cell_id)
60 }
61
62 pub fn get_context_mut(&mut self, cell_id: CellId) -> Option<&mut CellContext> {
64 self.contexts.get_mut(&cell_id)
65 }
66
67 pub fn reload_cell(
71 &mut self,
72 executor: &mut LinearExecutor,
73 cell_info: &CellInfo,
74 deps_hash: u64,
75 ) -> Result<CompiledCell> {
76 let cell_id = cell_info.id;
77
78 if let Some(mut ctx) = self.contexts.remove(&cell_id) {
80 tracing::info!("Cleaning up cell {:?} for reload", cell_id);
81 ctx.abort();
82 }
83
84 let saved_output = executor.state().get_output(cell_id);
86
87 let old_cell = executor.unload_cell(cell_id);
89
90 tracing::info!("Recompiling cell {:?}", cell_id);
92 let result = self.compiler.compile(cell_info, deps_hash);
93
94 match result {
95 CompilationResult::Success(compiled) | CompilationResult::Cached(compiled) => {
96 let dep_count = cell_info.dependencies.len();
98 executor.load_cell(compiled.clone(), dep_count)?;
99
100 let new_ctx = CellContext::new(cell_id, cell_info.name.clone());
102 self.contexts.insert(cell_id, new_ctx);
103
104 tracing::info!("Cell {:?} reloaded successfully", cell_id);
109 Ok(compiled)
110 }
111 CompilationResult::Failed { cell_id, errors } => {
112 tracing::error!("Cell {:?} compilation failed: {:?}", cell_id, errors);
114
115 if let Some(old_loaded_cell) = old_cell {
117 tracing::info!("Restoring old cell {:?} after compilation failure", cell_id);
118 executor.restore_cell(old_loaded_cell);
119 }
120
121 if let Some(output) = saved_output {
123 executor
124 .state_mut()
125 .store_output(cell_id, (*output).clone());
126 }
127
128 Err(Error::Compilation {
129 cell_id: Some(cell_id.to_string()),
130 message: format!("{} compilation errors", errors.len()),
131 })
132 }
133 }
134 }
135
136 pub fn reload_cells(
141 &mut self,
142 executor: &mut LinearExecutor,
143 cells: &[&CellInfo],
144 graph: &GraphEngine,
145 ) -> Result<Vec<CompiledCell>> {
146 let execution_order = graph.topological_order()?;
148 let mut sorted_cells: Vec<&CellInfo> = cells.to_vec();
149 sorted_cells.sort_by_key(|c| {
150 execution_order
151 .iter()
152 .position(|&id| id == c.id)
153 .unwrap_or(usize::MAX)
154 });
155
156 let mut compiled = Vec::new();
158 for cell in sorted_cells {
159 let deps_hash = self.calculate_deps_hash(cell, graph);
161 let result = self.reload_cell(executor, cell, deps_hash)?;
162 compiled.push(result);
163 }
164
165 Ok(compiled)
166 }
167
168 pub fn reload_cascade(
170 &mut self,
171 executor: &mut LinearExecutor,
172 cell_info: &CellInfo,
173 graph: &GraphEngine,
174 ) -> Result<Vec<CompiledCell>> {
175 let cell_id = cell_info.id;
176
177 let dependents = graph.invalidated_cells(cell_id);
179 let mut affected_ids: Vec<CellId> = vec![cell_id];
180 affected_ids.extend(dependents);
181
182 executor.state_mut().invalidate_many(&affected_ids);
184
185 let deps_hash = self.calculate_deps_hash(cell_info, graph);
187 let compiled = self.reload_cell(executor, cell_info, deps_hash)?;
188
189 Ok(vec![compiled])
193 }
194
195 fn calculate_deps_hash(&self, cell: &CellInfo, _graph: &GraphEngine) -> u64 {
197 use std::collections::hash_map::DefaultHasher;
198 use std::hash::{Hash, Hasher};
199
200 let mut hasher = DefaultHasher::new();
201
202 for dep in &cell.dependencies {
204 dep.param_name.hash(&mut hasher);
205 dep.param_type.hash(&mut hasher);
206 }
207
208 hasher.finish()
212 }
213
214 pub fn abort_all(&mut self) {
216 for (cell_id, mut ctx) in self.contexts.drain() {
217 tracing::info!("Aborting cell {:?}", cell_id);
218 ctx.abort();
219 }
220 }
221}
222
223impl Drop for HotReloader {
224 fn drop(&mut self) {
225 self.abort_all();
226 }
227}
228
229