pub type ActualSlabIndex = u32;
pub type VacantEntry<'a, TrieNode> =
    super::slab::VacantEntry<'a, TrieNode, TrieNode>;
pub type TrieNodeCell<CacheAlgoDataT> =
    UnsafeCell<MemOptimizedTrieNode<CacheAlgoDataT>>;
type Allocator<CacheAlgoDataT> =
    Slab<TrieNodeCell<CacheAlgoDataT>, TrieNodeCell<CacheAlgoDataT>>;
pub type AllocatorRef<'a, CacheAlgoDataT> =
    RwLockReadGuard<'a, Allocator<CacheAlgoDataT>>;
pub type AllocatorRefRef<'a, CacheAlgoDataT> =
    &'a AllocatorRef<'a, CacheAlgoDataT>;
pub type RLFUPosT = u32;
pub type DeltaMptsCacheAlgorithm = LRU<RLFUPosT, (DeltaMptId, DeltaMptDbKey)>;
pub type DeltaMptsCacheAlgoData =
    <DeltaMptsCacheAlgorithm as CacheAlgorithm>::CacheAlgoData;
pub type TrieNodeDeltaMpt = MemOptimizedTrieNode<DeltaMptsCacheAlgoData>;
pub type TrieNodeDeltaMptCell = TrieNodeCell<DeltaMptsCacheAlgoData>;
pub type SlabVacantEntryDeltaMpt<'a> = VacantEntry<'a, TrieNodeDeltaMptCell>;
pub type AllocatorRefRefDeltaMpt<'a> =
    &'a AllocatorRef<'a, DeltaMptsCacheAlgoData>;
pub type DeltaMptsNodeMemoryManager =
    NodeMemoryManager<DeltaMptsCacheAlgoData, DeltaMptsCacheAlgorithm>;
pub type DeltaMptsCacheManager =
    CacheManagerDeltaMpts<DeltaMptsCacheAlgoData, DeltaMptsCacheAlgorithm>;
impl CacheIndexTrait for DeltaMptDbKey {}
#[derive(MallocSizeOfDerive)]
pub struct NodeMemoryManager<
    CacheAlgoDataT: CacheAlgoDataTrait,
    CacheAlgorithmT: CacheAlgorithm<CacheAlgoData = CacheAlgoDataT>,
