[evolution-data-server] Bug 789147 - [IMAPx] Slow message move with UID MOVE



commit 60231bcf0cf4a108ec4a67443e00c20f2dfd3f20
Author: Milan Crha <mcrha redhat com>
Date:   Thu Nov 2 20:01:08 2017 +0100

    Bug 789147 - [IMAPx] Slow message move with UID MOVE

 src/camel/camel-folder-summary.c                |    1 +
 src/camel/providers/imapx/camel-imapx-command.c |    2 +
 src/camel/providers/imapx/camel-imapx-command.h |    4 +
 src/camel/providers/imapx/camel-imapx-server.c  |  166 +++++++++++------------
 src/camel/providers/imapx/camel-imapx-utils.c   |   34 +++--
 5 files changed, 106 insertions(+), 101 deletions(-)
---
diff --git a/src/camel/camel-folder-summary.c b/src/camel/camel-folder-summary.c
index fb54663..f966e8e 100644
--- a/src/camel/camel-folder-summary.c
+++ b/src/camel/camel-folder-summary.c
@@ -1241,6 +1241,7 @@ camel_folder_summary_get_array (CamelFolderSummary *summary)
 
        camel_folder_summary_lock (summary);
 
+       /* Do not set free_func on the array, it would break IMAPx code */
        res = g_ptr_array_sized_new (g_hash_table_size (summary->priv->uids));
        g_hash_table_foreach (summary->priv->uids, folder_summary_dupe_uids_to_array, res);
 
diff --git a/src/camel/providers/imapx/camel-imapx-command.c b/src/camel/providers/imapx/camel-imapx-command.c
index 74a72ac..e76f38e 100644
--- a/src/camel/providers/imapx/camel-imapx-command.c
+++ b/src/camel/providers/imapx/camel-imapx-command.c
@@ -71,6 +71,7 @@ camel_imapx_command_new (CamelIMAPXServer *is,
        real_ic->public.job_kind = job_kind;
        real_ic->public.status = NULL;
        real_ic->public.completed = FALSE;
+       real_ic->public.copy_move_expunged = NULL;
        g_queue_init (&real_ic->public.parts);
 
        if (format != NULL && *format != '\0') {
@@ -131,6 +132,7 @@ camel_imapx_command_unref (CamelIMAPXCommand *ic)
                /* Free the private stuff. */
 
                g_string_free (real_ic->buffer, TRUE);
+               g_slist_free (real_ic->public.copy_move_expunged);
 
                g_clear_error (&real_ic->error);
 
diff --git a/src/camel/providers/imapx/camel-imapx-command.h b/src/camel/providers/imapx/camel-imapx-command.h
index 836ac45..1300c25 100644
--- a/src/camel/providers/imapx/camel-imapx-command.h
+++ b/src/camel/providers/imapx/camel-imapx-command.h
@@ -74,6 +74,10 @@ struct _CamelIMAPXCommand {
 
        GQueue parts;
        GList *current_part;
+
+       /* list of expunged indexes, not UID-s,
+           received during copy/move operation, in reverse order */
+       GSList *copy_move_expunged;
 };
 
 CamelIMAPXCommand *
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index c1ef70d..ba968db 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -738,56 +738,6 @@ imapx_server_set_connection_timeout (GIOStream *connection,
        return previous_timeout;
 }
 
-static void
-imapx_expunge_uid_from_summary (CamelIMAPXServer *is,
-                                const gchar *uid,
-                                gboolean unsolicited)
-{
-       CamelFolder *folder;
-       CamelIMAPXMailbox *mailbox;
-       guint32 messages;
-
-       mailbox = camel_imapx_server_ref_pending_or_selected (is);
-
-       g_return_if_fail (mailbox != NULL);
-
-       folder = imapx_server_ref_folder (is, mailbox);
-       g_return_if_fail (folder != NULL);
-
-       messages = camel_imapx_mailbox_get_messages (mailbox);
-
-       if (unsolicited && messages > 0)
-               camel_imapx_mailbox_set_messages (mailbox, messages - 1);
-
-       g_return_if_fail (is->priv->changes != NULL);
-
-       camel_folder_summary_remove_uid (camel_folder_get_folder_summary (folder), uid);
-
-       g_mutex_lock (&is->priv->changes_lock);
-
-       camel_folder_change_info_remove_uid (is->priv->changes, uid);
-
-       if (camel_imapx_server_is_in_idle (is)) {
-               CamelFolderChangeInfo *changes;
-
-               changes = is->priv->changes;
-               is->priv->changes = camel_folder_change_info_new ();
-
-               g_mutex_unlock (&is->priv->changes_lock);
-
-               camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
-               imapx_update_store_summary (folder);
-               camel_folder_changed (folder, changes);
-
-               camel_folder_change_info_free (changes);
-       } else {
-               g_mutex_unlock (&is->priv->changes_lock);
-       }
-
-       g_object_unref (folder);
-       g_object_unref (mailbox);
-}
-
 /* untagged response handler functions */
 
 static gboolean
@@ -835,12 +785,11 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
                         GCancellable *cancellable,
                         GError **error)
 {
-       CamelIMAPXMailbox *mailbox;
-       gulong expunge = 0;
+       gulong expunged_idx;
 
        g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
 
-       expunge = is->priv->context->id;
+       expunged_idx = is->priv->context->id;
 
        COMMAND_LOCK (is);
 
@@ -849,33 +798,16 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
            is->priv->current_command->job_kind != CAMEL_IMAPX_JOB_MOVE_MESSAGE)) {
                COMMAND_UNLOCK (is);
 
-               c (is->priv->tagprefix, "ignoring untagged expunge: %lu\n", expunge);
+               c (is->priv->tagprefix, "ignoring untagged expunge: %lu\n", expunged_idx);
                return TRUE;
        }
 
