block-db 0.2.0

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

use crate::BlockDB;
use std::collections::HashMap;

/// Byte size meta-data for a `DataFile` or a `BlockDB`
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct ByteSize {
    pub used_bytes: usize,
    pub free_bytes: usize,
}

impl BlockDB {
    /// Obtain the `ByteSize` of the entire `BlockDB`.
    ///
    /// ---
    /// Example
    /// ```
    /// let block_db = BlockDB::open("./data", None).await?;
    ///
    /// let block_key: BlockKey = block_db.write(b"123").await?;
    ///
    /// let ByteSize {
    ///     used_bytes,  // 4096 (Default chunk size)
    ///     free_bytes,  // 0
    /// } = block_db.byte_size().await;
    /// ```
    pub async fn byte_size(&self) -> ByteSize {
        let mut used_bytes = 0;
        let mut free_bytes = 0;

        for (_, data_file) in self.data_files.read().await.clone() {
            let reader = data_file.read().await;

            used_bytes += reader.used_bytes;
            free_bytes += reader.free_bytes;
        }

        ByteSize {
            used_bytes,
            free_bytes,
        }
    }

    /// Obtain the `ByteSize` of a single `DataFile`.
    ///
    /// ---
    /// Example
    /// ```
    /// let block_db = BlockDB::open("./data", None).await?;
    ///
    /// let BlockKey { data_file_id, .. } = block_db.write(b"123").await?;
    ///
    /// let ByteSize {
    ///     used_bytes,  // 4096 (Default chunk size)
    ///     free_bytes,  // 0
    /// } = block_db.data_file_byte_size(data_file_id).await;
    /// ```
    pub async fn data_file_byte_size<S: AsRef<str>>(&self, data_file_id: S) -> Option<ByteSize> {
        if let Some(data_file) = self
            .data_files
            .read()
            .await
            .get(data_file_id.as_ref())
            .cloned()
        {
            return Some(data_file.read().await.byte_size());
        }

        None
    }

    /// Obtain a mapping of a `ByteSize` for each `DataFile`
    ///
    /// ---
    /// Example
    /// ```
    /// let block_db = BlockDB::open("./data", None).await?;
    ///
    /// let BlockKey { data_file_id, .. } = block_db.write(b"123").await?;
    ///
    /// // {
    /// //  "z-daZa": ByteSize {
    /// //              used_bytes: 4096, (Default chunk size)
    /// //              free_bytes: 0,
    /// //            },
    /// // }
    /// let byte_size_map = block_db.data_file_byte_size_map().await?;
    /// ```
    pub async fn data_file_byte_size_map(&self) -> HashMap<String, ByteSize> {
        let mut byte_size_map = HashMap::new();

        for (data_file_id, data_file) in self.data_files.read().await.clone() {
            byte_size_map.insert(data_file_id, data_file.read().await.byte_size());
        }

        byte_size_map
    }

    #[cfg(test)]
    pub(crate) async fn free_chunk_count(&self) -> usize {
        let mut chunks = 0;

        for (_, data_file) in self.data_files.read().await.clone() {
            chunks += data_file.read().await.free_chunk_count();
        }

        chunks
    }

    #[cfg(test)]
    pub(crate) async fn used_chunk_count(&self) -> usize {
        let mut chunks = 0;

        for (_, data_file) in self.data_files.read().await.clone() {
            chunks += data_file.read().await.used_chunk_count();
        }

        chunks
    }
}