[geary/wip/3.32-avatars: 35/40] Add basic Folks individual and pixbuf cache to AvatarStore



commit 1ebd14e77a7a4cab1bbbd8888696c502791c2745
Author: Michael Gratton <mike vee net>
Date:   Wed Feb 27 01:07:01 2019 +1100

    Add basic Folks individual and pixbuf cache to AvatarStore

 .../application/application-avatar-store.vala      | 95 +++++++++++++++++++---
 1 file changed, 83 insertions(+), 12 deletions(-)
---
diff --git a/src/client/application/application-avatar-store.vala 
b/src/client/application/application-avatar-store.vala
index 2ce2f2f8..16a14085 100644
--- a/src/client/application/application-avatar-store.vala
+++ b/src/client/application/application-avatar-store.vala
@@ -12,7 +12,57 @@
 public class Application.AvatarStore : Geary.BaseObject {
 
 
+    // Max age is low since we really only want to cache between
+    // conversation loads
+    private const int64 MAX_CACHE_AGE_US = 5 * 1000 * 1000;
+
+    private class CacheEntry {
+
+        // Store nulls so we can also cache avatars not found
+        public Folks.Individual? individual;
+
+        public int64 last_used;
+
+        private Gee.List<Gdk.Pixbuf> pixbufs = new Gee.LinkedList<Gdk.Pixbuf>();
+
+        public CacheEntry(Folks.Individual? individual, int64 last_used) {
+            this.individual = individual;
+            this.last_used = last_used;
+        }
+
+        public async Gdk.Pixbuf? load(int pixel_size,
+                                      GLib.Cancellable cancellable)
+            throws GLib.Error {
+            Gdk.Pixbuf? pixbuf = null;
+            foreach (Gdk.Pixbuf cached in this.pixbufs) {
+                if ((cached.height == pixel_size && cached.width >= pixel_size) ||
+                    (cached.width == pixel_size && cached.height >= pixel_size)) {
+                    pixbuf = cached;
+                    break;
+                }
+            }
+
+            if (pixbuf == null) {
+                Folks.Individual? individual = this.individual;
+                if (individual != null && individual.avatar != null) {
+                    GLib.InputStream data = yield individual.avatar.load_async(
+                        pixel_size, cancellable
+                    );
+                    pixbuf = yield new Gdk.Pixbuf.from_stream_at_scale_async(
+                        data, pixel_size, pixel_size, true, cancellable
+                    );
+                    this.pixbufs.add(pixbuf);
+                }
+            }
+            return pixbuf;
+        }
+
+    }
+
+
     private Folks.IndividualAggregator individuals;
+    private Gee.Map<string,CacheEntry?> cache =
+        new Gee.HashMap<string,CacheEntry?>();
 
 
     public AvatarStore(Folks.IndividualAggregator individuals) {
@@ -20,17 +70,46 @@ public class Application.AvatarStore : Geary.BaseObject {
     }
 
     public void close() {
-        // Noop
+        this.cache.clear();
     }
 
     public async Gdk.Pixbuf? load(Geary.RFC822.MailboxAddress mailbox,
                                   int pixel_size,
                                   GLib.Cancellable cancellable)
         throws GLib.Error {
+        CacheEntry match = yield get_match(mailbox.address);
+        return yield match.load(pixel_size, cancellable);
+    }
+
+
+    private async CacheEntry get_match(string address)
+        throws GLib.Error {
+        CacheEntry? entry = this.cache.get(address);
+        int64 now = GLib.get_monotonic_time();
+        if (entry != null) {
+            if (entry.last_used + MAX_CACHE_AGE_US >= now) {
+                entry.last_used = now;
+            } else {
+                entry = null;
+                this.cache.unset(address);
+            }
+        }
+
+        if (entry == null) {
+            Folks.Individual? match = yield search_match(address);
+            entry = new CacheEntry(match, now);
+            this.cache.set(address, entry);
+        }
+
+        return entry;
+    }
+
+    private async Folks.Individual? search_match(string address)
+        throws GLib.Error {
         Folks.SearchView view = new Folks.SearchView(
             this.individuals,
             new Folks.SimpleQuery(
-                mailbox.address,
+                address,
                 new string[] {
                     Folks.PersonaStore.detail_key(
                         Folks.PersonaDetail.EMAIL_ADDRESSES
@@ -45,22 +124,14 @@ public class Application.AvatarStore : Geary.BaseObject {
         if (!view.individuals.is_empty) {
             match = view.individuals.first();
         }
+
         try {
             yield view.unprepare();
         } catch (GLib.Error err) {
             warning("Error unpreparing Folks search: %s", err.message);
         }
 
-        Gdk.Pixbuf? pixbuf = null;
-        if (match != null && match.avatar != null) {
-            GLib.InputStream data = yield match.avatar.load_async(
-                pixel_size, cancellable
-            );
-            pixbuf = yield new Gdk.Pixbuf.from_stream_at_scale_async(
-                data, pixel_size, pixel_size, true, cancellable
-            );
-        }
-        return pixbuf;
+        return match;
     }
 
 }


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