[evolution-data-server/openismus-work-master: 3/10] EBookBackendFile: Avoid lost data in contact modifications
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/openismus-work-master: 3/10] EBookBackendFile: Avoid lost data in contact modifications
- Date: Thu, 24 Jan 2013 06:44:45 +0000 (UTC)
commit f998860768b93cd179ee4471d89fe33d3ba8a858
Author: Tristan Van Berkom <tristanvb openismus com>
Date: Thu Jan 24 14:57:03 2013 +0900
EBookBackendFile: Avoid lost data in contact modifications
When modifying contacts, ensure that the contact revisions are in
sync with the existing ones, otherwise report the E_DATA_BOOK_STATUS_OUT_OF_SYNC
error. This indicates that the client should refresh it's local copy
of the contact before trying to modify it again.
addressbook/backends/file/e-book-backend-file.c | 85 ++++++++++++++++++-----
1 files changed, 67 insertions(+), 18 deletions(-)
---
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index b86384c..5becc29 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -70,6 +70,7 @@ struct _EBookBackendFilePrivate {
gchar *revision;
gint rev_counter;
GRecMutex revision_mutex;
+ GRWLock lock;
EBookBackendSqliteDB *sqlitedb;
};
@@ -613,7 +614,7 @@ e_book_backend_file_new_revision (EBookBackendFile *bf)
* every DB modification is going to really be an overhead.
*/
static void
-e_book_backend_file_bump_revision (EBookBackendFile *bf)
+e_book_backend_file_bump_revision_locked (EBookBackendFile *bf)
{
GError *error = NULL;
@@ -640,6 +641,14 @@ e_book_backend_file_bump_revision (EBookBackendFile *bf)
}
static void
+e_book_backend_file_bump_revision (EBookBackendFile *bf)
+{
+ g_rw_lock_writer_lock (&(bf->priv->lock));
+ e_book_backend_file_bump_revision_locked (bf);
+ g_rw_lock_writer_unlock (&(bf->priv->lock));
+}
+
+static void
e_book_backend_file_load_revision (EBookBackendFile *bf)
{
GError *error = NULL;
@@ -662,18 +671,14 @@ e_book_backend_file_load_revision (EBookBackendFile *bf)
}
static void
-set_revision (EContact *contact)
+set_revision (EBookBackendFile *bf,
+ EContact *contact)
{
- gchar time_string[100] = {0};
- const struct tm *tm = NULL;
- time_t t;
-
- t = time (NULL);
- tm = gmtime (&t);
- if (tm)
- strftime (time_string, 100, "%Y-%m-%dT%H:%M:%SZ", tm);
- e_contact_set (contact, E_CONTACT_REV, time_string);
+ gchar *rev;
+ rev = e_book_backend_file_new_revision (bf);
+ e_contact_set (contact, E_CONTACT_REV, rev);
+ g_free (rev);
}
/****************************************************************
@@ -723,7 +728,7 @@ do_create (EBookBackendFile *bf,
rev = e_contact_get_const (contact, E_CONTACT_REV);
if (!(rev && *rev))
- set_revision (contact);
+ set_revision (bf, contact);
status = maybe_transform_vcard_for_photo (bf, NULL, contact, perror);
@@ -790,9 +795,13 @@ e_book_backend_file_create_contacts (EBookBackendSync *backend,
{
EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
+ g_rw_lock_writer_lock (&(bf->priv->lock));
+
if (do_create (bf, vcards, added_contacts, perror)) {
- e_book_backend_file_bump_revision (bf);
+ e_book_backend_file_bump_revision_locked (bf);
}
+
+ g_rw_lock_writer_unlock (&(bf->priv->lock));
}
static void
@@ -809,6 +818,8 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
gboolean delete_failed = FALSE;
const GSList *l;
+ g_rw_lock_writer_lock (&(bf->priv->lock));
+
for (l = id_list; l != NULL; l = l->next) {
const gchar *id;
EContact *contact;
@@ -855,13 +866,16 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
g_propagate_error (perror, local_error);
}
+ e_book_backend_file_bump_revision_locked (bf);
+
*ids = removed_ids;
} else {
*ids = NULL;
e_util_free_string_slist (removed_ids);
}
- e_book_backend_file_bump_revision (bf);
+ g_rw_lock_writer_unlock (&(bf->priv->lock));
+
e_util_free_object_slist (removed_contacts);
}
@@ -885,9 +899,12 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
return;
}
+ g_rw_lock_writer_lock (&(bf->priv->lock));
+
for (l = vcards; l != NULL; l = l->next) {
gchar *id;
EContact *contact, *old_contact;
+ const gchar *contact_rev, *old_contact_rev;
contact = e_contact_new_from_vcard (l->data);
id = e_contact_get (contact, E_CONTACT_UID);
@@ -914,7 +931,24 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
g_object_unref (contact);
break;
}
- old_contacts = g_slist_prepend (old_contacts, old_contact);
+
+ contact_rev = e_contact_get_const (contact, E_CONTACT_REV);
+ old_contact_rev = e_contact_get_const (old_contact, E_CONTACT_REV);
+
+ if (!contact_rev || !old_contact_rev ||
+ strcmp (contact_rev, old_contact_rev) != 0) {
+ g_set_error (perror, E_DATA_BOOK_ERROR,
+ E_DATA_BOOK_STATUS_OUT_OF_SYNC,
+ _("Tried to modify contact '%s' with out of sync revision"),
+ (gchar *)e_contact_get_const (contact, E_CONTACT_UID));
+
+ status = STATUS_ERROR;
+
+ g_free (id);
+ g_object_unref (contact);
+ g_object_unref (old_contact);
+ break;
+ }
/* Transform incomming photo blobs to uris before storing this to the DB */
status = maybe_transform_vcard_for_photo (bf, old_contact, contact, &local_error);
@@ -929,8 +963,9 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
}
/* update the revision (modified time of contact) */
- set_revision (contact);
+ set_revision (bf, contact);
+ old_contacts = g_slist_prepend (old_contacts, old_contact);
modified_contacts = g_slist_prepend (modified_contacts, contact);
ids = g_slist_prepend (ids, id);
}
@@ -959,6 +994,11 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
}
}
+ if (status != STATUS_ERROR)
+ e_book_backend_file_bump_revision_locked (bf);
+
+ g_rw_lock_writer_unlock (&(bf->priv->lock));
+
if (status != STATUS_ERROR) {
*contacts = g_slist_reverse (modified_contacts);
} else {
@@ -968,8 +1008,6 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
e_util_free_string_slist (ids);
g_slist_free_full (old_contacts, g_object_unref);
-
- e_book_backend_file_bump_revision (bf);
}
static void
@@ -988,9 +1026,12 @@ e_book_backend_file_get_contact (EBookBackendSync *backend,
return;
}
+ g_rw_lock_reader_lock (&(bf->priv->lock));
+
*vcard = e_book_backend_sqlitedb_get_vcard_string (bf->priv->sqlitedb,
SQLITEDB_FOLDER_ID, id,
NULL, NULL, &local_error);
+ g_rw_lock_reader_unlock (&(bf->priv->lock));
if (local_error) {
@@ -1027,10 +1068,12 @@ e_book_backend_file_get_contact_list (EBookBackendSync *backend,
return;
}
+ g_rw_lock_reader_lock (&(bf->priv->lock));
summary_list = e_book_backend_sqlitedb_search (
bf->priv->sqlitedb, SQLITEDB_FOLDER_ID,
query, NULL,
NULL, NULL, &local_error);
+ g_rw_lock_reader_unlock (&(bf->priv->lock));
if (summary_list) {
@@ -1072,10 +1115,12 @@ e_book_backend_file_get_contact_list_uids (EBookBackendSync *backend,
return;
}
+ g_rw_lock_reader_lock (&(bf->priv->lock));
uids = e_book_backend_sqlitedb_search_uids (
bf->priv->sqlitedb,
SQLITEDB_FOLDER_ID,
query, NULL, &local_error);
+ g_rw_lock_reader_unlock (&(bf->priv->lock));
if (uids == NULL && local_error != NULL) {
g_warning ("Failed to fetch contact ids: %s", local_error->message);
@@ -1187,11 +1232,13 @@ book_view_thread (gpointer data)
d (printf ("signalling parent thread\n"));
e_flag_set (closure->running);
+ g_rw_lock_reader_lock (&(bf->priv->lock));
summary_list = e_book_backend_sqlitedb_search (
bf->priv->sqlitedb,
SQLITEDB_FOLDER_ID,
query, fields_of_interest,
NULL, NULL, &local_error);
+ g_rw_lock_reader_unlock (&(bf->priv->lock));
if (!summary_list && local_error != NULL) {
g_warning (G_STRLOC ": Failed to query initial contacts: %s", local_error->message);
@@ -1606,6 +1653,7 @@ e_book_backend_file_finalize (GObject *object)
g_free (priv->photo_dirname);
g_free (priv->revision);
g_rec_mutex_clear (&priv->revision_mutex);
+ g_rw_lock_clear (&(priv->lock));
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_book_backend_file_parent_class)->finalize (object);
@@ -1648,6 +1696,7 @@ e_book_backend_file_init (EBookBackendFile *backend)
backend->priv = E_BOOK_BACKEND_FILE_GET_PRIVATE (backend);
g_rec_mutex_init (&backend->priv->revision_mutex);
+ g_rw_lock_init (&(backend->priv->lock));
g_signal_connect (
backend, "notify::online",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]