harmos_storage/manager/
shutdown.rs1use super::*;
22
23impl<C> StorageManager<C> {
38 #[tracing::instrument(name = "storage.manager.shutdown.close", level = "debug", skip_all, fields(outcome = "cancelled"))]
39 pub async fn close(&self) -> Result<()> {
40 let result = async {
41 {
42 let mut state = self.inner.state.lock().unwrap();
43 state.status.closing = true;
44 state.close_followers();
45 }
46 self.inner.notify();
47
48 let mut lifecycle =
49 tracing::Instrument::instrument(self.inner.lifecycle.write(), tracing::trace_span!("storage.lock.wait")).await;
50 let ready = {
51 let state = self.inner.state.lock().unwrap();
52 state.ready && !state.status.closed
53 };
54 if ready {
55 self.settle_transition().await;
56 self.settle_files().await?;
57 self.settle_deletions().await?;
58 let files = self.capture_files(None)?;
59 self.flush_domain(Domain::Data, None).await?;
60 self.persist_files(&files).await?;
61 self.retire_files();
62 self.flush_recovery().await?;
63 }
64 if ready {
65 self.release_snapshots().await?;
66 }
67 let mut changed = self.inner.changed.subscribe();
70 loop {
71 {
72 let state = self.inner.state.lock().unwrap();
73 if !state.pruning_objects {
74 break;
75 }
76 if !state.status.running {
77 return Err(Error::NotReady { domain: "storage worker" });
78 }
79 }
80 changed.changed().await.map_err(|_| Error::NotReady { domain: "storage" })?;
81 }
82 if lifecycle.primary_touched && !lifecycle.primary_closed {
83 tracing::Instrument::instrument(
84 self.inner.primary.close(),
85 tracing::debug_span!("storage.backend", method = "primary.close"),
86 )
87 .await?;
88 lifecycle.primary_closed = true;
89 }
90 if lifecycle.recovery_touched && !lifecycle.recovery_closed {
91 tracing::Instrument::instrument(
92 self.inner.recovery.close(),
93 tracing::debug_span!("storage.backend", method = "recovery.close"),
94 )
95 .await?;
96 lifecycle.recovery_closed = true;
97 }
98 self.retire_files();
100 {
101 let mut state = self.inner.state.lock().unwrap();
102 state.receipts.clear();
103 state.status.closed = true;
104 state.collect();
105 }
106 self.inner.notify();
107 if let Some(owner) = &lifecycle.owner {
108 owner.stop().await?;
109 }
110 lifecycle.owner = None;
111 self.inner.state.lock().unwrap().status.running = false;
114 self.inner.notify();
115 Ok(())
116 }
117 .await;
118 tracing::Span::current().record("outcome", if result.is_ok() { "completed" } else { "failed" });
119 result
120 }
121
122 pub(super) fn check_raw_recovery(&self) -> Result<()> {
123 if self.inner.state.lock().unwrap().journal_saved.is_some() {
124 return Err(Error::InvalidInput { field: "recovery ownership", reason: "managed journal owns recovery writes" });
125 }
126 Ok(())
127 }
128}
129
130