use std::{
collections::{HashMap, HashSet},
sync::Arc,
time::Instant,
};
use massa_models::{block_header::SecuredHeader, block_id::BlockId};
use massa_protocol_exports::PeerId;
use parking_lot::RwLock;
use schnellru::{ByLength, LruMap};
pub struct BlockCache {
pub checked_headers: LruMap<BlockId, SecuredHeader>,
pub blocks_known_by_peer: HashMap<PeerId, LruMap<BlockId, (bool, Instant)>>,
pub max_known_blocks_by_peer: u32,
}
impl BlockCache {
pub fn insert_peer_known_block(
&mut self,
from_peer_id: &PeerId,
block_ids: &[BlockId],
known: bool,
) {
let now = Instant::now();
let known_blocks = self
.blocks_known_by_peer
.entry(*from_peer_id)
.or_insert_with(|| LruMap::new(ByLength::new(self.max_known_blocks_by_peer)));
for block_id in block_ids {
known_blocks.insert(*block_id, (known, now));
}
}
}
impl BlockCache {
pub fn new(max_known_blocks: u32, max_known_blocks_by_peer: u32) -> Self {
Self {
checked_headers: LruMap::new(ByLength::new(max_known_blocks)),
blocks_known_by_peer: HashMap::new(),
max_known_blocks_by_peer,
}
}
pub fn update_cache(&mut self, peers_connected: &HashSet<PeerId>) {
self.blocks_known_by_peer
.retain(|peer_id, _| peers_connected.contains(peer_id));
for peer_id in peers_connected {
match self.blocks_known_by_peer.entry(*peer_id) {
std::collections::hash_map::Entry::Occupied(_) => {}
std::collections::hash_map::Entry::Vacant(entry) => {
entry.insert(LruMap::new(ByLength::new(self.max_known_blocks_by_peer)));
}
}
}
}
}
pub type SharedBlockCache = Arc<RwLock<BlockCache>>;