nodedb_lite/sync/array/
ack_sender.rs1use std::sync::Arc;
22use std::time::Duration;
23
24use nodedb_array::sync::replica_id::ReplicaId;
25use nodedb_types::sync::wire::SyncMessageType;
26use nodedb_types::sync::wire::array::ArrayAckMsg;
27use tokio::sync::mpsc;
28use tokio::task::JoinHandle;
29use tracing::warn;
30
31use crate::storage::engine::StorageEngine;
32
33use super::inbound::apply::LiteApplyEngine;
34use super::schema_registry::SchemaRegistry;
35
36pub const DEFAULT_ACK_INTERVAL: Duration = Duration::from_secs(30);
38
39pub fn spawn<S: StorageEngine + 'static>(
45 schemas: Arc<SchemaRegistry<S>>,
46 engine: Arc<LiteApplyEngine<S>>,
47 replica_id: ReplicaId,
48 tx: mpsc::Sender<Vec<u8>>,
49 interval: Duration,
50 mut stop: tokio::sync::oneshot::Receiver<()>,
51) -> JoinHandle<()> {
52 tokio::spawn(async move {
53 let mut ticker = tokio::time::interval(interval);
54 ticker.tick().await;
56
57 loop {
58 tokio::select! {
59 _ = ticker.tick() => {
60 send_acks(&schemas, &engine, replica_id, &tx).await;
61 }
62 _ = &mut stop => {
63 return;
64 }
65 }
66 }
67 })
68}
69
70async fn send_acks<S: StorageEngine>(
72 schemas: &SchemaRegistry<S>,
73 engine: &LiteApplyEngine<S>,
74 replica_id: ReplicaId,
75 tx: &mpsc::Sender<Vec<u8>>,
76) {
77 let arrays = schemas.list_arrays();
78 for array in &arrays {
79 let Some(ack_hlc) = engine.last_applied_hlc(array) else {
80 continue;
82 };
83
84 let msg = ArrayAckMsg {
85 array: array.clone(),
86 replica_id: replica_id.as_u64(),
87 ack_hlc_bytes: ack_hlc.to_bytes(),
88 applied_seq: 0,
89 status: nodedb_types::sync::wire::AckStatus::Applied,
90 };
91
92 let frame = match nodedb_types::sync::wire::SyncFrame::try_encode(
93 SyncMessageType::ArrayAck,
94 &msg,
95 ) {
96 Some(f) => f.to_bytes(),
97 None => {
98 warn!(
99 array = %array,
100 "ack_sender: SyncFrame encode failed for ArrayAck"
101 );
102 continue;
103 }
104 };
105
106 if tx.send(frame).await.is_err() {
107 return;
109 }
110 }
111}