[evolution-data-server/wip/offline-cache] Handle ECache revision change automatically
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/wip/offline-cache] Handle ECache revision change automatically
- Date: Wed, 17 May 2017 07:42:56 +0000 (UTC)
commit af76ef7f4e0ac0deb6944e05617b487c4249619e
Author: Milan Crha <mcrha redhat com>
Date: Wed May 17 09:42:41 2017 +0200
Handle ECache revision change automatically
src/addressbook/libedata-book/e-book-cache.c | 4 +
.../libedata-book/e-book-meta-backend.c | 33 ++++
src/calendar/libedata-cal/e-cal-cache.c | 4 +
src/calendar/libedata-cal/e-cal-meta-backend.c | 33 ++++
src/libebackend/e-cache.c | 163 +++++++++++++++++++-
src/libebackend/e-cache.h | 6 +
6 files changed, 240 insertions(+), 3 deletions(-)
---
diff --git a/src/addressbook/libedata-book/e-book-cache.c b/src/addressbook/libedata-book/e-book-cache.c
index 8b1916a..cb1fda2 100644
--- a/src/addressbook/libedata-book/e-book-cache.c
+++ b/src/addressbook/libedata-book/e-book-cache.c
@@ -4802,6 +4802,7 @@ e_book_cache_put_contacts (EBookCache *book_cache,
other_columns = e_cache_column_values_new ();
e_cache_lock (cache, E_CACHE_LOCK_WRITE);
+ e_cache_freeze_revision_change (cache);
for (clink = contacts, elink = extras; clink; clink = g_slist_next (clink), elink = g_slist_next
(elink)) {
EContact *contact = clink->data;
@@ -4833,6 +4834,7 @@ e_book_cache_put_contacts (EBookCache *book_cache,
break;
}
+ e_cache_thaw_revision_change (cache);
e_cache_unlock (cache, success ? E_CACHE_UNLOCK_COMMIT : E_CACHE_UNLOCK_ROLLBACK);
e_cache_column_values_free (other_columns);
@@ -4907,6 +4909,7 @@ e_book_cache_remove_contacts (EBookCache *book_cache,
cache = E_CACHE (book_cache);
e_cache_lock (cache, E_CACHE_LOCK_WRITE);
+ e_cache_freeze_revision_change (cache);
for (link = uids; success && link; link = g_slist_next (link)) {
const gchar *uid = link->data;
@@ -4914,6 +4917,7 @@ e_book_cache_remove_contacts (EBookCache *book_cache,
success = e_cache_remove (cache, uid, offline_flag, cancellable, error);
}
+ e_cache_thaw_revision_change (cache);
e_cache_unlock (cache, success ? E_CACHE_UNLOCK_COMMIT : E_CACHE_UNLOCK_ROLLBACK);
return success;
diff --git a/src/addressbook/libedata-book/e-book-meta-backend.c
b/src/addressbook/libedata-book/e-book-meta-backend.c
index edcff27..bde296b 100644
--- a/src/addressbook/libedata-book/e-book-meta-backend.c
+++ b/src/addressbook/libedata-book/e-book-meta-backend.c
@@ -66,6 +66,7 @@ struct _EBookMetaBackendPrivate {
used to detect false notifications on EBackend::online */
gulong source_changed_id;
gulong notify_online_id;
+ gulong revision_changed_id;
guint refresh_timeout_id;
gboolean refresh_after_authenticate;
@@ -2484,6 +2485,12 @@ e_book_meta_backend_dispose (GObject *object)
meta_backend->priv->notify_online_id = 0;
}
+ if (meta_backend->priv->revision_changed_id) {
+ if (meta_backend->priv->cache)
+ g_signal_handler_disconnect (meta_backend->priv->cache,
meta_backend->priv->revision_changed_id);
+ meta_backend->priv->revision_changed_id = 0;
+ }
+
g_hash_table_foreach (meta_backend->priv->view_cancellables, ebmb_cancel_view_cb, NULL);
if (meta_backend->priv->refresh_cancellable) {
@@ -2787,6 +2794,24 @@ e_book_meta_backend_get_connected_writable (EBookMetaBackend *meta_backend)
return result;
}
+static void
+ebmb_cache_revision_changed_cb (ECache *cache,
+ gpointer user_data)
+{
+ EBookMetaBackend *meta_backend = user_data;
+ gchar *revision;
+
+ g_return_if_fail (E_IS_CACHE (cache));
+ g_return_if_fail (E_IS_BOOK_META_BACKEND (meta_backend));
+
+ revision = e_cache_dup_revision (cache);
+ if (revision) {
+ e_book_backend_notify_property_changed (E_BOOK_BACKEND (meta_backend),
+ BOOK_BACKEND_PROPERTY_REVISION, revision);
+ g_free (revision);
+ }
+}
+
/**
* e_book_meta_backend_set_cache:
* @meta_backend: an #EBookMetaBackend
@@ -2817,9 +2842,17 @@ e_book_meta_backend_set_cache (EBookMetaBackend *meta_backend,
g_clear_error (&meta_backend->priv->create_cache_error);
+ if (meta_backend->priv->cache) {
+ g_signal_handler_disconnect (meta_backend->priv->cache,
+ meta_backend->priv->revision_changed_id);
+ }
+
g_clear_object (&meta_backend->priv->cache);
meta_backend->priv->cache = g_object_ref (cache);
+ meta_backend->priv->revision_changed_id = g_signal_connect_object (meta_backend->priv->cache,
+ "revision-changed", G_CALLBACK (ebmb_cache_revision_changed_cb), meta_backend, 0);
+
g_mutex_unlock (&meta_backend->priv->property_lock);
g_object_notify (G_OBJECT (meta_backend), "cache");
diff --git a/src/calendar/libedata-cal/e-cal-cache.c b/src/calendar/libedata-cal/e-cal-cache.c
index 8a186ed..24783bf 100644
--- a/src/calendar/libedata-cal/e-cal-cache.c
+++ b/src/calendar/libedata-cal/e-cal-cache.c
@@ -1945,6 +1945,7 @@ e_cal_cache_put_components (ECalCache *cal_cache,
other_columns = e_cache_column_values_new ();
e_cache_lock (cache, E_CACHE_LOCK_WRITE);
+ e_cache_freeze_revision_change (cache);
for (clink = components, elink = extras; clink; clink = g_slist_next (clink), elink = g_slist_next
(elink)) {
ECalComponent *component = clink->data;
@@ -1983,6 +1984,7 @@ e_cal_cache_put_components (ECalCache *cal_cache,
break;
}
+ e_cache_thaw_revision_change (cache);
e_cache_unlock (cache, success ? E_CACHE_UNLOCK_COMMIT : E_CACHE_UNLOCK_ROLLBACK);
e_cache_column_values_free (other_columns);
@@ -2065,6 +2067,7 @@ e_cal_cache_remove_components (ECalCache *cal_cache,
cache = E_CACHE (cal_cache);
e_cache_lock (cache, E_CACHE_LOCK_WRITE);
+ e_cache_freeze_revision_change (cache);
for (link = ids; success && link; link = g_slist_next (link)) {
const ECalComponentId *id = link->data;
@@ -2082,6 +2085,7 @@ e_cal_cache_remove_components (ECalCache *cal_cache,
g_free (uid);
}
+ e_cache_thaw_revision_change (cache);
e_cache_unlock (cache, success ? E_CACHE_UNLOCK_COMMIT : E_CACHE_UNLOCK_ROLLBACK);
return success;
diff --git a/src/calendar/libedata-cal/e-cal-meta-backend.c b/src/calendar/libedata-cal/e-cal-meta-backend.c
index 47e58de..49ee547 100644
--- a/src/calendar/libedata-cal/e-cal-meta-backend.c
+++ b/src/calendar/libedata-cal/e-cal-meta-backend.c
@@ -63,6 +63,7 @@ struct _ECalMetaBackendPrivate {
used to detect false notifications on EBackend::online */
gulong source_changed_id;
gulong notify_online_id;
+ gulong revision_changed_id;
guint refresh_timeout_id;
gboolean refresh_after_authenticate;
@@ -3178,6 +3179,12 @@ e_cal_meta_backend_dispose (GObject *object)
meta_backend->priv->notify_online_id = 0;
}
+ if (meta_backend->priv->revision_changed_id) {
+ if (meta_backend->priv->cache)
+ g_signal_handler_disconnect (meta_backend->priv->cache,
meta_backend->priv->revision_changed_id);
+ meta_backend->priv->revision_changed_id = 0;
+ }
+
g_hash_table_foreach (meta_backend->priv->view_cancellables, ecmb_cancel_view_cb, NULL);
if (meta_backend->priv->refresh_cancellable) {
@@ -3482,6 +3489,24 @@ e_cal_meta_backend_get_connected_writable (ECalMetaBackend *meta_backend)
return result;
}
+static void
+ecmb_cache_revision_changed_cb (ECache *cache,
+ gpointer user_data)
+{
+ ECalMetaBackend *meta_backend = user_data;
+ gchar *revision;
+
+ g_return_if_fail (E_IS_CACHE (cache));
+ g_return_if_fail (E_IS_CAL_META_BACKEND (meta_backend));
+
+ revision = e_cache_dup_revision (cache);
+ if (revision) {
+ e_cal_backend_notify_property_changed (E_CAL_BACKEND (meta_backend),
+ CAL_BACKEND_PROPERTY_REVISION, revision);
+ g_free (revision);
+ }
+}
+
/**
* e_cal_meta_backend_set_cache:
* @meta_backend: an #ECalMetaBackend
@@ -3512,9 +3537,17 @@ e_cal_meta_backend_set_cache (ECalMetaBackend *meta_backend,
g_clear_error (&meta_backend->priv->create_cache_error);
+ if (meta_backend->priv->cache) {
+ g_signal_handler_disconnect (meta_backend->priv->cache,
+ meta_backend->priv->revision_changed_id);
+ }
+
g_clear_object (&meta_backend->priv->cache);
meta_backend->priv->cache = g_object_ref (cache);
+ meta_backend->priv->revision_changed_id = g_signal_connect_object (meta_backend->priv->cache,
+ "revision-changed", G_CALLBACK (ecmb_cache_revision_changed_cb), meta_backend, 0);
+
g_mutex_unlock (&meta_backend->priv->property_lock);
g_object_notify (G_OBJECT (meta_backend), "cache");
diff --git a/src/libebackend/e-cache.c b/src/libebackend/e-cache.c
index 20d26bd..f35e0f0 100644
--- a/src/libebackend/e-cache.c
+++ b/src/libebackend/e-cache.c
@@ -64,11 +64,17 @@ struct _ECachePrivate {
guint32 in_transaction; /* Nested transaction counter */
ECacheLockType lock_type; /* The lock type acquired for the current transaction */
GCancellable *cancellable; /* User passed GCancellable, we abort an operation if cancelled */
+
+ guint32 revision_change_frozen;
+ gint revision_counter;
+ gint64 last_revision_time;
+ gboolean needs_revision_change;
};
enum {
BEFORE_PUT,
BEFORE_REMOVE,
+ REVISION_CHANGED,
LAST_SIGNAL
};
@@ -1042,8 +1048,9 @@ e_cache_dup_revision (ECache *cache)
* @cache: an #ECache
* @revision: (nullable): a revision to set; use %NULL to unset it
*
- * Sets the @revision of the whole @cache. This is meant to be
- * used by the descendants.
+ * Sets the @revision of the whole @cache. This is not meant to be
+ * used by the descendants, because the revision is updated automatically
+ * when needed. The descendants can listen to "revision-changed" signal.
*
* Since: 3.26
**/
@@ -1054,6 +1061,133 @@ e_cache_set_revision (ECache *cache,
g_return_if_fail (E_IS_CACHE (cache));
e_cache_set_key_internal (cache, FALSE, E_CACHE_KEY_REVISION, revision, NULL);
+
+ g_signal_emit (cache, signals[REVISION_CHANGED], 0, NULL);
+}
+
+/**
+ * e_cache_change_revision:
+ * @cache: an #ECache
+ *
+ * Instructs the @cache to change its revision. In case the revision
+ * change is frozen with e_cache_freeze_revision_change() it notes to
+ * change the revision once the revision change is fully thaw.
+ *
+ * Since: 3.26
+ **/
+void
+e_cache_change_revision (ECache *cache)
+{
+ g_return_if_fail (E_IS_CACHE (cache));
+
+ g_rec_mutex_lock (&cache->priv->lock);
+
+ if (e_cache_is_revision_change_frozen (cache)) {
+ cache->priv->needs_revision_change = TRUE;
+ } else {
+ gchar time_string[100] = { 0 };
+ const struct tm *tm = NULL;
+ time_t t;
+ gint64 revision_time;
+ gchar *revision;
+
+ revision_time = g_get_real_time () / (1000 * 1000);
+ t = (time_t) revision_time;
+
+ if (revision_time != cache->priv->last_revision_time) {
+ cache->priv->revision_counter = 0;
+ cache->priv->last_revision_time = revision_time;
+ }
+
+ tm = gmtime (&t);
+ if (tm)
+ strftime (time_string, 100, "%Y-%m-%dT%H:%M:%SZ", tm);
+
+ revision = g_strdup_printf ("%s(%d)", time_string, cache->priv->revision_counter++);
+
+ e_cache_set_revision (cache, revision);
+
+ g_free (revision);
+ }
+
+ g_rec_mutex_unlock (&cache->priv->lock);
+}
+
+/**
+ * e_cache_freeze_revision_change:
+ * @cache: an #ECache
+ *
+ * Freezes automatic revision change for the @cache. The function
+ * can be called multiple times, but each such call requires its
+ * pair function e_cache_thaw_revision_change() call. See also
+ * e_cache_change_revision().
+ *
+ * Since: 3.26
+ **/
+void
+e_cache_freeze_revision_change (ECache *cache)
+{
+ g_return_if_fail (E_IS_CACHE (cache));
+
+ g_rec_mutex_lock (&cache->priv->lock);
+
+ cache->priv->revision_change_frozen++;
+ g_warn_if_fail (cache->priv->revision_change_frozen != 0);
+
+ g_rec_mutex_unlock (&cache->priv->lock);
+}
+
+/**
+ * e_cache_thaw_revision_change:
+ * @cache: an #ECache
+ *
+ * Thaws automatic revision change for the @cache. It's the pair
+ * function of e_cache_freeze_revision_change().
+ *
+ * Since: 3.26
+ **/
+void
+e_cache_thaw_revision_change (ECache *cache)
+{
+ g_return_if_fail (E_IS_CACHE (cache));
+
+ g_rec_mutex_lock (&cache->priv->lock);
+
+ if (!cache->priv->revision_change_frozen) {
+ g_warn_if_fail (cache->priv->revision_change_frozen > 0);
+ } else {
+ cache->priv->revision_change_frozen--;
+ if (!cache->priv->revision_change_frozen &&
+ cache->priv->needs_revision_change) {
+ cache->priv->needs_revision_change = FALSE;
+ e_cache_change_revision (cache);
+ }
+ }
+
+ g_rec_mutex_unlock (&cache->priv->lock);
+}
+
+/**
+ * e_cache_is_revision_change_frozen:
+ * @cache: an #ECache
+ *
+ * Returns: Whether automatic revision change for the @cache
+ * is currently frozen.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cache_is_revision_change_frozen (ECache *cache)
+{
+ gboolean frozen;
+
+ g_return_val_if_fail (E_IS_CACHE (cache), FALSE);
+
+ g_rec_mutex_lock (&cache->priv->lock);
+ frozen = cache->priv->revision_change_frozen > 0;
+ g_rec_mutex_unlock (&cache->priv->lock);
+
+ return frozen;
}
/**
@@ -1292,6 +1426,9 @@ e_cache_put_locked (ECache *cache,
g_return_val_if_fail (klass->put_locked != NULL, FALSE);
success = klass->put_locked (cache, uid, revision, object, other_columns, offline_state,
is_replace, cancellable, error);
+
+ if (success)
+ e_cache_change_revision (cache);
}
e_cache_column_values_free (my_other_columns);
@@ -1429,6 +1566,9 @@ e_cache_remove (ECache *cache,
}
}
+ if (success)
+ e_cache_change_revision (cache);
+
e_cache_unlock (cache, success ? E_CACHE_UNLOCK_COMMIT : E_CACHE_UNLOCK_ROLLBACK);
return success;
@@ -1468,8 +1608,10 @@ e_cache_remove_all (ECache *cache,
if (success && uids)
success = klass->remove_all_locked (cache, uids, cancellable, error);
- if (success)
+ if (success) {
e_cache_sqlite_maybe_vacuum (cache, cancellable, NULL);
+ e_cache_change_revision (cache);
+ }
e_cache_unlock (cache, success ? E_CACHE_UNLOCK_COMMIT : E_CACHE_UNLOCK_ROLLBACK);
@@ -2894,6 +3036,17 @@ e_cache_class_init (ECacheClass *klass)
G_TYPE_CANCELLABLE,
G_TYPE_POINTER);
+ signals[REVISION_CHANGED] = g_signal_new (
+ "revision-changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECacheClass, revision_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 0,
+ G_TYPE_NONE);
+
e_sqlite3_vfs_init ();
}
@@ -2906,6 +3059,10 @@ e_cache_init (ECache *cache)
cache->priv->db = NULL;
cache->priv->cancellable = NULL;
cache->priv->in_transaction = 0;
+ cache->priv->revision_change_frozen = 0;
+ cache->priv->revision_counter = 0;
+ cache->priv->last_revision_time = 0;
+ cache->priv->needs_revision_change = FALSE;
g_rec_mutex_init (&cache->priv->lock);
}
diff --git a/src/libebackend/e-cache.h b/src/libebackend/e-cache.h
index c8dac06..18b3ed7 100644
--- a/src/libebackend/e-cache.h
+++ b/src/libebackend/e-cache.h
@@ -374,6 +374,7 @@ struct _ECacheClass {
const gchar *uid,
GCancellable *cancellable,
GError **error);
+ void (* revision_changed) (ECache *cache);
/* Padding for future expansion */
gpointer reserved[10];
@@ -393,6 +394,11 @@ void e_cache_set_version (ECache *cache,
gchar * e_cache_dup_revision (ECache *cache);
void e_cache_set_revision (ECache *cache,
const gchar *revision);
+void e_cache_change_revision (ECache *cache);
+void e_cache_freeze_revision_change (ECache *cache);
+void e_cache_thaw_revision_change (ECache *cache);
+gboolean e_cache_is_revision_change_frozen
+ (ECache *cache);
void e_cache_erase (ECache *cache);
gboolean e_cache_contains (ECache *cache,
const gchar *uid,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]