mod attachments;
mod handle;
mod registration;
#[cfg(test)]
pub(crate) mod tests;
pub use attachments::{AttachmentError, TypedAttachments};
pub use handle::BlockRegistrationHandle;
use crate::{events::EventsManager, tinylfu::FrequencyTracker};
use crate::blocks::SequenceHash;
use std::sync::{Arc, Weak};
use handle::BlockRegistrationHandleInner;
pub(crate) type PositionalRadixTree<V> = dynamo_tokens::PositionalRadixTree<V, SequenceHash>;
#[derive(Default)]
pub struct BlockRegistryBuilder {
frequency_tracker: Option<Arc<dyn FrequencyTracker<u128>>>,
event_manager: Option<Arc<EventsManager>>,
}
impl BlockRegistryBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn frequency_tracker(mut self, tracker: Arc<dyn FrequencyTracker<u128>>) -> Self {
self.frequency_tracker = Some(tracker);
self
}
pub fn event_manager(mut self, manager: Arc<EventsManager>) -> Self {
self.event_manager = Some(manager);
self
}
pub fn build(self) -> BlockRegistry {
BlockRegistry {
frequency_tracker: self.frequency_tracker,
event_manager: self.event_manager,
prt: Arc::new(PositionalRadixTree::new()),
}
}
}
#[derive(Clone)]
pub struct BlockRegistry {
pub(crate) prt: Arc<PositionalRadixTree<Weak<BlockRegistrationHandleInner>>>,
frequency_tracker: Option<Arc<dyn FrequencyTracker<u128>>>,
event_manager: Option<Arc<EventsManager>>,
}
impl BlockRegistry {
pub fn builder() -> BlockRegistryBuilder {
BlockRegistryBuilder::new()
}
pub fn new() -> Self {
Self::builder().build()
}
pub fn has_frequency_tracking(&self) -> bool {
self.frequency_tracker.is_some()
}
pub fn touch(&self, seq_hash: SequenceHash) {
if let Some(tracker) = &self.frequency_tracker {
tracker.touch(seq_hash.as_u128());
}
}
pub fn count(&self, seq_hash: SequenceHash) -> u32 {
if let Some(tracker) = &self.frequency_tracker {
tracker.count(seq_hash.as_u128())
} else {
0
}
}
pub fn check_presence<T: crate::blocks::BlockMetadata>(
&self,
seq_hashes: &[SequenceHash],
) -> Vec<(SequenceHash, bool)> {
seq_hashes
.iter()
.map(|&seq_hash| {
let handle_result = self.match_sequence_hash(seq_hash, false);
let present = handle_result
.as_ref()
.map(|handle| handle.has_block::<T>())
.unwrap_or(false);
tracing::debug!(
?seq_hash,
type_name = std::any::type_name::<T>(),
handle_found = handle_result.is_some(),
present,
"check_presence result"
);
(seq_hash, present)
})
.collect()
}
pub fn check_presence_any(
&self,
seq_hashes: &[SequenceHash],
type_ids: &[std::any::TypeId],
) -> Vec<(SequenceHash, bool)> {
seq_hashes
.iter()
.map(|&seq_hash| {
let present = self
.match_sequence_hash(seq_hash, false)
.map(|handle| handle.has_any_block(type_ids))
.unwrap_or(false);
(seq_hash, present)
})
.collect()
}
#[inline]
pub fn register_sequence_hash(&self, seq_hash: SequenceHash) -> BlockRegistrationHandle {
let map = self.prt.prefix(&seq_hash);
let mut weak = map.entry(seq_hash).or_default();
if let Some(inner) = weak.upgrade() {
return BlockRegistrationHandle::from_inner(inner);
}
let inner = self.create_registration(seq_hash);
*weak = Arc::downgrade(&inner);
let handle = BlockRegistrationHandle::from_inner(inner);
if let Some(event_manager) = &self.event_manager
&& let Err(e) = event_manager.on_block_registered(&handle)
{
tracing::warn!("Failed to register block with event manager: {}", e);
}
self.touch(seq_hash);
handle
}
#[allow(dead_code)]
pub(crate) fn transfer_registration(&self, seq_hash: SequenceHash) -> BlockRegistrationHandle {
let map = self.prt.prefix(&seq_hash);
let mut weak = map.entry(seq_hash).or_default();
match weak.upgrade() {
Some(inner) => BlockRegistrationHandle::from_inner(inner),
None => {
let inner = self.create_registration(seq_hash);
*weak = Arc::downgrade(&inner);
BlockRegistrationHandle::from_inner(inner)
}
}
}
fn create_registration(&self, seq_hash: SequenceHash) -> Arc<BlockRegistrationHandleInner> {
Arc::new(BlockRegistrationHandleInner::new(
seq_hash,
Arc::downgrade(&self.prt),
))
}
#[inline]
pub fn match_sequence_hash(
&self,
seq_hash: SequenceHash,
touch: bool,
) -> Option<BlockRegistrationHandle> {
let result = self
.prt
.prefix(&seq_hash)
.get(&seq_hash)
.and_then(|weak| weak.upgrade())
.map(BlockRegistrationHandle::from_inner);
if result.is_some() && touch {
self.touch(seq_hash);
}
result
}
#[inline]
pub fn is_registered(&self, seq_hash: SequenceHash) -> bool {
self.prt
.prefix(&seq_hash)
.get(&seq_hash)
.map(|weak| weak.strong_count() > 0)
.unwrap_or(false)
}
pub fn registered_count(&self) -> usize {
self.prt.len()
}
pub fn frequency_tracker(&self) -> Option<Arc<dyn FrequencyTracker<u128>>> {
self.frequency_tracker.clone()
}
}
impl Default for BlockRegistry {
fn default() -> Self {
Self::new()
}
}