libpijul_compat/apply/
apply.rs

1use backend::*;
2use patch::*;
3use rand;
4use std::collections::HashSet;
5use Result;
6
7impl<'env, T: rand::Rng> MutTxn<'env, T> {
8    /// Applies a patch to a repository. "new_patches" are patches that
9    /// just this repository has, and the remote repository doesn't have.
10    pub fn apply(
11        &mut self,
12        branch: &mut Branch,
13        patch: &Patch,
14        patch_id: PatchId,
15        timestamp: ApplyTimestamp,
16    ) -> Result<()> {
17        assert!(self.put_patches(&mut branch.patches, patch_id, timestamp)?);
18        assert!(self.put_revpatches(&mut branch.revpatches, timestamp, patch_id)?);
19        debug!("apply_raw");
20        // Here we need to first apply *all* the NewNodes, and then
21        // the Edges, because some of the NewNodes might be the
22        // children of newly deleted edges, and we need to add the
23        // corresponding pseudo-edges.
24        for ch in patch.changes().iter() {
25            if let Change::NewNodes {
26                ref up_context,
27                ref down_context,
28                ref line_num,
29                flag,
30                ref nodes,
31                ..
32            } = *ch
33            {
34                assert!(!nodes.is_empty());
35                debug!("apply: newnodes");
36                self.add_new_nodes(
37                    branch,
38                    patch_id,
39                    up_context,
40                    down_context,
41                    line_num,
42                    flag,
43                    nodes,
44                )?;
45            }
46        }
47        let mut parents: HashSet<Key<PatchId>> = HashSet::new();
48        let mut children: HashSet<Edge> = HashSet::new();
49        for ch in patch.changes().iter() {
50            if let Change::NewEdges {
51                previous,
52                flag,
53                ref edges,
54                ..
55            } = *ch
56            {
57                self.add_new_edges(
58                    branch,
59                    patch_id,
60                    Some(previous),
61                    flag,
62                    edges,
63                    &mut parents,
64                    &mut children,
65                )?;
66                debug!("apply_raw:edges.done");
67            }
68        }
69
70        // If there is a missing context, add pseudo-edges along the
71        // edges that deleted the conflict, until finding (in both
72        // directions) an alive context.
73        self.repair_deleted_contexts(branch, patch, patch_id)?;
74
75        Ok(())
76    }
77
78    /// Delete old versions of `edges`.
79    fn delete_old_edge(
80        &mut self,
81        branch: &mut Branch,
82        patch_id: PatchId,
83        previous: EdgeFlags,
84        from: Key<PatchId>,
85        to: Key<PatchId>,
86        introduced_by: PatchId,
87    ) -> Result<()> {
88        debug!(
89            "delete {:?} -> {:?} ({:?}) {:?}",
90            from, to, previous, introduced_by
91        );
92        // debug!("delete_old_edges: introduced_by = {:?}", e.introduced_by);
93        let mut deleted_e = Edge {
94            flag: previous,
95            dest: to,
96            introduced_by,
97        };
98        self.put_cemetery(from, &deleted_e, patch_id)?;
99        if !self.del_nodes_with_rev(branch, from, deleted_e)? {
100            debug!("killing pseudo instead {:?} {:?}", from, deleted_e);
101            deleted_e.flag |= EdgeFlags::PSEUDO_EDGE;
102            let result = self.del_nodes_with_rev(branch, from, deleted_e)?;
103            debug!("killed ? {:?}", result);
104        }
105        Ok(())
106    }
107
108    fn add_new_edges(
109        &mut self,
110        branch: &mut Branch,
111        patch_id: PatchId,
112        previous: Option<EdgeFlags>,
113        flag: EdgeFlags,
114        edges: &[NewEdge],
115        parents: &mut HashSet<Key<PatchId>>,
116        children: &mut HashSet<Edge>,
117    ) -> Result<()> {
118        for e in edges {
119            debug!("add_new_edges {:?}", e);
120            // If the edge has not been forgotten about,
121            // insert the new version.
122            let e_from = self.internal_key(&e.from, patch_id);
123            let e_to = self.internal_key(&e.to, patch_id);
124            assert!(e_from != e_to);
125            let to = if flag.contains(EdgeFlags::PARENT_EDGE) {
126                e_from
127            } else {
128                e_to
129            };
130
131            // If this is a deletion edge and not a folder edge, reconnect parents and children.
132            if flag.contains(EdgeFlags::DELETED_EDGE) && !flag.contains(EdgeFlags::FOLDER_EDGE) {
133                self.reconnect_parents_children(branch, patch_id, to, parents, children)?;
134            }
135
136            let introduced_by = self.internal_hash(&e.introduced_by, patch_id);
137
138            if let Some(previous) = previous {
139                self.delete_old_edge(branch, patch_id, previous, e_from, e_to, introduced_by)?
140            }
141
142            if flag.contains(EdgeFlags::DELETED_EDGE) && !flag.contains(EdgeFlags::FOLDER_EDGE) {
143                self.delete_old_pseudo_edges(branch, patch_id, to, children)?
144            }
145
146            // Let's build the edge we're about to insert.
147            let e = Edge {
148                flag,
149                dest: e_to,
150                introduced_by: patch_id.clone(),
151            };
152
153            // Finally, add the new version of the edge.
154            self.put_nodes_with_rev(branch, e_from, e)?;
155        }
156        Ok(())
157    }
158
159    /// Add pseudo edges from all keys of `parents` to all `dest` of
160    /// the edges in `children`, with the same edge flags as in
161    /// `children`, plus `PSEUDO_EDGE`.
162    pub fn reconnect_parents_children(
163        &mut self,
164        branch: &mut Branch,
165        patch_id: PatchId,
166        to: Key<PatchId>,
167        parents: &mut HashSet<Key<PatchId>>,
168        children: &mut HashSet<Edge>,
169    ) -> Result<()> {
170        // Collect all the alive parents of the source of this edge.
171        let mut edge = Edge::zero(EdgeFlags::PARENT_EDGE);
172        parents.clear();
173        parents.extend(
174            self.iter_nodes(&branch, Some((to, Some(&edge))))
175                .take_while(|&(k, v)| {
176                    k == to && v.flag <= EdgeFlags::PARENT_EDGE | EdgeFlags::PSEUDO_EDGE
177                })
178                .filter_map(|(_, v)| {
179                    if !v.flag.contains(EdgeFlags::EPSILON_EDGE)
180                        && self.is_alive_or_zombie(branch, v.dest)
181                    {
182                        Some(v.dest)
183                    } else {
184                        None
185                    }
186                }),
187        );
188
189        // Now collect all the alive children of the target of this edge.
190        edge.flag = EdgeFlags::empty();
191        children.clear();
192        children.extend(
193            self.iter_nodes(&branch, Some((to, Some(&edge))))
194                .take_while(|&(k, v)| {
195                    k == to && v.flag <= EdgeFlags::PSEUDO_EDGE | EdgeFlags::FOLDER_EDGE
196                })
197                .map(|(_, e)| *e),
198        );
199
200        debug!("reconnecting {:?} {:?}", parents, children);
201
202        for &parent in parents.iter() {
203            for e in children.iter() {
204                // If these are not already connected
205                // or pseudo-connected, add a
206                // pseudo-edge.
207                if parent != e.dest && !self.is_connected(branch, parent, e.dest) {
208                    let pseudo_edge = Edge {
209                        flag: e.flag | EdgeFlags::PSEUDO_EDGE,
210                        dest: e.dest,
211                        introduced_by: patch_id.clone(),
212                    };
213                    debug!("reconnect_parents_children: {:?} {:?}", parent, pseudo_edge);
214                    self.put_nodes_with_rev(branch, parent, pseudo_edge)?;
215                }
216            }
217        }
218        Ok(())
219    }
220
221    fn delete_old_pseudo_edges(
222        &mut self,
223        branch: &mut Branch,
224        patch_id: PatchId,
225        to: Key<PatchId>,
226        pseudo_edges: &mut HashSet<Edge>,
227    ) -> Result<()> {
228        // Now collect pseudo edges, and delete them.
229        pseudo_edges.clear();
230        for (_, to_edge) in self.iter_nodes(branch, Some((to, None)))
231            .take_while(|&(k, v)| k == to && v.flag < EdgeFlags::DELETED_EDGE)
232            .filter(|&(_, v)| v.flag.contains(EdgeFlags::PSEUDO_EDGE))
233        {
234            // Is this pseudo-edge a zombie marker? I.e. is there a
235            // deleted edge in parallel of it? Since we haven't yet
236            // introduced the new deleted edge, there is no possible
237            // risk of confusion here.
238            let mut e = Edge::zero(
239                EdgeFlags::DELETED_EDGE
240                    | (to_edge.flag & (EdgeFlags::PARENT_EDGE | EdgeFlags::FOLDER_EDGE)),
241            );
242            e.dest = to_edge.dest;
243            let mut is_zombie_marker = to_edge.introduced_by != patch_id
244                && (match self.iter_nodes(branch, Some((to, Some(&e)))).next() {
245                    Some((k, v)) if k == to && v.dest == e.dest && v.flag == e.flag => {
246                        v.introduced_by != patch_id
247                    }
248                    _ => false,
249                });
250            debug!(
251                "is_zombie_marker {:?}: {:?}",
252                to_edge.dest, is_zombie_marker
253            );
254            if !is_zombie_marker {
255                // This edge is not a zombie marker, we can delete it.
256                pseudo_edges.insert(*to_edge);
257            }
258        }
259        debug!("killing pseudo-edges from {:?}: {:?}", to, pseudo_edges);
260        for edge in pseudo_edges.drain() {
261            // Delete both directions.
262            self.del_nodes_with_rev(branch, to, edge)?;
263        }
264        Ok(())
265    }
266
267    /// Add the new nodes (not repairing missing contexts).
268    fn add_new_nodes(
269        &mut self,
270        branch: &mut Branch,
271        patch_id: PatchId,
272        up_context: &[Key<Option<Hash>>],
273        down_context: &[Key<Option<Hash>>],
274        line_num: &LineId,
275        flag: EdgeFlags,
276        nodes: &[Vec<u8>],
277    ) -> Result<()> {
278        debug!("up_context {:?}", up_context);
279        debug!("down_context {:?}", up_context);
280        let mut v = Key {
281            patch: patch_id.clone(),
282            line: line_num.clone(),
283        };
284        let mut e = Edge {
285            flag: flag ^ EdgeFlags::PARENT_EDGE,
286            dest: ROOT_KEY,
287            introduced_by: patch_id,
288        };
289
290        // Connect the first line to the up context.
291        for c in up_context {
292            e.dest = self.internal_key(c, patch_id);
293            debug!("up_context: put_nodes {:?} {:?}", v, e);
294            self.put_nodes_with_rev(branch, v, e)?;
295        }
296        debug!("up context done");
297
298        // Insert the contents and new nodes.
299        e.flag = flag;
300        e.dest.patch = patch_id;
301
302        let mut nodes = nodes.iter();
303        if let Some(first_line) = nodes.next() {
304            debug!("first_line = {:?}", first_line);
305            let value = self.alloc_value(&first_line)?;
306            debug!("put_contents {:?} {:?}", v, value);
307            self.put_contents(v, value)?;
308        }
309        for content in nodes {
310            e.dest.line = v.line + 1;
311            self.put_nodes_with_rev(branch, v, e)?;
312
313            v.line = e.dest.line;
314
315            if !content.is_empty() {
316                let value = self.alloc_value(&content)?;
317                debug!("put_contents {:?} {:?}", v, value);
318                self.put_contents(v, value)?;
319            }
320        }
321        debug!("newnodes core done");
322
323        // Connect the last new line to the down context.
324        for c in down_context {
325            e.dest = self.internal_key(c, patch_id);
326            self.put_nodes_with_rev(branch, v, e)?;
327        }
328        debug!("down context done");
329        Ok(())
330    }
331}