(
&mut self,
runtimes: Arc<HostRuntimes>,
program: Program,
policy: MigrationPolicy,
energy_monitor: Arc<dyn EnergyMonitor>,
on_panic: impl Fn() + Send
| 1191 | /// Either way, the [`UpdateDatabaseResult`] is returned. |
| 1192 | #[allow(clippy::too_many_arguments)] |
| 1193 | async fn update_module( |
| 1194 | &mut self, |
| 1195 | runtimes: Arc<HostRuntimes>, |
| 1196 | program: Program, |
| 1197 | policy: MigrationPolicy, |
| 1198 | energy_monitor: Arc<dyn EnergyMonitor>, |
| 1199 | on_panic: impl Fn() + Send + Sync + 'static, |
| 1200 | core: AllocatedJobCore, |
| 1201 | ) -> anyhow::Result<UpdateDatabaseResult> { |
| 1202 | let replica_ctx = &self.replica_ctx; |
| 1203 | let (scheduler, scheduler_starter) = Scheduler::open(self.replica_ctx.relational_db().clone()); |
| 1204 | |
| 1205 | let (program, module) = make_module_host( |
| 1206 | runtimes, |
| 1207 | replica_ctx.clone(), |
| 1208 | scheduler.clone(), |
| 1209 | program, |
| 1210 | energy_monitor, |
| 1211 | on_panic, |
| 1212 | core, |
| 1213 | ) |
| 1214 | .await?; |
| 1215 | |
| 1216 | // Get the old module info to diff against when building a migration plan. |
| 1217 | let old_module_info = self.module.borrow().info.clone(); |
| 1218 | |
| 1219 | let update_result = |
| 1220 | update_module(replica_ctx.relational_db(), &module, program, old_module_info, policy).await?; |
| 1221 | |
| 1222 | // Only replace the module + scheduler if the update succeeded. |
| 1223 | // Otherwise, we want the database to continue running with the old state. |
| 1224 | match update_result { |
| 1225 | UpdateDatabaseResult::NoUpdateNeeded | UpdateDatabaseResult::UpdatePerformed { .. } => { |
| 1226 | self.scheduler = scheduler; |
| 1227 | scheduler_starter.start(&module)?; |
| 1228 | let old_module = self.module.send_replace(module); |
| 1229 | old_module.exit().await; |
| 1230 | } |
| 1231 | |
| 1232 | // In this case, we need to disconnect all clients connected to the old module |
| 1233 | UpdateDatabaseResult::UpdatePerformedWithClientDisconnect { .. } => { |
| 1234 | // Replace the module first, so that new clients get the new module. |
| 1235 | let old_watcher = std::mem::replace(&mut self.module, watch::Sender::new(module.clone())); |
| 1236 | |
| 1237 | // Disconnect all clients connected to the old module. |
| 1238 | let connected_clients = replica_ctx.relational_db().connected_clients()?; |
| 1239 | for (identity, connection_id) in connected_clients { |
| 1240 | let client_actor_id = ClientActorId { |
| 1241 | identity, |
| 1242 | connection_id, |
| 1243 | name: ClientName(0), |
| 1244 | }; |
| 1245 | //NOTE: This will call disconnect reducer of the new module, not the old one. |
| 1246 | //It makes sense, as relationaldb is already updated to the new module. |
| 1247 | module.disconnect_client(client_actor_id).await; |
| 1248 | } |
| 1249 | |
| 1250 | self.scheduler = scheduler; |
no test coverage detected