[geary/wip/cx-reestablish: 8/8] Prevent concurrent open and closes of remote folder



commit 22097a0120b1f9a3eceb33d06cf8e32b743d66ec
Author: Jim Nelson <jim yorba org>
Date:   Fri Jan 16 10:50:07 2015 -0800

    Prevent concurrent open and closes of remote folder

 .../imap-engine/imap-engine-minimal-folder.vala    |   45 ++++++++++++++++++++
 1 files changed, 45 insertions(+), 0 deletions(-)
---
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala 
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index 11c262e..d78d737 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -48,6 +48,8 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
     private int remote_count = -1;
     private uint open_remote_timer_id = 0;
     private int reestablish_delay_msec = DEFAULT_REESTABLISH_DELAY_MSEC;
+    private Nonblocking.Mutex open_mutex = new Nonblocking.Mutex();
+    private Nonblocking.Mutex close_mutex = new Nonblocking.Mutex();
     
     public MinimalFolder(GenericAccount account, Imap.Account remote, ImapDB.Account local,
         ImapDB.Folder local_folder, SpecialFolderType special_folder_type) {
@@ -570,7 +572,29 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         open_remote_timer_id = 0;
     }
     
+    // Open the remote connection using a Mutex to prevent concurrency.
+    //
+    // start_remote_open_now() *should* prevent more than one open from occurring at the same time,
+    // but it's still wise to use a nonblocking primitive to prevent it if that does occur to at
+    // least keep Folder state cogent.
     private async void open_remote_async(Cancellable? cancellable) {
+        int token;
+        try {
+            token = yield open_mutex.claim_async(cancellable);
+        } catch (Error err) {
+            return;
+        }
+        
+        yield open_remote_locked_async(cancellable);
+        
+        try {
+            open_mutex.release(ref token);
+        } catch (Error err) {
+        }
+    }
+    
+    // Should only be called when open_mutex is locked, i.e. use open_remote_async()
+    private async void open_remote_locked_async(Cancellable? cancellable) {
         // watch for folder closing before this call got a chance to execute
         if (open_count == 0)
             return;
@@ -747,10 +771,31 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
             cancellable);
     }
     
+    // Close the remote connection and, if open_count is zero, the Folder itself.  A Mutex is used
+    // to prevent concurrency.
+    //
     // NOTE: This bypasses open_count and forces the Folder closed, reestablishing a connection if
     // open_count is greater than zero
     internal async void close_internal_async(Folder.CloseReason local_reason, Folder.CloseReason 
remote_reason,
         bool flush_pending, Cancellable? cancellable) {
+        int token;
+        try {
+            token = yield close_mutex.claim_async(cancellable);
+        } catch (Error err) {
+            return;
+        }
+        
+        yield close_internal_locked_async(local_reason, remote_reason, flush_pending, cancellable);
+        
+        try {
+            close_mutex.release(ref token);
+        } catch (Error err) {
+        }
+    }
+    
+    // Should only be called when close_mutex is locked, i.e. use close_internal_async()
+    private async void close_internal_locked_async(Folder.CloseReason local_reason,
+        Folder.CloseReason remote_reason, bool flush_pending, Cancellable? cancellable) {
         cancel_remote_open_timer();
         
         // only flushing pending ReplayOperations if this is a "clean" close, not forced due to


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