[evolution-data-server/gnome-3-16] Bug 751657 - ESource can be removed after its property change
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/gnome-3-16] Bug 751657 - ESource can be removed after its property change
- Date: Wed, 5 Aug 2015 14:24:19 +0000 (UTC)
commit 045d5157599365e314e648738fe75daf51334b73
Author: Milan Crha <mcrha redhat com>
Date: Wed Aug 5 16:24:15 2015 +0200
Bug 751657 - ESource can be removed after its property change
libebackend/e-source-registry-server.c | 212 ++++++++++++++++++++++++++++----
1 files changed, 186 insertions(+), 26 deletions(-)
---
diff --git a/libebackend/e-source-registry-server.c b/libebackend/e-source-registry-server.c
index 61aa39a..3edd829 100644
--- a/libebackend/e-source-registry-server.c
+++ b/libebackend/e-source-registry-server.c
@@ -66,6 +66,10 @@ struct _ESourceRegistryServerPrivate {
GMutex orphans_lock;
ESourceCredentialsProvider *credentials_provider;
+
+ GMutex file_monitor_lock;
+ GHashTable *file_monitor_events; /* gchar *uid ~> FileEventData * */
+ GSource *file_monitor_source;
};
enum {
@@ -414,44 +418,112 @@ source_registry_server_reload_cb (EDBusSourceManager *dbus_interface,
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)
{
- if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
+ 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;
- gchar *uid;
- uid = e_server_side_source_uid_from_file (file, NULL);
- if (!uid)
+ 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;
+ }
- source = e_source_registry_server_ref_source (server, uid);
+ g_object_unref (source);
+ }
- g_free (uid);
+ if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
+ ESource *source;
+ GError *error = NULL;
+
+ 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, file, &error);
+ 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);
} 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);
}
@@ -460,17 +532,9 @@ source_registry_server_monitor_changed_cb (GFileMonitor *monitor,
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;
@@ -485,6 +549,87 @@ source_registry_server_monitor_changed_cb (GFileMonitor *monitor,
}
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)
{
@@ -587,6 +732,14 @@ source_registry_server_dispose (GObject *object)
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;
@@ -599,6 +752,7 @@ source_registry_server_dispose (GObject *object)
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);
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (e_source_registry_server_parent_class)->
@@ -615,9 +769,11 @@ source_registry_server_finalize (GObject *object)
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);
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_source_registry_server_parent_class)->
@@ -966,6 +1122,10 @@ e_source_registry_server_init (ESourceRegistryServer *server)
server->priv->monitors = monitors;
g_mutex_init (&server->priv->sources_lock);
g_mutex_init (&server->priv->orphans_lock);
+ g_mutex_init (&server->priv->file_monitor_lock);
+
+ server->priv->file_monitor_source = NULL;
+ server->priv->file_monitor_events = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
file_event_data_free);
g_signal_connect (
source_manager, "handle-create-sources",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]