Skip to main content

nodedb_lite/nodedb/sync_delegate/
delegate_impl.rs

1//! `SyncDelegate` trait implementation for `NodeDbLite` — bridges the sync
2//! transport to NodeDbLite's engines. Split out of `mod.rs` to keep that file
3//! to module declarations only (a single trait impl cannot be split across
4//! multiple `impl` blocks, so it lives here as one file).
5
6#[cfg(not(target_arch = "wasm32"))]
7use crate::storage::engine::StorageEngine;
8
9#[cfg(not(target_arch = "wasm32"))]
10use super::super::core::NodeDbLite;
11
12#[cfg(not(target_arch = "wasm32"))]
13#[async_trait::async_trait]
14impl<S: StorageEngine> crate::sync::SyncDelegate for NodeDbLite<S> {
15    fn sync_identity(&self) -> crate::identity::LiteIdentity {
16        NodeDbLite::sync_identity(self)
17    }
18
19    async fn regenerate_identity(&self) {
20        if let Err(e) = NodeDbLite::regenerate_identity(self).await {
21            // The instance keeps authoring under a producer identity Origin has
22            // already rejected as forked, so every push from here is refused.
23            // Nothing local can repair that, and continuing quietly is how the
24            // replica ends up permanently desynced without a signal.
25            tracing::error!(
26                error = %e,
27                "SyncDelegate: fork recovery failed — this replica cannot sync until its \
28                 producer identity is replaced"
29            );
30        }
31    }
32
33    async fn rotate_peer_id(&self) {
34        if let Err(e) = NodeDbLite::rotate_peer_id(self).await {
35            tracing::error!(
36                error = %e,
37                "SyncDelegate: peer-id rotation failed — this replica cannot sync until its \
38                 Loro peer id is replaced"
39            );
40        }
41    }
42
43    fn pending_deltas(&self) -> Vec<crate::engine::crdt::engine::PendingDelta> {
44        self.pending_crdt_deltas().unwrap_or_default()
45    }
46
47    async fn set_pending_delta_seq(&self, mutation_id: u64, seq: u64) {
48        if let Err(e) = self.set_crdt_pending_delta_seq(mutation_id, seq) {
49            tracing::warn!(
50                mutation_id,
51                seq,
52                error = %e,
53                "SyncDelegate: set_pending_delta_seq failed"
54            );
55        }
56    }
57
58    fn acknowledge(&self, mutation_id: u64) {
59        if let Err(e) = self.acknowledge_deltas(mutation_id) {
60            tracing::warn!(mutation_id, error = %e, "SyncDelegate: acknowledge failed");
61        }
62    }
63
64    fn reject(&self, mutation_id: u64) {
65        if let Err(e) = self.reject_delta(mutation_id) {
66            tracing::warn!(mutation_id, error = %e, "SyncDelegate: reject failed");
67        }
68    }
69
70    fn reject_with_policy(
71        &self,
72        mutation_id: u64,
73        hint: &nodedb_types::sync::compensation::CompensationHint,
74    ) {
75        if let Err(error) = super::reject::handle_reject_with_policy_impl(self, mutation_id, hint) {
76            tracing::error!(mutation_id, %error, "delta rejection maintenance returned an error");
77        }
78    }
79
80    fn import_remote(&self, collection: &str, data: &[u8]) {
81        if let Err(e) = self.import_remote_deltas(collection, data) {
82            tracing::warn!(
83                collection = %collection,
84                error = %e,
85                "SyncDelegate: import_remote failed"
86            );
87        }
88    }
89
90    async fn apply_remote_row(
91        &self,
92        msg: &nodedb_types::sync::wire::RowPushMsg,
93    ) -> Result<(), nodedb_types::error::NodeDbError> {
94        let delete = matches!(msg.op, nodedb_types::sync::wire::RowOp::Delete);
95        self.apply_remote_row(&msg.collection, &msg.document_id, &msg.payload, delete)
96            .await
97    }
98
99    async fn handle_array_delta(
100        &self,
101        msg: &nodedb_types::sync::wire::ArrayDeltaMsg,
102    ) -> Option<nodedb_types::sync::wire::ArrayAckMsg> {
103        super::array::handle_array_delta_impl(self, msg).await
104    }
105
106    async fn handle_array_delta_batch(
107        &self,
108        msg: &nodedb_types::sync::wire::ArrayDeltaBatchMsg,
109    ) -> Option<nodedb_types::sync::wire::ArrayAckMsg> {
110        super::array::handle_array_delta_batch_impl(self, msg).await
111    }
112
113    async fn handle_array_reject(
114        &self,
115        msg: &nodedb_types::sync::wire::ArrayRejectMsg,
116    ) -> Option<nodedb_types::sync::wire::ArrayCatchupRequestMsg> {
117        super::array::handle_array_reject_impl(self, msg).await
118    }
119
120    async fn handle_array_snapshot(&self, msg: &nodedb_types::sync::wire::ArraySnapshotMsg) {
121        super::array::handle_array_snapshot_impl(self, msg).await
122    }
123
124    async fn handle_array_snapshot_chunk(
125        &self,
126        msg: &nodedb_types::sync::wire::ArraySnapshotChunkMsg,
127    ) -> Option<nodedb_types::sync::wire::ArrayAckMsg> {
128        super::array::handle_array_snapshot_chunk_impl(self, msg).await
129    }
130
131    fn begin_array_catchup(&self) -> Vec<nodedb_types::sync::wire::ArrayCatchupRequestMsg> {
132        super::array::begin_array_catchup_impl(self)
133    }
134
135    async fn pending_array_ops(
136        &self,
137        after: Option<nodedb_array::sync::hlc::Hlc>,
138        limit: usize,
139    ) -> Result<Vec<crate::sync::array::PendingArrayOp>, crate::error::LiteError> {
140        super::array::pending_array_ops_impl(self, after, limit).await
141    }
142
143    async fn persist_array_op_seq(
144        &self,
145        op: &crate::sync::array::PendingArrayOp,
146    ) -> Result<(), crate::error::LiteError> {
147        super::array::persist_array_op_seq_impl(self, op).await
148    }
149
150    async fn retire_array_ops(
151        &self,
152        hlcs: &[nodedb_array::sync::hlc::Hlc],
153    ) -> Result<(), crate::error::LiteError> {
154        super::array::retire_array_ops_impl(self, hlcs).await
155    }
156
157    fn array_schema_announce(
158        &self,
159        array: &str,
160    ) -> Result<Option<nodedb_types::sync::wire::ArraySchemaSyncMsg>, crate::error::LiteError> {
161        super::array::array_schema_announce_impl(self, array)
162    }
163
164    async fn pending_columnar_batches(
165        &self,
166    ) -> Vec<(
167        Vec<u8>,
168        crate::sync::outbound::columnar::PendingColumnarBatch,
169    )> {
170        super::columnar_handlers::pending_columnar_batches_impl(self).await
171    }
172
173    async fn mark_columnar_batch_in_flight(&self, batch_id: u64, durable_key: Vec<u8>) {
174        super::columnar_handlers::mark_columnar_batch_in_flight_impl(self, batch_id, durable_key)
175            .await
176    }
177
178    async fn ack_columnar_batch_in_flight(&self, batch_id: u64) {
179        super::columnar_handlers::ack_columnar_batch_in_flight_impl(self, batch_id).await
180    }
181
182    async fn acknowledge_columnar_batch(&self, durable_key: Vec<u8>) {
183        super::columnar_handlers::acknowledge_columnar_batch_impl(self, durable_key).await
184    }
185
186    async fn pending_vector_inserts(
187        &self,
188    ) -> Vec<(Vec<u8>, crate::sync::outbound::vector::PendingVectorInsert)> {
189        super::vector_handlers::pending_vector_inserts_impl(self).await
190    }
191
192    async fn mark_vector_insert_in_flight(&self, batch_id: u64, durable_key: Vec<u8>) {
193        super::vector_handlers::mark_vector_insert_in_flight_impl(self, batch_id, durable_key).await
194    }
195
196    async fn ack_vector_insert_in_flight(&self, batch_id: u64) {
197        super::vector_handlers::ack_vector_insert_in_flight_impl(self, batch_id).await
198    }
199
200    async fn acknowledge_vector_insert(&self, durable_key: Vec<u8>) {
201        super::vector_handlers::acknowledge_vector_insert_impl(self, durable_key).await
202    }
203
204    async fn pending_vector_deletes(
205        &self,
206    ) -> Vec<(Vec<u8>, crate::sync::outbound::vector::PendingVectorDelete)> {
207        super::vector_handlers::pending_vector_deletes_impl(self).await
208    }
209
210    async fn mark_vector_delete_in_flight(&self, batch_id: u64, durable_key: Vec<u8>) {
211        super::vector_handlers::mark_vector_delete_in_flight_impl(self, batch_id, durable_key).await
212    }
213
214    async fn ack_vector_delete_in_flight(&self, batch_id: u64) {
215        super::vector_handlers::ack_vector_delete_in_flight_impl(self, batch_id).await
216    }
217
218    async fn acknowledge_vector_delete(&self, durable_key: Vec<u8>) {
219        super::vector_handlers::acknowledge_vector_delete_impl(self, durable_key).await
220    }
221
222    async fn pending_fts_indexes(
223        &self,
224    ) -> Result<Vec<(Vec<u8>, crate::sync::outbound::fts::PendingFtsIndex)>, crate::error::LiteError>
225    {
226        super::fts_handlers::pending_fts_indexes_impl(self).await
227    }
228
229    async fn mark_fts_index_in_flight(&self, batch_id: u64, durable_key: Vec<u8>) {
230        super::fts_handlers::mark_fts_index_in_flight_impl(self, batch_id, durable_key).await
231    }
232
233    async fn ack_fts_index_in_flight(&self, batch_id: u64) {
234        super::fts_handlers::ack_fts_index_in_flight_impl(self, batch_id).await
235    }
236
237    async fn acknowledge_fts_index(&self, durable_key: Vec<u8>) {
238        super::fts_handlers::acknowledge_fts_index_impl(self, durable_key).await
239    }
240
241    async fn pending_fts_deletes(
242        &self,
243    ) -> Result<Vec<(Vec<u8>, crate::sync::outbound::fts::PendingFtsDelete)>, crate::error::LiteError>
244    {
245        super::fts_handlers::pending_fts_deletes_impl(self).await
246    }
247
248    async fn mark_fts_delete_in_flight(&self, batch_id: u64, durable_key: Vec<u8>) {
249        super::fts_handlers::mark_fts_delete_in_flight_impl(self, batch_id, durable_key).await
250    }
251
252    async fn ack_fts_delete_in_flight(&self, batch_id: u64) {
253        super::fts_handlers::ack_fts_delete_in_flight_impl(self, batch_id).await
254    }
255
256    async fn acknowledge_fts_delete(&self, durable_key: Vec<u8>) {
257        super::fts_handlers::acknowledge_fts_delete_impl(self, durable_key).await
258    }
259
260    async fn pending_spatial_inserts(
261        &self,
262    ) -> Vec<(
263        Vec<u8>,
264        crate::sync::outbound::spatial::PendingSpatialInsert,
265    )> {
266        super::spatial_handlers::pending_spatial_inserts_impl(self).await
267    }
268
269    async fn mark_spatial_insert_in_flight(&self, batch_id: u64, durable_key: Vec<u8>) {
270        super::spatial_handlers::mark_spatial_insert_in_flight_impl(self, batch_id, durable_key)
271            .await
272    }
273
274    async fn ack_spatial_insert_in_flight(&self, batch_id: u64) {
275        super::spatial_handlers::ack_spatial_insert_in_flight_impl(self, batch_id).await
276    }
277
278    async fn acknowledge_spatial_insert(&self, durable_key: Vec<u8>) {
279        super::spatial_handlers::acknowledge_spatial_insert_impl(self, durable_key).await
280    }
281
282    async fn pending_spatial_deletes(
283        &self,
284    ) -> Vec<(
285        Vec<u8>,
286        crate::sync::outbound::spatial::PendingSpatialDelete,
287    )> {
288        super::spatial_handlers::pending_spatial_deletes_impl(self).await
289    }
290
291    async fn mark_spatial_delete_in_flight(&self, batch_id: u64, durable_key: Vec<u8>) {
292        super::spatial_handlers::mark_spatial_delete_in_flight_impl(self, batch_id, durable_key)
293            .await
294    }
295
296    async fn ack_spatial_delete_in_flight(&self, batch_id: u64) {
297        super::spatial_handlers::ack_spatial_delete_in_flight_impl(self, batch_id).await
298    }
299
300    async fn acknowledge_spatial_delete(&self, durable_key: Vec<u8>) {
301        super::spatial_handlers::acknowledge_spatial_delete_impl(self, durable_key).await
302    }
303
304    async fn pending_timeseries_batches(
305        &self,
306    ) -> Vec<(
307        Vec<u8>,
308        crate::sync::outbound::timeseries::PendingTimeseriesBatch,
309    )> {
310        super::timeseries_handlers::pending_timeseries_batches_impl(self).await
311    }
312
313    async fn mark_timeseries_batch_in_flight(
314        &self,
315        stream_seq: u64,
316        batch_id: u64,
317        durable_key: Vec<u8>,
318    ) {
319        super::timeseries_handlers::mark_timeseries_batch_in_flight_impl(
320            self,
321            stream_seq,
322            batch_id,
323            durable_key,
324        )
325        .await
326    }
327
328    async fn ack_timeseries_batches_through_seq(&self, applied_seq: u64) {
329        super::timeseries_handlers::ack_timeseries_batches_through_seq_impl(self, applied_seq).await
330    }
331
332    async fn ack_timeseries_batch_by_id(&self, batch_id: u64) {
333        super::timeseries_handlers::ack_timeseries_batch_by_id_impl(self, batch_id).await
334    }
335
336    async fn acknowledge_timeseries_batch(&self, durable_key: Vec<u8>) {
337        super::timeseries_handlers::acknowledge_timeseries_batch_impl(self, durable_key).await
338    }
339
340    async fn pending_kv_writes(
341        &self,
342    ) -> Result<Vec<(Vec<u8>, crate::sync::outbound::kv::PendingKvWrite)>, crate::error::LiteError>
343    {
344        super::kv_handlers::pending_kv_writes_impl(self).await
345    }
346
347    async fn persist_kv_write_seq(
348        &self,
349        key: &[u8],
350        write: &crate::sync::outbound::kv::PendingKvWrite,
351    ) -> Result<(), crate::error::LiteError> {
352        super::kv_handlers::persist_kv_write_seq_impl(self, key, write).await
353    }
354
355    async fn mark_kv_write_in_flight(&self, batch_id: u64) {
356        super::kv_handlers::mark_kv_write_in_flight_impl(self, batch_id).await
357    }
358
359    async fn retire_kv_write(&self, batch_id: u64) -> Result<(), crate::error::LiteError> {
360        super::kv_handlers::retire_kv_write_impl(self, batch_id).await
361    }
362
363    async fn clear_engine_in_flight(&self) {
364        super::outbound_state::clear_engine_in_flight_impl(self).await
365    }
366
367    async fn next_stream_seq(&self, stream_id: u64) -> u64 {
368        super::outbound_state::next_stream_seq_impl(self, stream_id).await
369    }
370
371    async fn record_stream_ack(&self, stream_id: u64, applied_seq: u64) {
372        super::outbound_state::record_stream_ack_impl(self, stream_id, applied_seq).await
373    }
374
375    async fn persist_producer_state(&self, producer_id: u64, accepted_epoch: u64) {
376        super::producer_state::persist_producer_state_impl(self, producer_id, accepted_epoch).await
377    }
378
379    async fn load_producer_state(&self) -> (u64, u64) {
380        super::producer_state::load_producer_state_impl(self).await
381    }
382
383    async fn import_definition(&self, msg: &nodedb_types::sync::wire::DefinitionSyncMsg) {
384        if let Err(e) = super::definition_apply::apply_definition_sync(self, msg).await {
385            tracing::warn!(
386                definition_type = %msg.definition_type,
387                name = %msg.name,
388                error = %e,
389                "definition sync failed"
390            );
391        }
392    }
393
394    async fn import_collection_schema(
395        &self,
396        msg: &nodedb_types::sync::wire::CollectionSchemaSyncMsg,
397    ) {
398        if let Err(e) = self
399            .register_collection_from_descriptor(&msg.descriptor)
400            .await
401        {
402            tracing::warn!(
403                collection = %msg.descriptor.name,
404                error = %e,
405                "collection schema sync failed"
406            );
407        }
408    }
409
410    async fn get_collection_meta(
411        &self,
412        name: &str,
413    ) -> Option<crate::nodedb::collection::CollectionMeta> {
414        super::producer_state::get_collection_meta_impl(self, name).await
415    }
416
417    // ── Stable seq persistence ────────────────────────────────────────────────
418
419    async fn persist_columnar_seq(
420        &self,
421        key: &[u8],
422        batch: &crate::sync::outbound::columnar::PendingColumnarBatch,
423    ) -> Result<(), crate::error::LiteError> {
424        super::columnar_handlers::persist_columnar_seq_impl(self, key, batch).await
425    }
426
427    async fn persist_timeseries_seq(
428        &self,
429        key: &[u8],
430        batch: &crate::sync::outbound::timeseries::PendingTimeseriesBatch,
431    ) -> Result<(), crate::error::LiteError> {
432        super::timeseries_handlers::persist_timeseries_seq_impl(self, key, batch).await
433    }
434
435    async fn persist_vector_insert_seq(
436        &self,
437        key: &[u8],
438        insert: &crate::sync::outbound::vector::PendingVectorInsert,
439    ) -> Result<(), crate::error::LiteError> {
440        super::vector_handlers::persist_vector_insert_seq_impl(self, key, insert).await
441    }
442
443    async fn persist_vector_delete_seq(
444        &self,
445        key: &[u8],
446        delete: &crate::sync::outbound::vector::PendingVectorDelete,
447    ) -> Result<(), crate::error::LiteError> {
448        super::vector_handlers::persist_vector_delete_seq_impl(self, key, delete).await
449    }
450
451    async fn persist_fts_index_seq(
452        &self,
453        key: &[u8],
454        entry: &crate::sync::outbound::fts::PendingFtsIndex,
455    ) -> Result<(), crate::error::LiteError> {
456        super::fts_handlers::persist_fts_index_seq_impl(self, key, entry).await
457    }
458
459    async fn persist_fts_delete_seq(
460        &self,
461        key: &[u8],
462        entry: &crate::sync::outbound::fts::PendingFtsDelete,
463    ) -> Result<(), crate::error::LiteError> {
464        super::fts_handlers::persist_fts_delete_seq_impl(self, key, entry).await
465    }
466
467    async fn persist_spatial_insert_seq(
468        &self,
469        key: &[u8],
470        insert: &crate::sync::outbound::spatial::PendingSpatialInsert,
471    ) -> Result<(), crate::error::LiteError> {
472        super::spatial_handlers::persist_spatial_insert_seq_impl(self, key, insert).await
473    }
474
475    async fn persist_spatial_delete_seq(
476        &self,
477        key: &[u8],
478        delete: &crate::sync::outbound::spatial::PendingSpatialDelete,
479    ) -> Result<(), crate::error::LiteError> {
480        super::spatial_handlers::persist_spatial_delete_seq_impl(self, key, delete).await
481    }
482}