Add limit_commit_ids_to_related setting.

Each template received `commit_ids`, a list of ALL commit hashes known
to Itsy-Gitsy.  For large repos with hundreds of thousands or millions
of commits, this huge list uses lots of memory and takes a long time
to search.

`limit_commit_ids_to_related` reduces the list to just a handful of
relevant commits for certain templates, which can give a massive
performance boost.
This commit is contained in:
Trevor Bentley
2023-01-20 02:26:16 +01:00
parent 5f0f9978c9
commit c257ba12f0
4 changed files with 57 additions and 1 deletions
+1 -1
View File
@@ -183,7 +183,7 @@ Syntax highlighting uses syntect's pure-Rust implementation by default, to avoid
All metadata of all repositories, except for file contents, is held in memory. Large repositories can easily exhaust memory, and disk usage can also get quite high. There are several `limit_*` settings available in the configuration for restricting the amount of data held in memory, with the tradeoff of reducing the amount of data available for the generated output. `limit_context` and `limit_diffs` are particularly important restrictions to set on repositories with thousands of commits.
Small repositories with dozens to hundreds of commits can be generated on the order of a few seconds or less. Large repositories take *considerably* longer; parsing 1,115,000 commits from the Linux kernel repository with `limit_tree_depth = 3`, `limit_context = 100` and `limit_diffs = 0` took ~25 minutes on a fast laptop, and produced a ~5.6GB website. Peak memory usage was 8GB.
Small repositories with dozens to hundreds of commits can be generated on the order of a few seconds or less. Large repositories take *considerably* longer and significant amounts of RAM, but aggressively applying limits in the configuration can help; parsing 1,115,000 commits from the Linux kernel repository with syntax highlighting disabled, `limit_commit_ids_to_related = true`, `limit_tree_depth = 3`, `limit_context = 100` and `limit_diffs = 0` took ~7 minutes on a fast laptop, and produced a ~5.7GB website. Peak memory usage was ~8GB.
## Other Considerations
+21
View File
@@ -209,6 +209,27 @@ threads = 0
# This can also be set per-repository.
#limit_tags = 500
# Limit the `commit_ids` variable to only related commits
#
# Normally the `commit_ids` variable contains a list of *all* git
# commit hashes that Itsy-Gitsy is parsing. For large repos, this can
# be enormous, and take a lot of CPU time to search.
#
# Enabling this option limits `commit_ids` to only contain hashes of
# commits that are referenced by the current object:
#
# - in `history` templates, all commits on the current page
# - in `commit` templates, all the parent commits
# - in `branch` templates, the commit it references
# - in `tag` templates, the commit that it tags
#
# Enabling this provides a performance boost with the default
# templates with no tradeoffs. This is only a restriction for custom
# templates that require more metadata.
#
# This can also be set per-repository.
limit_commit_ids_to_related = true
# Limits directory depth to traverse when parsing files.
#
# Limits the number of directories traversed when enumerating files in the
+30
View File
@@ -454,6 +454,10 @@ impl GitsyGenerator {
})
.map_while(|x| x)
.collect();
if repo_desc.limit_commit_ids_to_related == Some(true) {
let parent_ids: Vec<String> = commits.keys().cloned().collect();
paged_ctx.insert("commit_ids", &parent_ids);
}
paged_ctx.insert("page", &pagination.with_relative_paths());
paged_ctx.insert("history", &page);
paged_ctx.insert("commits", &commits);
@@ -493,6 +497,15 @@ impl GitsyGenerator {
for (_id, commit) in &parsed_repo.commits {
ctx.try_insert("commit", &commit)
.expect("Failed to add commit to template engine.");
if repo_desc.limit_commit_ids_to_related == Some(true) {
let parent_ids: Vec<String> = commit
.parents
.iter()
.filter(|x| parsed_repo.commits.contains_key(*x))
.cloned()
.collect();
ctx.insert("commit_ids", &parent_ids);
}
for (templ_path, out_path) in self.settings.outputs.commit(Some(parsed_repo), Some(commit)) {
let templ_path = templ_path.to_str().expect(&format!(
"ERROR: a summary template path is invalid: {}",
@@ -593,6 +606,14 @@ impl GitsyGenerator {
let mut repo_bytes = 0;
for branch in &parsed_repo.branches {
ctx.insert("branch", branch);
if repo_desc.limit_commit_ids_to_related == Some(true) {
let parent_ids: Vec<String> = [&branch.full_hash]
.iter()
.filter(|x| parsed_repo.commits.contains_key(**x))
.map(|x| (**x).clone())
.collect();
ctx.insert("commit_ids", &parent_ids);
}
for (templ_path, out_path) in self.settings.outputs.branch(Some(parsed_repo), Some(branch)) {
let templ_path = templ_path.to_str().expect(&format!(
"ERROR: a summary template path is invalid: {}",
@@ -693,6 +714,15 @@ impl GitsyGenerator {
let mut repo_bytes = 0;
for tag in &parsed_repo.tags {
ctx.insert("tag", tag);
if repo_desc.limit_commit_ids_to_related == Some(true) {
let parent_ids: Vec<String> = [tag.tagged_id.as_deref()]
.iter()
.map_while(|x| *x)
.filter(|x| parsed_repo.commits.contains_key(*x))
.map(|x| x.to_string())
.collect();
ctx.insert("commit_ids", &parent_ids);
}
if let Some(tagged_id) = tag.tagged_id.as_ref() {
if let Some(commit) = parsed_repo.commits.get(tagged_id) {
ctx.insert("commit", &commit);
+5
View File
@@ -372,6 +372,7 @@ pub struct GitsySettingsRepo {
pub limit_commits: Option<usize>,
pub limit_branches: Option<usize>,
pub limit_tags: Option<usize>,
pub limit_commit_ids_to_related: Option<bool>,
pub limit_tree_depth: Option<usize>,
pub limit_file_size: Option<usize>,
pub limit_repo_size: Option<usize>,
@@ -413,6 +414,7 @@ pub struct GitsySettings {
pub limit_commits: Option<usize>,
pub limit_branches: Option<usize>,
pub limit_tags: Option<usize>,
pub limit_commit_ids_to_related: Option<bool>,
pub limit_tree_depth: Option<usize>,
pub limit_file_size: Option<usize>,
pub limit_repo_size: Option<usize>,
@@ -496,6 +498,7 @@ impl GitsySettings {
global_to_repo!(settings, repo, limit_commits);
global_to_repo!(settings, repo, limit_branches);
global_to_repo!(settings, repo, limit_tags);
global_to_repo!(settings, repo, limit_commit_ids_to_related);
global_to_repo!(settings, repo, limit_tree_depth);
global_to_repo!(settings, repo, limit_file_size);
global_to_repo!(settings, repo, limit_repo_size);
@@ -537,6 +540,7 @@ impl GitsySettings {
limit_commits: settings.limit_commits.clone(),
limit_branches: settings.limit_branches.clone(),
limit_tags: settings.limit_tags.clone(),
limit_commit_ids_to_related: settings.limit_commit_ids_to_related.clone(),
limit_tree_depth: settings.limit_tree_depth.clone(),
limit_file_size: settings.limit_file_size.clone(),
limit_repo_size: settings.limit_repo_size.clone(),
@@ -579,6 +583,7 @@ impl GitsySettings {
limit_commits: settings.limit_commits.clone(),
limit_branches: settings.limit_branches.clone(),
limit_tags: settings.limit_tags.clone(),
limit_commit_ids_to_related: settings.limit_commit_ids_to_related.clone(),
limit_tree_depth: settings.limit_tree_depth.clone(),
limit_file_size: settings.limit_file_size.clone(),
limit_repo_size: settings.limit_repo_size.clone(),