[tracker/drop-inotify] libtracker-miner: Handle MOVE(A->B)+DELETE(A) = DELETE(A)+MOVE(A->B) = MOVE(A->B)
- From: Aleksander Morgado <aleksm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/drop-inotify] libtracker-miner: Handle MOVE(A->B)+DELETE(A) = DELETE(A)+MOVE(A->B) = MOVE(A->B)
- Date: Mon, 5 Jul 2010 16:14:35 +0000 (UTC)
commit 9c87d35f8eb7f3343740ac3b9690314402d8192f
Author: Aleksander Morgado <aleksander lanedo com>
Date: Mon Jul 5 18:14:05 2010 +0200
libtracker-miner: Handle MOVE(A->B)+DELETE(A) = DELETE(A)+MOVE(A->B) = MOVE(A->B)
src/libtracker-miner/tracker-monitor.c | 379 ++++++++++++++++++++++---------
1 files changed, 269 insertions(+), 110 deletions(-)
---
diff --git a/src/libtracker-miner/tracker-monitor.c b/src/libtracker-miner/tracker-monitor.c
index 0bc245e..411a4c5 100644
--- a/src/libtracker-miner/tracker-monitor.c
+++ b/src/libtracker-miner/tracker-monitor.c
@@ -67,14 +67,18 @@ struct TrackerMonitorPrivate {
guint unpause_timeout_id;
#endif /* PAUSE_ON_IO */
- GHashTable *event_pairs;
+ GHashTable *pre_update;
+ GHashTable *pre_delete;
guint event_pairs_timeout_id;
};
typedef struct {
GFile *file;
+ gchar *file_uri;
+ GFile *other_file;
+ gchar *other_file_uri;
+ gboolean is_directory;
GTimeVal start_time;
- GTimeVal last_time;
guint32 event_type;
} EventData;
@@ -109,7 +113,8 @@ static void directory_monitor_cancel (GFileMonitor *dir_monito
static void event_data_free (gpointer data);
-
+static void emit_signal_for_event (TrackerMonitor *monitor,
+ EventData *event_data);
static guint signals[LAST_SIGNAL] = { 0, };
@@ -224,7 +229,12 @@ tracker_monitor_init (TrackerMonitor *object)
(GDestroyNotify) g_object_unref,
(GDestroyNotify) directory_monitor_cancel);
- priv->event_pairs =
+ priv->pre_update =
+ g_hash_table_new_full (g_file_hash,
+ (GEqualFunc) g_file_equal,
+ (GDestroyNotify) g_object_unref,
+ event_data_free);
+ priv->pre_delete =
g_hash_table_new_full (g_file_hash,
(GEqualFunc) g_file_equal,
(GDestroyNotify) g_object_unref,
@@ -329,7 +339,8 @@ tracker_monitor_finalize (GObject *object)
g_source_remove (priv->event_pairs_timeout_id);
}
- g_hash_table_unref (priv->event_pairs);
+ g_hash_table_unref (priv->pre_update);
+ g_hash_table_unref (priv->pre_delete);
g_hash_table_unref (priv->monitors);
G_OBJECT_CLASS (tracker_monitor_parent_class)->finalize (object);
@@ -460,8 +471,10 @@ check_is_directory (TrackerMonitor *monitor,
}
static EventData *
-event_data_new (GFile *file,
- guint32 event_type)
+event_data_new (GFile *file,
+ GFile *other_file,
+ gboolean is_directory,
+ guint32 event_type)
{
EventData *event;
GTimeVal now;
@@ -470,8 +483,16 @@ event_data_new (GFile *file,
g_get_current_time (&now);
event->file = g_object_ref (file);
+ event->file_uri = g_file_get_uri (file);
+ if (other_file) {
+ event->other_file = g_object_ref (other_file);
+ event->other_file_uri = g_file_get_uri (other_file);
+ } else {
+ event->other_file = NULL;
+ event->other_file_uri = NULL;
+ }
+ event->is_directory = is_directory;
event->start_time = now;
- event->last_time = now;
event->event_type = event_type;
return event;
@@ -485,6 +506,11 @@ event_data_free (gpointer data)
event = data;
g_object_unref (event->file);
+ g_free (event->file_uri);
+ if (event->other_file) {
+ g_object_unref (event->other_file);
+ g_free (event->other_file_uri);
+ }
g_slice_free (EventData, data);
}
@@ -610,60 +636,104 @@ static void
emit_signal_for_event (TrackerMonitor *monitor,
EventData *event_data)
{
- gboolean is_directory;
-
- is_directory = check_is_directory (monitor, event_data->file);
-
- if (event_data->event_type == G_FILE_MONITOR_EVENT_CREATED) {
+ switch (event_data->event_type) {
+ case G_FILE_MONITOR_EVENT_CREATED:
+ g_debug ("Emitting ITEM_CREATED for (%s) '%s'",
+ event_data->is_directory ? "DIRECTORY" : "FILE",
+ event_data->file_uri);
g_signal_emit (monitor,
signals[ITEM_CREATED], 0,
event_data->file,
- is_directory);
- } else {
+ event_data->is_directory);
+ break;
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ g_debug ("Emitting ITEM_UPDATED for (%s) '%s'",
+ event_data->is_directory ? "DIRECTORY" : "FILE",
+ event_data->file_uri);
g_signal_emit (monitor,
signals[ITEM_UPDATED], 0,
event_data->file,
- is_directory);
+ event_data->is_directory);
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ g_debug ("Emitting ITEM_DELETED for (%s) '%s'",
+ event_data->is_directory ? "DIRECTORY" : "FILE",
+ event_data->file_uri);
+ g_signal_emit (monitor,
+ signals[ITEM_DELETED], 0,
+ event_data->file,
+ event_data->is_directory);
+ break;
+ case G_FILE_MONITOR_EVENT_MOVED:
+ g_debug ("Emitting ITEM_MOVED for (%s) '%s->%s'",
+ event_data->is_directory ? "DIRECTORY" : "FILE",
+ event_data->file_uri,
+ event_data->other_file_uri);
+ g_signal_emit (monitor,
+ signals[ITEM_MOVED], 0,
+ event_data->file,
+ event_data->other_file,
+ event_data->is_directory,
+ TRUE);
+ if (event_data->is_directory) {
+ tracker_monitor_move (monitor,
+ event_data->file,
+ event_data->other_file);
+ }
+ break;
+ default:
+ break;
}
}
-static gboolean
-event_pairs_timeout_cb (gpointer user_data)
+static void
+event_pairs_process_in_ht (TrackerMonitor *monitor,
+ GHashTable *ht,
+ GTimeVal *now)
{
- TrackerMonitor *monitor;
GHashTableIter iter;
gpointer key, value;
- GTimeVal now;
-
- monitor = user_data;
- g_hash_table_iter_init (&iter, monitor->private->event_pairs);
- g_get_current_time (&now);
+ g_hash_table_iter_init (&iter, ht);
while (g_hash_table_iter_next (&iter, &key, &value)) {
- GFile *file = key;
EventData *event_data = value;
glong seconds;
- gchar *uri;
- seconds = now.tv_sec - event_data->start_time.tv_sec;
+ seconds = now->tv_sec - event_data->start_time.tv_sec;
if (seconds < 2) {
continue;
}
- uri = g_file_get_uri (file);
-
g_debug ("Event '%s' for URI '%s' has timed out (%ld seconds have elapsed)",
monitor_event_to_string (event_data->event_type),
- uri, seconds);
-
- g_free (uri);
+ event_data->file_uri,
+ seconds);
emit_signal_for_event (monitor, event_data);
g_hash_table_iter_remove (&iter);
}
+}
- if (g_hash_table_size (monitor->private->event_pairs) > 0) {
+static gboolean
+event_pairs_timeout_cb (gpointer user_data)
+{
+ TrackerMonitor *monitor;
+ GTimeVal now;
+
+ monitor = user_data;
+ g_get_current_time (&now);
+
+ /* Process PRE-UPDATE hash table */
+ event_pairs_process_in_ht (monitor, monitor->private->pre_update, &now);
+
+ /* Process PRE-DELETE hash table */
+ event_pairs_process_in_ht (monitor, monitor->private->pre_delete, &now);
+
+ if (g_hash_table_size (monitor->private->pre_update) > 0 ||
+ g_hash_table_size (monitor->private->pre_delete) > 0) {
return TRUE;
}
@@ -680,10 +750,9 @@ monitor_event_cb (GFileMonitor *file_monitor,
gpointer user_data)
{
TrackerMonitor *monitor;
- gchar *str1;
- gchar *str2;
- gboolean is_directory;
- EventData *event_data;
+ gchar *file_uri;
+ gchar *other_file_uri;
+ gboolean is_directory;
monitor = user_data;
@@ -692,19 +761,15 @@ monitor_event_cb (GFileMonitor *file_monitor,
return;
}
- str1 = g_file_get_path (file);
-
- if (other_file) {
- str2 = g_file_get_path (other_file);
- } else {
- str2 = NULL;
- }
+ /* Get URIs as paths may not be in UTF-8 */
+ file_uri = g_file_get_uri (file);
+ other_file_uri = other_file ? g_file_get_uri (other_file) : NULL;
- g_message ("Received monitor event:%d->'%s' for file:'%s' and other file:'%s'",
- event_type,
- monitor_event_to_string (event_type),
- str1,
- str2 ? str2 : "");
+ g_debug ("Received monitor event:%d->'%s' for file:'%s' and other file:'%s'",
+ event_type,
+ monitor_event_to_string (event_type),
+ file_uri,
+ other_file_uri ? other_file_uri : "");
is_directory = check_is_directory (monitor, file);
@@ -724,85 +789,179 @@ monitor_event_cb (GFileMonitor *file_monitor,
monitor);
#endif /* PAUSE_ON_IO */
- switch (event_type) {
- case G_FILE_MONITOR_EVENT_CHANGED:
- if (!monitor->private->use_changed_event) {
- /* Do nothing (using CHANGES_DONE_HINT) */
+ if (!is_directory) {
+ /* FILE Events */
+
+ switch (event_type) {
+ case G_FILE_MONITOR_EVENT_CREATED: {
+ /* - When a G_FILE_MONITOR_EVENT_CREATED(A) is received,
+ * -- Add it to the cache, replacing any previous element
+ * (shouldn't be any)
+ */
+ g_hash_table_replace (monitor->private->pre_update,
+ g_object_ref (file),
+ event_data_new (file, NULL, FALSE, event_type));
break;
}
- /* Fall through */
- case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
- if (!g_hash_table_lookup (monitor->private->event_pairs, file)) {
- g_hash_table_insert (monitor->private->event_pairs,
- g_object_ref (file),
- event_data_new (file, event_type));
+ case G_FILE_MONITOR_EVENT_CHANGED: {
+ /* If use_changed_event, treat as an ATTRIBUTE_CHANGED. Otherwise,
+ * assume there will be a CHANGES_DONE_HINT afterwards... */
+ if (!monitor->private->use_changed_event) {
+ EventData *previous_update_event_data;
+
+ /* Get previous event data, if any */
+ previous_update_event_data = g_hash_table_lookup (monitor->private->pre_update, file);
+
+ /* If there is a previous ATTRIBUTE_CHANGED still not notified,
+ * remove it, as we know there will be a CHANGES_DONE_HINT afterwards
+ */
+ if (previous_update_event_data &&
+ previous_update_event_data->event_type == G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED) {
+ g_hash_table_remove (monitor->private->pre_update, file);
+ }
+
+ break;
+ }
+ } /* Else, Fall through and treat as an ATTRIBUTE_CHANGED */
+
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: {
+ if (!g_hash_table_lookup (monitor->private->pre_update, file)) {
+ g_hash_table_insert (monitor->private->pre_update,
+ g_object_ref (file),
+ event_data_new (file, NULL, FALSE, event_type));
+ }
+
+ break;
}
- break;
- case G_FILE_MONITOR_EVENT_CREATED:
- if (!g_hash_table_lookup (monitor->private->event_pairs, file)) {
- g_hash_table_insert (monitor->private->event_pairs,
- g_object_ref (file),
- event_data_new (file, event_type));
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: {
+ EventData *previous_update_event_data;
+
+ /* Get previous event data, if any */
+ previous_update_event_data = g_hash_table_lookup (monitor->private->pre_update, file);
+
+ if (previous_update_event_data) {
+ emit_signal_for_event (monitor, previous_update_event_data);
+ g_hash_table_remove (monitor->private->pre_update, file);
+ } else {
+ EventData *new_event;
+
+ new_event = event_data_new (file, NULL, FALSE, event_type);
+ emit_signal_for_event (monitor, new_event);
+ event_data_free (new_event);
+ }
+
+ break;
}
- break;
+ case G_FILE_MONITOR_EVENT_DELETED: {
+ EventData *new_event;
- case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
- /* Note: the general case is that this event is the last
- * one after a series of EVENT_CHANGED ones. It may be the
- * case that after this one, an ATTRIBUTE_CHANGED one is
- * issued, as when downloading a file with wget, where
- * mtime of the file is modified. But this last case is
- * quite specific, so we will anyway signal the event
- * right away instead of adding it to the HT.
- */
+ new_event = event_data_new (file, NULL, FALSE, event_type);
+ emit_signal_for_event (monitor, new_event);
+ event_data_free (new_event);
- event_data = g_hash_table_lookup (monitor->private->event_pairs, file);
+ break;
+ }
+ case G_FILE_MONITOR_EVENT_MOVED: {
+ EventData *new_event;
- if (event_data) {
- emit_signal_for_event (monitor, event_data);
- g_hash_table_remove (monitor->private->event_pairs, file);
- } else {
- event_data = event_data_new (file, event_type);
- emit_signal_for_event (monitor, event_data);
- event_data_free (event_data);
+ new_event = event_data_new (file, other_file, FALSE, event_type);
+ emit_signal_for_event (monitor, new_event);
+ event_data_free (new_event);
+
+ break;
+ }
+ case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+ case G_FILE_MONITOR_EVENT_UNMOUNTED:
+ /* Do nothing */
+ break;
}
+ } else {
+ /* DIRECTORY Events */
- break;
- case G_FILE_MONITOR_EVENT_DELETED:
- if (is_directory) {
- tracker_monitor_remove_recursively (monitor, file);
+ switch (event_type) {
+ case G_FILE_MONITOR_EVENT_CREATED: {
+ EventData *new_event;
+
+ new_event = event_data_new (file, NULL, TRUE, event_type);
+ emit_signal_for_event (monitor, new_event);
+ event_data_free (new_event);
+
+ break;
}
- g_signal_emit (monitor,
- signals[ITEM_DELETED], 0,
- file,
- is_directory);
- break;
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGED: {
+ if (!g_hash_table_lookup (monitor->private->pre_update, file)) {
+ g_hash_table_insert (monitor->private->pre_update,
+ g_object_ref (file),
+ event_data_new (file, NULL, TRUE, event_type));
+ }
- case G_FILE_MONITOR_EVENT_MOVED:
- g_signal_emit (monitor,
- signals[ITEM_MOVED], 0,
- file,
- other_file,
- is_directory,
- TRUE);
-
- if (is_directory) {
- tracker_monitor_move (monitor, file, other_file);
+ break;
}
- break;
+ case G_FILE_MONITOR_EVENT_DELETED: {
+ EventData *previous_delete_event_data;
- case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
- case G_FILE_MONITOR_EVENT_UNMOUNTED:
- /* Do nothing */
- break;
+ previous_delete_event_data = g_hash_table_lookup (monitor->private->pre_delete, file);
+
+ if (previous_delete_event_data &&
+ previous_delete_event_data->event_type == G_FILE_MONITOR_EVENT_MOVED) {
+ g_debug ("Processing MOVE(A->B) + DELETE(A) as MOVE(A->B) for directory '%s->%s'",
+ previous_delete_event_data->file_uri,
+ previous_delete_event_data->other_file_uri);
+
+ emit_signal_for_event (monitor, previous_delete_event_data);
+ g_hash_table_remove (monitor->private->pre_delete, file);
+ } else {
+ g_hash_table_insert (monitor->private->pre_delete,
+ g_object_ref (file),
+ event_data_new (file, NULL, TRUE, event_type));
+ }
+
+ break;
+ }
+
+ case G_FILE_MONITOR_EVENT_MOVED: {
+ EventData *previous_delete_event_data;
+
+ previous_delete_event_data = g_hash_table_lookup (monitor->private->pre_delete, file);
+
+ if (previous_delete_event_data &&
+ previous_delete_event_data->event_type == G_FILE_MONITOR_EVENT_DELETED) {
+ EventData *new_event;
+
+ new_event = event_data_new (file, other_file, TRUE, G_FILE_MONITOR_EVENT_MOVED);
+ g_debug ("Processing DELETE(A) + MOVE(A->B) as MOVE(A->B) for directory '%s->%s'",
+ new_event->file_uri,
+ new_event->other_file_uri);
+ emit_signal_for_event (monitor, new_event);
+ event_data_free (new_event);
+
+ /* And remove the previous DELETE */
+ g_hash_table_remove (monitor->private->pre_delete, file);
+ } else {
+ g_hash_table_insert (monitor->private->pre_delete,
+ g_object_ref (file),
+ event_data_new (file, other_file, TRUE, event_type));
+ }
+
+ break;
+ }
+
+ case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+ case G_FILE_MONITOR_EVENT_UNMOUNTED:
+ /* Do nothing */
+ break;
+ }
}
- if (g_hash_table_size (monitor->private->event_pairs) > 0) {
+ if (g_hash_table_size (monitor->private->pre_update) > 0 ||
+ g_hash_table_size (monitor->private->pre_delete) > 0) {
if (monitor->private->event_pairs_timeout_id == 0) {
g_debug ("Waiting for event pairs");
monitor->private->event_pairs_timeout_id =
@@ -818,8 +977,8 @@ monitor_event_cb (GFileMonitor *file_monitor,
monitor->private->event_pairs_timeout_id = 0;
}
- g_free (str1);
- g_free (str2);
+ g_free (file_uri);
+ g_free (other_file_uri);
}
static GFileMonitor *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]