1use backend::*;
5use conflict;
6use std::cmp::min;
7use std::collections::{HashMap, HashSet};
8use Result;
9
10use rand;
11use std;
12
13bitflags! {
14 struct Flags: u8 {
15 const LINE_HALF_DELETED = 4;
16 const LINE_VISITED = 2;
17 const LINE_ONSTACK = 1;
18 }
19}
20
21#[derive(Debug)]
26pub struct Line {
27 pub key: Key<PatchId>,
29
30 flags: Flags,
34 children: usize,
35 n_children: usize,
36 index: usize,
37 lowlink: usize,
38 scc: usize,
39}
40
41impl Line {
42 pub fn is_zombie(&self) -> bool {
43 self.flags.contains(Flags::LINE_HALF_DELETED)
44 }
45}
46
47#[derive(Debug)]
53pub struct Graph {
54 pub lines: Vec<Line>,
57 children: Vec<(Option<Edge>, VertexId)>,
61}
62
63#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
64struct VertexId(usize);
65
66const DUMMY_VERTEX: VertexId = VertexId(0);
67
68impl std::ops::Index<VertexId> for Graph {
69 type Output = Line;
70 fn index(&self, idx: VertexId) -> &Self::Output {
71 self.lines.index(idx.0)
72 }
73}
74impl std::ops::IndexMut<VertexId> for Graph {
75 fn index_mut(&mut self, idx: VertexId) -> &mut Self::Output {
76 self.lines.index_mut(idx.0)
77 }
78}
79
80use std::io::Write;
81
82impl Graph {
83 fn children(&self, i: VertexId) -> &[(Option<Edge>, VertexId)] {
84 let ref line = self[i];
85 &self.children[line.children..line.children + line.n_children]
86 }
87
88 fn child(&self, i: VertexId, j: usize) -> &(Option<Edge>, VertexId) {
89 &self.children[self[i].children + j]
90 }
91
92 pub fn debug<W: Write>(
93 &self,
94 txn: &Txn,
95 branch: &Branch,
96 add_others: bool,
97 introduced_by: bool,
98 mut w: W,
99 ) -> std::io::Result<()> {
100 writeln!(w, "digraph {{")?;
101 let mut cache = HashMap::new();
102 if add_others {
103 for (line, i) in self.lines.iter().zip(0..) {
104 cache.insert(line.key, i);
105 }
106 }
107 let mut others = HashSet::new();
108 for (line, i) in self.lines.iter().zip(0..) {
109 let contents = {
110 if let Some(c) = txn.get_contents(line.key) {
111 let c = c.into_cow();
112 if let Ok(c) = std::str::from_utf8(&c) {
113 c.split_at(std::cmp::min(50, c.len())).0.to_string()
114 } else {
115 "<INVALID>".to_string()
116 }
117 } else {
118 "".to_string()
119 }
120 };
121 let contents = format!("{:?}", contents);
122 let contents = contents.split_at(contents.len() - 1).0.split_at(1).1;
123 writeln!(
124 w,
125 "n_{}[label=\"{}: {}.{}: {}\"];",
126 i,
127 i,
128 line.key.patch.to_base58(),
129 line.key.line.to_hex(),
130 contents
131 )?;
132
133 if add_others && !line.key.is_root() {
134 for (_, v) in txn.iter_nodes(branch, Some((line.key, None)))
135 .take_while(|&(k, _)| k == line.key)
136 {
137 if let Some(dest) = cache.get(&v.dest) {
138 writeln!(
139 w,
140 "n_{} -> n_{}[color=red,label=\"{:?}{}{}\"];",
141 i,
142 dest,
143 v.flag.bits(),
144 if introduced_by { " " } else { "" },
145 if introduced_by {
146 v.introduced_by.to_base58()
147 } else {
148 String::new()
149 }
150 )?;
151 } else {
152 if !others.contains(&v.dest) {
153 others.insert(v.dest);
154 writeln!(
155 w,
156 "n_{}[label=\"{}.{}\",color=red];",
157 v.dest.to_base58(),
158 v.dest.patch.to_base58(),
159 v.dest.line.to_hex()
160 )?;
161 }
162 writeln!(
163 w,
164 "n_{} -> n_{}[color=red,label=\"{:?}{}{}\"];",
165 i,
166 v.dest.to_base58(),
167 v.flag.bits(),
168 if introduced_by { " " } else { "" },
169 if introduced_by {
170 v.introduced_by.to_base58()
171 } else {
172 String::new()
173 }
174 )?;
175 }
176 }
177 }
178 for &(ref edge, VertexId(j)) in
179 &self.children[line.children..line.children + line.n_children]
180 {
181 if let Some(ref edge) = *edge {
182 writeln!(
183 w,
184 "n_{}->n_{}[label=\"{:?}{}{}\"];",
185 i,
186 j,
187 edge.flag.bits(),
188 if introduced_by { " " } else { "" },
189 if introduced_by {
190 edge.introduced_by.to_base58()
191 } else {
192 String::new()
193 }
194 )?
195 } else {
196 writeln!(w, "n_{}->n_{}[label=\"none\"];", i, j)?
197 }
198 }
199 }
200 writeln!(w, "}}")?;
201 Ok(())
202 }
203}
204
205use sanakirja::value::Value;
206pub trait LineBuffer<'a, T: 'a + Transaction> {
208 fn output_line(&mut self, key: &Key<PatchId>, contents: Value<'a, T>) -> Result<()>;
209
210 fn output_conflict_marker(&mut self, s: &'a str) -> Result<()>;
211 fn begin_conflict(&mut self) -> Result<()> {
212 self.output_conflict_marker(conflict::START_MARKER)
213 }
214 fn conflict_next(&mut self) -> Result<()> {
215 self.output_conflict_marker(conflict::SEPARATOR)
216 }
217 fn end_conflict(&mut self) -> Result<()> {
218 self.output_conflict_marker(conflict::END_MARKER)
219 }
220}
221
222impl<'a, T: 'a + Transaction, W: std::io::Write> LineBuffer<'a, T> for W {
223 fn output_line(&mut self, k: &Key<PatchId>, c: Value<T>) -> Result<()> {
224 for chunk in c {
225 debug!("output line {:?} {:?}", k, std::str::from_utf8(chunk));
226 self.write_all(chunk)?
227 }
228 Ok(())
229 }
230
231 fn output_conflict_marker(&mut self, s: &'a str) -> Result<()> {
232 self.write(s.as_bytes())?;
233 Ok(())
234 }
235}
236
237#[derive(Clone, Debug)]
238pub struct Visits {
239 pub first: usize,
240 pub last: usize,
241 pub begins_conflict: bool,
242 pub ends_conflict: bool,
243 pub has_brothers: bool,
244}
245
246impl Default for Visits {
247 fn default() -> Self {
248 Visits {
249 first: 0,
250 last: 0,
251 ends_conflict: false,
252 begins_conflict: false,
253 has_brothers: false,
254 }
255 }
256}
257
258pub struct DFS {
259 visits: Vec<Visits>,
260 counter: usize,
261 has_conflicts: bool,
262}
263
264impl DFS {
265 pub fn new(n: usize) -> Self {
266 DFS {
267 visits: vec![Visits::default(); n],
268 counter: 1,
269 has_conflicts: false,
270 }
271 }
272}
273
274impl DFS {
275 fn mark_discovered(&mut self, scc: usize) {
276 if self.visits[scc].first == 0 {
277 self.visits[scc].first = self.counter;
278 self.counter += 1;
279 }
280 }
281
282 fn mark_last_visit(&mut self, scc: usize) {
283 self.mark_discovered(scc);
284 self.visits[scc].last = self.counter;
285 self.counter += 1;
286 }
287
288 fn first_visit(&self, scc: usize) -> usize {
289 self.visits[scc].first
290 }
291
292 fn last_visit(&self, scc: usize) -> usize {
293 self.visits[scc].last
294 }
295
296 fn ends_conflict(&mut self, scc: usize) {
297 self.visits[scc].ends_conflict = true
298 }
299 fn begins_conflict(&mut self, scc: usize) {
300 self.visits[scc].begins_conflict = true;
301 self.has_conflicts = true
302 }
303 fn has_brothers(&mut self, scc: usize) {
304 self.visits[scc].has_brothers = true
305 }
306}
307
308impl Graph {
309 fn tarjan(&mut self) -> Vec<Vec<VertexId>> {
313 if self.lines.len() <= 1 {
314 return vec![vec![VertexId(0)]];
315 }
316
317 let mut call_stack = vec![(VertexId(1), 0, true)];
318
319 let mut index = 0;
320 let mut stack = Vec::new();
321 let mut scc = Vec::new();
322 while let Some((n_l, i, first_visit)) = call_stack.pop() {
323 if first_visit {
324 let ref mut l = self[n_l];
326 debug!("tarjan: {:?}", l.key);
327 (*l).index = index;
328 (*l).lowlink = index;
329 (*l).flags = (*l).flags | Flags::LINE_ONSTACK | Flags::LINE_VISITED;
330 debug!("{:?} {:?} chi", (*l).key, (*l).n_children);
331 stack.push(n_l);
332 index = index + 1;
333 } else {
334 let &(_, n_child) = self.child(n_l, i);
335 self[n_l].lowlink = std::cmp::min(self[n_l].lowlink, self[n_child].lowlink);
336 }
337
338 let call_stack_length = call_stack.len();
339 for j in i..self[n_l].n_children {
340 let &(_, n_child) = self.child(n_l, j);
341 if !self[n_child].flags.contains(Flags::LINE_VISITED) {
342 call_stack.push((n_l, j, false));
343 call_stack.push((n_child, 0, true));
344 break;
345 } else {
347 if self[n_child].flags.contains(Flags::LINE_ONSTACK) {
348 self[n_l].lowlink = min(self[n_l].lowlink, self[n_child].index)
349 }
350 }
351 }
352 if call_stack_length < call_stack.len() {
353 continue;
355 }
356 if self[n_l].index == self[n_l].lowlink {
359 let mut v = Vec::new();
360 loop {
361 match stack.pop() {
362 None => break,
363 Some(n_p) => {
364 self[n_p].scc = scc.len();
365 self[n_p].flags = self[n_p].flags ^ Flags::LINE_ONSTACK;
366 v.push(n_p);
367 if n_p == n_l {
368 break;
369 }
370 }
371 }
372 }
373 scc.push(v);
374 }
375 }
376 scc
377 }
378
379 fn dfs<A: Transaction, R>(
382 &mut self,
383 txn: &GenericTxn<A, R>,
384 branch: &Branch,
385 scc: &[Vec<VertexId>],
386 dfs: &mut DFS,
387 forward: &mut Vec<(Key<PatchId>, Edge)>,
388 ) {
389 let mut call_stack: Vec<(_, HashSet<usize>, _, _)> =
390 vec![(scc.len() - 1, HashSet::new(), true, None)];
391 while let Some((n_scc, mut forward_scc, is_first_child, descendants)) = call_stack.pop() {
392 debug!("dfs, n_scc = {:?}", n_scc);
393 for &VertexId(id) in scc[n_scc].iter() {
394 debug!("dfs, n_scc: {:?}", self.lines[id].key);
395 }
396 dfs.mark_discovered(n_scc);
397 debug!(
398 "scc: {:?}, first {} last {}",
399 n_scc,
400 dfs.first_visit(n_scc),
401 dfs.last_visit(n_scc)
402 );
403 let mut descendants = if let Some(descendants) = descendants {
404 descendants
405 } else {
406 let mut descendants = Vec::new();
418 for cousin in scc[n_scc].iter() {
419 for &(_, n_child) in self.children(*cousin) {
420 let child_component = self[n_child].scc;
421 if child_component < n_scc {
422 descendants.push(child_component)
424 }
425 }
426 }
427 descendants.sort();
428 debug!("sorted descendants: {:?}", descendants);
429 descendants
430 };
431
432 let mut recursive_call = None;
434 while let Some(child) = descendants.pop() {
435 debug!(
436 "child {:?}, first {} last {}",
437 child,
438 dfs.first_visit(child),
439 dfs.last_visit(child)
440 );
441 if dfs.first_visit(child) == 0 {
442 recursive_call = Some(child);
444 if !is_first_child {
445 debug!("!is_first_child, n_scc = {:?}", n_scc);
447 dfs.begins_conflict(n_scc);
448 dfs.has_brothers(child)
449 }
450 break;
451 } else if dfs.last_visit(child) < dfs.first_visit(n_scc) {
452 dfs.ends_conflict(child)
453 } else if dfs.first_visit(n_scc) < dfs.first_visit(child) {
454 debug!("last_visit to {:?}: {:?}", child, dfs.last_visit(child));
456 forward_scc.insert(child);
457 }
458 }
459 if let Some(child) = recursive_call {
460 call_stack.push((n_scc, forward_scc, false, Some(descendants)));
461 call_stack.push((child, HashSet::new(), true, None));
462 } else {
463 dfs.mark_last_visit(n_scc);
464 for cousin in scc[n_scc].iter() {
466 for &(ref edge, n_child) in self.children(*cousin) {
467 if let Some(mut edge) = *edge {
468 if forward_scc.contains(&self[n_child].scc)
470 && edge.flag.contains(EdgeFlags::PSEUDO_EDGE)
471 && !txn.test_edge(
472 branch,
473 self[*cousin].key,
474 edge.dest,
475 EdgeFlags::DELETED_EDGE,
476 EdgeFlags::DELETED_EDGE,
477 ) {
478 debug!("forward: {:?} {:?}", self[*cousin].key, edge);
479 forward.push((self[*cousin].key, edge))
480 }
481
482 edge.flag = EdgeFlags::PSEUDO_EDGE;
484 edge.introduced_by = ROOT_PATCH_ID;
485 let mut edges = txn.iter_nodes(
486 branch,
487 Some((self[*cousin].key, Some(&edge))),
488 ).take_while(|&(k, v)| {
489 k == self[*cousin].key && v.dest == edge.dest
490 && v.flag <= EdgeFlags::FOLDER_EDGE | EdgeFlags::PSEUDO_EDGE
491 });
492 edges.next(); forward.extend(edges.map(|(k, &v)| (k, v))); }
495 }
496 }
497 }
498 }
499 }
500}
501
502impl<A: Transaction, R> GenericTxn<A, R> {
503 pub fn retrieve<'a>(&'a self, branch: &Branch, key0: Key<PatchId>) -> Graph {
507 let mut graph = Graph {
508 lines: Vec::new(),
509 children: Vec::new(),
510 };
511 graph.lines.push(Line {
513 key: ROOT_KEY,
514 flags: Flags::empty(),
515 children: 0,
516 n_children: 0,
517 index: 0,
518 lowlink: 0,
519 scc: 0,
520 });
521
522 let mut cache: HashMap<Key<PatchId>, VertexId> = HashMap::new();
524 cache.insert(ROOT_KEY.clone(), DUMMY_VERTEX);
525 let mut stack = Vec::new();
526 if self.get_nodes(&branch, key0, None).is_some() {
527 stack.push(key0)
528 }
529 while let Some(key) = stack.pop() {
530 if cache.contains_key(&key) {
531 continue;
533 }
534
535 let idx = VertexId(graph.lines.len());
536 cache.insert(key.clone(), idx);
537
538 debug!("{:?}", key);
539 let mut is_zombie = false;
540 let mut first_edge = Edge::zero(EdgeFlags::PARENT_EDGE | EdgeFlags::DELETED_EDGE);
543 let mut nodes = self.iter_nodes(&branch, Some((key, Some(&first_edge))));
544 if let Some((k, v)) = nodes.next() {
545 debug!("zombie? {:?} {:?}", k, v);
546 if k == key
547 && (v.flag | EdgeFlags::FOLDER_EDGE == first_edge.flag | EdgeFlags::FOLDER_EDGE)
548 {
549 if key == key0 {
553 first_edge.flag = EdgeFlags::PARENT_EDGE;
554 nodes = self.iter_nodes(&branch, Some((key, Some(&first_edge))));
555 if let Some((_, v)) = nodes.next() {
556 is_zombie = v.flag | EdgeFlags::FOLDER_EDGE
558 == first_edge.flag | EdgeFlags::FOLDER_EDGE
559 }
560 } else {
561 is_zombie = true
562 }
563 }
564 }
565 debug!("is_zombie: {:?}", is_zombie);
566 let mut l = Line {
567 key: key.clone(),
568 flags: if is_zombie {
569 Flags::LINE_HALF_DELETED
570 } else {
571 Flags::empty()
572 },
573 children: graph.children.len(),
574 n_children: 0,
575 index: 0,
576 lowlink: 0,
577 scc: 0,
578 };
579
580 let mut last_flag = EdgeFlags::empty();
581 let mut last_dest = ROOT_KEY;
582
583 for (_, v) in self.iter_nodes(&branch, Some((key, None)))
584 .take_while(|&(k, v)| {
585 k == key
586 && v.flag
587 <= EdgeFlags::PSEUDO_EDGE | EdgeFlags::FOLDER_EDGE
588 | EdgeFlags::EPSILON_EDGE
589 }) {
590 debug!("-> v = {:?}", v);
591 if last_flag == EdgeFlags::PSEUDO_EDGE && last_dest == v.dest {
592 } else {
594 graph.children.push((Some(v.clone()), DUMMY_VERTEX));
595 l.n_children += 1;
596 if !cache.contains_key(&v.dest) {
597 stack.push(v.dest.clone())
598 } else {
599 debug!("v already visited");
600 }
601 last_flag = v.flag;
602 last_dest = v.dest;
603 }
604 }
605 if l.n_children == 0 {
607 debug!("no children for {:?}", l);
608 graph.children.push((None, DUMMY_VERTEX));
609 l.n_children = 1;
610 }
611 graph.lines.push(l)
612 }
613 for &mut (ref child_key, ref mut child_idx) in graph.children.iter_mut() {
614 if let Some(ref child_key) = *child_key {
615 if let Some(idx) = cache.get(&child_key.dest) {
616 *child_idx = *idx
617 }
618 }
619 }
620 graph
621 }
622}
623
624struct ConflictMarkers<'b> {
630 current_is_zombie: bool,
631 current_conflicts: usize,
632 graph: &'b Graph,
633}
634
635impl<'b> ConflictMarkers<'b> {
636 fn output_zombie_markers_if_needed<'a, A: Transaction + 'a, B: LineBuffer<'a, A>>(
637 &mut self,
638 buf: &mut B,
639 vertex: VertexId,
640 ) -> Result<()> {
641 if self.graph[vertex].is_zombie() {
642 if !self.current_is_zombie {
643 debug!("begin zombie conflict: vertex = {:?}", self.graph[vertex]);
644 self.current_is_zombie = true;
645 buf.begin_conflict()?;
646 }
647 } else if self.current_is_zombie {
648 if !self.current_is_zombie {
650 debug!("end zombie conflict: vertex = {:?}", self.graph[vertex]);
651 }
652 self.current_is_zombie = false;
653 buf.end_conflict()?;
654 }
655 Ok(())
656 }
657
658 fn begin_conflict<'a, A: Transaction + 'a, B: LineBuffer<'a, A>>(
659 &mut self,
660 buf: &mut B,
661 ) -> Result<()> {
662 buf.begin_conflict()?;
663 self.current_conflicts += 1;
664 Ok(())
665 }
666 fn end_conflict<'a, A: Transaction + 'a, B: LineBuffer<'a, A>>(
667 &mut self,
668 buf: &mut B,
669 ) -> Result<()> {
670 if self.current_conflicts > 0 {
671 buf.end_conflict()?;
672 self.current_conflicts -= 1;
673 }
674 Ok(())
675 }
676}
677
678#[derive(Debug, Clone)]
681enum ConflictLine {
682 Conflict(Vec<Vec<ConflictLine>>),
683 Line(VertexId),
684}
685
686impl<'a, A: Transaction + 'a, R> GenericTxn<A, R> {
687 fn output_conflict<B: LineBuffer<'a, A>>(
688 &'a self,
689 conflicts: &mut ConflictMarkers,
690 buf: &mut B,
691 graph: &Graph,
692 scc: &[Vec<VertexId>],
693 conflict: &mut [Vec<ConflictLine>],
694 ) -> Result<()> {
695 let mut is_first = true;
696 for side in conflict {
697 if !is_first && !side.is_empty() {
698 buf.conflict_next()?;
699 }
700 is_first = false;
701 debug!("side = {:?}", side);
702 for i in side {
703 match *i {
704 ConflictLine::Line(i) => {
705 conflicts.output_zombie_markers_if_needed(buf, i)?;
706 let key = graph[i].key;
707 if let Some(cont) = self.get_contents(key) {
708 debug!("outputting {:?}", cont);
709 buf.output_line(&key, cont)?;
710 }
711 }
712 ConflictLine::Conflict(ref mut c) => {
713 debug!("begin conflict {:?}", c);
714 sort_conflict(graph, c);
715 conflicts.begin_conflict(buf)?;
716 self.output_conflict(conflicts, buf, graph, scc, c)?;
717 conflicts.end_conflict(buf)?;
718 debug!("end conflict");
719 }
720 }
721 }
722 }
723 Ok(())
724 }
725
726 pub fn output_file<B: LineBuffer<'a, A>>(
727 &'a self,
728 branch: &Branch,
729 buf: &mut B,
730 graph: &mut Graph,
731 forward: &mut Vec<(Key<PatchId>, Edge)>,
732 ) -> Result<bool> {
733 debug!("output_file");
734 if graph.lines.len() <= 1 {
735 return Ok(false);
736 }
737 let scc = graph.tarjan(); debug!("There are {} SCC", scc.len());
739 debug!("SCCs = {:?}", scc);
740
741 let mut dfs = DFS::new(scc.len());
742 graph.dfs(self, branch, &scc, &mut dfs, forward);
743
744 debug!("dfs done");
745
746 buf.output_line(&graph.lines[1].key, Value::from_slice(b""))?;
747 let mut conflict_tree = conflict_tree(graph, &scc, &dfs)?;
748 debug!("conflict_tree = {:?}", conflict_tree);
749 let mut conflicts = ConflictMarkers {
750 current_is_zombie: false,
751 current_conflicts: 0,
752 graph: &graph,
753 };
754 self.output_conflict(&mut conflicts, buf, graph, &scc, &mut conflict_tree)?;
755 conflicts.output_zombie_markers_if_needed(buf, DUMMY_VERTEX)?;
757 debug!("/output_file");
758 Ok(dfs.has_conflicts)
759 }
760}
761
762fn side_ends_at(graph: &Graph, side: &[ConflictLine], id: VertexId) -> bool {
763 for j in side.iter() {
764 match *j {
765 ConflictLine::Line(j) => {
766 if graph.children(j).iter().any(|&(_, x)| x == id) {
767 return true;
768 }
769 }
770 ConflictLine::Conflict(ref sides) => {
771 if sides.iter().any(|side| side_ends_at(graph, side, id)) {
772 return true;
773 }
774 }
775 }
776 }
777 false
778}
779
780fn conflict_tree(
781 graph: &Graph,
782 scc: &[Vec<VertexId>],
783 dfs: &DFS,
784) -> Result<Vec<Vec<ConflictLine>>> {
785 let mut i = scc.len() - 1;
786
787 let mut stack: Vec<Vec<Vec<ConflictLine>>> = vec![Vec::new()];
788 loop {
789 if dfs.visits[i].ends_conflict && stack.len() > 1 {
790 debug!("End conflict {:?}", dfs.visits[i]);
791 let conflict = stack.pop().unwrap();
792
793 let mut remaining_sides = Vec::new();
797 let mut current_conflict = Vec::with_capacity(conflict.len());
798 for side in conflict.iter() {
799 if side_ends_at(graph, side, scc[i][0]) {
802 current_conflict.push(side.clone())
803 } else {
804 remaining_sides.push(side.clone())
805 }
806 }
807 debug!("remaining sides = {:?}", remaining_sides);
808 if !remaining_sides.is_empty() {
809 remaining_sides.push(vec![ConflictLine::Conflict(current_conflict)]);
817 stack.push(remaining_sides);
818 } else {
819 if let Some(ref mut last) = stack.last_mut() {
824 if let Some(ref mut last) = last.last_mut() {
825 last.push(ConflictLine::Conflict(current_conflict))
826 }
827 }
828 }
829 } else if dfs.visits[i].has_brothers {
830 if let Some(ref mut top) = stack.last_mut() {
831 top.push(Vec::new())
833 }
834 }
835
836 if scc[i].len() > 1 {
837 debug!("cycle conflict: {:?}", scc);
838 if let Some(ref mut last) = stack.last_mut() {
841 if let Some(ref mut last) = last.last_mut() {
842 last.push(ConflictLine::Conflict(
843 scc[i]
844 .iter()
845 .map(|&x| vec![ConflictLine::Line(x)])
846 .collect(),
847 ))
848 }
849 }
850 } else if scc[i].len() == 1 {
851 let key = graph[scc[i][0]].key;
852 debug!("scc[{}].len() = 1, key = {:?}", i, key);
853 if key != ROOT_KEY {
854 if let Some(ref mut top) = stack.last_mut() {
855 if top.is_empty() {
857 top.push(Vec::new())
858 }
859 if let Some(ref mut last_side) = top.last_mut() {
860 last_side.push(ConflictLine::Line(scc[i][0]))
861 }
862 }
863 }
864 }
865
866 if dfs.visits[i].begins_conflict {
867 debug!("Begin conflict {:?} {:?}", i, dfs.visits[i]);
868 stack.push(Vec::new());
869 }
870
871 if i == 0 {
872 break;
873 } else {
874 i -= 1
875 }
876 }
877 Ok(stack.pop().unwrap())
878}
879
880fn sort_conflict(graph: &Graph, conflict: &mut [Vec<ConflictLine>]) {
881 conflict.sort_by(|a, b| first_line(graph, a).cmp(&first_line(graph, b)))
882}
883
884fn first_line(graph: &Graph, conflict: &[ConflictLine]) -> Option<Key<PatchId>> {
885 let mut result = None;
886 for side in conflict {
887 match *side {
888 ConflictLine::Line(l) => {
889 result = if result.is_none() {
890 Some(graph[l].key)
891 } else {
892 min(result, Some(graph[l].key))
893 }
894 }
895 ConflictLine::Conflict(ref c) => {
896 let first = c.iter().filter_map(|side| first_line(graph, side)).min();
897 if result.is_none() {
898 result = first
899 } else if first.is_some() {
900 result = min(result, first)
901 }
902 }
903 }
904 }
905 result
906}
907
908impl<'env, R: rand::Rng> MutTxn<'env, R> {
909 pub fn remove_redundant_edges(
910 &mut self,
911 branch: &mut Branch,
912 forward: &[(Key<PatchId>, Edge)],
913 ) -> Result<()> {
914 for &(key, edge) in forward.iter() {
915 self.del_nodes_with_rev(branch, key, edge)?;
916 }
917 Ok(())
918 }
919}