1use crate::change::{Change, Lamport};
2use crate::dag::{Dag, DagNode};
3use crate::id::{Counter, ID};
4use crate::span::{HasId, HasLamport};
5use crate::sync::Mutex;
6use crate::version::{shrink_frontiers, Frontiers, ImVersionVector, VersionVector};
7use loro_common::{HasCounter, HasCounterSpan, HasIdSpan, HasLamportSpan, PeerID};
8use once_cell::sync::OnceCell;
9use rle::{HasIndex, HasLength, Mergable, Sliceable};
10use rustc_hash::FxHashSet;
11use smallvec::SmallVec;
12use std::cmp::Ordering;
13use std::collections::{BTreeMap, BTreeSet, BinaryHeap};
14use std::fmt::Display;
15use std::ops::{ControlFlow, Deref};
16use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
17use std::sync::Arc;
18use tracing::instrument;
19
20use super::change_store::BatchDecodeInfo;
21use super::ChangeStore;
22
23#[derive(Debug)]
26pub struct AppDag {
27 change_store: ChangeStore,
28 map: Mutex<BTreeMap<ID, AppDagNode>>,
33 frontiers: Frontiers,
35 vv: VersionVector,
37 shallow_since_frontiers: Frontiers,
39 shallow_root_frontiers_deps: Frontiers,
41 shallow_since_vv: ImVersionVector,
43 unparsed_vv: Mutex<VersionVector>,
49 unhandled_dep_points: Mutex<BTreeSet<ID>>,
53 pending_txn_node: Option<AppDagNode>,
54 import_rollback_has_journal: AtomicBool,
55 import_rollback: Mutex<Option<AppDagRollback>>,
56}
57
58#[derive(Debug)]
59pub(crate) struct AppDagRollback {
60 frontiers: Frontiers,
61 vv: VersionVector,
62 unparsed_vv: VersionVector,
63 shallow_since_frontiers: Frontiers,
64 shallow_root_frontiers_deps: Frontiers,
65 shallow_since_vv: ImVersionVector,
66 pending_txn_node: Option<AppDagNode>,
67 map_entries_before_mutation: BTreeMap<ID, Option<AppDagNode>>,
68 unhandled_dep_point_log: Vec<UnhandledDepPointLog>,
69}
70
71#[derive(Debug)]
72enum UnhandledDepPointLog {
73 Added(ID),
74 Removed(ID),
75}
76
77#[derive(Debug, Clone)]
78pub struct AppDagNode {
79 inner: Arc<AppDagNodeInner>,
80}
81
82impl Deref for AppDagNode {
83 type Target = AppDagNodeInner;
84
85 fn deref(&self) -> &Self::Target {
86 &self.inner
87 }
88}
89
90impl AppDagNode {
91 pub fn new(inner: AppDagNodeInner) -> Self {
92 Self {
93 inner: Arc::new(inner),
94 }
95 }
96}
97
98#[derive(Debug, Clone)]
99pub struct AppDagNodeInner {
100 pub(crate) peer: PeerID,
101 pub(crate) cnt: Counter,
102 pub(crate) lamport: Lamport,
103 pub(crate) deps: Frontiers,
104 pub(crate) vv: OnceCell<ImVersionVector>,
105 pub(crate) has_succ: bool,
109 pub(crate) len: usize,
110}
111
112impl From<AppDagNodeInner> for AppDagNode {
113 fn from(inner: AppDagNodeInner) -> Self {
114 AppDagNode {
115 inner: Arc::new(inner),
116 }
117 }
118}
119
120impl AppDag {
121 pub(super) fn new(change_store: ChangeStore) -> Self {
122 Self {
123 change_store,
124 map: Mutex::new(BTreeMap::new()),
125 frontiers: Frontiers::default(),
126 vv: VersionVector::default(),
127 unparsed_vv: Mutex::new(VersionVector::default()),
128 unhandled_dep_points: Mutex::new(BTreeSet::new()),
129 shallow_since_frontiers: Default::default(),
130 shallow_root_frontiers_deps: Default::default(),
131 shallow_since_vv: Default::default(),
132 pending_txn_node: None,
133 import_rollback_has_journal: AtomicBool::new(false),
134 import_rollback: Mutex::new(None),
135 }
136 }
137
138 pub fn frontiers(&self) -> &Frontiers {
139 &self.frontiers
140 }
141
142 pub fn vv(&self) -> &VersionVector {
143 &self.vv
144 }
145
146 pub fn shallow_since_vv(&self) -> &ImVersionVector {
147 &self.shallow_since_vv
148 }
149
150 pub fn shallow_since_frontiers(&self) -> &Frontiers {
151 &self.shallow_since_frontiers
152 }
153
154 pub(crate) fn begin_import_rollback(&mut self) {
155 let old_vv_is_empty = self.vv.is_empty();
156 let mut rollback = self.import_rollback.lock();
157 debug_assert!(rollback.is_none());
158 *rollback = Some(AppDagRollback {
159 frontiers: self.frontiers.clone(),
160 vv: self.vv.clone(),
161 unparsed_vv: self.unparsed_vv.lock().clone(),
162 shallow_since_frontiers: self.shallow_since_frontiers.clone(),
163 shallow_root_frontiers_deps: self.shallow_root_frontiers_deps.clone(),
164 shallow_since_vv: self.shallow_since_vv.clone(),
165 pending_txn_node: self.pending_txn_node.clone(),
166 map_entries_before_mutation: BTreeMap::new(),
167 unhandled_dep_point_log: Vec::new(),
168 });
169 self.import_rollback_has_journal
170 .store(!old_vv_is_empty, AtomicOrdering::Relaxed);
171 }
172
173 pub(crate) fn commit_import_rollback(&mut self) {
174 self.import_rollback_has_journal
175 .store(false, AtomicOrdering::Relaxed);
176 *self.import_rollback.lock() = None;
177 }
178
179 pub(crate) fn rollback_import(&mut self) {
180 self.import_rollback_has_journal
181 .store(false, AtomicOrdering::Relaxed);
182 let Some(checkpoint) = self.import_rollback.lock().take() else {
183 return;
184 };
185
186 let imported_spans = self.vv.sub_iter(&checkpoint.vv).collect::<Vec<_>>();
187 let mut map = self.map.lock();
188 for span in imported_spans {
189 let start = ID::new(span.peer, span.counter.start);
190 let end = ID::new(span.peer, span.counter.end);
191 let keys = map.range(start..end).map(|(id, _)| *id).collect::<Vec<_>>();
192 for key in keys {
193 map.remove(&key);
194 }
195 }
196
197 for (id, node) in checkpoint.map_entries_before_mutation {
198 if let Some(node) = node {
199 map.insert(id, node);
200 } else {
201 map.remove(&id);
202 }
203 }
204 drop(map);
205
206 self.frontiers = checkpoint.frontiers;
207 self.vv = checkpoint.vv.clone();
208 self.shallow_since_frontiers = checkpoint.shallow_since_frontiers;
209 self.shallow_root_frontiers_deps = checkpoint.shallow_root_frontiers_deps;
210 self.shallow_since_vv = checkpoint.shallow_since_vv;
211 *self.unparsed_vv.lock() = checkpoint.unparsed_vv;
212
213 let mut unhandled_dep_points = self.unhandled_dep_points.lock();
214 if checkpoint.vv.is_empty() {
215 unhandled_dep_points.clear();
216 }
217 for item in checkpoint.unhandled_dep_point_log.into_iter().rev() {
218 match item {
219 UnhandledDepPointLog::Added(id) => {
220 unhandled_dep_points.remove(&id);
221 }
222 UnhandledDepPointLog::Removed(id) => {
223 unhandled_dep_points.insert(id);
224 }
225 }
226 }
227 drop(unhandled_dep_points);
228
229 self.pending_txn_node = checkpoint.pending_txn_node;
230 }
231
232 fn record_map_entry_before_mutation(&self, map: &BTreeMap<ID, AppDagNode>, id: ID) {
233 if !self
234 .import_rollback_has_journal
235 .load(AtomicOrdering::Relaxed)
236 {
237 return;
238 }
239
240 self.record_map_entry_before_replacement(id, map.get(&id).cloned());
241 }
242
243 fn record_map_entry_before_replacement(&self, id: ID, old: Option<AppDagNode>) {
244 if !self
245 .import_rollback_has_journal
246 .load(AtomicOrdering::Relaxed)
247 {
248 return;
249 }
250
251 let mut rollback = self.import_rollback.lock();
252 let Some(rollback) = rollback.as_mut() else {
253 return;
254 };
255
256 let old_end = rollback.vv.get(&id.peer).copied().unwrap_or(0);
257 if id.counter >= old_end {
258 return;
259 }
260
261 rollback
262 .map_entries_before_mutation
263 .entry(id)
264 .or_insert(old);
265 }
266
267 fn record_unhandled_dep_point_added(&self, id: ID) {
268 if !self
269 .import_rollback_has_journal
270 .load(AtomicOrdering::Relaxed)
271 {
272 return;
273 }
274
275 if let Some(rollback) = self.import_rollback.lock().as_mut() {
276 rollback
277 .unhandled_dep_point_log
278 .push(UnhandledDepPointLog::Added(id));
279 }
280 }
281
282 fn record_unhandled_dep_point_removed(&self, id: ID) {
283 if !self
284 .import_rollback_has_journal
285 .load(AtomicOrdering::Relaxed)
286 {
287 return;
288 }
289
290 if let Some(rollback) = self.import_rollback.lock().as_mut() {
291 rollback
292 .unhandled_dep_point_log
293 .push(UnhandledDepPointLog::Removed(id));
294 }
295 }
296
297 pub fn is_empty(&self) -> bool {
298 self.vv.is_empty()
299 }
300
301 #[tracing::instrument(skip_all, name = "handle_new_change")]
302 pub(super) fn handle_new_change(
303 &mut self,
304 change: &Change,
305 from_local: bool,
306 rollback_old_vv: Option<&VersionVector>,
307 ) {
308 let len = change.content_len();
309 self.update_version_on_new_change(change, from_local);
310 #[cfg(debug_assertions)]
311 {
312 let unhandled_dep_points = self.unhandled_dep_points.lock();
313 let c = unhandled_dep_points
314 .range(change.id_start()..change.id_end())
315 .count();
316 assert!(c == 0);
317 }
318
319 let mut inserted = false;
320 if change.deps_on_self() {
321 let record_old_node_before_merge = rollback_old_vv
322 .and_then(|vv| vv.get(&change.id.peer).copied())
323 .filter(|old_end| *old_end == change.id.counter);
324 inserted =
326 self.with_last_mut_of_peer(change.id.peer, record_old_node_before_merge, |last| {
327 let (_, last) = last.unwrap();
328 if last.has_succ {
329 return false;
331 }
332
333 assert_eq!(last.peer, change.id.peer, "peer id is not the same");
334 assert_eq!(
335 last.cnt + last.len as Counter,
336 change.id.counter,
337 "counter is not continuous"
338 );
339 assert_eq!(
340 last.lamport + last.len as Lamport,
341 change.lamport,
342 "lamport is not continuous"
343 );
344 let last = Arc::make_mut(&mut last.inner);
345 last.len = (change.id.counter - last.cnt) as usize + len;
346 last.has_succ = false;
347 true
348 });
349 }
350
351 if !inserted {
352 let node: AppDagNode = AppDagNodeInner {
353 vv: OnceCell::new(),
354 peer: change.id.peer,
355 cnt: change.id.counter,
356 lamport: change.lamport,
357 deps: change.deps.clone(),
358 has_succ: false,
359 len,
360 }
361 .into();
362
363 let mut map = self.map.lock();
364 map.insert(node.id_start(), node);
365 self.handle_deps_break_points(change.deps.iter(), change.id.peer, Some(&mut map));
366 }
367 }
368
369 fn try_with_node_mut<R>(
370 &self,
371 map: &mut BTreeMap<ID, AppDagNode>,
372 id: ID,
373 f: impl FnOnce(Option<(ID, &mut AppDagNode)>) -> R,
374 ) -> R {
375 let x = map.range_mut(..=id).next_back();
376 if let Some((node_id, node)) = x {
377 if node.contains_id(id) {
378 f(Some((*node_id, node)))
379 } else {
380 f(None)
381 }
382 } else {
383 f(None)
384 }
385 }
386
387 pub(crate) fn calc_unknown_lamport_change(&self, change: &mut Change) -> Result<(), ()> {
389 for dep in change.deps.iter() {
390 match self.get_lamport(&dep) {
391 Some(lamport) => {
392 change.lamport = change.lamport.max(lamport + 1);
393 }
394 None => return Err(()),
395 }
396 }
397 Ok(())
398 }
399
400 pub(crate) fn find_deps_of_id(&self, id: ID) -> Frontiers {
401 let Some(node) = self.get(id) else {
402 return Frontiers::default();
403 };
404
405 let offset = id.counter - node.cnt;
406 if offset == 0 {
407 node.deps.clone()
408 } else {
409 ID::new(id.peer, node.cnt + offset - 1).into()
410 }
411 }
412
413 pub(crate) fn with_last_mut_of_peer<R>(
414 &mut self,
415 peer: PeerID,
416 record_if_before: Option<Counter>,
417 f: impl FnOnce(Option<(ID, &mut AppDagNode)>) -> R,
418 ) -> R {
419 self.lazy_load_last_of_peer(peer);
420 let mut binding = self.map.lock();
421 let last = binding
422 .range_mut(..=ID::new(peer, Counter::MAX))
423 .next_back()
424 .map(|(id, v)| {
425 if record_if_before.is_some_and(|old_end| id.counter < old_end) {
426 self.record_map_entry_before_replacement(*id, Some(v.clone()));
427 }
428 (*id, v)
429 });
430 f(last)
431 }
432
433 fn update_version_on_new_change(&mut self, change: &Change, from_local: bool) {
434 if from_local {
435 assert!(self.pending_txn_node.take().is_some());
436 assert_eq!(
437 self.vv.get(&change.id.peer).copied().unwrap_or(0),
438 change.ctr_end()
439 );
440 } else {
441 let id_last = change.id_last();
442 self.frontiers
443 .update_frontiers_on_new_change(id_last, &change.deps);
444 assert!(self.pending_txn_node.is_none());
445 assert_eq!(
446 self.vv.get(&change.id.peer).copied().unwrap_or(0),
447 change.id.counter
448 );
449 self.vv.extend_to_include_last_id(id_last);
450 }
451 }
452
453 pub(super) fn lazy_load_last_of_peer(&mut self, peer: u64) {
454 let unparsed_vv = self.unparsed_vv.lock();
455 if !unparsed_vv.contains_key(&peer) || self.vv[&peer] >= unparsed_vv[&peer] {
456 return;
457 }
458
459 let Some(nodes) = self.change_store.get_last_dag_nodes_for_peer(peer) else {
460 panic!("unparsed vv don't match with change store. Peer:{peer} is not in change store")
461 };
462
463 self.lazy_load_nodes_internal(nodes, peer, None);
464 }
465
466 fn lazy_load_nodes_internal(
467 &self,
468 nodes: Vec<AppDagNode>,
469 peer: u64,
470 map_input: Option<&mut BTreeMap<ID, AppDagNode>>,
471 ) {
472 assert!(!nodes.is_empty());
473 let mut map_guard = None;
474 let map = map_input.unwrap_or_else(|| {
475 map_guard = Some(self.map.lock());
476 map_guard.as_mut().unwrap()
477 });
478 let new_dag_start_counter_for_the_peer = nodes[0].cnt;
479 let nodes_cnt_end = nodes.last().unwrap().ctr_end();
480 let mut unparsed_vv = self.unparsed_vv.lock();
481 let end_counter = unparsed_vv[&peer];
482 assert!(end_counter <= nodes_cnt_end);
483 let mut deps_on_others = Vec::new();
484 let mut break_point_set = self.unhandled_dep_points.lock();
485 for mut node in nodes {
486 if node.cnt >= end_counter {
487 break;
489 }
490
491 if node.cnt + node.len as Counter > end_counter {
492 node = node.slice(0, (end_counter - node.cnt) as usize);
493 }
495
496 for dep in node.deps.iter() {
497 if dep.peer != peer {
498 deps_on_others.push(dep);
499 }
500 }
501
502 let break_point_ends: Vec<_> = break_point_set
504 .range(node.id_start()..node.id_end())
505 .map(|id| (id.counter - node.cnt) as usize + 1)
506 .collect();
507 if break_point_ends.is_empty() {
508 self.record_map_entry_before_mutation(map, node.id_start());
509 map.insert(node.id_start(), node);
510 } else {
511 let mut slice_start = 0;
512 for slice_end in break_point_ends.iter().copied() {
513 let mut slice_node = node.slice(slice_start, slice_end);
514 let inner = Arc::make_mut(&mut slice_node.inner);
515 inner.has_succ = true;
516 self.record_map_entry_before_mutation(map, slice_node.id_start());
517 map.insert(slice_node.id_start(), slice_node);
518 slice_start = slice_end;
519 }
520
521 let last_break_point = break_point_ends.last().copied().unwrap();
522 if last_break_point != node.len {
523 let slice_node = node.slice(last_break_point, node.len);
524 self.record_map_entry_before_mutation(map, slice_node.id_start());
525 map.insert(slice_node.id_start(), slice_node);
526 }
527
528 for break_point in break_point_ends.into_iter() {
529 let id = node.id_start().inc(break_point as Counter - 1);
530 if break_point_set.remove(&id) {
531 self.record_unhandled_dep_point_removed(id);
532 }
533 }
534 }
535 }
536
537 if new_dag_start_counter_for_the_peer == 0 {
538 unparsed_vv.remove(&peer);
539 } else {
540 unparsed_vv.insert(peer, new_dag_start_counter_for_the_peer);
541 }
542 drop(unparsed_vv);
543 drop(break_point_set);
544 self.handle_deps_break_points(deps_on_others.iter().copied(), peer, Some(map));
545 }
546
547 fn handle_deps_break_points(
548 &self,
549 ids: impl IntoIterator<Item = ID>,
550 skip_peer: PeerID,
551 map: Option<&mut BTreeMap<ID, AppDagNode>>,
552 ) {
553 let mut map_guard = None;
554 let map = map.unwrap_or_else(|| {
555 map_guard = Some(self.map.lock());
556 map_guard.as_mut().unwrap()
557 });
558 for id in ids {
559 if id.peer == skip_peer {
560 continue;
561 }
562
563 let mut handled = false;
564 let ans = self.try_with_node_mut(map, id, |target| {
565 let (target_id, target) = target?;
567 if target.ctr_last() == id.counter {
568 self.record_map_entry_before_replacement(target_id, Some(target.clone()));
569 let target = Arc::make_mut(&mut target.inner);
570 handled = true;
571 target.has_succ = true;
572 None
573 } else {
574 let new_node =
579 target.slice(id.counter as usize - target.cnt as usize + 1, target.len);
580 self.record_map_entry_before_replacement(target_id, Some(target.clone()));
581 let target = Arc::make_mut(&mut target.inner);
582 target.len -= new_node.len;
583 Some(new_node)
584 }
585 });
586
587 if let Some(new_node) = ans {
588 self.record_map_entry_before_mutation(map, new_node.id_start());
589 map.insert(new_node.id_start(), new_node);
590 } else if !handled {
591 let mut unhandled_dep_points = self.unhandled_dep_points.lock();
592 if unhandled_dep_points.insert(id) {
593 self.record_unhandled_dep_point_added(id);
594 }
595 }
596 }
597 }
598
599 fn ensure_lazy_load_node(&self, id: ID) {
600 if self.shallow_since_vv.includes_id(id) {
601 return;
602 }
603
604 loop {
605 let unparsed_end = {
608 let unparsed_vv = self.unparsed_vv.lock();
609 unparsed_vv.get(&id.peer).copied().unwrap_or(0)
610 };
611 if unparsed_end <= id.counter {
612 return;
613 }
614
615 let last_unparsed_id = ID::new(id.peer, unparsed_end - 1);
616 let Some(nodes) = self
617 .change_store
618 .get_dag_nodes_that_contains(last_unparsed_id)
619 else {
620 panic!("unparsed vv don't match with change store. Id:{id} is not in change store")
621 };
622
623 self.lazy_load_nodes_internal(nodes, id.peer, None);
624 }
625 }
626
627 pub fn total_parsed_dag_node(&self) -> usize {
628 self.map.lock().len()
629 }
630
631 pub(crate) fn set_version_by_fast_snapshot_import(&mut self, v: BatchDecodeInfo) {
632 assert!(self.vv.is_empty());
633 *self.unparsed_vv.lock() = v.vv.clone();
634 self.vv = v.vv;
635 self.frontiers = v.frontiers;
636 if let Some((vv, f)) = v.start_version {
637 if !f.is_empty() {
638 assert!(f.len() == 1);
639 let id = f.as_single().unwrap();
640 let node = self.get(id).unwrap();
641 assert!(node.cnt == id.counter);
642 self.shallow_root_frontiers_deps = node.deps.clone();
643 }
644 self.shallow_since_frontiers = f;
645 self.shallow_since_vv = ImVersionVector::from_vv(&vv);
646 }
647 }
648
649 #[instrument(skip(self))]
659 pub fn check_dag_correctness(&self) {
660 {
661 let unparsed_vv = self.unparsed_vv.lock().clone();
663 for (peer, cnt) in unparsed_vv.iter() {
664 if *cnt == 0 {
665 continue;
666 }
667
668 let mut end_cnt = *cnt;
669 let init_counter = self.shallow_since_vv.get(peer).copied().unwrap_or(0);
670 while end_cnt > init_counter {
671 let cnt = end_cnt - 1;
672 self.ensure_lazy_load_node(ID::new(*peer, cnt));
673 end_cnt = self.unparsed_vv.lock().get(peer).copied().unwrap_or(0);
674 }
675 }
676
677 self.unparsed_vv.lock().clear();
678 }
679 {
680 let map = self.map.lock();
682 let mut last_end_id = ID::new(0, 0);
683 for (&id, node) in map.iter() {
684 let init_counter = self.shallow_since_vv.get(&id.peer).copied().unwrap_or(0);
685 if id.peer == last_end_id.peer {
686 assert!(id.counter == last_end_id.counter);
687 } else {
688 assert_eq!(id.counter, init_counter);
689 }
690
691 last_end_id = id.inc(node.len as Counter);
692 }
693 }
694 {
695 let map = self.map.lock();
697 check_always_dep_on_last_id(&map);
698 }
699 {
700 let map = self.map.lock();
702 'outer: for (_, node) in map.iter() {
703 let mut this_lamport = 0;
704 for dep in node.deps.iter() {
705 if self.shallow_since_vv.includes_id(dep) {
706 continue 'outer;
707 }
708
709 let (_, dep_node) = map.range(..=dep).next_back().unwrap();
710 this_lamport = this_lamport.max(dep_node.lamport_end());
711 }
712
713 assert_eq!(this_lamport, node.lamport);
714 }
715 }
716 {
717 let map = self.map.lock().clone();
719 'outer: for (_, node) in map.iter() {
720 let actual_vv = self.ensure_vv_for(node);
721 let mut expected_vv = ImVersionVector::default();
722 for dep in node.deps.iter() {
723 if self.shallow_since_vv.includes_id(dep) {
724 continue 'outer;
725 }
726
727 let (_, dep_node) = map.range(..=dep).next_back().unwrap();
728 self.ensure_vv_for(dep_node);
729 expected_vv.extend_to_include_vv(dep_node.vv.get().unwrap().iter());
730 expected_vv.extend_to_include_last_id(dep);
731 }
732
733 assert_eq!(actual_vv, expected_vv);
734 }
735 }
736 {
737 let mut maybe_frontiers = FxHashSet::default();
739 let map = self.map.lock();
740 for (_, node) in map.iter() {
741 maybe_frontiers.insert(node.id_last());
742 }
743
744 for (_, node) in map.iter() {
745 for dep in node.deps.iter() {
746 maybe_frontiers.remove(&dep);
747 }
748 }
749
750 let frontiers = self.frontiers.iter().collect::<FxHashSet<_>>();
751 assert_eq!(maybe_frontiers, frontiers);
752 }
753 }
754
755 pub(crate) fn can_export_shallow_snapshot_on(&self, deps: &Frontiers) -> bool {
756 for id in deps.iter() {
757 if !self.vv.includes_id(id) {
758 return false;
759 }
760 }
761
762 if self.is_before_shallow_root(deps) {
763 return false;
764 }
765
766 true
767 }
768
769 pub(crate) fn is_before_shallow_root(&self, deps: &Frontiers) -> bool {
770 if self.shallow_since_vv.is_empty() {
775 return false;
776 }
777
778 if deps.is_empty() {
779 return true;
780 }
781
782 if deps.iter().any(|x| self.shallow_since_vv.includes_id(x)) {
783 return true;
784 }
785
786 if deps
787 .iter()
788 .any(|x| self.shallow_since_frontiers.contains(&x))
789 {
790 return deps != &self.shallow_since_frontiers;
791 }
792
793 false
794 }
795
796 pub(crate) fn import_deps_before_shallow_root(&self, deps: &Frontiers) -> bool {
797 if self.shallow_since_vv.is_empty() {
798 return false;
799 }
800
801 if deps.is_empty() {
802 return true;
803 }
804
805 if deps == &self.shallow_root_frontiers_deps {
813 return true;
814 }
815
816 let shallow_vv = VersionVector::from_im_vv(&self.shallow_since_vv);
817 if let Some(vv) = self.frontiers_to_vv(deps) {
818 return !vv.includes_vv(&shallow_vv);
819 }
820
821 if deps
826 .iter()
827 .any(|id| self.shallow_since_frontiers.contains(&id))
828 {
829 return false;
830 }
831
832 deps.iter().any(|id| self.shallow_since_vv.includes_id(id))
833 }
834
835 pub(crate) fn travel_ancestors(
839 &self,
840 id: ID,
841 f: &mut dyn FnMut(&AppDagNode) -> ControlFlow<()>,
842 ) {
843 struct PendingNode(AppDagNode);
844 impl PartialEq for PendingNode {
845 fn eq(&self, other: &Self) -> bool {
846 self.0.lamport_last() == other.0.lamport_last() && self.0.peer == other.0.peer
847 }
848 }
849 impl Eq for PendingNode {}
850 impl PartialOrd for PendingNode {
851 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
852 Some(self.cmp(other))
853 }
854 }
855 impl Ord for PendingNode {
856 fn cmp(&self, other: &Self) -> Ordering {
857 self.0
858 .lamport_last()
859 .cmp(&other.0.lamport_last())
860 .then_with(|| self.0.peer.cmp(&other.0.peer))
861 }
862 }
863
864 let mut visited = FxHashSet::default();
865 let mut pending: BinaryHeap<PendingNode> = BinaryHeap::new();
866 pending.push(PendingNode(self.get(id).unwrap()));
867 while let Some(PendingNode(node)) = pending.pop() {
868 if f(&node).is_break() {
869 break;
870 }
871
872 for dep in node.deps.iter() {
873 let Some(dep_node) = self.get(dep) else {
874 continue;
875 };
876 if visited.contains(&dep_node.id_start()) {
877 continue;
878 }
879
880 visited.insert(dep_node.id_start());
881 pending.push(PendingNode(dep_node));
882 }
883 }
884 }
885
886 pub(crate) fn update_version_on_new_local_op(
887 &mut self,
888 deps: &Frontiers,
889 start_id: ID,
890 start_lamport: Lamport,
891 len: usize,
892 ) {
893 let last_id = start_id.inc(len as Counter - 1);
894 self.vv.set_last(last_id);
896 self.frontiers.update_frontiers_on_new_change(last_id, deps);
897 match &mut self.pending_txn_node {
898 Some(node) => {
899 assert!(
900 node.peer == start_id.peer
901 && node.cnt + node.len as Counter == start_id.counter
902 && deps.len() == 1
903 && deps.as_single().unwrap().peer == start_id.peer
904 );
905 let inner = Arc::make_mut(&mut node.inner);
906 inner.len += len;
907 }
908 None => {
909 let node = AppDagNode {
910 inner: Arc::new(AppDagNodeInner {
911 peer: start_id.peer,
912 cnt: start_id.counter,
913 lamport: start_lamport,
914 deps: deps.clone(),
915 vv: OnceCell::new(),
916 has_succ: false,
917 len,
918 }),
919 };
920 self.pending_txn_node = Some(node);
921 }
922 }
923 }
924
925 pub(crate) fn latest_vv_contains_peer(&self, peer: PeerID) -> bool {
926 self.vv.contains_key(&peer) && *self.vv.get(&peer).unwrap() > 0
927 }
928}
929
930fn check_always_dep_on_last_id(map: &BTreeMap<ID, AppDagNode>) {
931 for (_, node) in map.iter() {
932 for dep in node.deps.iter() {
933 let Some((&dep_id, dep_node)) = map.range(..=dep).next_back() else {
934 continue;
936 };
937 assert_eq!(dep_node.id_start(), dep_id);
938 if dep_node.contains_id(dep) {
939 assert_eq!(dep_node.id_last(), dep);
940 }
941 }
942 }
943}
944
945impl HasIndex for AppDagNode {
946 type Int = Counter;
947 fn get_start_index(&self) -> Self::Int {
948 self.cnt
949 }
950
951 fn get_end_index(&self) -> Self::Int {
952 self.cnt + self.len as Counter
953 }
954}
955
956impl Sliceable for AppDagNode {
957 fn slice(&self, from: usize, to: usize) -> Self {
958 AppDagNodeInner {
959 peer: self.peer,
960 cnt: self.cnt + from as Counter,
961 lamport: self.lamport + from as Lamport,
962 deps: if from > 0 {
963 Frontiers::from_id(self.id_start().inc(from as Counter - 1))
964 } else {
965 self.deps.clone()
966 },
967 vv: if let Some(vv) = self.vv.get() {
968 let mut new = vv.clone();
969 new.insert(self.peer, self.cnt + from as Counter);
970 OnceCell::with_value(new)
971 } else {
972 OnceCell::new()
973 },
974 has_succ: if to == self.len { self.has_succ } else { true },
975 len: to - from,
976 }
977 .into()
978 }
979}
980
981impl HasId for AppDagNode {
982 fn id_start(&self) -> ID {
983 ID {
984 peer: self.peer,
985 counter: self.cnt,
986 }
987 }
988}
989
990impl HasCounter for AppDagNode {
991 fn ctr_start(&self) -> Counter {
992 self.cnt
993 }
994}
995
996impl HasLength for AppDagNode {
997 fn atom_len(&self) -> usize {
998 self.len
999 }
1000
1001 fn content_len(&self) -> usize {
1002 self.len
1003 }
1004}
1005
1006impl Mergable for AppDagNode {
1007 fn is_mergable(&self, other: &Self, _conf: &()) -> bool
1008 where
1009 Self: Sized,
1010 {
1011 !self.has_succ
1012 && self.peer == other.peer
1013 && self.cnt + self.len as Counter == other.cnt
1014 && other.deps.len() == 1
1015 && self.lamport + self.len as Lamport == other.lamport
1016 && other.deps.as_single().unwrap().peer == self.peer
1017 }
1018
1019 fn merge(&mut self, other: &Self, _conf: &())
1020 where
1021 Self: Sized,
1022 {
1023 assert_eq!(
1024 other.deps.as_single().unwrap().counter,
1025 self.cnt + self.len as Counter - 1
1026 );
1027 let this = Arc::make_mut(&mut self.inner);
1028 this.len += other.len;
1029 this.has_succ = other.has_succ;
1030 }
1031}
1032
1033impl HasLamport for AppDagNode {
1034 fn lamport(&self) -> Lamport {
1035 self.lamport
1036 }
1037}
1038
1039impl DagNode for AppDagNode {
1040 fn deps(&self) -> &Frontiers {
1041 &self.deps
1042 }
1043}
1044
1045impl Dag for AppDag {
1046 type Node = AppDagNode;
1047
1048 fn frontier(&self) -> &Frontiers {
1049 &self.frontiers
1050 }
1051
1052 fn get(&self, id: ID) -> Option<Self::Node> {
1053 self.ensure_lazy_load_node(id);
1054 let binding = self.map.lock();
1055 if let Some(x) = binding.range(..=id).next_back() {
1056 if x.1.contains_id(id) {
1057 return Some(x.1.clone());
1060 }
1061 }
1062
1063 if let Some(node) = &self.pending_txn_node {
1064 if node.peer == id.peer && node.cnt <= id.counter {
1065 assert!(node.cnt + node.len as Counter > id.counter);
1066 return Some(node.clone());
1067 }
1068 }
1069
1070 None
1071 }
1072
1073 fn vv(&self) -> &VersionVector {
1074 &self.vv
1075 }
1076
1077 fn contains(&self, id: ID) -> bool {
1078 self.vv.includes_id(id)
1079 }
1080}
1081
1082impl AppDag {
1083 pub fn get_vv(&self, id: ID) -> Option<ImVersionVector> {
1087 self.get(id).map(|x| {
1088 let mut vv = self.ensure_vv_for(&x);
1089 vv.insert(id.peer, id.counter + 1);
1090 vv
1091 })
1092 }
1093
1094 pub(crate) fn ensure_vv_for(&self, target_node: &AppDagNode) -> ImVersionVector {
1095 if target_node.vv.get().is_none() {
1096 let mut stack: SmallVec<[AppDagNode; 4]> = smallvec::smallvec![target_node.clone()];
1103 while let Some(top_node) = stack.pop() {
1104 if top_node.vv.get().is_some() {
1105 continue;
1106 }
1107
1108 let mut ans_vv = ImVersionVector::default();
1109 if top_node.deps == self.shallow_root_frontiers_deps {
1110 for (&p, &c) in self.shallow_since_vv.iter() {
1111 ans_vv.insert(p, c);
1112 }
1113 } else {
1114 let mut all_deps_processed = true;
1115 for id in top_node.deps.iter() {
1116 let Some(node) = self.get(id) else {
1117 if self.shallow_since_vv.includes_id(id) {
1118 continue;
1119 }
1120
1121 panic!("deps should be in the dag");
1122 };
1123 if node.vv.get().is_none() {
1124 if all_deps_processed {
1125 stack.push(top_node.clone());
1126 }
1127 all_deps_processed = false;
1128 stack.push(node);
1129 continue;
1130 };
1131 }
1132
1133 if !all_deps_processed {
1134 continue;
1135 }
1136
1137 for id in top_node.deps.iter() {
1138 let Some(node) = self.get(id) else {
1139 if self.shallow_since_vv.includes_id(id) {
1140 ans_vv.extend_to_include_vv(self.shallow_since_vv.iter());
1141 continue;
1142 }
1143
1144 panic!("deps should be in the dag");
1145 };
1146 let dep_vv = node.vv.get().unwrap();
1147 if ans_vv.is_empty() {
1148 ans_vv = dep_vv.clone();
1149 } else {
1150 ans_vv.extend_to_include_vv(dep_vv.iter());
1151 }
1152
1153 ans_vv.insert(node.peer, node.ctr_end());
1154 }
1155 }
1156
1157 let _ = top_node.vv.set(ans_vv);
1161 }
1162 }
1163
1164 target_node.vv.get().unwrap().clone()
1165 }
1166
1167 pub fn cmp_version(&self, a: ID, b: ID) -> Option<Ordering> {
1170 if a.peer == b.peer {
1171 return Some(a.counter.cmp(&b.counter));
1172 }
1173
1174 let a = self.get_vv(a).unwrap();
1175 let b = self.get_vv(b).unwrap();
1176 a.partial_cmp(&b)
1177 }
1178
1179 pub fn get_lamport(&self, id: &ID) -> Option<Lamport> {
1180 self.get(*id).and_then(|node| {
1181 assert!(id.counter >= node.cnt);
1182 if node.cnt + node.len as Counter > id.counter {
1183 Some(node.lamport + (id.counter - node.cnt) as Lamport)
1184 } else {
1185 None
1186 }
1187 })
1188 }
1189
1190 pub fn get_change_lamport_from_deps(&self, deps: &Frontiers) -> Option<Lamport> {
1191 let mut lamport = 0;
1192 for id in deps.iter() {
1193 let x = self.get_lamport(&id)?;
1194 lamport = lamport.max(x + 1);
1195 }
1196
1197 Some(lamport)
1198 }
1199
1200 pub fn frontiers_to_vv(&self, frontiers: &Frontiers) -> Option<VersionVector> {
1204 if frontiers == &self.shallow_root_frontiers_deps {
1205 let vv = VersionVector::from_im_vv(&self.shallow_since_vv);
1206 return Some(vv);
1207 }
1208
1209 let mut vv: VersionVector = Default::default();
1210 for id in frontiers.iter() {
1211 let x = self.get(id)?;
1212 let target_vv = self.ensure_vv_for(&x);
1213 vv.extend_to_include_vv(target_vv.iter());
1214 vv.extend_to_include_last_id(id);
1215 }
1216
1217 Some(vv)
1218 }
1219
1220 #[allow(unused)]
1221 pub(crate) fn frontiers_to_im_vv(&self, frontiers: &Frontiers) -> ImVersionVector {
1222 if frontiers.is_empty() {
1223 return Default::default();
1224 }
1225
1226 let mut iter = frontiers.iter();
1227 let mut vv = {
1228 let id = iter.next().unwrap();
1229 let Some(x) = self.get(id) else {
1230 unreachable!()
1231 };
1232 let mut vv = self.ensure_vv_for(&x);
1233 vv.extend_to_include_last_id(id);
1234 vv
1235 };
1236
1237 for id in iter {
1238 let Some(x) = self.get(id) else {
1239 unreachable!()
1240 };
1241 let x = self.ensure_vv_for(&x);
1242 vv.extend_to_include_vv(x.iter());
1243 vv.extend_to_include_last_id(id);
1244 }
1245
1246 vv
1247 }
1248
1249 pub fn im_vv_to_frontiers(&self, vv: &ImVersionVector) -> Frontiers {
1250 if vv.is_empty() {
1251 return Default::default();
1252 }
1253
1254 let this = vv;
1255 let last_ids: Frontiers = this
1256 .iter()
1257 .filter_map(|(client_id, cnt)| {
1258 if *cnt <= 0 {
1259 return None;
1260 }
1261
1262 if self
1263 .shallow_since_vv
1264 .includes_id(ID::new(*client_id, *cnt - 1))
1265 {
1266 return None;
1267 }
1268
1269 Some(ID::new(*client_id, cnt - 1))
1270 })
1271 .collect();
1272
1273 if last_ids.is_empty() {
1274 return self.shallow_since_frontiers.clone();
1275 }
1276
1277 shrink_frontiers(&last_ids, self).unwrap()
1278 }
1279
1280 pub fn vv_to_frontiers(&self, vv: &VersionVector) -> Frontiers {
1281 if vv.is_empty() {
1282 return Default::default();
1283 }
1284
1285 let this = vv;
1286 let last_ids: Frontiers = this
1287 .iter()
1288 .filter_map(|(client_id, cnt)| {
1289 if *cnt <= 0 {
1290 return None;
1291 }
1292
1293 if self
1294 .shallow_since_vv
1295 .includes_id(ID::new(*client_id, *cnt - 1))
1296 {
1297 return None;
1298 }
1299
1300 Some(ID::new(*client_id, cnt - 1))
1301 })
1302 .collect();
1303
1304 if last_ids.is_empty() {
1305 return self.shallow_since_frontiers.clone();
1306 }
1307
1308 shrink_frontiers(&last_ids, self).unwrap()
1309 }
1310
1311 pub(crate) fn frontiers_to_next_lamport(&self, frontiers: &Frontiers) -> Lamport {
1312 if frontiers.is_empty() {
1313 return 0;
1314 }
1315
1316 let mut iter = frontiers.iter();
1317 let mut lamport = {
1318 let id = iter.next().unwrap();
1319 let Some(x) = self.get(id) else {
1320 unreachable!()
1321 };
1322 assert!(id.counter >= x.cnt);
1323 (id.counter - x.cnt) as Lamport + x.lamport + 1
1324 };
1325
1326 for id in iter {
1327 let Some(x) = self.get(id) else {
1328 unreachable!()
1329 };
1330 assert!(id.counter >= x.cnt);
1331 lamport = lamport.max((id.counter - x.cnt) as Lamport + x.lamport + 1);
1332 }
1333
1334 lamport
1335 }
1336
1337 pub fn get_frontiers(&self) -> &Frontiers {
1338 &self.frontiers
1339 }
1340
1341 pub fn cmp_with_frontiers(&self, other: &Frontiers) -> Ordering {
1345 if &self.frontiers == other {
1346 Ordering::Equal
1347 } else if other.iter().all(|id| self.vv.includes_id(id)) {
1348 Ordering::Greater
1349 } else {
1350 Ordering::Less
1351 }
1352 }
1353
1354 pub fn cmp_frontiers(
1359 &self,
1360 a: &Frontiers,
1361 b: &Frontiers,
1362 ) -> Result<Option<Ordering>, FrontiersNotIncluded> {
1363 let a = self.frontiers_to_vv(a).ok_or(FrontiersNotIncluded)?;
1364 let b = self.frontiers_to_vv(b).ok_or(FrontiersNotIncluded)?;
1365 Ok(a.partial_cmp(&b))
1366 }
1367}
1368
1369#[derive(Debug, PartialEq, Eq)]
1370pub struct FrontiersNotIncluded;
1371impl Display for FrontiersNotIncluded {
1372 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1373 f.write_str("The given Frontiers are not included by the doc")
1374 }
1375}
1376
1377#[cfg(test)]
1378mod ensure_vv_for_tests {
1379 use super::*;
1380 use crate::arena::SharedArena;
1381 use std::sync::atomic::AtomicI64;
1382
1383 fn make_dag_node(peer: PeerID, cnt: Counter, len: usize, deps: Frontiers) -> AppDagNode {
1384 AppDagNodeInner {
1385 vv: OnceCell::new(),
1386 peer,
1387 cnt,
1388 lamport: cnt as Lamport,
1389 deps,
1390 has_succ: false,
1391 len,
1392 }
1393 .into()
1394 }
1395
1396 fn make_shallow_dag_for_import_deps() -> AppDag {
1397 let change_store = ChangeStore::new_mem(&SharedArena::new(), Arc::new(AtomicI64::new(0)));
1398 let mut dag = AppDag::new(change_store);
1399 let root_deps = Frontiers::from_id(ID::new(1, 1));
1400 let boundary = make_dag_node(1, 2, 1, root_deps.clone());
1401
1402 {
1403 let mut map = dag.map.lock();
1404 map.insert(boundary.id_start(), boundary);
1405 }
1406
1407 dag.shallow_since_vv.insert(1, 2);
1408 dag.shallow_since_frontiers = Frontiers::from_id(ID::new(1, 2));
1409 dag.shallow_root_frontiers_deps = root_deps;
1410 dag
1411 }
1412
1413 #[test]
1431 fn diamond_dep_ensure_vv_for_does_not_double_set() {
1432 let change_store = ChangeStore::new_mem(&SharedArena::new(), Arc::new(AtomicI64::new(0)));
1433 let dag = AppDag::new(change_store);
1434
1435 let x = make_dag_node(1, 0, 1, Frontiers::default());
1436 let y = make_dag_node(2, 0, 1, Frontiers::from_id(ID::new(1, 0)));
1437 let mut z_deps = Frontiers::default();
1438 z_deps.push(ID::new(1, 0));
1439 z_deps.push(ID::new(2, 0));
1440 let z = make_dag_node(3, 0, 1, z_deps);
1441
1442 {
1443 let mut map = dag.map.lock();
1444 map.insert(x.id_start(), x);
1445 map.insert(y.id_start(), y);
1446 map.insert(z.id_start(), z.clone());
1447 }
1448
1449 let vv = dag.ensure_vv_for(&z);
1453 assert_eq!(vv.get(&1).copied(), Some(1));
1454 assert_eq!(vv.get(&2).copied(), Some(1));
1455 assert!(vv.get(&3).is_none());
1456 }
1457
1458 #[test]
1459 fn import_deps_before_shallow_root_rejects_trimmed_history_dep() {
1460 let dag = make_shallow_dag_for_import_deps();
1461 let deps = Frontiers::from_id(ID::new(1, 0));
1462
1463 assert!(dag.frontiers_to_vv(&deps).is_none());
1464 assert!(dag.import_deps_before_shallow_root(&deps));
1465 }
1466
1467 #[test]
1472 fn import_deps_before_shallow_root_rejects_deps_equal_to_root_deps() {
1473 let dag = make_shallow_dag_for_import_deps();
1474 let deps = Frontiers::from_id(ID::new(1, 1));
1475
1476 assert!(dag.frontiers_to_vv(&deps).is_some());
1478 assert!(dag.import_deps_before_shallow_root(&deps));
1480 }
1481
1482 #[test]
1483 fn import_deps_before_shallow_root_allows_boundary_with_missing_peer() {
1484 let dag = make_shallow_dag_for_import_deps();
1485 let mut deps = Frontiers::default();
1486 deps.push(ID::new(1, 2));
1487 deps.push(ID::new(2, 0));
1488
1489 assert!(dag.frontiers_to_vv(&deps).is_none());
1490 assert!(!dag.import_deps_before_shallow_root(&deps));
1491 }
1492
1493 #[test]
1494 fn import_deps_before_shallow_root_allows_missing_non_trimmed_dep() {
1495 let dag = make_shallow_dag_for_import_deps();
1496 let deps = Frontiers::from_id(ID::new(2, 0));
1497
1498 assert!(dag.frontiers_to_vv(&deps).is_none());
1499 assert!(!dag.import_deps_before_shallow_root(&deps));
1500 }
1501}