block-db 0.2.0

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

use super::{state::ChunkCount, TestDB};
use crate::{size::ByteSize, tests::util::size_bytes};

impl TestDB {
    pub async fn compact<Bytes: AsRef<[u8]>>(
        &mut self,
        data_file_ids: Option<Vec<&str>>,
        freed_bytes: Vec<Bytes>,
    ) -> Result<(), String> {
        let mut compacted_free_bytes = 0;

        macro_rules! compact_data_file {
            ($data_file_id:expr, $data_file:expr) => {
                let freed_bytes = $data_file.write().await.compact().await.map_err(|err| {
                    format!("Failed to compact DataFile {} \n {err:?}", $data_file_id)
                })?;
                compacted_free_bytes += freed_bytes;

                let ByteSize {
                    free_bytes: data_file_free_bytes,
                    ..
                } = self
                    .test_state
                    .data_file_byte_size_map
                    .entry($data_file_id.to_string())
                    .or_default();

                let ChunkCount { free, .. } = self
                    .test_state
                    .data_file_chunk_count_map
                    .entry($data_file_id)
                    .or_default();

                *free -= freed_bytes / self.chunk_size;

                *data_file_free_bytes -= freed_bytes;
            };
        }

        if let Some(data_file_ids) = data_file_ids {
            let data_files = self.block_db.data_files.read().await.clone();

            for data_file_id in data_file_ids {
                compact_data_file!(
                    data_file_id.to_string(),
                    data_files
                        .get(data_file_id)
                        .ok_or(format!("Failed to get DataFile {data_file_id} to compact"))?
                );
            }
        } else {
            for (data_file_id, data_file) in self.block_db.data_files.read().await.clone() {
                compact_data_file!(data_file_id, data_file);
            }
        }

        let ByteSize {
            free_bytes: block_db_free_bytes,
            ..
        } = &mut self.test_state.block_db_byte_size;

        *block_db_free_bytes -= compacted_free_bytes;

        let compacted_bytes = freed_bytes
            .iter()
            .map(|bytes| size_bytes(bytes.as_ref(), self.chunk_size))
            .sum::<usize>();

        if compacted_bytes != compacted_free_bytes {
            return Err(format!(
                "{compacted_bytes} != {compacted_free_bytes} \n Invalid total compacted bytes size"
            ));
        }

        self.test_state
            .assert_against_block_db(&self.block_db)
            .await
    }
}