tree_builder: populate base trees by recursion

Suppose many override entries share the same parent directories, it should
be cheaper to look up the tree_cache from leaf than root. I also think
recursion is easier to follow than for loop.
This commit is contained in:
Yuya Nishihara 2023-06-01 10:47:26 +09:00
parent 941f41e62e
commit 6872051270

View file

@ -19,7 +19,7 @@ use itertools::Itertools as _;
use crate::backend; use crate::backend;
use crate::backend::{TreeId, TreeValue}; use crate::backend::{TreeId, TreeValue};
use crate::repo_path::{RepoPath, RepoPathJoin}; use crate::repo_path::RepoPath;
use crate::store::Store; use crate::store::Store;
use crate::tree::Tree; use crate::tree::Tree;
@ -115,30 +115,32 @@ impl TreeBuilder {
} }
fn get_base_trees(&self) -> BTreeMap<RepoPath, backend::Tree> { fn get_base_trees(&self) -> BTreeMap<RepoPath, backend::Tree> {
let store = self.store.clone(); let store = &self.store;
let mut tree_cache = { let mut tree_cache = {
let dir = RepoPath::root(); let dir = RepoPath::root();
let tree = store.get_tree(&dir, &self.base_tree_id).unwrap(); let tree = store.get_tree(&dir, &self.base_tree_id).unwrap();
BTreeMap::from([(dir, tree)]) BTreeMap::from([(dir, tree)])
}; };
let mut populate_trees = |dir: &RepoPath| { fn populate_trees<'a>(
let mut current_dir = RepoPath::root(); tree_cache: &'a mut BTreeMap<RepoPath, Tree>,
for component in dir.components() { store: &Arc<Store>,
let next_dir = current_dir.join(component); dir: RepoPath,
let current_tree = tree_cache.get(&current_dir).unwrap(); ) -> &'a Tree {
if !tree_cache.contains_key(&next_dir) { // `if let Some(tree) = ...` doesn't pass lifetime check as of Rust 1.69.0
let tree = current_tree if tree_cache.contains_key(&dir) {
.sub_tree(component) return tree_cache.get(&dir).unwrap();
.unwrap_or_else(|| Tree::null(self.store.clone(), next_dir.clone()));
tree_cache.insert(next_dir.clone(), tree);
}
current_dir = next_dir;
} }
}; let (parent, basename) = dir.split().expect("root must be populated");
let tree = populate_trees(tree_cache, store, parent)
.sub_tree(basename)
.unwrap_or_else(|| Tree::null(store.clone(), dir.clone()));
tree_cache.entry(dir).or_insert(tree)
}
for path in self.overrides.keys() { for path in self.overrides.keys() {
let parent = path.parent().unwrap(); let parent = path.parent().unwrap();
populate_trees(&parent); populate_trees(&mut tree_cache, store, parent);
} }
tree_cache tree_cache