[evolution-data-server] I#208 - Avoid race condition when refreshing collection backend



commit 0714fdcbef7a03d1f15890d2f77537fd5c52467a
Author: Milan Crha <mcrha redhat com>
Date:   Fri Aug 28 14:21:05 2020 +0200

    I#208 - Avoid race condition when refreshing collection backend
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/208

 src/libebackend/e-collection-backend.c             | 63 ++++++++++++++++++++++
 src/libebackend/e-collection-backend.h             |  6 +++
 src/libebackend/e-webdav-collection-backend.c      | 11 ++++
 src/modules/google-backend/module-google-backend.c |  5 +-
 4 files changed, 84 insertions(+), 1 deletion(-)
---
diff --git a/src/libebackend/e-collection-backend.c b/src/libebackend/e-collection-backend.c
index d1b899fcee..7be6b8f184 100644
--- a/src/libebackend/e-collection-backend.c
+++ b/src/libebackend/e-collection-backend.c
@@ -75,6 +75,8 @@ struct _ECollectionBackendPrivate {
 
        gint64 last_populate_call;
        guint scheduled_populate_idle_id;
+
+       volatile gint populate_freeze_count;
 };
 
 enum {
@@ -625,6 +627,9 @@ collection_backend_populate_idle_cb (gpointer user_data)
 
        backend->priv->scheduled_populate_idle_id = 0;
 
+       if (e_collection_backend_get_populate_frozen (backend))
+               return FALSE;
+
        class = E_COLLECTION_BACKEND_GET_CLASS (backend);
        g_return_val_if_fail (class != NULL, FALSE);
        g_return_val_if_fail (class->populate != NULL, FALSE);
@@ -646,6 +651,9 @@ collection_backend_schedule_populate_idle (ECollectionBackend *backend,
 {
        g_return_if_fail (E_IS_COLLECTION_BACKEND (backend));
 
+       if (e_collection_backend_get_populate_frozen (backend))
+               return;
+
        if (!force) {
                /* Let automatically check for new child sources only once per day.
                   Users can still force this manually using e_source_registry_refresh_backend(). */
@@ -2020,3 +2028,58 @@ e_collection_backend_schedule_populate (ECollectionBackend *backend)
        if (e_backend_get_online (E_BACKEND (backend)))
                collection_backend_schedule_populate_idle (backend, TRUE);
 }
+
+/**
+ * e_collection_backend_get_populate_frozen:
+ * @backend: an #ECollectionBackend
+ *
+ * Returns: Whether the backend has currently frozen (disabled) populate of its content.
+ *
+ * Since: 3.38
+ **/
+gboolean
+e_collection_backend_get_populate_frozen (ECollectionBackend *backend)
+{
+       g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), FALSE);
+
+       return g_atomic_int_get (&backend->priv->populate_freeze_count) > 0;
+}
+
+/**
+ * e_collection_backend_freeze_populate:
+ * @backend: an #ECollectionBackend
+ *
+ * Freezes populate of the backend's content. This is used to avoid calling
+ * populate multiple times in parallel.
+ * Every call to this function should be followed by the call
+ * of e_collection_backend_thaw_populate() to reverse the effect of this function,
+ * regardless of the return value of this function.
+ *
+ * Returns: %TRUE, when this is the first freeze call
+ *
+ * Since: 3.38
+ **/
+gboolean
+e_collection_backend_freeze_populate (ECollectionBackend *backend)
+{
+       g_return_val_if_fail (E_IS_COLLECTION_BACKEND (backend), FALSE);
+
+       return !g_atomic_int_add (&backend->priv->populate_freeze_count, 1);
+}
+
+/**
+ * e_collection_backend_thaw_populate:
+ * @backend: an #ECollectionBackend
+ *
+ * Thaws populate of the backend's content. This is a pair function
+ * for e_collection_backend_freeze_populate().
+ *
+ * Since: 3.38
+ **/
+void
+e_collection_backend_thaw_populate (ECollectionBackend *backend)
+{
+       g_return_if_fail (E_IS_COLLECTION_BACKEND (backend));
+
+       g_atomic_int_add (&backend->priv->populate_freeze_count, -1);
+}
diff --git a/src/libebackend/e-collection-backend.h b/src/libebackend/e-collection-backend.h
index 695358d51e..f96a7099f1 100644
--- a/src/libebackend/e-collection-backend.h
+++ b/src/libebackend/e-collection-backend.h
@@ -171,6 +171,12 @@ void               e_collection_backend_authenticate_children
                                                 const ENamedParameters *credentials);
 void           e_collection_backend_schedule_populate
                                                (ECollectionBackend *backend);
