diff -up evolution-data-server-3.12.11/libebackend/e-source-registry-server.c.goa-source-change-removed evolution-data-server-3.12.11/libebackend/e-source-registry-server.c
--- evolution-data-server-3.12.11/libebackend/e-source-registry-server.c.goa-source-change-removed 2014-11-11 18:40:25.000000000 +0100
+++ evolution-data-server-3.12.11/libebackend/e-source-registry-server.c 2015-08-17 16:55:07.401935846 +0200
@@ -87,6 +87,10 @@ struct _ESourceRegistryServerPrivate {
GHashTable *waiting_auths;
guint authentication_count;
+
+ GMutex file_monitor_lock;
+ GHashTable *file_monitor_events; /* gchar *uid ~> FileEventData * */
+ GSource *file_monitor_source;
};
struct _AuthRequest {
@@ -899,51 +903,121 @@ source_registry_server_reload_cb (EDBusS
return TRUE;
}
+typedef struct _FileEventData {
+ GFile *file;
+ GFileMonitorEvent event_type;
+} FileEventData;
+
+static FileEventData *
+file_event_data_new (GFile *file,
+ GFileMonitorEvent event_type)
+{
+ FileEventData *fed;
+
+ fed = g_new0 (FileEventData, 1);
+ fed->file = g_object_ref (file);
+ fed->event_type = event_type;
+
+ return fed;
+}
+
static void
-source_registry_server_monitor_changed_cb (GFileMonitor *monitor,
- GFile *file,
- GFile *other_file,
- GFileMonitorEvent event_type,
- ESourceRegistryServer *server)
+file_event_data_free (gpointer ptr)
{
+ FileEventData *fed = ptr;
+
+ if (fed) {
+ g_clear_object (&fed->file);
+ g_free (fed);
+ }
+}
+
+static void
+source_registry_server_process_file_monitor_event (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ const gchar *uid = key;
+ const FileEventData *fed = value;
+ ESourceRegistryServer *server = user_data;
+ GFileMonitorEvent event_type;
+
+ g_return_if_fail (uid != NULL);
+ g_return_if_fail (fed != NULL);
+
+ event_type = fed->event_type;
+
+ if (e_source_registry_debug_enabled ()) {
+ e_source_registry_debug_print ("Processing file monitor event %s (%u) for UID: %s\n",
+ event_type == G_FILE_MONITOR_EVENT_CHANGED ? "CHANGED" :
+ event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT ? "CHANGES_DONE_HINT" :
+ event_type == G_FILE_MONITOR_EVENT_DELETED ? "DELETED" :
+ event_type == G_FILE_MONITOR_EVENT_CREATED ? "CREATED" :
+ event_type == G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED ? "ATTRIBUTE_CHANGED" :
+ event_type == G_FILE_MONITOR_EVENT_PRE_UNMOUNT ? "PRE_UNMOUNT" :
+ event_type == G_FILE_MONITOR_EVENT_UNMOUNTED ? "UNMOUNTED" :
+ event_type == G_FILE_MONITOR_EVENT_MOVED ? "MOVED" : "???",
+ event_type,
+ uid);
+ }
+
+ if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
+ event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) {
+ ESource *source;
+ GError *error = NULL;
+
+ source = e_source_registry_server_ref_source (server, uid);
+
+ /* If the source does not exist, create it; parsing may have
+ * failed when the file was originally created. This can happen
+ * if the file is created (empty), then e-source-registry-server
+ * detects it, then it’s populated and made valid.
+ *
+ * Otherwise, reload the file since it has changed. */
+ if (source == NULL) {
+ event_type = G_FILE_MONITOR_EVENT_CREATED;
+ } else if (!e_server_side_source_load (E_SERVER_SIDE_SOURCE (source), NULL, &error)) {
+ g_warning ("Error reloading source ‘%s’: %s", uid, error->message);
+
+ g_error_free (error);
+ g_object_unref (source);
+
+ return;
+ }
+
+ g_object_unref (source);
+ }
+
if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
ESource *source;
GError *error = NULL;
- /* it can return NULL source for hidden files */
- source = e_server_side_source_new (server, file, &error);
+ source = e_source_registry_server_ref_source (server, uid);
+
+ if (!source) {
+ /* it can return NULL source for hidden files */
+ source = e_server_side_source_new (server, fed->file, &error);
+ }
if (!error && source) {
/* File monitors are only placed on directories
* where data sources are writable and removable,
* so it should be safe to assume these flags. */
- e_server_side_source_set_writable (
- E_SERVER_SIDE_SOURCE (source), TRUE);
- e_server_side_source_set_removable (
- E_SERVER_SIDE_SOURCE (source), TRUE);
+ e_server_side_source_set_writable (E_SERVER_SIDE_SOURCE (source), TRUE);
+ e_server_side_source_set_removable (E_SERVER_SIDE_SOURCE (source), TRUE);
e_source_registry_server_add_source (server, source);
- g_object_unref (source);
} else if (error) {
- e_source_registry_server_load_error (
- server, file, error);
+ e_source_registry_server_load_error (server, fed->file, error);
g_error_free (error);
}
}
if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
ESource *source;
- gchar *uid;
-
- uid = e_server_side_source_uid_from_file (file, NULL);
-
- if (uid == NULL)
- return;
source = e_source_registry_server_ref_source (server, uid);
- g_free (uid);
-
if (source == NULL)
return;
@@ -958,6 +1032,87 @@ source_registry_server_monitor_changed_c
}
static gboolean
+source_registry_server_process_file_monitor_events_cb (gpointer user_data)
+{
+ ESourceRegistryServer *server = user_data;
+ GHashTable *events;
+
+ if (g_source_is_destroyed (g_main_current_source ()))
+ return FALSE;
+
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), FALSE);
+
+ g_mutex_lock (&server->priv->file_monitor_lock);
+ events = server->priv->file_monitor_events;
+ server->priv->file_monitor_events = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, file_event_data_free);
+ g_mutex_unlock (&server->priv->file_monitor_lock);
+
+ g_hash_table_foreach (events, source_registry_server_process_file_monitor_event, server);
+ g_hash_table_destroy (events);
+
+ return FALSE;
+}
+
+static void
+source_registry_server_monitor_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ ESourceRegistryServer *server)
+{
+ if (e_source_registry_debug_enabled ()) {
+ gchar *uri;
+
+ uri = g_file_get_uri (file);
+ e_source_registry_debug_print ("Handling file monitor event %s (%u) for URI: %s\n",
+ event_type == G_FILE_MONITOR_EVENT_CHANGED ? "CHANGED" :
+ event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT ? "CHANGES_DONE_HINT" :
+ event_type == G_FILE_MONITOR_EVENT_DELETED ? "DELETED" :
+ event_type == G_FILE_MONITOR_EVENT_CREATED ? "CREATED" :
+ event_type == G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED ? "ATTRIBUTE_CHANGED" :
+ event_type == G_FILE_MONITOR_EVENT_PRE_UNMOUNT ? "PRE_UNMOUNT" :
+ event_type == G_FILE_MONITOR_EVENT_UNMOUNTED ? "UNMOUNTED" :
+ event_type == G_FILE_MONITOR_EVENT_MOVED ? "MOVED" : "???",
+ event_type,
+ uri);
+ g_free (uri);
+ }
+
+ if (event_type == G_FILE_MONITOR_EVENT_CHANGED ||
+ event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT ||
+ event_type == G_FILE_MONITOR_EVENT_CREATED ||
+ event_type == G_FILE_MONITOR_EVENT_DELETED) {
+ gchar *uid;
+
+ uid = e_server_side_source_uid_from_file (file, NULL);
+
+ if (uid == NULL)
+ return;
+
+ g_mutex_lock (&server->priv->file_monitor_lock);
+ /* This overwrites any previous events, aka the last wins
+ (overwrite can be DELETE + CREATE, which handles it correctly). */
+ g_hash_table_insert (server->priv->file_monitor_events, uid, file_event_data_new (file, event_type));
+
+ if (server->priv->file_monitor_source) {
+ g_source_destroy (server->priv->file_monitor_source);
+ g_source_unref (server->priv->file_monitor_source);
+ }
+
+ server->priv->file_monitor_source = g_timeout_source_new_seconds (3);
+ g_source_set_callback (
+ server->priv->file_monitor_source,
+ source_registry_server_process_file_monitor_events_cb,
+ server, NULL);
+ g_source_attach (
+ server->priv->file_monitor_source,
+ server->priv->main_context);
+
+ g_mutex_unlock (&server->priv->file_monitor_lock);
+ }
+}
+
+static gboolean
source_registry_server_traverse_cb (GNode *node,
GQueue *queue)
{
@@ -1047,6 +1202,14 @@ source_registry_server_dispose (GObject
priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (object);
+ g_mutex_lock (&priv->file_monitor_lock);
+ if (priv->file_monitor_source) {
+ g_source_destroy (priv->file_monitor_source);
+ g_source_unref (priv->file_monitor_source);
+ priv->file_monitor_source = NULL;
+ }
+ g_mutex_unlock (&priv->file_monitor_lock);
+
if (priv->main_context != NULL) {
g_main_context_unref (priv->main_context);
priv->main_context = NULL;
@@ -1065,6 +1228,7 @@ source_registry_server_dispose (GObject
g_hash_table_remove_all (priv->sources);
g_hash_table_remove_all (priv->orphans);
g_hash_table_remove_all (priv->monitors);
+ g_hash_table_remove_all (priv->file_monitor_events);
g_hash_table_remove_all (priv->running_auths);
g_hash_table_remove_all (priv->waiting_auths);
@@ -1084,9 +1248,11 @@ source_registry_server_finalize (GObject
g_hash_table_destroy (priv->sources);
g_hash_table_destroy (priv->orphans);
g_hash_table_destroy (priv->monitors);
+ g_hash_table_destroy (priv->file_monitor_events);
g_mutex_clear (&priv->sources_lock);
g_mutex_clear (&priv->orphans_lock);
+ g_mutex_clear (&priv->file_monitor_lock);
g_mutex_clear (&priv->auth_lock);
g_hash_table_destroy (priv->running_auths);
diff -up evolution-data-server-3.12.11/libedataserver/e-source.c.goa-source-change-removed evolution-data-server-3.12.11/libedataserver/e-source.c
--- evolution-data-server-3.12.11/libedataserver/e-source.c.goa-source-change-removed 2015-08-17 16:55:07.344936312 +0200
+++ evolution-data-server-3.12.11/libedataserver/e-source.c 2015-08-17 16:55:07.402935838 +0200
@@ -126,9 +126,6 @@ struct _ESourcePrivate {
GSource *changed;
GMutex changed_lock;
- GSource *data_change;
- GMutex data_change_lock;
-
GMutex property_lock;
gchar *display_name;
@@ -790,26 +787,13 @@ source_parse_dbus_data (ESource *source,
return TRUE;
}
-static gboolean
-source_idle_data_change_cb (gpointer user_data)
+static void
+source_notify_dbus_data_cb (EDBusSource *dbus_source,
+ GParamSpec *pspec,
+ ESource *source)
{
- ESource *source = E_SOURCE (user_data);
GError *local_error = NULL;
- /* If the ESource is still initializing itself in a different
- * thread, skip the signal emission and try again on the next
- * main loop iteration. This is a busy wait but it should be
- * a very short wait. */
- if (!source->priv->initialized)
- return TRUE;
-
- g_mutex_lock (&source->priv->data_change_lock);
- if (source->priv->data_change != NULL) {
- g_source_unref (source->priv->data_change);
- source->priv->data_change = NULL;
- }
- g_mutex_unlock (&source->priv->data_change_lock);
-
g_rec_mutex_lock (&source->priv->lock);
/* Since the source data came from a GKeyFile structure on the
@@ -823,27 +807,6 @@ source_idle_data_change_cb (gpointer use
}
g_rec_mutex_unlock (&source->priv->lock);
-
- return FALSE;
-}
-
-static void
-source_notify_dbus_data_cb (EDBusSource *dbus_source,
- GParamSpec *pspec,
- ESource *source)
-{
- g_mutex_lock (&source->priv->data_change_lock);
- if (source->priv->data_change == NULL) {
- source->priv->data_change = g_idle_source_new ();
- g_source_set_callback (
- source->priv->data_change,
- source_idle_data_change_cb,
- source, NULL);
- g_source_attach (
- source->priv->data_change,
- source->priv->main_context);
- }
- g_mutex_unlock (&source->priv->data_change_lock);
}
static gboolean
@@ -1066,14 +1029,6 @@ source_dispose (GObject *object)
}
g_mutex_unlock (&priv->changed_lock);
- g_mutex_lock (&priv->data_change_lock);
- if (priv->data_change != NULL) {
- g_source_destroy (priv->data_change);
- g_source_unref (priv->data_change);
- priv->data_change = NULL;
- }
- g_mutex_unlock (&priv->data_change_lock);
-
g_hash_table_remove_all (priv->extensions);
/* Chain up to parent's dispose() method. */
@@ -1088,7 +1043,6 @@ source_finalize (GObject *object)
priv = E_SOURCE_GET_PRIVATE (object);
g_mutex_clear (&priv->changed_lock);
- g_mutex_clear (&priv->data_change_lock);
g_mutex_clear (&priv->property_lock);
g_free (priv->display_name);
@@ -2092,7 +2046,6 @@ e_source_init (ESource *source)
source->priv = E_SOURCE_GET_PRIVATE (source);
g_mutex_init (&source->priv->changed_lock);
- g_mutex_init (&source->priv->data_change_lock);
g_mutex_init (&source->priv->property_lock);
source->priv->key_file = g_key_file_new ();
source->priv->extensions = extensions;