pub fn record_single_thread<T, W: WorkingCopyRead + Clone, C: ChangeStore + Clone>(
        &mut self,
        txn: ArcTxn<T>,
        diff_algorithm: diff::Algorithm,
        stop_early: bool,
        diff_separator: ®ex::bytes::Regex,
        channel: ChannelRef<T>,
        working_copy: &W,
        changes: &C,
        prefix: &str,
    ) -> Result<(), RecordError<C::Error, W::Error, T>>
    where
        T: ChannelMutTxnT + TreeTxnT,
        <W as WorkingCopyRead>::Error: 'static,
    {
        info!("Starting to record");
        let now = std::time::Instant::now();
        let mut stack = vec![(RecordItem::root(), components(prefix))];
        while let Some((mut item, mut components)) = stack.pop() {
            debug!("stack.pop() = Some({:?})", item);
            // Check for moves and file conflicts.
            let vertex: Option<Position<Option<ChangeId>>> =
                self.recorded_inodes.lock().get(&item.inode).cloned();
            let mut root_vertices = Vec::new();
            let vertex = if let Some(vertex) = vertex {
                vertex
            } else if item.inode == Inode::ROOT {
                debug!("TAKING LOCK {}", line!());
                let txn = txn.read();
                debug!("TAKEN");
                let channel = channel.r.read();
                // Test for a "root" vertex below the null one.
                let f0 = EdgeFlags::FOLDER | EdgeFlags::BLOCK;
                let f1 = f0 | EdgeFlags::PSEUDO;
                self.recorded_inodes
                    .lock()
                    .insert(Inode::ROOT, Position::ROOT.to_option());
                let mut has_nonempty_root = false;
                for e in iter_adjacent(&*txn, txn.graph(&*channel), Vertex::ROOT, f0, f1)? {
                    let e = e?;
                    let child = txn.find_block(txn.graph(&*channel), e.dest()).unwrap();
                    if child.start == child.end {
                        // This is the "new" format, with multiple
                        // roots, and `grandchild` is one of the
                        // roots.
                        let grandchild =
                            iter_adjacent(&*txn, txn.graph(&*channel), *child, f0, f1)?
                                .next()
                                .unwrap()?
                                .dest();
                        root_vertices.push(grandchild);
                        self.delete_obsolete_children(
                            &*txn,
                            txn.graph(&channel),
                            working_copy,
                            changes,
                            &item.full_path,
                            grandchild,
                        )?;
                    } else {
                        // Single-root repository, we need to follow
                        // the root's children.
                        has_nonempty_root = true
                    }
                }
                debug!("has_nonempty_root: {:?}", has_nonempty_root);
                debug!("root_vertices: {:?}", root_vertices);
                if has_nonempty_root && !root_vertices.is_empty() {
                    // This repository is mixed between "zero" roots,
                    // and new-style-roots.
                    root_vertices.push(Position::ROOT)
                }
                Position::ROOT.to_option()
            } else if let Some(vertex) = get_inodes_::<_, C, W>(&txn, &channel, &item.inode)? {
                {
                    let txn = txn.read();
                    let channel = channel.r.read();
                    let graph = txn.graph(&*channel);
                    self.delete_obsolete_children(
                        &*txn,
                        &graph,
                        working_copy,
                        changes,
                        &item.full_path,
                        vertex,
                    )?;
                }
                let rec = self.recorded();
                let new_papa = {
                    let mut recorded = self.recorded_inodes.lock();
                    recorded.insert(item.inode, vertex.to_option());
                    recorded.get(&item.papa).cloned()
                };
                rec.lock().record_existing_file(
                    &txn,
                    diff_algorithm,
                    stop_early,
                    &diff_separator,
                    &channel,
                    working_copy.clone(),
                    changes,
                    &item,
                    new_papa,
                    vertex,
                )?;
                vertex.to_option()
            } else {
                let rec = self.recorded();
                debug!("TAKING LOCK {}", line!());
                let mut rec = rec.lock();
                match rec.add_file(working_copy, item.clone()) {
                    Ok(Some(vertex)) => {
                        // Path addition (maybe just a single directory).
                        self.recorded_inodes.lock().insert(item.inode, vertex);
                        vertex
                    }
                    _ => continue,
                }
            };
            if root_vertices.is_empty() {
                // Move on to the next step.
                debug!("TAKING LOCK {}", line!());
                let txn = txn.read();
                let channel = channel.r.read();
                self.push_children::<_, _, C>(
                    &*txn,
                    &*channel,
                    working_copy,
                    &mut item,
                    &mut components,
                    vertex,
                    &mut stack,
                    prefix,
                    changes,
                )?;
            } else {
                for vertex in root_vertices {
                    let txn = txn.read();
                    let channel = channel.r.read();
                    if !vertex.change.is_root() {
                        let mut r = self.new_root.lock();
                        let age = txn
                            .get_changeset(txn.changes(&*channel), &vertex.change)?
                            .unwrap();
                        if let Some((_, a)) = *r {
                            if a < (*age).into() {
                                *r = Some((vertex.to_option(), (*age).into()))
                            }
                        } else {
                            *r = Some((vertex.to_option(), (*age).into()))
                        }
                    }
                    item.v_papa = vertex.to_option();
                    self.push_children::<_, _, C>(
                        &*txn,
                        &*channel,
                        working_copy,
                        &mut item,
                        &mut components,
                        vertex.to_option(),
                        &mut stack,
                        prefix,
                        changes,
                    )?;
                }
            }
        }
        crate::TIMERS.lock().unwrap().record += now.elapsed();
        info!("record done");
        Ok(())
    }