+gboolean       e_collection_backend_get_populate_frozen
+                                               (ECollectionBackend *backend);
+gboolean       e_collection_backend_freeze_populate
+                                               (ECollectionBackend *backend);
+void           e_collection_backend_thaw_populate
+                                               (ECollectionBackend *backend);
 
 G_END_DECLS
 
diff --git a/src/libebackend/e-webdav-collection-backend.c b/src/libebackend/e-webdav-collection-backend.c
index b63c687b09..7f9880f2fb 100644
--- a/src/libebackend/e-webdav-collection-backend.c
+++ b/src/libebackend/e-webdav-collection-backend.c
@@ -303,6 +303,11 @@ webdav_collection_backend_populate (ECollectionBackend *collection)
        ESource *source;
        GList *list, *liter;
 
+       if (!e_collection_backend_freeze_populate (collection)) {
+               e_collection_backend_thaw_populate (collection);
+               return;
+       }
+
        /* Chain up to parent's method. */
        E_COLLECTION_BACKEND_CLASS (e_webdav_collection_backend_parent_class)->populate (collection);
 
@@ -359,6 +364,8 @@ webdav_collection_backend_populate (ECollectionBackend *collection)
        }
 
        g_object_unref (server);
+
+       e_collection_backend_thaw_populate (collection);
 }
 
 static void
@@ -532,6 +539,8 @@ e_webdav_collection_backend_discover_sync (EWebDAVCollectionBackend *webdav_back
            (!e_source_collection_get_contacts_enabled (collection_extension) || !contacts_url))
                return E_SOURCE_AUTHENTICATION_ACCEPTED;
 
+       e_collection_backend_freeze_populate (collection);
+
        credentials_empty = !credentials || !e_named_parameters_count (credentials) ||
                (e_named_parameters_count (credentials) == 1 && e_named_parameters_exists (credentials, 
E_SOURCE_CREDENTIAL_SSL_TRUST));
 
@@ -638,5 +647,7 @@ e_webdav_collection_backend_discover_sync (EWebDAVCollectionBackend *webdav_back
        g_hash_table_destroy (known_sources);
        e_named_parameters_free (credentials_copy);
 
+       e_collection_backend_thaw_populate (collection);
+
        return result;
 }
diff --git a/src/modules/google-backend/module-google-backend.c 
b/src/modules/google-backend/module-google-backend.c
index 2d1091225c..2b1fcf4736 100644
--- a/src/modules/google-backend/module-google-backend.c
+++ b/src/modules/google-backend/module-google-backend.c
@@ -502,6 +502,8 @@ google_backend_authenticate_sync (EBackend *backend,
        g_return_val_if_fail (e_source_collection_get_calendar_enabled (collection_extension) ||
                e_source_collection_get_contacts_enabled (collection_extension), 
E_SOURCE_AUTHENTICATION_ERROR);
 
+       e_collection_backend_freeze_populate (collection);
+
        if (credentials && !e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME)) {
                credentials_copy = e_named_parameters_new_clone (credentials);
                e_named_parameters_set (credentials_copy, E_SOURCE_CREDENTIAL_USERNAME, 
e_source_collection_get_identity (collection_extension));
@@ -609,6 +611,8 @@ google_backend_authenticate_sync (EBackend *backend,
        g_hash_table_destroy (known_sources);
        e_named_parameters_free (credentials_copy);
 
+       e_collection_backend_thaw_populate (collection);
+
        return result;
 }
 
@@ -721,7 +725,6 @@ google_backend_populate (ECollectionBackend *backend)
                        google_backend_add_contacts (backend);
                g_list_free_full (list, (GDestroyNotify) g_object_unref);
        }
-
 }
 
 static gchar *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]