-       COMMAND_UNLOCK (is);
-
-       c (is->priv->tagprefix, "expunged: %lu\n", expunge);
-
-       mailbox = camel_imapx_server_ref_pending_or_selected (is);
-
-       if (mailbox != NULL) {
-               CamelFolder *folder;
-               gchar *uid;
-
-               folder = imapx_server_ref_folder (is, mailbox);
-               g_return_val_if_fail (folder != NULL, FALSE);
-
-               uid = camel_imapx_dup_uid_from_summary_index (folder, expunge - 1);
+       c (is->priv->tagprefix, "expunged: %lu\n", expunged_idx);
 
-               if (uid != NULL)
-                       imapx_expunge_uid_from_summary (is, uid, TRUE);
+       is->priv->current_command->copy_move_expunged = g_slist_prepend (
+               is->priv->current_command->copy_move_expunged, GUINT_TO_POINTER (expunged_idx));
 
-               g_object_unref (folder);
-               g_free (uid);
-       }
-
-       g_clear_object (&mailbox);
+       COMMAND_UNLOCK (is);
 
        return TRUE;
 }
@@ -4296,6 +4228,7 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
        gboolean use_move_command = FALSE;
        CamelIMAPXCommand *ic;
        CamelFolder *folder;
+       CamelFolderChangeInfo *changes = NULL;
        GHashTable *source_infos;
        gboolean remove_junk_flags;
        gboolean success = TRUE;
@@ -4377,6 +4310,61 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                        use_move_command ? _("Error moving messages") : _("Error copying messages"),
                        cancellable, error);
 
+               if (ic->copy_move_expunged) {
+                       CamelFolderSummary *summary;
+
+                       ic->copy_move_expunged = g_slist_reverse (ic->copy_move_expunged);
+
+                       summary = camel_folder_get_folder_summary (folder);
+                       if (summary) {
+                               GPtrArray *array;
+
+                               array = camel_folder_summary_get_array (summary);
+                               if (array) {
+                                       GSList *slink;
+                                       GList *removed_uids = NULL, *llink;
+
+                                       camel_folder_sort_uids (folder, array);
+
+                                       for (slink = ic->copy_move_expunged; slink; slink = g_slist_next 
(slink)) {
+                                               guint expunged_idx = GPOINTER_TO_UINT (slink->data) - 1;
+
+                                               if (expunged_idx < array->len) {
+                                                       const gchar *uid = g_ptr_array_index (array, 
expunged_idx);
+
+                                                       if (uid) {
+                                                               removed_uids = g_list_prepend (removed_uids, 
(gpointer) uid);
+                                                               g_ptr_array_remove_index (array, 
expunged_idx);
+                                                       }
+                                               }
+                                       }
+
+                                       if (removed_uids) {
+                                               CamelFolderSummary *summary;
+
+                                               summary = camel_folder_get_folder_summary (folder);
+
+                                               camel_folder_summary_remove_uids (summary, removed_uids);
+
+                                               for (llink = removed_uids; llink; llink = g_list_next 
(llink)) {
+                                                       const gchar *uid = llink->data;
+
+                                                       if (!changes)
+                                                               changes = camel_folder_change_info_new ();
+
+                                                       camel_folder_change_info_remove_uid (changes, uid);
+
+                                                       g_ptr_array_add (array, (gpointer) uid);
+                                               }
+
+                                               g_list_free (removed_uids);
+                                       }
+
+                                       camel_folder_summary_free_array (array);
+                               }
+                       }
+               }
+
                if (success) {
                        struct _status_info *copyuid_status = is->priv->copyuid_status;
 
@@ -4467,8 +4455,6 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                                CamelFolderChangeInfo *changes = NULL;
                                gint jj;
 
-                               camel_folder_freeze (folder);
-
                                for (jj = last_index; jj < ii; jj++) {
                                        const gchar *uid = uids->pdata[jj];
 
@@ -4483,17 +4469,6 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                                                }
                                        }
                                }
