file_manager: bundle inotify delete events

When a directory is deleted this attempts to suppress delete events for all children.  Clients only need to be notified of the parent node, as its deletion implies all children have been deleted.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Arksine 2021-03-21 18:24:01 -04:00 committed by Eric Callahan
parent db0eb8f22b
commit bb00825cd2
1 changed files with 28 additions and 24 deletions

View File

@ -614,15 +614,16 @@ class INotifyHandler:
self.watches[new_path] = wd
self.watched_dirs[wd] = (new_root, new_path)
def _process_deleted_files(self, dir_path):
def _process_deleted_items(self, dir_path):
if dir_path not in self.pending_delete_events:
return
root, files, hdl = self.pending_delete_events.pop(dir_path)
for fname in files:
file_path = os.path.join(dir_path, fname)
self._clear_metadata(root, file_path)
root, items, hdl = self.pending_delete_events.pop(dir_path)
for (item_name, isdir) in items:
item_path = os.path.join(dir_path, item_name)
item_type = "dir" if isdir else "file"
self._clear_metadata(root, item_path, isdir)
self._notify_filelist_changed(
"delete_file", root, file_path)
f"delete_{item_type}", root, item_path)
def _remove_stale_cookie(self, cookie):
pending_evt = self.pending_move_events.pop(cookie, None)
@ -729,6 +730,24 @@ class INotifyHandler:
else:
self._process_file_event(evt, root, child_path)
def _schedule_delete_event(self, root, item_path, is_dir):
if is_dir:
self.remove_watch(item_path, need_low_level_rm=False)
# Remove pending delete events for children if they exist
pending_evt = self.pending_delete_events.pop(item_path, None)
if pending_evt is not None:
delete_hdl = pending_evt[2]
self.ioloop.remove_timeout(delete_hdl)
parent_path, item_name = os.path.split(item_path)
items = set()
if parent_path in self.pending_delete_events:
root, items, delete_hdl = self.pending_delete_events[parent_path]
self.ioloop.remove_timeout(delete_hdl)
items.add((item_name, is_dir))
delete_hdl = self.ioloop.call_later(
INOTIFY_DELETE_TIME, self._process_deleted_items, parent_path)
self.pending_delete_events[parent_path] = (root, items, delete_hdl)
def _process_dir_event(self, evt, root, child_path):
if evt.name and evt.name[0] == ".":
# ignore changes to the hidden directories
@ -740,14 +759,7 @@ class INotifyHandler:
"create_dir", root, child_path)
elif evt.mask & iFlags.DELETE:
logging.debug(f"Inotify directory delete: {root}, {evt.name}")
self.remove_watch(child_path, need_low_level_rm=False)
pending_evt = self.pending_delete_events.pop(child_path, None)
if pending_evt is not None:
delete_hdl = pending_evt[2]
self.ioloop.remove_timeout(delete_hdl)
self._clear_metadata(root, child_path, True)
self._notify_filelist_changed(
"delete_dir", root, child_path)
self._schedule_delete_event(root, child_path, True)
elif evt.mask & iFlags.MOVED_FROM:
logging.debug(f"Inotify directory move from: {root}, {evt.name}")
hdl = self.ioloop.call_later(
@ -791,19 +803,11 @@ class INotifyHandler:
if root == "gcodes" and ext == ".ufp":
# Don't notify deleted ufp files
return
dir_path, fname = os.path.split(child_path)
files = set()
if dir_path in self.pending_delete_events:
root, files, delete_hdl = self.pending_delete_events[dir_path]
self.ioloop.remove_timeout(delete_hdl)
files.add(fname)
delete_hdl = self.ioloop.call_later(
INOTIFY_MOVE_TIME, self._process_deleted_files, dir_path)
self.pending_delete_events[dir_path] = (root, files, delete_hdl)
self._schedule_delete_event(root, child_path, False)
elif evt.mask & iFlags.MOVED_FROM:
logging.debug(f"Inotify file move from: {root}, {evt.name}")
hdl = self.ioloop.call_later(
INOTIFY_DELETE_TIME, self._remove_stale_cookie, evt.cookie)
INOTIFY_MOVE_TIME, self._remove_stale_cookie, evt.cookie)
self.pending_move_events[evt.cookie] = (
root, child_path, hdl, False)
self._clear_metadata(root, child_path)