> {
    size_limit: u32,
    idle_size: u32,
    allocator: RwLock<Allocator<CacheAlgoDataT>>,
    cache: Mutex<CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>>,
    db_load_lock: Mutex<()>,
    db_load_counter: AtomicUsize,
    uncached_leaf_load_times: AtomicUsize,
    uncached_leaf_db_loads: AtomicUsize,
    pub compute_merkle_db_loads: AtomicUsize,
    children_merkle_db_loads: AtomicUsize,
}
impl<
        CacheAlgoDataT: CacheAlgoDataTrait,
        CacheAlgorithmT: CacheAlgorithm<CacheAlgoData = CacheAlgoDataT>,
    > NodeMemoryManager<CacheAlgoDataT, CacheAlgorithmT>
{
    pub const MAX_CACHED_TRIE_NODES_DISK_HYBRID: u32 = 10_000_000;
    pub const MAX_CACHED_TRIE_NODES_R_LFU_COUNTER: u32 = (Self::R_LFU_FACTOR
        * Self::MAX_CACHED_TRIE_NODES_DISK_HYBRID as f64)
        as u32;
    pub const MAX_DIRTY_AND_TEMPORARY_TRIE_NODES: u32 = 5_000_000;
    pub const MAX_TRIE_NODES_MEM_ONLY: u32 = 27_600_000;
    pub const R_LFU_FACTOR: f64 = 4.0;
    pub const START_CAPACITY: u32 = 1_000_000;
}
impl<
        CacheAlgoDataT: CacheAlgoDataTrait,
        CacheAlgorithmT: CacheAlgorithm<
            CacheAlgoData = CacheAlgoDataT,
            CacheIndex = (DeltaMptId, DeltaMptDbKey),
        >,
    > NodeMemoryManager<CacheAlgoDataT, CacheAlgorithmT>
{
    pub fn new(
        cache_start_size: u32, cache_size: u32, idle_size: u32,
        _node_ref_map_vec_size: u32, cache_algorithm: CacheAlgorithmT,
    ) -> Self {
        let size_limit = cache_size + idle_size;
        Self {
            size_limit,
            idle_size,
            allocator: RwLock::new(
                Slab::with_capacity((cache_start_size + idle_size) as usize)
                    .into(),
            ),
            cache: Mutex::new(CacheManagerDeltaMpts {
                node_ref_map: NodeRefMapDeltaMpts::new(),
                cache_algorithm,
            }),
            db_load_lock: Default::default(),
            db_load_counter: Default::default(),
            uncached_leaf_db_loads: Default::default(),
            uncached_leaf_load_times: Default::default(),
            compute_merkle_db_loads: Default::default(),
            children_merkle_db_loads: Default::default(),
        }
    }
    pub fn get_allocator(&self) -> AllocatorRef<CacheAlgoDataT> {
        self.allocator.read_recursive()
    }
    pub fn get_cache_manager(
        &self,
    ) -> &Mutex<CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>> {
        &self.cache
    }
    pub fn enlarge(&self) -> Result<()> {
        let allocator_upgradable_read = self.allocator.upgradable_read();
        let allocator_capacity = allocator_upgradable_read.capacity();
        let occupied_size = allocator_upgradable_read.len();
        let idle = allocator_capacity - occupied_size;
        let should_idle = self.idle_size as usize;
        if idle >= should_idle || allocator_capacity == self.size_limit as usize
        {
            return Ok(());
        }
        let mut add_size = should_idle - idle;
        if add_size < allocator_capacity {
            add_size = allocator_capacity;
        }
        let max_add_size = self.size_limit as usize - occupied_size;
        if add_size >= max_add_size {
            add_size = max_add_size;
        }
        let mut allocator_mut =
            RwLockUpgradableReadGuard::upgrade(allocator_upgradable_read);
        allocator_mut.reserve_exact(add_size)?;
        Ok(())
    }
    pub fn delete_mpt_from_cache(&self, mpt_id: DeltaMptId) {
        let cache_mut = &mut *self.cache.lock();
        let cache_infos =
            cache_mut.node_ref_map.get_all_cache_infos_from_mpt(mpt_id);
        for (db_key, cache_info) in cache_infos {
            self.delete_from_cache(
                &mut cache_mut.cache_algorithm,
                &mut cache_mut.node_ref_map,
                (mpt_id, db_key),
                cache_info,
            );
            cache_mut.node_ref_map.delete((mpt_id, db_key));
        }
    }
    pub fn log_uncached_key_access(&self, db_load_count: i32) {
        if db_load_count != 0 {
            self.uncached_leaf_db_loads
                .fetch_add(db_load_count as usize, Ordering::Relaxed);
            self.uncached_leaf_load_times
                .fetch_add(1, Ordering::Relaxed);
        }
    }
    pub unsafe fn get_in_memory_cell<'a>(
        allocator: AllocatorRefRef<'a, CacheAlgoDataT>, cache_slot: usize,
    ) -> &'a TrieNodeCell<CacheAlgoDataT> {
        allocator.get_unchecked(cache_slot)
    }
    pub unsafe fn get_in_memory_node_mut<'a>(
        allocator: AllocatorRefRef<'a, CacheAlgoDataT>, cache_slot: usize,
    ) -> &'a mut MemOptimizedTrieNode<CacheAlgoDataT> {
        allocator.get_unchecked(cache_slot).get_as_mut()
    }
    fn load_from_db<'c: 'a, 'a>(
        &self, allocator: AllocatorRefRef<'a, CacheAlgoDataT>,
        cache_manager: &'c Mutex<
            CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
        >,
        db: &mut DeltaDbOwnedReadTraitObj, mpt_id: DeltaMptId,
        db_key: DeltaMptDbKey,
    ) -> Result<
        GuardedValue<
            MutexGuard<
                'c,
                CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
            >,
            &'a TrieNodeCell<CacheAlgoDataT>,
        >,
    > {
        self.db_load_counter.fetch_add(1, Ordering::Relaxed);
        let tmp: i64 = db_key.try_into().unwrap();
        trace!("load_from_db: {:?} {:?}", db_key, tmp);
        let rlp_bytes = db
            .get_mut_with_number_key(
                db_key.try_into().expect("not exceed i64::MAX"),
            )?
            .unwrap();
        let rlp = Rlp::new(rlp_bytes.as_ref());
        let mut trie_node = MemOptimizedTrieNode::decode(&rlp)?;
        let mut cache_manager_locked = cache_manager.lock();
        let trie_cell_ref: &TrieNodeCell<CacheAlgoDataT>;
        let cache_mut = &mut *cache_manager_locked;
        match cache_mut.node_ref_map.get_cache_info((mpt_id, db_key)) {
            None => {}
            Some(cache_info) => match cache_info.get_cache_info() {
                TrieCacheSlotOrCacheAlgoData::TrieCacheSlot(_cache_slot) => {
                    unreachable!()
                }
                TrieCacheSlotOrCacheAlgoData::CacheAlgoData(
                    cache_algo_data,
                ) => {
                    trie_node.cache_algo_data = *cache_algo_data;
                }
            },
        }
        let slot = allocator.insert(&trie_node)?;
        trie_cell_ref = unsafe { allocator.get_unchecked(slot) };
        let cache_insertion_result = cache_mut
            .node_ref_map
            .insert((mpt_id, db_key), slot as ActualSlabIndex);
        if cache_insertion_result.is_err() {
            allocator.remove(slot)?;
            cache_insertion_result?;
        }
        Ok(GuardedValue::new(cache_manager_locked, trie_cell_ref))
    }
    pub fn load_children_merkles_from_db(
        &self, db: &mut DeltaDbOwnedReadTraitObj, db_key: DeltaMptDbKey,
    ) -> Result<Option<CompactedChildrenTable<MerkleHash>>> {
        self.children_merkle_db_loads
            .fetch_add(1, Ordering::Relaxed);
        let rlp_bytes = match db.get_mut(format!("cm{}", db_key).as_bytes())? {
            None => return Ok(None),
            Some(rlp_bytes) => rlp_bytes,
        };
        let rlp = Rlp::new(rlp_bytes.as_ref());
        let table = CompactedChildrenTable::from(
            ChildrenTable::<MerkleHash>::decode(&rlp)?,
        );
        Ok(Some(table))
    }
    fn delete_from_cache(
        &self, cache_algorithm: &mut CacheAlgorithmT,
        node_ref_map: &mut NodeRefMapDeltaMpts<CacheAlgoDataT>,
        cache_index: CacheAlgorithmT::CacheIndex,
        cache_info: CacheableNodeRefDeltaMpt<CacheAlgoDataT>,
    ) {
        cache_algorithm
            .delete(cache_index, &mut NodeCacheUtil::new(self, node_ref_map));
        match cache_info.get_cache_info() {
            TrieCacheSlotOrCacheAlgoData::TrieCacheSlot(slot) => {
                self.get_allocator().remove((*slot) as usize).unwrap();
            }
            _ => {}
        }
    }
    unsafe fn delete_cache_evicted_unchecked(
        &self,
        cache_mut: &mut CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
        evicted_cache_index: CacheAlgorithmT::CacheIndex,
    ) {
        let cache_info =
            cache_mut.node_ref_map.delete(evicted_cache_index).unwrap();
        match cache_info.get_cache_info() {
            TrieCacheSlotOrCacheAlgoData::TrieCacheSlot(slot) => {
                self.get_allocator().remove((*slot) as usize).unwrap();
            }
            _ => {}
        }
    }
    unsafe fn delete_cache_evicted_keep_cache_algo_data_unchecked(
        &self,
        cache_mut: &mut CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
        evicted_keep_cache_algo_data_cache_index: CacheAlgorithmT::CacheIndex,
    ) {
        let slot = *cache_mut
            .node_ref_map
            .get_cache_info(evicted_keep_cache_algo_data_cache_index)
            .unwrap()
            .get_slot()
            .unwrap() as usize;
        cache_mut.node_ref_map.set_cache_info(
            evicted_keep_cache_algo_data_cache_index,
            CacheableNodeRefDeltaMpt::new(
                TrieCacheSlotOrCacheAlgoData::CacheAlgoData(
                    self.get_allocator()
                        .get_unchecked(slot)
                        .get_ref()
                        .cache_algo_data,
                ),
            ),
        );
        self.get_allocator().remove(slot).unwrap();
    }
    pub fn call_cache_algorithm_access(
        &self,
        cache_mut: &mut CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
        cache_index: CacheAlgorithmT::CacheIndex,
    ) {
        let cache_access_result;
        {
            let mut cache_store_util =
                NodeCacheUtil::new(self, &mut cache_mut.node_ref_map);
            cache_access_result = cache_mut
                .cache_algorithm
                .access(cache_index, &mut cache_store_util);
        }
        match cache_access_result {
            CacheAccessResult::MissReplaced {
                evicted: evicted_cache_indices,
                evicted_keep_cache_algo_data:
                    evicted_keep_cache_algo_data_cache_indices,
            } => unsafe {
                for evicted_cache_index in evicted_cache_indices {
                    self.delete_cache_evicted_unchecked(
                        cache_mut,
                        evicted_cache_index,
                    );
                }
                for evicted_keep_cache_algo_data_cache_index in
                    evicted_keep_cache_algo_data_cache_indices
                {
                    self.delete_cache_evicted_keep_cache_algo_data_unchecked(
                        cache_mut,
                        evicted_keep_cache_algo_data_cache_index,
                    );
                }
            },
            _ => {}
        }
    }
    pub unsafe fn dirty_node_as_mut_unchecked<'a>(
        &self, allocator: AllocatorRefRef<'a, CacheAlgoDataT>,
        node: &mut NodeRefDeltaMpt,
    ) -> &'a mut MemOptimizedTrieNode<CacheAlgoDataT> {
        match node {
            NodeRefDeltaMpt::Committed { db_key: _ } => {
                unreachable!();
            }
            NodeRefDeltaMpt::Dirty { ref index } => NodeMemoryManager::<
                CacheAlgoDataT,
                CacheAlgorithmT,
            >::get_in_memory_node_mut(
                &allocator,
                *index as usize,
            ),
        }
    }
    unsafe fn load_unowned_node_cell_internal_unchecked<'c: 'a, 'a>(
        &self, allocator: AllocatorRefRef<'a, CacheAlgoDataT>,
        node: NodeRefDeltaMpt,
        cache_manager: &'c Mutex<
            CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
        >,
        db: &mut DeltaDbOwnedReadTraitObj, mpt_id: DeltaMptId,
        is_loaded_from_db: &mut bool,
    ) -> Result<
        GuardedValue<
            Option<
                MutexGuard<
                    'c,
                    CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
                >,
            >,
            &'a TrieNodeCell<CacheAlgoDataT>,
        >,
    > {
        match node {
            NodeRefDeltaMpt::Committed { ref db_key } => {
                let mut cache_manager_mut_wrapped = Some(cache_manager.lock());
                let maybe_cache_slot = cache_manager_mut_wrapped
                    .as_mut()
                    .unwrap()
                    .node_ref_map
                    .get_cache_info((mpt_id, *db_key))
                    .and_then(|x| x.get_slot());
                let trie_node = match maybe_cache_slot {
                    Some(cache_slot) => {
                        NodeMemoryManager::<
                            CacheAlgoDataT,
                            CacheAlgorithmT,
                        >::get_in_memory_cell(
                            &allocator, *cache_slot as usize
                        )
                    }
                    None => {
                        cache_manager_mut_wrapped.take();
                        let _db_load_mutex = self.db_load_lock.lock();
                        cache_manager_mut_wrapped = Some(cache_manager.lock());
                        let maybe_cache_slot = cache_manager_mut_wrapped
                            .as_mut()
                            .unwrap()
                            .node_ref_map
                            .get_cache_info((mpt_id, *db_key))
                            .and_then(|x| x.get_slot());
                        match maybe_cache_slot {
                            Some(cache_slot) => NodeMemoryManager::<
                                CacheAlgoDataT,
                                CacheAlgorithmT,
                            >::get_in_memory_cell(
                                &allocator,
                                *cache_slot as usize,
                            ),
                            None => {
                                cache_manager_mut_wrapped.take();
                                let (guard, loaded_trie_node) = self
                                    .load_from_db(
                                        allocator,
                                        cache_manager,
                                        db,
                                        mpt_id,
                                        *db_key,
                                    )?
                                    .into();
                                cache_manager_mut_wrapped = Some(guard);
                                *is_loaded_from_db = true;
                                loaded_trie_node
                            }
                        }
                    }
                };
                self.call_cache_algorithm_access(
                    cache_manager_mut_wrapped.as_mut().unwrap(),
                    (mpt_id, *db_key),
                );
                Ok(GuardedValue::new(cache_manager_mut_wrapped, trie_node))
            }
            NodeRefDeltaMpt::Dirty { index: _ } => unreachable!(),
        }
    }
    unsafe fn get_cached_node_mut_unchecked<'a>(
        &self, allocator: AllocatorRefRef<'a, CacheAlgoDataT>,
        slot: ActualSlabIndex,
    ) -> &'a mut MemOptimizedTrieNode<CacheAlgoDataT> {
        NodeMemoryManager::<CacheAlgoDataT, CacheAlgorithmT>::get_in_memory_node_mut(
            &allocator,
            slot as usize,
        )
    }
    pub fn node_cell_with_cache_manager<'c: 'a, 'a>(
        &self, allocator: AllocatorRefRef<'a, CacheAlgoDataT>,
        node: NodeRefDeltaMpt,
        cache_manager: &'c Mutex<
            CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
        >,
        db: &mut DeltaDbOwnedReadTraitObj, mpt_id: DeltaMptId,
        is_loaded_from_db: &mut bool,
    ) -> Result<
        GuardedValue<
            Option<
                MutexGuard<
                    'c,
                    CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
                >,
            >,
            &'a TrieNodeCell<CacheAlgoDataT>,
        >,
    > {
        match node {
            NodeRefDeltaMpt::Committed { db_key: _ } => unsafe {
                self.load_unowned_node_cell_internal_unchecked(
                    allocator,
                    node,
                    cache_manager,
                    db,
                    mpt_id,
                    is_loaded_from_db,
                )
            },
            NodeRefDeltaMpt::Dirty { ref index } => unsafe {
                Ok(GuardedValue::new(None, NodeMemoryManager::<
                    CacheAlgoDataT,
                    CacheAlgorithmT,
                >::get_in_memory_cell(
                    &allocator,
                    *index as usize,
                )))
            },
        }
    }
    pub fn node_as_ref_with_cache_manager<'c: 'a, 'a>(
        &self, allocator: AllocatorRefRef<'a, CacheAlgoDataT>,
        node: NodeRefDeltaMpt,
        cache_manager: &'c Mutex<
            CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
        >,
        db: &mut DeltaDbOwnedReadTraitObj, mpt_id: DeltaMptId,
        is_loaded_from_db: &mut bool,
    ) -> Result<
        GuardedValue<
            Option<
                MutexGuard<
                    'c,
                    CacheManagerDeltaMpts<CacheAlgoDataT, CacheAlgorithmT>,
                >,
            >,
            &'a MemOptimizedTrieNode<CacheAlgoDataT>,
        >,
    > {
        self.node_cell_with_cache_manager(
            allocator,
            node,
            cache_manager,
            db,
            mpt_id,
            is_loaded_from_db,
        )
        .map(|gv| {
            let (g, v) = gv.into();
            GuardedValue::new(g, v.get_ref())
        })
    }
    pub fn new_node<'a>(
        allocator: AllocatorRefRef<'a, CacheAlgoDataT>,
    ) -> Result<(
        NodeRefDeltaMpt,
        VacantEntry<'a, TrieNodeCell<CacheAlgoDataT>>,
    )> {
        let vacant_entry = allocator.vacant_entry()?;
        let node = NodeRefDeltaMpt::Dirty {
            index: vacant_entry.key() as ActualSlabIndex,
        };
        Ok((node, vacant_entry))
    }
    pub fn free_owned_node(
        &self, node: &mut NodeRefDeltaMpt, mpt_id: DeltaMptId,
    ) {
        let slot = match node {
            NodeRefDeltaMpt::Committed { ref db_key } => {
                let maybe_cache_info =
                    self.cache.lock().node_ref_map.delete((mpt_id, *db_key));
                let maybe_cache_slot = maybe_cache_info
                    .as_ref()
                    .and_then(|cache_info| cache_info.get_slot());
                match maybe_cache_slot {
                    None => return,
                    Some(slot) => *slot,
                }
            }
            NodeRefDeltaMpt::Dirty { ref index } => *index,
        };
        self.get_allocator().remove(slot as usize).unwrap();
    }
    pub fn log_usage(&self) {
        self.cache.lock().log_usage();
        let allocator_ref = self.get_allocator();
        debug!(
            "trie node allocator: max allowed size: {}, \
             configured idle_size: {}, size: {}, allocated: {}",
            self.size_limit,
            self.idle_size,
            allocator_ref.capacity(),
            allocator_ref.len()
        );
        debug!(
            "number of nodes loaded from db {}",
            self.db_load_counter.load(Ordering::Relaxed)
        );
        debug!(
            "number of uncached leaf node loads {}",
            self.uncached_leaf_load_times.load(Ordering::Relaxed)
        );
        debug!(
            "number of db loads for uncached leaf nodes {}",
            self.uncached_leaf_db_loads.load(Ordering::Relaxed)
        );
        debug!(
            "number of db loads for merkle computation {}",
            self.compute_merkle_db_loads.load(Ordering::Relaxed)
        );
        debug!(
            "number of db loads for children merkles {}",
            self.children_merkle_db_loads.load(Ordering::Relaxed)
        );
    }
}
struct NodeCacheUtil<
    'a,
    CacheAlgoDataT: CacheAlgoDataTrait,
    CacheAlgorithmT: CacheAlgorithm<CacheAlgoData = CacheAlgoDataT>,
