Skip to content

Track file modification times to ignore metadata-only changes#251

Merged
mehmetozguldev merged 5 commits into
athasdev:masterfrom
ninet33n19:fix/file-reload-issue
Aug 6, 2025
Merged

Track file modification times to ignore metadata-only changes#251
mehmetozguldev merged 5 commits into
athasdev:masterfrom
ninet33n19:fix/file-reload-issue

Conversation

@ninet33n19

Copy link
Copy Markdown
Contributor

Description

This pull request addresses a critical bug in the file watcher that caused it to incorrectly trigger modified events when a file was only read, not changed. Read operations on some operating systems update a file's access time (atime), which the watcher was misinterpreting as a content modification. This led to infinite reload loops in the application.

The solution is to make the watcher track each file's modification time (mtime). An event is now only considered a "modification" if the file's mtime has actually changed, effectively filtering out noise from metadata-only updates.

  • Refactored known_files from Arc<Mutex<HashSet<PathBuf>>> to Arc<Mutex<HashMap<PathBuf, SystemTime>>> to store file modification timestamps.
  • Updated the determine_event_type logic to compare the file's current mtime against the stored timestamp before firing an event.
  • Modified setup_path_watching and setup_directory_watching to record the initial mtime of a file when it is first added to the watcher.
  • Prevents an infinite reload loop that occurred when opening and reading a file triggered a watch event.

Screenshots/Videos

N/A - This change is purely in the backend file-watching logic and has no visual component. The result is the absence of erroneous logging and reloading.

Related Issues

Fixes #197

Switch known_files from HashSet to HashMap<PathBuf, SystemTime> to track
modification times. Only emit file change events when the modification
time changes, ignoring metadata-only updates such as access time
changes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request fixes a critical bug in the file watcher where read operations on files were incorrectly triggering modified events, causing infinite reload loops. The solution involves tracking file modification times (mtime) to distinguish between actual content changes and metadata-only updates.

  • Refactored known_files from a HashSet<PathBuf> to a HashMap<PathBuf, SystemTime> to store file modification timestamps
  • Modified event determination logic to compare current mtime against stored timestamps before emitting events
  • Updated file and directory watching setup to record initial modification times
Comments suppressed due to low confidence (1)

src-tauri/src/file_watcher.rs:143

  • [nitpick] The variable name known_files_map is redundant since the parameter is already called known_files. Consider using a simpler name like known_files or files for the local variable.
      let mut known_files_map = known_files.lock().unwrap();

let _ = app_handle.emit("file-changed", &change_event);
}
}
}

Copilot AI Aug 5, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This closing brace appears to be orphaned and would cause a compilation error. The function structure seems incorrect - there should be a closing brace for the function at line 103, not an additional one here.

Copilot uses AI. Check for mistakes.
Comment thread src-tauri/src/file_watcher.rs Outdated
Comment on lines +149 to +151
let current_mtime = metadata
.modified()
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);

Copilot AI Aug 5, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using UNIX_EPOCH as a fallback for modification time could be misleading. Consider using a more recent timestamp or handling the error case explicitly to avoid confusion about when a file was actually modified.

Suggested change
let current_mtime = metadata
.modified()
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
let current_mtime = match metadata.modified() {
Ok(mtime) => mtime,
Err(_) => return Some(FileChangeType::Modified),
};

Copilot uses AI. Check for mistakes.
Comment thread src-tauri/src/file_watcher.rs Outdated
Comment on lines +196 to +203
let mtime = metadata
.modified()
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
self
.known_files
.lock()
.unwrap()
.insert(path_buf.clone(), mtime);

Copilot AI Aug 5, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using UNIX_EPOCH as a fallback for modification time could be misleading. Consider using a more recent timestamp or handling the error case explicitly to avoid confusion about when a file was actually modified.

Suggested change
let mtime = metadata
.modified()
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
self
.known_files
.lock()
.unwrap()
.insert(path_buf.clone(), mtime);
match metadata.modified() {
Ok(mtime) => {
self
.known_files
.lock()
.unwrap()
.insert(path_buf.clone(), mtime);
}
Err(e) => {
eprintln!("Failed to get modification time for {:?}: {}", path_buf, e);
// Optionally, you could return an error here instead of just logging.
}
}

Copilot uses AI. Check for mistakes.
Comment thread src-tauri/src/file_watcher.rs Outdated
Comment on lines +227 to +230
let mtime = metadata
.modified()
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
known_files.insert(path, mtime);

Copilot AI Aug 5, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using UNIX_EPOCH as a fallback for modification time could be misleading. Consider using a more recent timestamp or handling the error case explicitly to avoid confusion about when a file was actually modified.

Suggested change
let mtime = metadata
.modified()
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
known_files.insert(path, mtime);
if let Ok(mtime) = metadata.modified() {
known_files.insert(path, mtime);
} else {
// Optionally log: could not get modification time for path
}

Copilot uses AI. Check for mistakes.
ninet33n19 and others added 4 commits August 5, 2025 21:01
- Replace Created/Modified with Opened/Reloaded event types - Emit
Opened event when a file is watched - Improve handling of file
modification times and error cases - Add logging for metadata access
issues

@mehmetozguldev mehmetozguldev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mehmetozguldev mehmetozguldev merged commit 3246fb2 into athasdev:master Aug 6, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Opening a file causes editor to keep reloading the file

3 participants