Compare commits

...

2 Commits

2 changed files with 60 additions and 12 deletions

View File

@ -110,20 +110,19 @@ impl Delta {
out
}
/// Given a chain of deltas, ordered from last to first, calculate the "contribution" for each
/// state.
/// Given a chain of deltas, calculate the "contribution" for each state.
///
/// The contribution of a delta in a given chain is defined as the parts of the state produced
/// by this chain that are actually provided by this delta. This comes down to calculating the
/// strict difference of this delta and all of its successive deltas.
/// For each delta, its contribution is the part of its added and removed files that isn't
/// overwritten by any of its following deltas.
pub fn contributions<I>(deltas: I) -> Vec<State>
where
I: IntoIterator,
I::IntoIter: DoubleEndedIterator,
I::Item: Borrow<Delta>,
{
let mut contributions: Vec<State> = Vec::new();
let mut deltas = deltas.into_iter();
let mut deltas = deltas.into_iter().rev();
if let Some(first_delta) = deltas.next() {
// From last to first, we calculate the strict difference of the delta with the union of all its
@ -138,8 +137,7 @@ impl Delta {
}
}
// contributions.reverse();
contributions.reverse();
contributions
}
@ -242,4 +240,56 @@ mod tests {
let expected = Delta::default().with_added("dir_1", ["file1", "file2"]);
assert_eq!(expected, b.union(&a));
}
#[test]
fn test_difference() {
let a = Delta::default()
.with_added("dir1", ["file1", "file2"])
.with_removed("dir1", ["file3", "file4"]);
let b = Delta::default()
.with_added("dir1", ["file1"])
.with_removed("dir1", ["file3"]);
let expected = Delta::default()
.with_added("dir1", ["file2"])
.with_removed("dir1", ["file4"]);
assert_eq!(a.difference(&b), expected);
assert_eq!(b.difference(&a), Delta::default());
}
#[test]
fn test_strict_difference() {
let a = Delta::default()
.with_added("dir1", ["file1", "file2"])
.with_removed("dir1", ["file3", "file4"]);
let b = Delta::default()
.with_added("dir1", ["file1", "file4"])
.with_removed("dir1", ["file3"]);
let expected = Delta::default().with_added("dir1", ["file2"]);
assert_eq!(a.strict_difference(&b), expected);
assert_eq!(b.strict_difference(&a), Delta::default());
}
#[test]
fn test_contributions() {
let deltas = [
Delta::default().with_added("dir1", ["file4"]),
Delta::default().with_added("dir1", ["file1", "file2"]),
Delta::default()
.with_added("dir1", ["file1"])
.with_added("dir2", ["file3"]),
Delta::default()
.with_added("dir1", ["file2"])
.with_removed("dir2", ["file3"]),
];
let expected = [
State::default().with_dir("dir1", ["file4"]),
State::default(),
State::default().with_dir("dir1", ["file1"]),
State::default().with_dir("dir1", ["file2"]),
];
assert_eq!(Delta::contributions(deltas), expected);
}
}

View File

@ -229,9 +229,8 @@ where
.map(|_| ()),
// Incremental backups are exported one by one according to their contribution
BackupType::Incremental => {
let contributions = Delta::contributions(
chain.iter().take(index + 1).map(|b| &b.delta).rev(),
);
let contributions =
Delta::contributions(chain.iter().take(index + 1).map(|b| &b.delta));
let tar_gz = OpenOptions::new()
.write(true)
@ -245,7 +244,6 @@ where
// overwritten by their successors anyways.
for (contribution, backup) in contributions
.iter()
.rev()
.zip(chain.iter().take(index + 1))
.filter(|(contribution, _)| !contribution.is_empty())
{