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