@@ -255,7 +255,7 @@ impl Snapshot {
fn reparent_entry(
&mut self,
child_inode: u64,
- new_filename: Option<&OsStr>,
+ new_path: Option<&Path>,
old_parent_inode: Option<u64>,
new_parent_inode: Option<u64>,
) {
@@ -282,11 +282,11 @@ impl Snapshot {
let mut old_parent_entry = None;
let mut new_parent_entry = None;
for removed_entry in removed_entries {
- if removed_entry.ino() == child_inode {
+ if removed_entry.inode() == child_inode {
child_entry = Some(removed_entry);
- } else if Some(removed_entry.ino()) == old_parent_inode {
+ } else if Some(removed_entry.inode()) == old_parent_inode {
old_parent_entry = Some(removed_entry);
- } else if Some(removed_entry.ino()) == new_parent_inode {
+ } else if Some(removed_entry.inode()) == new_parent_inode {
new_parent_entry = Some(removed_entry);
}
}
@@ -294,12 +294,47 @@ impl Snapshot {
// Update the child entry's parent.
let mut child_entry = child_entry.expect("cannot reparent non-existent entry");
child_entry.set_parent(new_parent_inode);
- if let Some(new_filename) = new_filename {
- child_entry.set_name(new_filename);
+ if let Some(new_path) = new_path {
+ let new_path = new_path.strip_prefix(self.path.parent().unwrap()).unwrap();
+ child_entry.set_name(new_path.file_name().unwrap());
+
+ // Recompute the PathEntry for each file under this subtree.
+ let mut stack = Vec::new();
+ stack.push((child_entry, new_path.parent().unwrap().to_path_buf()));
+ while let Some((mut entry, mut new_path)) = stack.pop() {
+ new_path.push(entry.name());
+ match &mut entry {
+ Entry::Dir {
+ children, inode, ..
+ } => {
+ for child_inode in children.as_ref() {
+ let child_entry = self.entries.get(child_inode).unwrap();
+ stack.push((child_entry.clone(), new_path.clone()));
+ }
+
+ // Descendant directories don't need to be mutated because their properties
+ // haven't changed, so only re-insert this directory if it is the entry we
+ // were reparenting.
+ if *inode == child_inode {
+ insertions.push(Edit::Insert(entry));
+ }
+ }
+ Entry::File {
+ inode,
+ is_ignored,
+ path,
+ ..
+ } => {
+ *path = PathEntry::new(*inode, &new_path, *is_ignored);
+ insertions.push(Edit::Insert(entry));
+ }
+ }
+ }
+ } else {
+ insertions.push(Edit::Insert(child_entry));
}
- insertions.push(Edit::Insert(child_entry));
- // Remove the child entry from it's old parent's children.
+ // Remove the child entry from its old parent's children.
if let Some(mut old_parent_entry) = old_parent_entry {
if let Entry::Dir { children, .. } = &mut old_parent_entry {
*children = children
@@ -313,7 +348,7 @@ impl Snapshot {
}
}
- // Add the child entry to it's new parent's children.
+ // Add the child entry to its new parent's children.
if let Some(mut new_parent_entry) = new_parent_entry {
if let Entry::Dir { children, .. } = &mut new_parent_entry {
*children = children
@@ -410,7 +445,7 @@ pub enum Entry {
}
impl Entry {
- fn ino(&self) -> u64 {
+ fn inode(&self) -> u64 {
match self {
Entry::Dir { inode, .. } => *inode,
Entry::File { inode, .. } => *inode,
@@ -455,7 +490,7 @@ impl sum_tree::Item for Entry {
fn summary(&self) -> Self::Summary {
EntrySummary {
- max_ino: self.ino(),
+ max_ino: self.inode(),
file_count: if matches!(self, Self::File { .. }) {
1
} else {
@@ -469,7 +504,7 @@ impl sum_tree::KeyedItem for Entry {
type Key = u64;
fn key(&self) -> Self::Key {
- self.ino()
+ self.inode()
}
}
@@ -753,13 +788,13 @@ impl BackgroundScanner {
// If this path currently exists on the filesystem, then ensure that the snapshot's
// entry for this path is up-to-date.
Ok(Some((fs_entry, ignore))) => {
- let fs_inode = fs_entry.ino();
+ let fs_inode = fs_entry.inode();
let fs_parent_inode = fs_entry.parent();
// If the snapshot already contains an entry for this path, then ensure that the
// entry has the correct inode and parent.
if let Some(snapshot_entry) = snapshot_entry {
- let snapshot_inode = snapshot_entry.ino();
+ let snapshot_inode = snapshot_entry.inode();
let snapshot_parent_inode = snapshot_entry.parent();
// If the snapshot entry already matches the filesystem, then skip to the
@@ -781,7 +816,7 @@ impl BackgroundScanner {
let snapshot_parent_inode = snapshot_entry_for_inode.parent();
snapshot.reparent_entry(
fs_inode,
- path.file_name(),
+ Some(&path),
snapshot_parent_inode,
fs_parent_inode,
);
@@ -825,7 +860,7 @@ impl BackgroundScanner {
// If this path no longer exists on the filesystem, then remove it from the snapshot.
Ok(None) => {
if let Some(snapshot_entry) = snapshot_entry {
- let snapshot_inode = snapshot_entry.ino();
+ let snapshot_inode = snapshot_entry.inode();
let snapshot_parent_inode = snapshot_entry.parent();
snapshot.reparent_entry(snapshot_inode, None, snapshot_parent_inode, None);
possible_removed_inodes.insert(snapshot_inode);
@@ -1167,6 +1202,9 @@ mod tests {
let operations = env::var("OPERATIONS")
.map(|o| o.parse().unwrap())
.unwrap_or(40);
+ let initial_entries = env::var("INITIAL_ENTRIES")
+ .map(|o| o.parse().unwrap())
+ .unwrap_or(20);
let seeds = if let Ok(seed) = env::var("SEED").map(|s| s.parse().unwrap()) {
seed..seed + 1
} else {
@@ -1178,7 +1216,7 @@ mod tests {
let mut rng = StdRng::seed_from_u64(seed);
let root_dir = tempdir::TempDir::new(&format!("test-{}", seed)).unwrap();
- for _ in 0..20 {
+ for _ in 0..initial_entries {
randomly_mutate_tree(root_dir.path(), 1.0, &mut rng).unwrap();
}
log::info!("Generated initial tree");
@@ -1201,12 +1239,14 @@ mod tests {
if !events.is_empty() && rng.gen_bool(0.4) {
let len = rng.gen_range(0..=events.len());
let to_deliver = events.drain(0..len).collect::<Vec<_>>();
+ log::info!("Delivering events: {:#?}", to_deliver);
scanner.process_events(to_deliver);
} else {
events.extend(randomly_mutate_tree(root_dir.path(), 0.6, &mut rng).unwrap());
mutations_len -= 1;
}
}
+ log::info!("Quiescing: {:#?}", events);
scanner.process_events(events);
let (notify_tx, _notify_rx) = smol::channel::unbounded();