> {
    node_memory_manager: &'a NodeMemoryManager<CacheAlgoDataT, CacheAlgorithmT>,
    node_ref_map: &'a mut NodeRefMapDeltaMpts<CacheAlgoDataT>,
}
impl<
        'a,
        CacheAlgoDataT: CacheAlgoDataTrait,
        CacheAlgorithmT: CacheAlgorithm<CacheAlgoData = CacheAlgoDataT>,
    > NodeCacheUtil<'a, CacheAlgoDataT, CacheAlgorithmT>
{
    fn new(
        node_memory_manager: &'a NodeMemoryManager<
            CacheAlgoDataT,
            CacheAlgorithmT,
        >,
        node_ref_map: &'a mut NodeRefMapDeltaMpts<CacheAlgoDataT>,
    ) -> Self {
        NodeCacheUtil {
            node_memory_manager,
            node_ref_map,
        }
    }
}
impl<
        'a,
        CacheAlgoDataT: CacheAlgoDataTrait,
        CacheAlgorithmT: CacheAlgorithm<
            CacheAlgoData = CacheAlgoDataT,
            CacheIndex = (DeltaMptId, DeltaMptDbKey),
        >,
    > CacheStoreUtil for NodeCacheUtil<'a, CacheAlgoDataT, CacheAlgorithmT>
{
    type CacheAlgoData = CacheAlgoDataT;
    type ElementIndex = CacheAlgorithmT::CacheIndex;
    fn get(&self, cache_idnex: Self::ElementIndex) -> Self::CacheAlgoData {
        match self
            .node_ref_map
            .get_cache_info(cache_idnex)
            .unwrap()
            .get_cache_info()
        {
            TrieCacheSlotOrCacheAlgoData::TrieCacheSlot(slot) => {
                let allocator = self.node_memory_manager.get_allocator();
                unsafe {
                    self.node_memory_manager
                        .get_cached_node_mut_unchecked(&allocator, *slot)
                        .cache_algo_data
                }
            }
            TrieCacheSlotOrCacheAlgoData::CacheAlgoData(cache_algo_data) => {
                cache_algo_data.clone()
            }
        }
    }
    fn set(
        &mut self, cache_index: Self::ElementIndex,
        algo_data: &Self::CacheAlgoData,
    ) {
        match self
            .node_ref_map
            .get_cache_info(cache_index)
            .unwrap()
            .get_cache_info()
        {
            TrieCacheSlotOrCacheAlgoData::TrieCacheSlot(slot) => {
                let allocator = self.node_memory_manager.get_allocator();
                unsafe {
                    self.node_memory_manager
                        .get_cached_node_mut_unchecked(&allocator, *slot)
                        .cache_algo_data = *algo_data;
                }
            }
            TrieCacheSlotOrCacheAlgoData::CacheAlgoData(_) => {
                self.node_ref_map.set_cache_info(
                    cache_index,
                    CacheableNodeRefDeltaMpt::new(
                        TrieCacheSlotOrCacheAlgoData::CacheAlgoData(*algo_data),
                    ),
                );
            }
        }
    }
}
use super::{
    super::{
        super::{
            storage_db::delta_db_manager::DeltaDbOwnedReadTraitObj,
            utils::{guarded_value::*, UnsafeCellExtension},
        },
        errors::*,
        merkle_patricia_trie::children_table::*,
    },
    cache::algorithm::{
        lru::LRU, CacheAccessResult, CacheAlgoDataTrait, CacheAlgorithm,
        CacheIndexTrait, CacheStoreUtil,
    },
    cache_manager_delta_mpts::CacheManagerDeltaMpts,
    mem_optimized_trie_node::MemOptimizedTrieNode,
    node_ref_map::*,
    slab::Slab,
    NodeRefDeltaMpt,
};
use malloc_size_of_derive::MallocSizeOf as MallocSizeOfDerive;
use parking_lot::{
    Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard,
};
use primitives::MerkleHash;
use rlp::*;
use std::{
    cell::UnsafeCell,
    convert::TryInto,
    sync::atomic::{AtomicUsize, Ordering},
};