Detect cycles when scanning a directory
This commit is contained in:
parent
df33556693
commit
b48118830f
1 changed files with 44 additions and 17 deletions
|
@ -47,7 +47,7 @@ use std::{
|
||||||
task::Poll,
|
task::Poll,
|
||||||
time::{Duration, SystemTime},
|
time::{Duration, SystemTime},
|
||||||
};
|
};
|
||||||
use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap};
|
use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap, TreeSet};
|
||||||
use util::{ResultExt, TryFutureExt};
|
use util::{ResultExt, TryFutureExt};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -1491,6 +1491,16 @@ impl LocalSnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ancestor_inodes_for_path(&self, path: &Path) -> TreeSet<u64> {
|
||||||
|
let mut inodes = TreeSet::default();
|
||||||
|
for ancestor in path.ancestors().skip(1) {
|
||||||
|
if let Some(entry) = self.entry_for_path(ancestor) {
|
||||||
|
inodes.insert(entry.inode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inodes
|
||||||
|
}
|
||||||
|
|
||||||
fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool) -> Arc<IgnoreStack> {
|
fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool) -> Arc<IgnoreStack> {
|
||||||
let mut new_ignores = Vec::new();
|
let mut new_ignores = Vec::new();
|
||||||
for ancestor in abs_path.ancestors().skip(1) {
|
for ancestor in abs_path.ancestors().skip(1) {
|
||||||
|
@ -2053,14 +2063,16 @@ impl BackgroundScanner {
|
||||||
async fn scan_dirs(&mut self) -> Result<()> {
|
async fn scan_dirs(&mut self) -> Result<()> {
|
||||||
let root_char_bag;
|
let root_char_bag;
|
||||||
let root_abs_path;
|
let root_abs_path;
|
||||||
let next_entry_id;
|
let root_inode;
|
||||||
let is_dir;
|
let is_dir;
|
||||||
|
let next_entry_id;
|
||||||
{
|
{
|
||||||
let snapshot = self.snapshot.lock();
|
let snapshot = self.snapshot.lock();
|
||||||
root_char_bag = snapshot.root_char_bag;
|
root_char_bag = snapshot.root_char_bag;
|
||||||
root_abs_path = snapshot.abs_path.clone();
|
root_abs_path = snapshot.abs_path.clone();
|
||||||
|
root_inode = snapshot.root_entry().map(|e| e.inode);
|
||||||
|
is_dir = snapshot.root_entry().map_or(false, |e| e.is_dir());
|
||||||
next_entry_id = snapshot.next_entry_id.clone();
|
next_entry_id = snapshot.next_entry_id.clone();
|
||||||
is_dir = snapshot.root_entry().map_or(false, |e| e.is_dir())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Populate ignores above the root.
|
// Populate ignores above the root.
|
||||||
|
@ -2088,12 +2100,18 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
if is_dir {
|
if is_dir {
|
||||||
let path: Arc<Path> = Arc::from(Path::new(""));
|
let path: Arc<Path> = Arc::from(Path::new(""));
|
||||||
|
let mut ancestor_inodes = TreeSet::default();
|
||||||
|
if let Some(root_inode) = root_inode {
|
||||||
|
ancestor_inodes.insert(root_inode);
|
||||||
|
}
|
||||||
|
|
||||||
let (tx, rx) = channel::unbounded();
|
let (tx, rx) = channel::unbounded();
|
||||||
self.executor
|
self.executor
|
||||||
.block(tx.send(ScanJob {
|
.block(tx.send(ScanJob {
|
||||||
abs_path: root_abs_path.to_path_buf(),
|
abs_path: root_abs_path.to_path_buf(),
|
||||||
path,
|
path,
|
||||||
ignore_stack,
|
ignore_stack,
|
||||||
|
ancestor_inodes,
|
||||||
scan_queue: tx.clone(),
|
scan_queue: tx.clone(),
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -2195,24 +2213,30 @@ impl BackgroundScanner {
|
||||||
root_char_bag,
|
root_char_bag,
|
||||||
);
|
);
|
||||||
|
|
||||||
if child_metadata.is_dir {
|
if child_entry.is_dir() {
|
||||||
let is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, true);
|
let is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, true);
|
||||||
child_entry.is_ignored = is_ignored;
|
child_entry.is_ignored = is_ignored;
|
||||||
new_entries.push(child_entry);
|
|
||||||
new_jobs.push(ScanJob {
|
if !job.ancestor_inodes.contains(&child_entry.inode) {
|
||||||
abs_path: child_abs_path,
|
let mut ancestor_inodes = job.ancestor_inodes.clone();
|
||||||
path: child_path,
|
ancestor_inodes.insert(child_entry.inode);
|
||||||
ignore_stack: if is_ignored {
|
new_jobs.push(ScanJob {
|
||||||
IgnoreStack::all()
|
abs_path: child_abs_path,
|
||||||
} else {
|
path: child_path,
|
||||||
ignore_stack.clone()
|
ignore_stack: if is_ignored {
|
||||||
},
|
IgnoreStack::all()
|
||||||
scan_queue: job.scan_queue.clone(),
|
} else {
|
||||||
});
|
ignore_stack.clone()
|
||||||
|
},
|
||||||
|
ancestor_inodes,
|
||||||
|
scan_queue: job.scan_queue.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false);
|
child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false);
|
||||||
new_entries.push(child_entry);
|
}
|
||||||
};
|
|
||||||
|
new_entries.push(child_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.snapshot
|
self.snapshot
|
||||||
|
@ -2292,11 +2316,13 @@ impl BackgroundScanner {
|
||||||
fs_entry.is_ignored = ignore_stack.is_all();
|
fs_entry.is_ignored = ignore_stack.is_all();
|
||||||
snapshot.insert_entry(fs_entry, self.fs.as_ref());
|
snapshot.insert_entry(fs_entry, self.fs.as_ref());
|
||||||
if metadata.is_dir {
|
if metadata.is_dir {
|
||||||
|
let ancestor_inodes = snapshot.ancestor_inodes_for_path(&path);
|
||||||
self.executor
|
self.executor
|
||||||
.block(scan_queue_tx.send(ScanJob {
|
.block(scan_queue_tx.send(ScanJob {
|
||||||
abs_path,
|
abs_path,
|
||||||
path,
|
path,
|
||||||
ignore_stack,
|
ignore_stack,
|
||||||
|
ancestor_inodes,
|
||||||
scan_queue: scan_queue_tx.clone(),
|
scan_queue: scan_queue_tx.clone(),
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -2458,6 +2484,7 @@ struct ScanJob {
|
||||||
path: Arc<Path>,
|
path: Arc<Path>,
|
||||||
ignore_stack: Arc<IgnoreStack>,
|
ignore_stack: Arc<IgnoreStack>,
|
||||||
scan_queue: Sender<ScanJob>,
|
scan_queue: Sender<ScanJob>,
|
||||||
|
ancestor_inodes: TreeSet<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UpdateIgnoreStatusJob {
|
struct UpdateIgnoreStatusJob {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue