block_db/recover.rs
1// Authors: Robert Lopez
2
3use crate::{error::Error, wal::BlockDBState, BlockDB};
4use std::{collections::HashMap, sync::Arc};
5use tokio::sync::RwLock;
6
7impl BlockDB {
8 /// Recovers the state of the `BlockDB` by replaying its WAL,
9 /// as well as the WALs for all `DataFile`s. Invalid `DataFile`s
10 /// and `DataBlock`s are deleted during the process.
11 ///
12 /// This method complements `BlockDB::uncorrupt`, and is intended
13 /// for cases where the file structure has become corrupted through
14 /// external means — not via `BlockDB` methods themselves (e.g.,
15 /// hardware issues or filesystem corruption).
16 ///
17 /// As noted in `uncorrupt`, you should ensure filesystem and hardware
18 /// stability before invoking this method, as such corruption usually
19 /// indicates a deeper issue with the environment.
20 ///
21 /// If this method fails repeatedly, it likely means the WAL(s)
22 /// themselves are irreparably corrupted — in which case manual deletion
23 /// of the `BlockDB` may be required.
24 ///
25 /// ---
26 /// - **Atomic**
27 /// - **Non-corruptible**
28 ///
29 /// ---
30 /// Example
31 /// ``` let mut block_db = BlockDB::open("./data", None).await?;
32 ///
33 /// block_db.recover().await?;
34 /// ```
35 pub async fn recover(&mut self) -> Result<(), Error> {
36 let BlockDBState { valid_data_files } = self.wal.write().await.replay(None).await?;
37
38 let mut new_data_files = HashMap::new();
39 for (id, data_file) in self.data_files.read().await.clone() {
40 if valid_data_files.contains(&id) {
41 data_file.write().await.recover().await?;
42
43 new_data_files.insert(id, data_file);
44 } else {
45 let _ = data_file.write().await.delete().await;
46 }
47 }
48
49 self.data_files = Arc::new(RwLock::new(new_data_files));
50
51 Ok(())
52 }
53}