remove unused methods in FileId map, and revert to what seemed functional.

Previously, roots were always empty and it was unclear what the purpose
of the customization was.

It's probably best to re-add it along with a test maybe.
This commit is contained in:
Sebastian Thiel 2024-05-24 15:57:21 +02:00
parent cdf508e04c
commit e68b789a32
No known key found for this signature in database
GPG Key ID: 9CB5EE7895E8268B
6 changed files with 70 additions and 67 deletions

View File

@ -49,7 +49,7 @@ pub trait FileIdCache {
/// Add a new path to the cache or update its value.
///
/// This will be called if a new file or directory is created or if an existing file is overridden.
fn add_path(&mut self, path: &Path);
fn add_path(&mut self, path: &Path, recursive_mode: RecursiveMode);
/// Remove a path from the cache.
///
@ -59,7 +59,11 @@ pub trait FileIdCache {
/// Re-scan all paths.
///
/// This will be called if the notification back-end has dropped events.
fn rescan(&mut self);
fn rescan(&mut self, roots: &[(PathBuf, RecursiveMode)]) {
for (root, recursive_mode) in roots {
self.add_path(root, *recursive_mode);
}
}
}
/// A cache to hold the file system IDs of all watched files.
@ -69,34 +73,9 @@ pub trait FileIdCache {
#[derive(Debug, Clone, Default)]
pub struct FileIdMap {
paths: HashMap<PathBuf, FileId>,
roots: Vec<(PathBuf, RecursiveMode)>,
}
impl FileIdMap {
/// Add a path to the cache.
///
/// If `recursive_mode` is `Recursive`, all children will be added to the cache as well
/// and all paths will be kept up-to-date in case of changes like new files being added,
/// files being removed or renamed.
#[allow(dead_code)]
pub fn add_root(&mut self, path: impl Into<PathBuf>, recursive_mode: RecursiveMode) {
let path = path.into();
self.roots.push((path.clone(), recursive_mode));
self.add_path(&path);
}
/// Remove a path form the cache.
///
/// If the path was added with `Recursive` mode, all children will also be removed from the cache.
#[allow(dead_code)]
pub fn remove_root(&mut self, path: impl AsRef<Path>) {
self.roots.retain(|(root, _)| !root.starts_with(&path));
self.remove_path(path.as_ref());
}
fn dir_scan_depth(is_recursive: bool) -> usize {
if is_recursive {
usize::max_value()
@ -111,18 +90,8 @@ impl FileIdCache for FileIdMap {
self.paths.get(path)
}
fn add_path(&mut self, path: &Path) {
let is_recursive = self
.roots
.iter()
.find_map(|(root, recursive_mode)| {
if path.starts_with(root) {
Some(*recursive_mode == RecursiveMode::Recursive)
} else {
None
}
})
.unwrap_or_default();
fn add_path(&mut self, path: &Path, recursive_mode: RecursiveMode) {
let is_recursive = recursive_mode == RecursiveMode::Recursive;
for (path, file_id) in WalkDir::new(path)
.follow_links(true)
@ -141,10 +110,4 @@ impl FileIdCache for FileIdMap {
fn remove_path(&mut self, path: &Path) {
self.paths.retain(|p, _| !p.starts_with(path));
}
fn rescan(&mut self) {
for (root, _) in self.roots.clone() {
self.add_path(&root);
}
}
}

View File

@ -27,6 +27,7 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use std::path::Path;
use std::{
collections::{HashMap, VecDeque},
path::PathBuf,
@ -46,7 +47,7 @@ use std::time::Instant;
use file_id::FileId;
use notify::{
event::{ModifyKind, RemoveKind, RenameMode},
Error, ErrorKind, Event, EventKind, RecommendedWatcher, Watcher,
Error, ErrorKind, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher,
};
use parking_lot::Mutex;
@ -123,6 +124,7 @@ impl Queue {
#[derive(Debug)]
pub(crate) struct DebounceDataInner<T> {
queues: HashMap<PathBuf, Queue>,
roots: Vec<(PathBuf, RecursiveMode)>,
cache: T,
rename_event: Option<(DebouncedEvent, Option<FileId>)>,
rescan_event: Option<DebouncedEvent>,
@ -134,6 +136,7 @@ impl<T: FileIdCache> DebounceDataInner<T> {
pub(crate) fn new(cache: T, timeout: Duration) -> Self {
Self {
queues: HashMap::new(),
roots: Vec::new(),
cache,
rename_event: None,
rescan_event: None,
@ -227,7 +230,7 @@ impl<T: FileIdCache> DebounceDataInner<T> {
tracing::trace!("Received event: {:?}", event);
if event.need_rescan() {
self.cache.rescan();
self.cache.rescan(&self.roots);
self.rescan_event = Some(event.into());
return;
}
@ -236,8 +239,7 @@ impl<T: FileIdCache> DebounceDataInner<T> {
match &event.kind {
EventKind::Create(_) => {
self.cache.add_path(path);
self.cache.add_path(path, self.recursive_mode(path));
self.push_event(event, Instant::now());
}
EventKind::Modify(ModifyKind::Name(rename_mode)) => {
@ -271,7 +273,7 @@ impl<T: FileIdCache> DebounceDataInner<T> {
}
_ => {
if self.cache.cached_file_id(path).is_none() {
self.cache.add_path(path);
self.cache.add_path(path, self.recursive_mode(path));
}
self.push_event(event, Instant::now());
@ -279,6 +281,19 @@ impl<T: FileIdCache> DebounceDataInner<T> {
}
}
fn recursive_mode(&self, path: &Path) -> RecursiveMode {
self.roots
.iter()
.find_map(|(root, recursive_mode)| {
if path.starts_with(root) {
Some(*recursive_mode)
} else {
None
}
})
.unwrap_or(RecursiveMode::NonRecursive)
}
fn handle_rename_from(&mut self, event: Event) {
let time = Instant::now();
let path = &event.paths[0];
@ -293,7 +308,8 @@ impl<T: FileIdCache> DebounceDataInner<T> {
}
fn handle_rename_to(&mut self, event: Event) {
self.cache.add_path(&event.paths[0]);
let path = &event.paths[0];
self.cache.add_path(path, self.recursive_mode(path));
let trackers_match = self
.rename_event
@ -313,7 +329,7 @@ impl<T: FileIdCache> DebounceDataInner<T> {
.and_then(|(_, id)| id.as_ref())
.and_then(|from_file_id| {
self.cache
.cached_file_id(&event.paths[0])
.cached_file_id(path)
.map(|to_file_id| from_file_id == to_file_id)
})
.unwrap_or_default();
@ -488,15 +504,36 @@ impl<T: Watcher, C: FileIdCache> Debouncer<T, C> {
self.stop.store(true, Ordering::Relaxed);
}
fn add_root(&mut self, path: impl Into<PathBuf>, recursive_mode: RecursiveMode) {
let path = path.into();
let mut data = self.data.lock();
// skip, if the root has already been added
if data.roots.iter().any(|(p, _)| p == &path) {
return;
}
data.roots.push((path.clone(), recursive_mode));
data.cache.add_path(&path, recursive_mode);
}
// Note that code for unwatching/remove_root is available in the history.
pub fn watch(
&mut self,
path: impl AsRef<Path>,
recursive_mode: RecursiveMode,
) -> notify::Result<()> {
self.watcher.watch(path.as_ref(), recursive_mode)?;
self.add_root(path.as_ref(), recursive_mode);
Ok(())
}
/// Indicates that on the next tick of the debouncer thread, all events should be emitted.
pub fn flush_nonblocking(&self) {
self.flush.store(true, Ordering::Relaxed);
}
/// Access to the internally used notify Watcher backend
pub fn watcher(&mut self) -> &mut T {
&mut self.watcher
}
}
impl<T: Watcher, C: FileIdCache> Drop for Debouncer<T, C> {

View File

@ -34,8 +34,10 @@ use mock_instant::Instant;
pub(crate) use schema::TestCase;
use mock_instant::MockClock;
use notify::RecursiveMode;
use pretty_assertions::assert_eq;
use rstest::rstest;
use std::path::PathBuf;
#[rstest]
fn state(
@ -87,8 +89,7 @@ fn state(
let time = Instant::now();
let mut state = test_case.state.into_debounce_data_inner(time);
// TODO: bring that back
// state.roots = vec![(PathBuf::from("/"), RecursiveMode::Recursive)];
state.roots = vec![(PathBuf::from("/"), RecursiveMode::Recursive)];
for event in test_case.events {
let event = event.into_debounced_event(time, None);
@ -171,6 +172,7 @@ mod utils {
use crate::debouncer::FileIdCache;
use file_id::FileId;
use notify::RecursiveMode;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
@ -191,9 +193,11 @@ mod utils {
self.paths.get(path)
}
fn add_path(&mut self, path: &Path) {
fn add_path(&mut self, path: &Path, recursive_mode: RecursiveMode) {
for (file_path, file_id) in &self.file_system {
if file_path == path || file_path.starts_with(path) {
if file_path == path
|| (file_path.starts_with(path) && recursive_mode == RecursiveMode::Recursive)
{
self.paths.insert(file_path.clone(), *file_id);
}
}
@ -202,7 +206,5 @@ mod utils {
fn remove_path(&mut self, path: &Path) {
self.paths.remove(path);
}
fn rescan(&mut self) {}
}
}

View File

@ -286,6 +286,7 @@ impl State {
DebounceDataInner {
queues,
roots: Vec::new(),
cache,
rename_event,
rescan_event,

View File

@ -8,7 +8,7 @@ use crate::{debouncer::new_debouncer, events::InternalEvent};
use anyhow::{anyhow, Context, Result};
use gitbutler_core::ops::OPLOG_FILE_NAME;
use gitbutler_core::projects::ProjectId;
use notify::{RecommendedWatcher, Watcher};
use notify::RecommendedWatcher;
use tokio::task;
use tracing::Level;
@ -88,12 +88,11 @@ pub fn spawn(
// Start the watcher, but retry if there are transient errors.
backoff::retry(policy, || {
let watcher = debouncer.watcher();
watcher
debouncer
.watch(worktree_path, notify::RecursiveMode::Recursive)
.and_then(|()| {
if let Some(git_dir) = extra_git_dir_to_watch {
watcher.watch(git_dir, notify::RecursiveMode::Recursive)
debouncer.watch(git_dir, notify::RecursiveMode::Recursive)
} else {
Ok(())
}

View File

@ -42,6 +42,7 @@
cache: {
/watch/file-a: 1
/watch/file-b: 2
/watch/file-c: 3
}
events: {
short: []