Skip to content

Commit

Permalink
Integrate cache to blame with existing algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
holodorum authored and Byron committed Feb 22, 2025
1 parent 2a63083 commit 68abfa1
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 8 deletions.
1 change: 1 addition & 0 deletions gitoxide-core/src/repository/blame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub fn blame_file(
suspect,
cache,
&mut resource_cache,
None,
file.as_bstr(),
range,
)?;
Expand Down
55 changes: 48 additions & 7 deletions gix-blame/src/file/function.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use super::{process_changes, Change, UnblamedHunk};
use super::{process_changes, update_blame_with_changes, Change, UnblamedHunk};
use crate::types::BlameCacheObject;
use crate::{BlameEntry, Error, Outcome, Statistics};
use gix_diff::blob::intern::TokenSource;
use gix_diff::tree::Visit;
use gix_hash::ObjectId;
use gix_object::{
bstr::{BStr, BString},
bstr::{BStr, BString, ByteSlice},
FindExt,
};
use gix_traverse::commit::find as find_commit;
Expand Down Expand Up @@ -66,6 +67,7 @@ pub fn file(
suspect: ObjectId,
cache: Option<gix_commitgraph::Graph>,
resource_cache: &mut gix_diff::blob::Platform,
blame_cache: Option<BlameCacheObject>,
file_path: &BStr,
range: Option<Range<u32>>,
) -> Result<Outcome, Error> {
Expand All @@ -87,17 +89,56 @@ pub fn file(
}

let range_in_blamed_file = one_based_inclusive_to_zero_based_exclusive_range(range, num_lines_in_blamed)?;
let mut hunks_to_blame = vec![UnblamedHunk {
range_in_blamed_file: range_in_blamed_file.clone(),
suspects: [(suspect, range_in_blamed_file)].into(),
}];

let (blame_entries, mut hunks_to_blame) = match blame_cache {
Some(blame_cache) => {
// If there is a cache, we first get the diff between the current commit and the commit
// we passed as the cache.
let old_file_id = file_id(&blame_cache.cache_id, &mut buf, &mut buf2)?;
let changes = blob_changes(
&odb,
resource_cache,
blamed_file_entry_id,
old_file_id,
file_path.as_bstr(),
&mut stats,
)?;

// If there are no changes, we can return the cache as is immediately.
if changes.iter().all(|change| matches!(change, Change::Unchanged(_))) {
return Ok(Outcome {
entries: blame_cache.entries.clone(),
blob: blamed_file_blob,
statistics: stats,
});
}
// Otherwise, we update the cache with the new changes.
let (blame_entries, hunks_to_blame) = update_blame_with_changes(blame_cache.entries, changes, suspect);
// If there are no more hunks to blame, we can return the result immediately.
if hunks_to_blame.is_empty() {
return Ok(Outcome {
entries: blame_entries,
blob: blamed_file_blob,
statistics: stats,
});
}
(blame_entries, hunks_to_blame)
}
None => {
let hunks_to_blame = vec![UnblamedHunk {
range_in_blamed_file: range_in_blamed_file.clone(),
suspects: [(suspect, range_in_blamed_file)].into(),
}];
(Vec::new(), hunks_to_blame)
}
};

let (mut buf, mut buf2) = (Vec::new(), Vec::new());
let commit = find_commit(cache.as_ref(), &odb, &suspect, &mut buf)?;
let mut queue: gix_revwalk::PriorityQueue<CommitTime, ObjectId> = gix_revwalk::PriorityQueue::new();
queue.insert(commit_time(commit)?, suspect);

let mut out = Vec::new();
let mut out = blame_entries;
let mut diff_state = gix_diff::tree::State::default();
let mut previous_entry: Option<(ObjectId, ObjectId)> = None;
'outer: while let Some(suspect) = queue.pop_value() {
Expand Down
2 changes: 1 addition & 1 deletion gix-blame/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
mod error;
pub use error::Error;
mod types;
pub use types::{BlameEntry, Outcome, Statistics};
pub use types::{BlameCacheObject, BlameEntry, Outcome, Statistics};

mod file;
pub use file::function::file;
9 changes: 9 additions & 0 deletions gix-blame/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ impl SubAssign<u32> for Offset {
}
}

#[derive(Debug, PartialEq)]
/// A cache of blame entries that can be used to speed up subsequent blames.
pub struct BlameCacheObject {
/// The entries of the cache.
pub entries: Vec<BlameEntry>,
/// The commit that was blamed to produce these entries.
pub cache_id: ObjectId,
}

/// A mapping of a section of the *Blamed File* to the section in a *Source File* that introduced it.
///
/// Both ranges are of the same size, but may use different [starting points](Range::start). Naturally,
Expand Down
3 changes: 3 additions & 0 deletions gix-blame/tests/blame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ macro_rules! mktest {
suspect,
None,
&mut resource_cache,
None,
format!("{}.txt", $case).as_str().into(),
None,
)?
Expand Down Expand Up @@ -257,6 +258,7 @@ fn diff_disparity() {
suspect,
None,
&mut resource_cache,
None,
format!("{case}.txt").as_str().into(),
None,
)
Expand Down Expand Up @@ -285,6 +287,7 @@ fn line_range() {
suspect,
None,
&mut resource_cache,
None,
"simple.txt".into(),
Some(1..2),
)
Expand Down

0 comments on commit 68abfa1

Please sign in to comment.