use super::event::{CdcEvent, PendingEvent};
use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
static NEXT_EPOCH: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1);
fn next_epoch() -> u64 {
NEXT_EPOCH.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
}
pub const DEFAULT_CAPACITY: usize = 65_536;
pub const MAX_CAPACITY: usize = 10_000_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CdcEnrichment {
#[default]
Off,
Full,
}
impl CdcEnrichment {
pub fn as_str(&self) -> &'static str {
match self {
CdcEnrichment::Off => "off",
CdcEnrichment::Full => "full",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct CdcHandoff {
pub epoch: u64,
pub last_seq: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CdcStatus {
pub epoch: u64,
pub capacity: usize,
pub enrichment: CdcEnrichment,
pub buffered: usize,
pub earliest: u64,
pub current: u64,
}
#[derive(Debug)]
pub struct CdcLog {
epoch: u64,
next_seq: u64,
capacity: usize,
enrichment: CdcEnrichment,
events: VecDeque<CdcEvent>,
}
impl CdcLog {
pub(crate) fn new(capacity: usize, enrichment: CdcEnrichment) -> Self {
Self {
epoch: next_epoch(),
next_seq: 1,
capacity: capacity.max(1),
enrichment,
events: VecDeque::new(),
}
}
pub fn epoch(&self) -> u64 {
self.epoch
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn enrichment(&self) -> CdcEnrichment {
self.enrichment
}
pub fn current(&self) -> u64 {
self.next_seq - 1
}
pub fn earliest(&self) -> u64 {
self.events.front().map_or(self.next_seq, |event| event.seq)
}
pub fn len(&self) -> usize {
self.events.len()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
pub fn status(&self) -> CdcStatus {
CdcStatus {
epoch: self.epoch,
capacity: self.capacity,
enrichment: self.enrichment,
buffered: self.events.len(),
earliest: self.earliest(),
current: self.current(),
}
}
pub(crate) fn append(&mut self, pending: Vec<PendingEvent>) {
for event in pending {
self.events.push_back(CdcEvent {
seq: self.next_seq,
kind: event.kind,
change: event.change,
});
self.next_seq += 1;
while self.events.len() > self.capacity {
self.events.pop_front();
}
}
}
pub(crate) fn reconfigure(&mut self, capacity: usize, enrichment: CdcEnrichment) {
self.capacity = capacity.max(1);
self.enrichment = enrichment;
while self.events.len() > self.capacity {
self.events.pop_front();
}
}
pub fn since(&self, from: u64, limit: Option<usize>) -> Vec<&CdcEvent> {
let iter = self.events.iter().filter(move |event| event.seq > from);
match limit {
Some(limit) => iter.take(limit).collect(),
None => iter.collect(),
}
}
}