sof 0.17.1

Solana Observer Framework for low-latency shred ingestion and plugin-driven transaction observation
Documentation
use super::*;

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
struct OutstandingRepairKey {
    slot: u64,
    index: u32,
    kind: MissingShredRequestKind,
}

impl OutstandingRepairKey {
    #[cfg(any(feature = "gossip-bootstrap", test))]
    const fn from_request(request: &MissingShredRequest) -> Self {
        Self {
            slot: request.slot,
            index: request.index,
            kind: request.kind,
        }
    }
}

#[derive(Debug)]
pub struct OutstandingRepairRequests {
    entries: HashMap<OutstandingRepairKey, Instant>,
    #[cfg(any(feature = "gossip-bootstrap", test))]
    timeout: Duration,
}

impl OutstandingRepairRequests {
    pub fn new(timeout: Duration) -> Self {
        #[cfg(not(any(feature = "gossip-bootstrap", test)))]
        let _ = timeout;
        Self {
            entries: HashMap::new(),
            #[cfg(any(feature = "gossip-bootstrap", test))]
            timeout,
        }
    }

    #[cfg(feature = "gossip-bootstrap")]
    pub fn purge_expired(&mut self, now: Instant) -> usize {
        let before = self.entries.len();
        self.entries
            .retain(|_, sent_at| now.saturating_duration_since(*sent_at) < self.timeout);
        before.saturating_sub(self.entries.len())
    }

    #[cfg(any(feature = "gossip-bootstrap", test))]
    pub fn try_reserve(&mut self, request: &MissingShredRequest, now: Instant) -> bool {
        let key = OutstandingRepairKey::from_request(request);
        if let Some(sent_at) = self.entries.get_mut(&key) {
            if now.saturating_duration_since(*sent_at) < self.timeout {
                return false;
            }
            *sent_at = now;
            return true;
        }
        let _ = self.entries.insert(key, now);
        true
    }

    #[cfg(feature = "gossip-bootstrap")]
    pub fn release(&mut self, request: &MissingShredRequest) {
        let _ = self
            .entries
            .remove(&OutstandingRepairKey::from_request(request));
    }

    pub fn on_shred_received(&mut self, slot: u64, index: u32) -> usize {
        let mut removed = 0_usize;
        if self
            .entries
            .remove(&OutstandingRepairKey {
                slot,
                index,
                kind: MissingShredRequestKind::WindowIndex,
            })
            .is_some()
        {
            removed = removed.saturating_add(1);
        }
        let before = self.entries.len();
        self.entries.retain(|key, _| {
            !(key.kind == MissingShredRequestKind::HighestWindowIndex
                && key.slot == slot
                && key.index <= index)
        });
        removed.saturating_add(before.saturating_sub(self.entries.len()))
    }

    pub fn len(&self) -> usize {
        self.entries.len()
    }
}