block-db 0.2.0

Local, multi-threaded, durable byte DB.
Documentation
// 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(())
    }
}