repo: extract add_heads() that can import commits from multiple heads

This allows us to reorder commits to be indexed in bulk.

The incremental update optimization is applied only for a single head. This
could be tried for multiple heads, but it's unlikely that every head has
a single new commit for each.
This commit is contained in:
Yuya Nishihara 2023-08-12 09:11:31 +09:00
parent 157a0e748b
commit 73a4b7f5bf

View file

@ -16,12 +16,12 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::fs;
use std::io::ErrorKind; use std::io::ErrorKind;
use std::ops::Deref; use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use std::{fs, slice};
use itertools::Itertools; use itertools::Itertools;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@ -915,38 +915,49 @@ impl MutableRepo {
} }
pub fn add_head(&mut self, head: &Commit) { pub fn add_head(&mut self, head: &Commit) {
self.add_heads(slice::from_ref(head));
}
pub fn add_heads(&mut self, heads: &[Commit]) {
let current_heads = self.view.get_mut().heads(); let current_heads = self.view.get_mut().heads();
// Use incremental update for common case of adding a single commit on top a // Use incremental update for common case of adding a single commit on top a
// current head. TODO: Also use incremental update when adding a single // current head. TODO: Also use incremental update when adding a single
// commit on top a non-head. // commit on top a non-head.
if head match heads {
.parent_ids() [] => {}
.iter() [head]
.all(|parent_id| current_heads.contains(parent_id)) if head
{ .parent_ids()
self.index.add_commit(head); .iter()
self.view.get_mut().add_head(head.id()); .all(|parent_id| current_heads.contains(parent_id)) =>
for parent_id in head.parent_ids() { {
self.view.get_mut().remove_head(parent_id); self.index.add_commit(head);
self.view.get_mut().add_head(head.id());
for parent_id in head.parent_ids() {
self.view.get_mut().remove_head(parent_id);
}
} }
} else { _ => {
let missing_commits = dag_walk::topo_order_forward( let missing_commits = dag_walk::topo_order_forward(
vec![head.clone()], heads.iter().cloned(),
|commit: &Commit| commit.id().clone(), |commit: &Commit| commit.id().clone(),
|commit: &Commit| -> Vec<Commit> { |commit: &Commit| -> Vec<Commit> {
commit commit
.parent_ids() .parent_ids()
.iter() .iter()
.filter(|id| !self.index().has_id(id)) .filter(|id| !self.index().has_id(id))
.map(|id| self.store().get_commit(id).unwrap()) .map(|id| self.store().get_commit(id).unwrap())
.collect() .collect()
}, },
); );
for missing_commit in &missing_commits { for missing_commit in &missing_commits {
self.index.add_commit(missing_commit); self.index.add_commit(missing_commit);
}
for head in heads {
self.view.get_mut().add_head(head.id());
}
self.view.mark_dirty();
} }
self.view.get_mut().add_head(head.id());
self.view.mark_dirty();
} }
} }