[geary/gnome-43] engine: Cancel any remote folders update before marking a message



commit 0e6846cbf5d6d45f5b7f636f7a96119849182fd7
Author: Cédric Bellegarde <cedric bellegarde adishatz org>
Date:   Thu Sep 22 11:49:05 2022 +0200

    engine: Cancel any remote folders update before marking a message
    
    When marking a message, a race condition can happen:
    - A remote folders update is already running
    - We mark the message locally and replay it remotely
    - The previous remote update result restores invalid values locally

 src/client/application/application-controller.vala   |  2 ++
 src/engine/api/geary-account.vala                    |  5 +++++
 .../imap-engine/imap-engine-account-processor.vala   | 20 ++++++++++++++++++++
 .../imap-engine/imap-engine-generic-account.vala     |  9 +++++++++
 test/mock/mock-account.vala                          |  7 +++++++
 5 files changed, 43 insertions(+)
---
diff --git a/src/client/application/application-controller.vala 
b/src/client/application/application-controller.vala
index e6c5dfe46..1339a0342 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -2002,6 +2002,8 @@ private class Application.MarkEmailCommand : TrivialCommand, EmailCommand {
 
     public override async void execute(GLib.Cancellable? cancellable)
         throws GLib.Error {
+        this.location.account.cancel_remote_update();
+
         yield this.store.mark_email_async(
             this.email, this.to_add, this.to_remove, cancellable
         );
diff --git a/src/engine/api/geary-account.vala b/src/engine/api/geary-account.vala
index 787fcbad9..4811f1051 100644
--- a/src/engine/api/geary-account.vala
+++ b/src/engine/api/geary-account.vala
@@ -309,6 +309,11 @@ public abstract class Geary.Account : BaseObject, Logging.Source {
      */
     public abstract bool is_open();
 
+    /**
+     * Cancel any running/pending remote update for this {@link Account}.
+     */
+    public abstract void cancel_remote_update();
+
     /**
      * Rebuild the local data stores for this {@link Account}.
      *
diff --git a/src/engine/imap-engine/imap-engine-account-processor.vala 
b/src/engine/imap-engine/imap-engine-account-processor.vala
index 0e5cc2f02..1fc08f9d9 100644
--- a/src/engine/imap-engine/imap-engine-account-processor.vala
+++ b/src/engine/imap-engine/imap-engine-account-processor.vala
@@ -78,6 +78,26 @@ internal class Geary.ImapEngine.AccountProcessor :
         this.queue.revoke(op);
     }
 
+    // Revokes all operations with the given type; returns true if at least one
+    // operation with the given type was found
+    public bool dequeue_by_type(GLib.Type type) {
+        bool found = false;
+        if (this.current_op != null &&
+            this.current_op.get_type() == type &&
+            this.op_cancellable != null) {
+            this.op_cancellable.cancel();
+            this.op_cancellable = null;
+            found = true;
+        }
+        this.queue.revoke_matching((op) => {
+            if (op.get_type() == type) {
+                found = true;
+            }
+            return op.get_type() == type;
+        });
+        return found;
+    }
+
     public void stop() {
         this.is_running = false;
         if (this.op_cancellable != null) {
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala 
b/src/engine/imap-engine/imap-engine-generic-account.vala
index a459274b6..2db971640 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -229,6 +229,15 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
         return open;
     }
 
+    /** {@inheritDoc} */
+    public override void cancel_remote_update() {
+        // Cancel and update again
+        if (this.processor.dequeue_by_type(typeof(UpdateRemoteFolders))) {
+            debug("Cancelled a remote update! Updating again...\n");
+            update_remote_folders(false);
+        }
+    }
+
     public override async void rebuild_async(GLib.Cancellable? cancellable = null)
         throws GLib.Error {
         if (this.open) {
diff --git a/test/mock/mock-account.vala b/test/mock/mock-account.vala
index f617f9693..ceee35ef6 100644
--- a/test/mock/mock-account.vala
+++ b/test/mock/mock-account.vala
@@ -58,6 +58,13 @@ public class Mock.Account : Geary.Account,
         }
     }
 
+    public override void cancel_remote_update() {
+        try {
+            void_call("cancel_remote_update", {});
+        } catch (GLib.Error err) {
+        }
+    }
+
     public override async void rebuild_async(GLib.Cancellable? cancellable = null)
         throws GLib.Error {
         void_call("rebuild_async", { cancellable });


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