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