[geary/wip/778276-better-flag-updates: 11/25] Modernise EmailPrefetcher a bit.



commit 724202d112c5ba40359fb0c6eefe811418efe750
Author: Michael James Gratton <mike vee net>
Date:   Mon Nov 20 20:19:57 2017 +1100

    Modernise EmailPrefetcher a bit.
    
    Not strictly necessary for this bug, but may as well since we're here.
    
    * src/engine/imap-engine/imap-engine-email-prefetcher.vala
      (EmailPrefetcher): Use a TimeoutManager and an explicit open and close
      call from MinimalFolder.

 .../imap-engine/imap-engine-email-prefetcher.vala  |  107 ++++++++-----------
 .../imap-engine/imap-engine-minimal-folder.vala    |   27 +++--
 2 files changed, 61 insertions(+), 73 deletions(-)
---
diff --git a/src/engine/imap-engine/imap-engine-email-prefetcher.vala 
b/src/engine/imap-engine/imap-engine-email-prefetcher.vala
index 9a072fd..c46628e 100644
--- a/src/engine/imap-engine/imap-engine-email-prefetcher.vala
+++ b/src/engine/imap-engine/imap-engine-email-prefetcher.vala
@@ -21,60 +21,49 @@ private class Geary.ImapEngine.EmailPrefetcher : Object {
         default = new Nonblocking.CountingSemaphore(null); }
     
     private unowned ImapEngine.MinimalFolder folder;
-    private int start_delay_sec;
     private Nonblocking.Mutex mutex = new Nonblocking.Mutex();
     private Gee.TreeSet<Geary.Email> prefetch_emails = new Gee.TreeSet<Geary.Email>(
         Email.compare_recv_date_descending);
-    private uint schedule_id = 0;
-    private Cancellable cancellable = new Cancellable();
-    
+    private TimeoutManager prefetch_timer;
+    private Cancellable? cancellable = null;
+
+
     public EmailPrefetcher(ImapEngine.MinimalFolder folder, int start_delay_sec = PREFETCH_DELAY_SEC) {
-        assert(start_delay_sec > 0);
-        
         this.folder = folder;
-        this.start_delay_sec = start_delay_sec;
-        
-        folder.opened.connect(on_opened);
-        folder.closed.connect(on_closed);
-        folder.email_locally_appended.connect(on_local_expansion);
-        folder.email_locally_inserted.connect(on_local_expansion);
-    }
-    
-    ~EmailPrefetcher() {
-        if (schedule_id != 0)
-            message("Warning: Geary.EmailPrefetcher destroyed before folder closed");
-        
-        folder.opened.disconnect(on_opened);
-        folder.closed.disconnect(on_closed);
-        folder.email_locally_appended.disconnect(on_local_expansion);
-        folder.email_locally_inserted.disconnect(on_local_expansion);
+
+        if (start_delay_sec <= 0) {
+            start_delay_sec = PREFETCH_DELAY_SEC;
+        }
+
+        this.prefetch_timer = new TimeoutManager.seconds(
+            start_delay_sec, () => { do_prefetch_async.begin(); }
+        );
     }
