1 use super::{LocalApplyError, Workspace};
2 use crate::change::{Change, NewVertex};
3 use crate::pristine::*;
4 use crate::{ChangeId, EdgeFlags, Hash, Vertex};
5 
put_newvertex<T: GraphMutTxnT>( txn: &mut T, graph: &mut T::Graph, ch: &Change, ws: &mut Workspace, change: ChangeId, n: &NewVertex<Option<Hash>>, ) -> Result<(), LocalApplyError<T::GraphError>>6 pub fn put_newvertex<T: GraphMutTxnT>(
7     txn: &mut T,
8     graph: &mut T::Graph,
9     ch: &Change,
10     ws: &mut Workspace,
11     change: ChangeId,
12     n: &NewVertex<Option<Hash>>,
13 ) -> Result<(), LocalApplyError<T::GraphError>> {
14     let vertex = Vertex {
15         change,
16         start: n.start,
17         end: n.end,
18     };
19     if txn.find_block_end(graph, vertex.end_pos()).is_ok()
20         || txn.find_block(graph, vertex.start_pos()).is_ok()
21     {
22         error!("Invalid change: {:?}", vertex);
23         return Err(LocalApplyError::InvalidChange);
24     }
25     debug!(
26         "put_newvertex {:?} {:?} {:?} {:?} {:?}",
27         vertex, n.up_context, n.down_context, n.flag, change
28     );
29     assert!(ws.deleted_by.is_empty());
30     for up in n.up_context.iter() {
31         let up = internal_pos(txn, up, change)?;
32         if put_up_context(txn, graph, ch, ws, up)? && n.flag.contains(EdgeFlags::FOLDER) {
33             return Err(LocalApplyError::InvalidChange);
34         }
35     }
36     for down in n.down_context.iter() {
37         let down = internal_pos(txn, down, change)?;
38         if down.change == change {
39             return Err(LocalApplyError::InvalidChange);
40         }
41         if put_down_context(txn, graph, ch, ws, down)? && !n.flag.contains(EdgeFlags::FOLDER) {
42             return Err(LocalApplyError::InvalidChange);
43         }
44     }
45     debug!("deleted by: {:?}", ws.deleted_by);
46 
47     let up_flag = n.flag | EdgeFlags::BLOCK | EdgeFlags::DELETED;
48     for up in ws.up_context.drain(..) {
49         assert_ne!(up, vertex);
50         if !n.flag.contains(EdgeFlags::FOLDER) {
51             for change in ws.deleted_by.iter() {
52                 put_graph_with_rev(txn, graph, up_flag, up, vertex, *change)?;
53             }
54         }
55         put_graph_with_rev(txn, graph, n.flag | EdgeFlags::BLOCK, up, vertex, change)?;
56     }
57     debug!("down_context {:?}", ws.down_context);
58     let mut down_flag = n.flag;
59     if !n.flag.is_folder() {
60         down_flag -= EdgeFlags::BLOCK
61     }
62     for down in ws.down_context.drain(..) {
63         assert_ne!(down, vertex);
64         put_graph_with_rev(txn, graph, down_flag, vertex, down, change)?;
65         if n.flag.is_folder() {
66             ws.missing_context.files.insert(down);
67         }
68     }
69     ws.deleted_by.clear();
70     Ok(())
71 }
72 
put_up_context<T: GraphMutTxnT>( txn: &mut T, graph: &mut T::Graph, ch: &Change, ws: &mut Workspace, up: Position<ChangeId>, ) -> Result<bool, LocalApplyError<T::GraphError>>73 fn put_up_context<T: GraphMutTxnT>(
74     txn: &mut T,
75     graph: &mut T::Graph,
76     ch: &Change,
77     ws: &mut Workspace,
78     up: Position<ChangeId>,
79 ) -> Result<bool, LocalApplyError<T::GraphError>> {
80     let up_vertex = if up.change.is_root() {
81         Vertex::ROOT
82     } else {
83         debug!("put_up_context {:?}", up);
84         let k = *txn.find_block_end(graph, up)?;
85         assert_eq!(k.change, up.change);
86         assert!(k.start <= up.pos);
87         debug!("k = {:?}", k);
88         if k.start < up.pos && k.end > up.pos {
89             // The missing context "graphs" are only used at the
90             // DELETION stage, check that:
91             assert!(ws.missing_context.graphs.0.is_empty());
92             txn.split_block(graph, &k, up.pos, &mut ws.adjbuf)?
93         }
94         Vertex {
95             change: k.change,
96             start: k.start,
97             end: up.pos,
98         }
99     };
100     debug!("up_vertex {:?}", up_vertex);
101     let flag0 = EdgeFlags::PARENT | EdgeFlags::BLOCK;
102     let flag1 = flag0 | EdgeFlags::DELETED | EdgeFlags::FOLDER;
103     let mut is_non_folder = false;
104     for parent in iter_adjacent(txn, graph, up_vertex, flag0, flag1)? {
105         let parent = parent?;
106         is_non_folder |=
107             parent.flag() & (EdgeFlags::PARENT | EdgeFlags::FOLDER) == EdgeFlags::PARENT;
108         if parent
109             .flag()
110             .contains(EdgeFlags::PARENT | EdgeFlags::DELETED | EdgeFlags::BLOCK)
111         {
112             let introduced_by = txn.get_external(&parent.introduced_by())?.unwrap().into();
113             if !ch.knows(&introduced_by) {
114                 ws.deleted_by.insert(parent.introduced_by());
115             }
116         }
117     }
118     ws.up_context.push(up_vertex);
119     Ok(is_non_folder)
120 }
121 
put_down_context<T: GraphMutTxnT>( txn: &mut T, graph: &mut T::Graph, ch: &Change, ws: &mut Workspace, down: Position<ChangeId>, ) -> Result<bool, LocalApplyError<T::GraphError>>122 fn put_down_context<T: GraphMutTxnT>(
123     txn: &mut T,
124     graph: &mut T::Graph,
125     ch: &Change,
126     ws: &mut Workspace,
127     down: Position<ChangeId>,
128 ) -> Result<bool, LocalApplyError<T::GraphError>> {
129     let k = *txn.find_block(&graph, down)?;
130     assert_eq!(k.change, down.change);
131     assert!(k.end >= down.pos);
132     if k.start < down.pos && k.end > down.pos {
133         // The missing context "graphs" are only used at the
134         // DELETION stage, check that:
135         assert!(ws.missing_context.graphs.0.is_empty());
136         txn.split_block(graph, &k, down.pos, &mut ws.adjbuf)?
137     }
138     let down_vertex = Vertex {
139         change: k.change,
140         start: down.pos,
141         end: k.end,
142     };
143     debug!("down_vertex {:?}", down_vertex);
144 
145     let flag0 = EdgeFlags::PARENT;
146     let flag1 = flag0 | EdgeFlags::FOLDER | EdgeFlags::BLOCK | EdgeFlags::DELETED;
147     let mut is_folder = false;
148     for parent in iter_adjacent(txn, &graph, down_vertex, flag0, flag1)? {
149         let parent = parent?;
150         is_folder |= parent
151             .flag()
152             .contains(EdgeFlags::PARENT | EdgeFlags::FOLDER);
153         if parent.flag().contains(EdgeFlags::PARENT | EdgeFlags::BLOCK) {
154             if parent.flag().contains(EdgeFlags::DELETED) {
155                 let introduced_by = txn.get_external(&parent.introduced_by())?.unwrap().into();
156                 if !ch.knows(&introduced_by) {
157                     ws.deleted_by.insert(parent.introduced_by());
158                 }
159             }
160         }
161     }
162     ws.down_context.push(down_vertex);
163     Ok(is_folder)
164 }
165