[geary/wip/285-cancelled-commands] Ensure that cancelled commands throw a cancelled error, not a timeout



commit 2c8a232f97dfc4b3a50a36af9b6a6ea3a1795f0c
Author: Michael Gratton <mike vee net>
Date:   Thu Mar 7 11:24:06 2019 +1100

    Ensure that cancelled commands throw a cancelled error, not a timeout
    
    Commands that were cancelled, e.g. because the network connection was
    lost and so commands in progress were backed out, were throwing
    timeout errors to callers of wait_until_complete since they had received
    no response. This was causing e.g. account operations to fail, and the
    alleged timeout be reported as problem in the UI.
    
    This takes note of whether a command was cancelled and throws an
    appropriate error in wait_until_complete if so. Callers can then clean
    up and choose to be more circumspect in their error reporting.
    
    Fixes #285

 src/engine/imap/command/imap-command.vala | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)
---
diff --git a/src/engine/imap/command/imap-command.vala b/src/engine/imap/command/imap-command.vala
index dd6eb18d..76964b17 100644
--- a/src/engine/imap/command/imap-command.vala
+++ b/src/engine/imap/command/imap-command.vala
@@ -79,6 +79,7 @@ public class Geary.Imap.Command : BaseObject {
         new Geary.Nonblocking.Semaphore();
 
     private bool timed_out = false;
+    private bool cancelled = false;
 
     private Geary.Nonblocking.Spinlock? literal_spinlock = null;
     private GLib.Cancellable? literal_cancellable = null;
@@ -209,10 +210,12 @@ public class Geary.Imap.Command : BaseObject {
      * Cancels this command's execution.
      *
      * When this method is called, all locks will be released,
-     * including {@link wait_until_complete}.
+     * including {@link wait_until_complete}, which will then throw a
+     * `GLib.IOError.CANCELLED` error.
      */
     internal virtual void cancel_command() {
         cancel_send();
+        this.cancelled = true;
         this.response_timer.reset();
         this.complete_lock.blind_notify();
     }
@@ -220,17 +223,23 @@ public class Geary.Imap.Command : BaseObject {
     /**
      * Yields until the command has been completed or cancelled.
      *
-     * Throws an error if cancelled, if the command is cancelled, or
-     * if the command's response was bad.
+     * Throws an error if the command or the cancellable argument is
+     * cancelled, if the command timed out, or if the command's
+     * response was bad.
      */
     public async void wait_until_complete(GLib.Cancellable cancellable)
         throws GLib.Error {
         yield this.complete_lock.wait_async(cancellable);
 
+        if (this.cancelled) {
+            throw new GLib.IOError.CANCELLED(
+                "%s: Command was cancelled", to_brief_string()
+            );
+        }
+
         if (this.timed_out) {
             throw new ImapError.TIMED_OUT(
-                "%s: No command response was received",
-                to_brief_string()
+                "%s: Command timed out", to_brief_string()
             );
         }
 


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