Skip to content

Commit 68abfa1

Browse files
holodorumByron
authored andcommitted
Integrate cache to blame with existing algorithm
1 parent 2a63083 commit 68abfa1

File tree

5 files changed

+62
-8
lines changed

5 files changed

+62
-8
lines changed

gitoxide-core/src/repository/blame.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub fn blame_file(
4343
suspect,
4444
cache,
4545
&mut resource_cache,
46+
None,
4647
file.as_bstr(),
4748
range,
4849
)?;

gix-blame/src/file/function.rs

+48-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use super::{process_changes, Change, UnblamedHunk};
1+
use super::{process_changes, update_blame_with_changes, Change, UnblamedHunk};
2+
use crate::types::BlameCacheObject;
23
use crate::{BlameEntry, Error, Outcome, Statistics};
34
use gix_diff::blob::intern::TokenSource;
45
use gix_diff::tree::Visit;
56
use gix_hash::ObjectId;
67
use gix_object::{
7-
bstr::{BStr, BString},
8+
bstr::{BStr, BString, ByteSlice},
89
FindExt,
910
};
1011
use gix_traverse::commit::find as find_commit;
@@ -66,6 +67,7 @@ pub fn file(
6667
suspect: ObjectId,
6768
cache: Option<gix_commitgraph::Graph>,
6869
resource_cache: &mut gix_diff::blob::Platform,
70+
blame_cache: Option<BlameCacheObject>,
6971
file_path: &BStr,
7072
range: Option<Range<u32>>,
7173
) -> Result<Outcome, Error> {
@@ -87,17 +89,56 @@ pub fn file(
8789
}
8890

8991
let range_in_blamed_file = one_based_inclusive_to_zero_based_exclusive_range(range, num_lines_in_blamed)?;
90-
let mut hunks_to_blame = vec![UnblamedHunk {
91-
range_in_blamed_file: range_in_blamed_file.clone(),
92-
suspects: [(suspect, range_in_blamed_file)].into(),
93-
}];
92+
93+
let (blame_entries, mut hunks_to_blame) = match blame_cache {
94+
Some(blame_cache) => {
95+
// If there is a cache, we first get the diff between the current commit and the commit
96+
// we passed as the cache.
97+
let old_file_id = file_id(&blame_cache.cache_id, &mut buf, &mut buf2)?;
98+
let changes = blob_changes(
99+
&odb,
100+
resource_cache,
101+
blamed_file_entry_id,
102+
old_file_id,
103+
file_path.as_bstr(),
104+
&mut stats,
105+
)?;
106+
107+
// If there are no changes, we can return the cache as is immediately.
108+
if changes.iter().all(|change| matches!(change, Change::Unchanged(_))) {
109+
return Ok(Outcome {
110+
entries: blame_cache.entries.clone(),
111+
blob: blamed_file_blob,
112+
statistics: stats,
113+
});
114+
}
115+
// Otherwise, we update the cache with the new changes.
116+
let (blame_entries, hunks_to_blame) = update_blame_with_changes(blame_cache.entries, changes, suspect);
117+
// If there are no more hunks to blame, we can return the result immediately.
118+
if hunks_to_blame.is_empty() {
119+
return Ok(Outcome {
120+
entries: blame_entries,
121+
blob: blamed_file_blob,
122+
statistics: stats,
123+
});
124+
}
125+
(blame_entries, hunks_to_blame)
126+
}
127+
None => {
128+
let hunks_to_blame = vec![UnblamedHunk {
129+
range_in_blamed_file: range_in_blamed_file.clone(),
130+
suspects: [(suspect, range_in_blamed_file)].into(),
131+
}];
132+
(Vec::new(), hunks_to_blame)
133+
}
134+
};
94135

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

100-
let mut out = Vec::new();
141+
let mut out = blame_entries;
101142
let mut diff_state = gix_diff::tree::State::default();
102143
let mut previous_entry: Option<(ObjectId, ObjectId)> = None;
103144
'outer: while let Some(suspect) = queue.pop_value() {

gix-blame/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
mod error;
1818
pub use error::Error;
1919
mod types;
20-
pub use types::{BlameEntry, Outcome, Statistics};
20+
pub use types::{BlameCacheObject, BlameEntry, Outcome, Statistics};
2121

2222
mod file;
2323
pub use file::function::file;

gix-blame/src/types.rs

+9
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ impl SubAssign<u32> for Offset {
117117
}
118118
}
119119

120+
#[derive(Debug, PartialEq)]
121+
/// A cache of blame entries that can be used to speed up subsequent blames.
122+
pub struct BlameCacheObject {
123+
/// The entries of the cache.
124+
pub entries: Vec<BlameEntry>,
125+
/// The commit that was blamed to produce these entries.
126+
pub cache_id: ObjectId,
127+
}
128+
120129
/// A mapping of a section of the *Blamed File* to the section in a *Source File* that introduced it.
121130
///
122131
/// Both ranges are of the same size, but may use different [starting points](Range::start). Naturally,

gix-blame/tests/blame.rs

+3
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ macro_rules! mktest {
190190
suspect,
191191
None,
192192
&mut resource_cache,
193+
None,
193194
format!("{}.txt", $case).as_str().into(),
194195
None,
195196
)?
@@ -257,6 +258,7 @@ fn diff_disparity() {
257258
suspect,
258259
None,
259260
&mut resource_cache,
261+
None,
260262
format!("{case}.txt").as_str().into(),
261263
None,
262264
)
@@ -285,6 +287,7 @@ fn line_range() {
285287
suspect,
286288
None,
287289
&mut resource_cache,
290+
None,
288291
"simple.txt".into(),
289292
Some(1..2),
290293
)

0 commit comments

Comments
 (0)