[tracker-miners/wip/carlosg/fix-monitor-race-condition: 2/2] libtracker-miner: Handle race condition in renaming directories
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker-miners/wip/carlosg/fix-monitor-race-condition: 2/2] libtracker-miner: Handle race condition in renaming directories
- Date: Sat, 1 Aug 2020 12:20:37 +0000 (UTC)
commit ea61ffba04f186bfdc554a98eccdae05c0c18238
Author: Carlos Garnacho <carlosg gnome org>
Date: Sat Aug 1 14:11:19 2020 +0200
libtracker-miner: Handle race condition in renaming directories
When a recursively indexed directory is renamed, we have 2 ongoing
events: G_FILE_MONITOR_EVENT_DELETED from the GFileMonitor set in the
directory itself, and G_FILE_MONITOR_EVENT_RENAMED from the parent
directory GFileMonitor.
When a directory is renamed, we have to throw away the monitors in the
old location, and add them back in the new location. This sometimes
happens right in time to ignore the DELETED event, and sometimes it
doesn't.
Add a short-lived caching of DELETED events, so we can handle those
situations correctly. If the DELETED event corresponded to this situation
the event would be silenced away, otherwise it would be emitted in an
idle callback.
Fixes: https://gitlab.gnome.org/GNOME/tracker-miners/-/issues/92
src/libtracker-miner/tracker-monitor.c | 50 +++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
---
diff --git a/src/libtracker-miner/tracker-monitor.c b/src/libtracker-miner/tracker-monitor.c
index 2aa495c6f..65e722384 100644
--- a/src/libtracker-miner/tracker-monitor.c
+++ b/src/libtracker-miner/tracker-monitor.c
@@ -70,6 +70,7 @@ typedef struct {
GFile *file;
gboolean is_directory;
GFileMonitorEvent event_type;
+ guint source_id;
} CachedEvent;
enum {
@@ -195,6 +196,9 @@ tracker_monitor_class_init (TrackerMonitorClass *klass)
static void
cached_event_free (CachedEvent *event)
{
+ if (event->source_id != 0)
+ g_source_remove (event->source_id);
+
g_object_unref (event->file);
g_free (event);
}
@@ -664,6 +668,34 @@ cache_event (TrackerMonitor *monitor,
}
}
+static gboolean
+flush_event_idle_cb (gpointer user_data)
+{
+ CachedEvent *event = user_data;
+ TrackerMonitorPrivate *priv = tracker_monitor_get_instance_private (event->monitor);
+
+ event->source_id = 0;
+ emit_signal_for_event (event->monitor, event->event_type,
+ event->is_directory, event->file, NULL);
+ g_hash_table_remove (priv->cached_events, event->file);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+flush_event_later (TrackerMonitor *monitor,
+ GFile *file)
+{
+ TrackerMonitorPrivate *priv = tracker_monitor_get_instance_private (monitor);
+ CachedEvent *event;
+
+ event = g_hash_table_lookup (priv->cached_events, file);
+ if (!event)
+ return;
+
+ event->source_id = g_idle_add (flush_event_idle_cb, event);
+}
+
static void
monitor_event_cb (GFileMonitor *file_monitor,
GFile *file,
@@ -715,6 +747,20 @@ monitor_event_cb (GFileMonitor *file_monitor,
monitor_event_to_string (event_type),
file_uri,
other_file_uri));
+
+ if (is_directory &&
+ (event_type == G_FILE_MONITOR_EVENT_RENAMED ||
+ event_type == G_FILE_MONITOR_EVENT_MOVED_OUT) &&
+ prev_event &&
+ prev_event->event_type == G_FILE_MONITOR_EVENT_DELETED) {
+ /* If a directory is moved, there is also an EVENT_DELETED
+ * coming from the GFileMonitor on the folder itself (as the
+ * folder being monitored no longer exists). We may receive
+ * this event before this one, we should ensure it's cleared
+ * out.
+ */
+ g_hash_table_remove (priv->cached_events, file);
+ }
}
switch (event_type) {
@@ -738,7 +784,9 @@ monitor_event_cb (GFileMonitor *file_monitor,
/* In any case, cached events are stale */
g_hash_table_remove (priv->cached_events, file);
- /* Fall through */
+ cache_event (monitor, file, event_type, is_directory);
+ flush_event_later (monitor, file);
+ break;
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
emit_signal_for_event (monitor, event_type,
is_directory, file, NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]