block-db 0.2.0

Local, multi-threaded, durable byte DB.
Documentation
// Authors: Robert Lopez

use super::{error::Error, BlockDB, BlockKey};
use std::collections::HashMap;

impl BlockDB {
    /// Reads the bytes of a `DataBlock` from a `DataFile`.
    ///
    /// Returns `None` if either the `data_file_id` or `data_block_id` does not exist.
    ///
    /// ---
    /// - **Atomic**
    /// - **Non-corruptible**
    ///
    /// ---
    /// Example
    /// ``` let block_db = BlockDB::open("./data", None).await?;
    ///
    /// // BlockKey { data_file_id, data_block_id }
    /// let block_key = block_db.write(b"Hello World").await?;
    ///
    /// // b"Hello World".to_vec()
    /// let data = block_db.read(&block_key).await?.unwrap();
    /// ```
    /// ---
    pub async fn read(
        &self,
        BlockKey {
            data_file_id,
            data_block_id,
        }: &BlockKey,
    ) -> Result<Option<Vec<u8>>, Error> {
        if let Some(data_file) = self.data_files.read().await.get(data_file_id).cloned() {
            return data_file.write().await.read(data_block_id).await;
        }

        Ok(None)
    }

    /// Reads the bytes of multiple `DataBlock`s in a single, consistent view.
    ///
    /// ---
    /// - **Atomic**
    /// - **Non-corruptible**
    ///
    /// ---
    /// Example
    /// ``` let block_db = BlockDB::open("./data", None).await?;
    ///
    /// let block_key_one = block_db.write(b"Hello").await?;
    /// let block_key_two = block_db.write(b"World").await?;
    ///
    /// // {
    /// //   BlockKey { .. } : Some(b"Hello"),
    /// //   BlockKey { .. } : Some(b"World"),
    /// // }
    /// let read_many_map = block_db.read_many(vec![&block_key_one, &block_key_two]).await?;
    /// ```
    /// ---
    pub async fn read_many(
        &self,
        keys: Vec<&BlockKey>,
    ) -> Result<HashMap<BlockKey, Option<Vec<u8>>>, Error> {
        let data_files = self.data_files.read().await.clone();
        let mut data_file_locks = HashMap::new();

        for BlockKey { data_file_id, .. } in keys.iter() {
            if !data_file_locks.contains_key(data_file_id) {
                if let Some(data_file) = data_files.get(data_file_id) {
                    data_file_locks.insert(data_file_id, data_file.write().await);
                }
            }
        }

        let mut data_blocks_map = HashMap::new();

        for block_key in keys {
            if let Some(data_file_lock) = data_file_locks.get_mut(&block_key.data_file_id) {
                data_blocks_map.insert(
                    block_key.clone(),
                    data_file_lock.read(&block_key.data_block_id).await?,
                );
            } else {
                data_blocks_map.insert(block_key.clone(), None);
            }
        }

        Ok(data_blocks_map)
    }
}