[evolution-data-server] addressbook: Improve bulk contact removal code



commit 510d4c84ea9c97777ef9e804e2662bca045424cc
Author: Christophe Dumez <christophe dumez intel com>
Date:   Tue Oct 4 16:26:52 2011 +0300

    addressbook: Improve bulk contact removal code
    
    The patch makes use of Berkeley DB transations in the file backend
    and roll back the transaction in case of error to make the
    behavior consistent with bulk addition.
    
    This patch also makes the webdav backend behave as expected since
    it does not support bulk removal and the implementation was broken.

 addressbook/backends/file/e-book-backend-file.c    |   68 ++++++++++++++------
 .../backends/webdav/e-book-backend-webdav.c        |   48 ++++++++------
 2 files changed, 76 insertions(+), 40 deletions(-)
---
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index da34e5a..bcab4ce 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -438,48 +438,76 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
 	DB               *db = bf->priv->file_db;
-	DBT               id_dbt;
+	DB_ENV           *env = bf->priv->env;
+	DB_TXN           *txn = NULL;
 	gint              db_error;
-	const gchar      *id;
-	GSList           *removed_cards = NULL;
+	GSList           *removed_ids = NULL;
 	const GSList     *l;
-	GError           *error = NULL;
 
 	if (!db) {
 		g_propagate_error (perror, EDB_NOT_OPENED_ERROR);
 		return;
 	}
 
-	for (l = id_list; l; l = l->next) {
+	/* Begin transaction */
+	db_error = env->txn_begin(env, NULL, &txn, 0);
+	if (db_error != 0) {
+		g_warning (G_STRLOC ": env->txn_begin failed with %s", db_strerror (db_error));
+		db_error_to_gerror (db_error, perror);
+		return;
+	}
+
+	for (l = id_list; l != NULL; l = l->next) {
+		const gchar *id;
+		DBT id_dbt;
+
 		id = l->data;
 
 		string_to_dbt (id, &id_dbt);
 
-		db_error = db->del (db, NULL, &id_dbt, 0);
-		if (0 != db_error) {
+		db_error = db->del (db, txn, &id_dbt, 0);
+		if (db_error != 0) {
 			g_warning (G_STRLOC ": db->del failed with %s", db_strerror (db_error));
 			db_error_to_gerror (db_error, perror);
-			continue;
+			/* Abort as soon as a removal fails */
+			break;
 		}
 
-		removed_cards = g_slist_prepend (removed_cards, g_strdup (id));
+		removed_ids = g_slist_prepend (removed_ids, g_strdup (id));
 	}
 
-	/* if we actually removed some, try to sync */
-	if (removed_cards) {
-		db_error = db->sync (db, 0);
-		if (db_error != 0)
-			g_warning (G_STRLOC ": db->sync failed with %s", db_strerror (db_error));
+	if (db_error == 0) {
+		/* Commit transaction */
+		db_error = txn->commit (txn, 0);
+		if (db_error == 0) {
+			/* Flush cache information to disk */
+			if (db->sync (db, 0) != 0) {
+				g_warning ("db->sync failed with %s", db_strerror (db_error));
+			}
+		} else {
+			g_warning (G_STRLOC ": txn->commit failed with %s", db_strerror (db_error));
+			db_error_to_gerror (db_error, perror);
+		}
+	} else {
+		/* Rollback transaction */
+		txn->abort (txn);
 	}
 
-	if (!e_book_backend_sqlitedb_remove_contacts (bf->priv->sqlitedb,
+	if (db_error == 0) {
+		GError *error = NULL;
+		/* Remove from summary as well */
+		if (!e_book_backend_sqlitedb_remove_contacts (bf->priv->sqlitedb,
 						      SQLITEDB_FOLDER_ID,
-						      removed_cards, &error)) {
-		g_warning ("Failed to remove contacts from the summary: %s", error->message);
-		g_error_free (error);
-	}
+						      removed_ids, &error)) {
+			g_warning ("Failed to remove contacts from the summary: %s", error->message);
+			g_error_free (error);
+		}
 
-	*ids = removed_cards;
+		*ids = removed_ids;
+	} else {
+		*ids = NULL;
+		e_util_free_string_slist (removed_ids);
+	}
 }
 
 static void
diff --git a/addressbook/backends/webdav/e-book-backend-webdav.c b/addressbook/backends/webdav/e-book-backend-webdav.c
index 2b0fc0d..d595674 100644
--- a/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -413,8 +413,9 @@ e_book_backend_webdav_remove_contacts (EBookBackend *backend,
 {
 	EBookBackendWebdav        *webdav      = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv        = webdav->priv;
-	GSList                    *deleted_ids = NULL;
-	const GSList              *list;
+	gchar                     *uid         = id_list->data;
+	GSList                     deleted_ids = {NULL,};
+	guint                      status;
 
 	if (!e_backend_get_online (E_BACKEND (backend))) {
 		e_data_book_respond_remove_contacts (book, opid,
@@ -422,28 +423,35 @@ e_book_backend_webdav_remove_contacts (EBookBackend *backend,
 		return;
 	}
 
-	for (list = id_list; list != NULL; list = list->next) {
-		const gchar *uid = (const gchar *) list->data;
-		guint       status;
-
-		status = delete_contact (webdav, uid);
-		if (status != 204) {
-			if (status == 401 || status == 407) {
-				e_data_book_respond_remove_contacts (book, opid, webdav_handle_auth_request (webdav),
-								    deleted_ids);
-			} else {
-				g_warning("DELETE failed with HTTP status %d", status);
-			}
-			continue;
+	/* We make the assumption that the ID list we're passed is always exactly one element long, since we haven't specified "bulk-removes"
+	 * in our static capability list. */
+	if (id_list->next != NULL) {
+		e_data_book_respond_remove_contacts (book, opid,
+		                                     EDB_ERROR_EX (NOT_SUPPORTED,
+		                                     _("The backend does not support bulk removals")),
+		                                     NULL);
+		return;
+	}
+
+	status = delete_contact (webdav, uid);
+	if (status != 204) {
+		if (status == 401 || status == 407) {
+			e_data_book_respond_remove_contacts (book, opid,
+			                                     webdav_handle_auth_request (webdav), NULL);
+		} else {
+			g_warning("DELETE failed with HTTP status %d", status);
+			e_data_book_respond_remove_contacts (book, opid,
+			                                     e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_OTHER_ERROR,
+						                         "DELETE failed with HTTP status %d", status),
+			                                     NULL);
 		}
-		e_book_backend_cache_remove_contact (priv->cache, uid);
-		deleted_ids = g_slist_append (deleted_ids, list->data);
+		return;
 	}
 
-	e_data_book_respond_remove_contacts (book, opid,
-			EDB_ERROR (SUCCESS),  deleted_ids);
+	e_book_backend_cache_remove_contact (priv->cache, uid);
 
-	g_slist_free (deleted_ids);
+	deleted_ids.data = uid;
+	e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (SUCCESS), &deleted_ids);
 }
 
 static void



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