Bug 676403 - imapx: Syncing folder after server-side deletion of many messages is...
authorDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 19 May 2012 23:40:53 +0000 (00:40 +0100)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Mon, 21 May 2012 12:19:41 +0000 (13:19 +0100)
Fix this by introducing a new camel_folder_change_info_remove_uids()
function, and using it for the 'vanished' code. This reduces the time taken
from about 40ms per message, to about 50µs.

camel/camel-folder-summary.c
camel/camel-folder-summary.h
camel/camel-imapx-server.c

index 43c7c98..8dad22c 100644 (file)
@@ -3232,6 +3232,54 @@ camel_folder_summary_remove_uid (CamelFolderSummary *summary,
        return res;
 }
 
+/**
+ * camel_folder_summary_remove_uids:
+ * @summary: a #CamelFolderSummary object
+ * @uids: a GList of uids
+ *
+ * Remove a specific info record from the summary, by @uid.
+ *
+ * Returns: Whether the @uid was found and removed from the @summary.
+ *
+ * Since: 3.4.3
+ **/
+gboolean
+camel_folder_summary_remove_uids (CamelFolderSummary *summary,
+                                 GList *uids)
+{
+       CamelStore *parent_store;
+       const gchar *full_name;
+       GList *l;
+       gboolean res = TRUE;
+
+       g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
+       g_return_val_if_fail (uids != NULL, FALSE);
+
+       camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+       for (l = g_list_first(uids); l; l = g_list_next(l)) {
+               gpointer ptr_uid = NULL, ptr_flags = NULL;
+               if (g_hash_table_lookup_extended (summary->priv->uids, l->data, &ptr_uid, &ptr_flags)) {
+                       const gchar *uid_copy = camel_pstring_strdup (l->data);
+                       folder_summary_update_counts_by_flags (summary, GPOINTER_TO_UINT (ptr_flags), TRUE);
+                       g_hash_table_remove (summary->priv->uids, uid_copy);
+                       g_hash_table_remove (summary->priv->loaded_infos, uid_copy);
+                       camel_pstring_free (uid_copy);
+               }
+       }
+
+       full_name = camel_folder_get_full_name (summary->priv->folder);
+       parent_store = camel_folder_get_parent_store (summary->priv->folder);
+       if (camel_db_delete_uids (parent_store->cdb_w, full_name, uids, NULL) != 0)
+               res = FALSE;
+
+       camel_folder_summary_touch (summary);
+       camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+       return res;
+}
+
+
 static struct _node *
 my_list_append (struct _node **list,
                 struct _node *n)
index cb66520..dacacab 100644 (file)
@@ -402,6 +402,8 @@ gboolean            camel_folder_summary_remove     (CamelFolderSummary *summary,
 
 gboolean               camel_folder_summary_remove_uid (CamelFolderSummary *summary,
                                                         const gchar *uid);
+gboolean               camel_folder_summary_remove_uids(CamelFolderSummary *summary,
+                                                        GList *uids);
 
 /* remove all items */
 gboolean               camel_folder_summary_clear      (CamelFolderSummary *summary,
index 5afd519..a527aae 100644 (file)
@@ -1140,6 +1140,7 @@ imapx_untagged (CamelIMAPXServer *is,
        }
        case IMAPX_VANISHED: {
                GPtrArray *uids;
+               GList *uid_list = NULL;
                gboolean unsolicited = TRUE;
                gint i;
                guint len;
@@ -1163,11 +1164,30 @@ imapx_untagged (CamelIMAPXServer *is,
                uids = imapx_parse_uids (is->stream, cancellable, error);
                if (uids == NULL)
                        return FALSE;
+
+               if (unsolicited) {
+                       CamelIMAPXFolder *ifolder = (CamelIMAPXFolder *)is->select_folder;
+
+                       if (ifolder->exists_on_server < uids->len) {
+                               c(is->tagprefix, "Error: exists_on_folder %d is fewer than vanished %d\n",
+                                 ifolder->exists_on_server, uids->len);
+                               ifolder->exists_on_server = 0;
+                       } else
+                               ifolder->exists_on_server -= uids->len;
+               }
+               if (is->changes == NULL)
+                       is->changes = camel_folder_change_info_new ();
+
                for (i = 0; i < uids->len; i++) {
                        gchar *uid = g_strdup_printf("%u", GPOINTER_TO_UINT(g_ptr_array_index (uids, i)));
+
                        c(is->tagprefix, "vanished: %s\n", uid);
-                       imapx_expunge_uid_from_summary (is, uid, unsolicited);
+
+                       uid_list = g_list_append(uid_list, uid);
+                       camel_folder_change_info_remove_uid (is->changes, uid);
                }
+               camel_folder_summary_remove_uids(is->select_folder->summary, uid_list);
+               is->expunged = g_list_concat(is->expunged, uid_list);
                g_ptr_array_free (uids, FALSE);
                break;
        }
@@ -3940,10 +3960,10 @@ imapx_job_scan_changes_done (CamelIMAPXServer *is,
                        gchar *uid = (gchar *) l->data;
 
                        camel_folder_change_info_remove_uid (data->changes, uid);
-                       camel_folder_summary_remove_uid (s, uid);
                }
 
                if (removed != NULL) {
+                       camel_folder_summary_remove_uids (s, removed);
                        camel_folder_summary_touch (s);
 
                        g_list_free_full (removed, (GDestroyNotify) g_free);