[evolution-data-server/openismus-work-master: 5/13] EBookBackendFile: Avoid lost data in contact modifications



commit bd9bb0760de4af61bf76ed849056f0585d893eaa
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 |  101 ++++++++++++++++-------
 1 files changed, 72 insertions(+), 29 deletions(-)
---
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index b86384c..9a28a8b 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -69,7 +69,8 @@ struct _EBookBackendFilePrivate {
 	gchar     *photo_dirname;
 	gchar     *revision;
 	gint       rev_counter;
-	GRecMutex  revision_mutex;
+	gboolean   revision_guards;
+	GRWLock    lock;
 
 	EBookBackendSqliteDB *sqlitedb;
 };
@@ -617,8 +618,6 @@ e_book_backend_file_bump_revision (EBookBackendFile *bf)
 {
 	GError *error = NULL;
 
-	g_rec_mutex_lock (&bf->priv->revision_mutex);
-
 	g_free (bf->priv->revision);
 	bf->priv->revision = e_book_backend_file_new_revision (bf);
 
@@ -635,8 +634,6 @@ e_book_backend_file_bump_revision (EBookBackendFile *bf)
 	e_book_backend_notify_property_changed (E_BOOK_BACKEND (bf),
 						BOOK_BACKEND_PROPERTY_REVISION,
 						bf->priv->revision);
-
-	g_rec_mutex_unlock (&bf->priv->revision_mutex);
 }
 
 static void
@@ -644,7 +641,7 @@ e_book_backend_file_load_revision (EBookBackendFile *bf)
 {
 	GError *error = NULL;
 
-	g_rec_mutex_lock (&bf->priv->revision_mutex);
+	g_rw_lock_writer_lock (&(bf->priv->lock));
 
 	if (!e_book_backend_sqlitedb_get_revision (bf->priv->sqlitedb,
 						   SQLITEDB_FOLDER_ID,
@@ -658,22 +655,19 @@ e_book_backend_file_load_revision (EBookBackendFile *bf)
 		e_book_backend_file_bump_revision (bf);
 	}
 
-	g_rec_mutex_unlock (&bf->priv->revision_mutex);
+	g_rw_lock_writer_unlock (&(bf->priv->lock));
 }
 
+
 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 +717,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 +784,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);
 	}
+
+	g_rw_lock_writer_unlock (&(bf->priv->lock));
 }
 
 static void
@@ -809,6 +807,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 +855,16 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 			g_propagate_error (perror, local_error);
 		}
 
+		e_book_backend_file_bump_revision (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 +888,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 +920,26 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
 			g_object_unref (contact);
 			break;
 		}
-		old_contacts = g_slist_prepend (old_contacts, old_contact);
+
+		if (bf->priv->revision_guards) {
+			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 +954,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 +985,11 @@ e_book_backend_file_modify_contacts (EBookBackendSync *backend,
 		}
 	}
 
+	if (status != STATUS_ERROR)
+		e_book_backend_file_bump_revision (bf);
+
+	g_rw_lock_writer_unlock (&(bf->priv->lock));
+
 	if (status != STATUS_ERROR) {
 		*contacts = g_slist_reverse (modified_contacts);
 	} else {
@@ -968,8 +999,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 +1017,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 +1059,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 +1106,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 +1223,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);
@@ -1278,6 +1316,7 @@ e_book_backend_file_open (EBookBackendSync *backend,
 	GError           *local_error = NULL;
 	gboolean          populated;
 	ESourceBackendSummarySetup *setup;
+	ESourceRevisionGuards *guards;
 
 	source = e_backend_get_source (E_BACKEND (backend));
 	registry = e_book_backend_get_registry (E_BOOK_BACKEND (backend));
@@ -1287,7 +1326,11 @@ e_book_backend_file_open (EBookBackendSync *backend,
 	backup   = g_build_filename (dirname, "addressbook.db.old", NULL);
 
 	g_type_ensure (E_TYPE_SOURCE_BACKEND_SUMMARY_SETUP);
+	g_type_ensure (E_TYPE_SOURCE_REVISION_GUARDS);
 	setup = e_source_get_extension (source, E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP);
+	guards = e_source_get_extension (source, E_SOURCE_EXTENSION_REVISION_GUARDS);
+
+	bf->priv->revision_guards = e_source_revision_guards_get_enabled (guards);
 
 	/* The old BDB exists, lets migrate that to sqlite right away
 	 */
@@ -1461,11 +1504,11 @@ e_book_backend_file_open (EBookBackendSync *backend,
 	e_book_backend_notify_readonly (E_BOOK_BACKEND (backend), FALSE);
 	e_book_backend_notify_opened (E_BOOK_BACKEND (backend), NULL /* Success */);
 
-	g_rec_mutex_lock (&bf->priv->revision_mutex);
+	g_rw_lock_reader_lock (&(bf->priv->lock));
 	e_book_backend_notify_property_changed (E_BOOK_BACKEND (backend),
 						BOOK_BACKEND_PROPERTY_REVISION,
 						bf->priv->revision);
-	g_rec_mutex_unlock (&bf->priv->revision_mutex);
+	g_rw_lock_reader_unlock (&(bf->priv->lock));
 }
 
 static gboolean
@@ -1498,9 +1541,9 @@ e_book_backend_file_get_backend_property (EBookBackendSync *backend,
 		*prop_value = e_data_book_string_slist_to_comma_string (fields);
 		g_slist_free (fields);
 	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REVISION)) {
-		g_rec_mutex_lock (&bf->priv->revision_mutex);
+		g_rw_lock_reader_lock (&(bf->priv->lock));
 		*prop_value = g_strdup (bf->priv->revision);
-		g_rec_mutex_unlock (&bf->priv->revision_mutex);
+		g_rw_lock_reader_unlock (&(bf->priv->lock));
 	} else {
 		processed = FALSE;
 	}
@@ -1605,7 +1648,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);
@@ -1647,7 +1690,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]