use crate::leader_buffer::SLOTS_PER_LEADER;
use crate::leader_entry::LeaderEntry;
#[derive(Debug, Clone)]
pub struct ScheduleSnapshot {
epoch: u64,
epoch_start_slot: u64,
first_leader_index: u64,
leaders: Box<[LeaderEntry]>,
}
impl ScheduleSnapshot {
#[inline]
pub fn new(epoch: u64, epoch_start_slot: u64, leaders: Box<[LeaderEntry]>) -> Self {
Self {
epoch,
epoch_start_slot,
first_leader_index: epoch_start_slot / SLOTS_PER_LEADER,
leaders,
}
}
#[inline]
pub fn epoch(&self) -> u64 {
self.epoch
}
#[inline]
pub fn epoch_start_slot(&self) -> u64 {
self.epoch_start_slot
}
#[inline]
pub fn leaders_len(&self) -> usize {
self.leaders.len()
}
#[inline]
pub fn leaders(&self) -> &[LeaderEntry] {
&self.leaders
}
#[inline]
pub fn covers_slot(&self, slot: u64) -> bool {
let leader_index = slot / SLOTS_PER_LEADER;
leader_index >= self.first_leader_index
&& leader_index < self.first_leader_index + self.leaders.len() as u64
}
#[inline]
pub fn get_leader_at_slot(&self, slot: u64) -> Option<LeaderEntry> {
let index = self.index_for_slot(slot)?;
Some(self.leaders[index])
}
#[inline]
pub fn get_next_leaders_into(&self, start_slot: u64, buffer: &mut [LeaderEntry]) -> usize {
let mut written = 0usize;
let mut leader_index = (start_slot / SLOTS_PER_LEADER).max(self.first_leader_index);
while written < buffer.len() {
let offset = leader_index.saturating_sub(self.first_leader_index) as usize;
if offset >= self.leaders.len() {
break;
}
buffer[written] = self.leaders[offset];
written += 1;
leader_index += 1;
}
written
}
#[inline]
fn index_for_slot(&self, slot: u64) -> Option<usize> {
let leader_index = slot / SLOTS_PER_LEADER;
if leader_index < self.first_leader_index {
return None;
}
let offset = leader_index - self.first_leader_index;
(offset < self.leaders.len() as u64).then_some(offset as usize)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::leader_entry::LeaderPubkey;
#[test]
fn schedule_snapshot_indexes_by_leader() {
let leader = LeaderEntry::new_ipv4(
LeaderPubkey::new([1; 32]),
[127, 0, 0, 1],
8000,
[127, 0, 0, 1],
8001,
);
let snapshot = ScheduleSnapshot::new(1, 100, vec![leader, LeaderEntry::EMPTY].into());
assert!(snapshot.covers_slot(100));
assert_eq!(
snapshot.get_leader_at_slot(103).unwrap().pubkey.to_bytes()[0],
1
);
assert!(snapshot.get_leader_at_slot(108).is_none());
}
}