arrowbatch 1.14.0

Reader for arrow-batch format
Documentation
use std::sync::{Arc, Mutex, MutexGuard};

use arrow::record_batch::RecordBatch;
use moka::sync::Cache;

use crate::reader::get_relative_table_index;
use crate::{
    proto::{
        read_batch, read_metadata, ArrowBatchFileMetadata
    },
    reader::ArrowBatchContext
};


pub struct ArrowBatchCache {
    context: Arc<Mutex<ArrowBatchContext>>,

    pub table_cache: Cache<String, Arc<RecordBatch>>,
    pub metadata_cache: Cache<u64, ArrowBatchFileMetadata>,
}

impl ArrowBatchCache {
    const DEFAULT_TABLE_CACHE: u64 = 3;

    pub fn new(
        context: Arc<Mutex<ArrowBatchContext>>
    ) -> Self {
        ArrowBatchCache {
            context,
            table_cache: Cache::new(Self::DEFAULT_TABLE_CACHE),
            metadata_cache: Cache::new(Self::DEFAULT_TABLE_CACHE),
        }
    }

    pub fn get_metadata_for(
        &self,
        adjusted_ordinal: u64,
        locked_context: Option<Arc<MutexGuard<ArrowBatchContext>>>
    ) -> u64 {
        let must_lock = locked_context.is_none();
        let context = if must_lock {
            Arc::new(self.context.lock().unwrap())
        } else {
            locked_context.unwrap()
        };

        let file_path = context.table_file_map
            .get(&adjusted_ordinal)
            .expect(format!("File path for {} not found", adjusted_ordinal).as_str());

        if self.metadata_cache.contains_key(&adjusted_ordinal) {
            return adjusted_ordinal;
        }

        let meta = read_metadata(file_path).unwrap();
        self.metadata_cache.insert(adjusted_ordinal, meta);
        if must_lock {
            drop(context);
        }
        adjusted_ordinal
    }

    pub fn direct_load_table(
        &self,
        adjusted_ordinal: u64,
        batch_index: usize,
        locked_context: Option<Arc<MutexGuard<ArrowBatchContext>>>
    ) -> Option<RecordBatch> {
        let must_lock = locked_context.is_none();
        let context = if must_lock {
            Arc::new(self.context.lock().unwrap())
        } else {
            locked_context.unwrap()
        };

        let table_file_map = context.table_file_map.clone();

        let file_path = table_file_map
            .get(&adjusted_ordinal);

        if must_lock {
            drop(context);
        }

        match file_path {
            Some(path) => {
                let metadata = self.metadata_cache.get(&adjusted_ordinal).unwrap();
                let table = read_batch(path, &metadata, batch_index).unwrap();
                Some(table)
            }
            None => None
        }
    }

    pub fn get_table_for(
        &self,
        ordinal: u64,
        locked_context: Option<Arc<MutexGuard<ArrowBatchContext>>>
    ) -> Option<Arc<RecordBatch>> {
        let must_lock = locked_context.is_none();
        let context = if must_lock {
            Arc::new(self.context.lock().unwrap())
        } else {
            locked_context.unwrap()
        };

        let adjusted_ordinal = context.get_ordinal(ordinal);

        let bucket_metadata_key =
            self.get_metadata_for(adjusted_ordinal, Some(context.clone()));

        let bucket_metadata = self.metadata_cache.get(&bucket_metadata_key).unwrap();

        let (batch_index, _) = get_relative_table_index(ordinal, &bucket_metadata);

        let cache_key = format!("{}-{}", adjusted_ordinal, batch_index);

        if self.table_cache.contains_key(&cache_key) {
            let cached_table = self.table_cache.get(&cache_key).unwrap();
            return Some(cached_table);
        }

        let table = self.direct_load_table(
            adjusted_ordinal,
            batch_index as usize,
            Some(context.clone())
        ).unwrap();

        let arc_table = Arc::new(table);

        self.table_cache.insert(cache_key.clone(), arc_table.clone());

        if must_lock {
            drop(context);
        };

        Some(arc_table)
    }

}