-
-                               if (changes && camel_folder_change_info_changed (changes)) {
-                                       camel_folder_summary_touch (camel_folder_get_folder_summary (folder));
-                                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), 
NULL);
-                                       camel_folder_changed (folder, changes);
-                               }
-
-                               camel_folder_thaw (folder);
-
-                               if (changes)
-                                       camel_folder_change_info_free (changes);
                        }
                }
 
@@ -4501,6 +4476,21 @@ camel_imapx_server_copy_message_sync (CamelIMAPXServer *is,
                is->priv->copyuid_status = NULL;
 
                camel_imapx_command_unref (ic);
+
+               camel_operation_progress (cancellable, ii * 100 / data_uids->len);
+       }
+
+       if (changes) {
+               if (camel_folder_change_info_changed (changes)) {
+                       camel_folder_summary_touch (camel_folder_get_folder_summary (folder));
+                       camel_folder_summary_save (camel_folder_get_folder_summary (folder), NULL);
+
+                       imapx_update_store_summary (folder);
+
+                       camel_folder_changed (folder, changes);
+               }
+
+               camel_folder_change_info_free (changes);
        }
 
        g_hash_table_destroy (source_infos);
diff --git a/src/camel/providers/imapx/camel-imapx-utils.c b/src/camel/providers/imapx/camel-imapx-utils.c
index 478bf53..cc861d5 100644
--- a/src/camel/providers/imapx/camel-imapx-utils.c
+++ b/src/camel/providers/imapx/camel-imapx-utils.c
@@ -2653,6 +2653,7 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
        CamelIMAPXFolder *imapx_folder;
        CamelIMAPXSummary *imapx_summary;
        CamelIMAPXMailbox *mailbox;
+       GPtrArray *summary_array;
        guint64 last_known_uidvalidity;
        guint64 last_known_modsequence;
        guint32 last_known_message_cnt;
@@ -2667,9 +2668,16 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
        imapx_folder = CAMEL_IMAPX_FOLDER (folder);
        imapx_summary = CAMEL_IMAPX_SUMMARY (camel_folder_get_folder_summary (folder));
 
+       summary_array = camel_folder_summary_get_array (CAMEL_FOLDER_SUMMARY (imapx_summary));
+       g_return_val_if_fail (summary_array != NULL, FALSE);
+
+       camel_folder_sort_uids (folder, summary_array);
+
        mailbox = camel_imapx_folder_ref_mailbox (imapx_folder);
-       if (!mailbox)
+       if (!mailbox) {
+               camel_folder_summary_free_array (summary_array);
                return FALSE;
+       }
 
        last_known_uidvalidity = camel_imapx_mailbox_get_uidvalidity (mailbox);
        last_known_modsequence = imapx_summary->modseq;
@@ -2682,16 +2690,16 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
 
        if (summary_total > 0) {
                guint last = summary_total - 1;
-               gchar *begin, *end;
 
-               begin = camel_imapx_dup_uid_from_summary_index (folder, 0);
-               end = camel_imapx_dup_uid_from_summary_index (folder, last);
+               if (0 < summary_array->len && last < summary_array->len) {
+                       const gchar *begin, *end;
 
-               if (begin != NULL && end != NULL)
-                       known_uid_set = g_strconcat (begin, ":", end, NULL);
+                       begin = g_ptr_array_index (summary_array, 0);
+                       end = g_ptr_array_index (summary_array, last);
 
-               g_free (begin);
-               g_free (end);
+                       if (begin && end)
+                               known_uid_set = g_strconcat (begin, ":", end, NULL);
+               }
        }
 
        /* Make sure we have valid QRESYNC arguments. */
@@ -2736,7 +2744,7 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
                do {
                        guint32 summary_index;
                        gchar buf[10];
-                       gchar *uid;
+                       const gchar *uid;
 
                        ii = MIN (ii * 3, sequence_limit);
                        summary_index = sequence_limit - ii;
@@ -2754,12 +2762,12 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
                                "%" G_GUINT32_FORMAT,
                                summary_index + 1);
 
-                       uid = camel_imapx_dup_uid_from_summary_index (
-                               folder, summary_index);
+                       uid = NULL;
+                       if (summary_index < summary_array->len)
+                               uid = g_ptr_array_index (summary_array, summary_index);
                        if (uid != NULL) {
                                g_string_prepend (seqs, buf);
                                g_string_prepend (uids, uid);
-                               g_free (uid);
                        }
                } while (ii < sequence_limit);
 
@@ -2776,7 +2784,7 @@ camel_imapx_command_add_qresync_parameter (CamelIMAPXCommand *ic,
 
 exit:
        g_free (known_uid_set);
-
+       camel_folder_summary_free_array (summary_array);
        g_object_unref (mailbox);
 
        return parameter_added;


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