use std::sync::Arc;
use std::time::Duration;
use nodedb_array::sync::replica_id::ReplicaId;
use nodedb_types::sync::wire::SyncMessageType;
use nodedb_types::sync::wire::array::ArrayAckMsg;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use tracing::warn;
use crate::storage::engine::StorageEngine;
use super::inbound::apply::LiteApplyEngine;
use super::schema_registry::SchemaRegistry;
pub const DEFAULT_ACK_INTERVAL: Duration = Duration::from_secs(30);
pub fn spawn<S: StorageEngine + 'static>(
schemas: Arc<SchemaRegistry<S>>,
engine: Arc<LiteApplyEngine<S>>,
replica_id: ReplicaId,
tx: mpsc::Sender<Vec<u8>>,
interval: Duration,
mut stop: tokio::sync::oneshot::Receiver<()>,
) -> JoinHandle<()> {
tokio::spawn(async move {
let mut ticker = tokio::time::interval(interval);
ticker.tick().await;
loop {
tokio::select! {
_ = ticker.tick() => {
send_acks(&schemas, &engine, replica_id, &tx).await;
}
_ = &mut stop => {
return;
}
}
}
})
}
async fn send_acks<S: StorageEngine>(
schemas: &SchemaRegistry<S>,
engine: &LiteApplyEngine<S>,
replica_id: ReplicaId,
tx: &mpsc::Sender<Vec<u8>>,
) {
let arrays = schemas.list_arrays();
for array in &arrays {
let Some(ack_hlc) = engine.last_applied_hlc(array) else {
continue;
};
let msg = ArrayAckMsg {
array: array.clone(),
replica_id: replica_id.as_u64(),
ack_hlc_bytes: ack_hlc.to_bytes(),
applied_seq: 0,
status: nodedb_types::sync::wire::AckStatus::Applied,
};
let frame = match nodedb_types::sync::wire::SyncFrame::try_encode(
SyncMessageType::ArrayAck,
&msg,
) {
Some(f) => f.to_bytes(),
None => {
warn!(
array = %array,
"ack_sender: SyncFrame encode failed for ArrayAck"
);
continue;
}
};
if tx.send(frame).await.is_err() {
return;
}
}
}