-    
-    private void on_opened(Geary.Folder.OpenState open_state) {
-        if (open_state != Geary.Folder.OpenState.BOTH)
-            return;
-        
-        cancellable = new Cancellable();
-        
+
+    public void open() {
+        this.cancellable = new Cancellable();
+
+        this.folder.email_locally_appended.connect(on_local_expansion);
+        this.folder.email_locally_inserted.connect(on_local_expansion);
+
         // acquire here since .begin() only schedules for later
-        active_sem.acquire();
-        do_prepare_all_local_async.begin();
+        this.active_sem.acquire();
+        this.do_prepare_all_local_async.begin();
     }
-    
-    private void on_closed(Geary.Folder.CloseReason close_reason) {
-        // cancel for any reason ... this will be called multiple times, but the following operations
-        // can be executed any number of times and still get the desired results
-        cancellable.cancel();
-        
-        if (schedule_id != 0) {
-            Source.remove(schedule_id);
-            schedule_id = 0;
-            
-            // since an acquire was done when scheduled, need to notify when cancelled
-            active_sem.blind_notify();
+
+    public void close() {
+        if (this.prefetch_timer.is_running) {
+            this.prefetch_timer.reset();
+            // since an acquire was done when scheduled, need to
+            // notify when cancelled
+            this.active_sem.blind_notify();
         }
+
+        this.folder.email_locally_appended.disconnect(on_local_expansion);
+        this.folder.email_locally_inserted.disconnect(on_local_expansion);
+        this.cancellable = null;
     }
-    
+
     private void on_local_expansion(Gee.Collection<Geary.EmailIdentifier> ids) {
         // it's possible to be notified of an append prior to remote open; don't prefetch until
         // that occurs
@@ -85,30 +74,24 @@ private class Geary.ImapEngine.EmailPrefetcher : Object {
         active_sem.acquire();
         do_prepare_new_async.begin(ids);
     }
-    
+
     // emails should include PROPERTIES
     private void schedule_prefetch(Gee.Collection<Geary.Email>? emails) {
         if (emails == null || emails.size == 0)
             return;
-        
-        debug("%s: scheduling %d emails for prefetching", folder.to_string(), emails.size);
-        
-        prefetch_emails.add_all(emails);
-        
+
+        debug("%s: scheduling %d emails for prefetching",
+              folder.to_string(), emails.size);
+        this.prefetch_emails.add_all(emails);
+
         // only increment active state if not rescheduling
-        if (schedule_id != 0)
-            Source.remove(schedule_id);
-        else
-            active_sem.acquire();
-        
-        schedule_id = Timeout.add_seconds(start_delay_sec, () => {
-            schedule_id = 0;
-            do_prefetch_async.begin();
-            
-            return false;
-        });
+        if (!this.prefetch_timer.is_running) {
+            this.active_sem.acquire();
+        }
+
+        this.prefetch_timer.start();
     }
-    
+
     private async void do_prepare_all_local_async() {
         Gee.List<Geary.Email>? list = null;
         try {
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala 
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index a7423f3..5b90256 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -107,16 +107,15 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         );
         this.local = local;
         this.local_folder = local_folder;
-        _special_folder_type = special_folder_type;
-        _properties.add(local_folder.get_properties());
-        replay_queue = new ReplayQueue(this);
-        
+        this.local_folder.email_complete.connect(on_email_complete);
+
         email_flag_watcher = new EmailFlagWatcher(this);
         email_flag_watcher.email_flags_changed.connect(on_email_flags_changed);
-        
-        email_prefetcher = new EmailPrefetcher(this);
-        
-        local_folder.email_complete.connect(on_email_complete);
+
+        this._special_folder_type = special_folder_type;
+        this._properties.add(local_folder.get_properties());
+        this.replay_queue = new ReplayQueue(this);
+        this.email_prefetcher = new EmailPrefetcher(this);
 
         // Notify now to ensure that wait_for_close_async does not
         // block if never opened.
@@ -798,7 +797,10 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         }
         
         _properties.add(remote_folder.properties);
-        
+
+        // Now that the remote is open, update messages.
+        this.email_prefetcher.open();
+
         // notify any subscribers with similar information
         notify_opened(Geary.Folder.OpenState.BOTH, remote_count);
     }
@@ -824,10 +826,13 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
         // decrement open_count and, if zero, continue closing Folder
         if (open_count == 0 || --open_count > 0)
             return false;
-        
+
+        // Close the prefetcher early so it stops using the remote ASAP
+        this.email_prefetcher.close();
+
         if (remote_folder != null)
             _properties.remove(remote_folder.properties);
-        
+
         // block anyone from wait_until_open_async(), as this is no longer open
         remote_semaphore.reset();
         


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