[gnome-music/wip/gbsneto/artwork-queue] albumartcache: Limit concurrent lookups to 24



commit 742a7c4d7164f2df4b0963d0a3ea9ede1fb4b76f
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Jun 24 00:52:20 2017 -0300

    albumartcache: Limit concurrent lookups to 24
    
    The current AlbumArtCache implementation does not keep track
    of the number of concurrent lookups that are being executed.
    
    When dealing with a small number of items this is acceptable,
    but once the number of music items grow, this poses a big
    problem. In fact, the biggest bottleneck for when Music is
    loading is caused by the thousands of lookups finishing almost
    at the same time and overloading GTK+ machinery.
    
    Fix that by introducing a limit to the number of concurrent
    lookups being executed. When the limit is hit, the lookups
    are queued and executed once a new lookup slot is available.
    
    Notice that downloads are not considered lookups, and file
    loading is done in parallel to cover fetching.

 gnomemusic/albumartcache.py |   48 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 47 insertions(+), 1 deletions(-)
---
diff --git a/gnomemusic/albumartcache.py b/gnomemusic/albumartcache.py
index 4b44d10..c00cd38 100644
--- a/gnomemusic/albumartcache.py
+++ b/gnomemusic/albumartcache.py
@@ -46,6 +46,41 @@ import gnomemusic.utils as utils
 
 logger = logging.getLogger(__name__)
 
+# Variables shared across instances
+MAX_SIMULTANEOUS_LOOKUPS = 24
+_lookup_queue = []
+_n_lookups = 0
+
+
+@log
+def _push_lookup_counter(cache, item, art_size, callback, itr):
+    """Push a lookup counter or queue the lookup if needed"""
+    global _lookup_queue
+    global _n_lookups
+
+    # If reached the limit, queue the operation
+    if _n_lookups >= MAX_SIMULTANEOUS_LOOKUPS:
+        _lookup_queue.append((cache, item, art_size, callback, itr))
+        return False
+    else:
+        _n_lookups += 1
+        return True
+
+
+@log
+def _pop_lookup_counter():
+    """Pops a lookup counter, and consume the lookup queue if needed"""
+    global _lookup_queue
+    global _n_lookups
+
+    _n_lookups -= 1
+
+    # An available lookup slot appeared! Let's continue looking
+    # up for artwork then
+    if _n_lookups < MAX_SIMULTANEOUS_LOOKUPS and _lookup_queue:
+        (cache, item, art_size, callback, itr) = _lookup_queue.pop(0)
+        cache.lookup(item, art_size, callback, itr)
+
 
 @log
 def _make_icon_frame(pixbuf, art_size=None, scale=1):
@@ -235,7 +270,8 @@ class AlbumArtCache(GObject.GObject):
         :param callback: Callback function when retrieved
         :param itr: Iter to return with callback
         """
-        self._lookup_local(item, callback, itr, art_size)
+        if _push_lookup_counter(self, item, art_size, callback, itr):
+            self._lookup_local(item, callback, itr, art_size)
 
     @log
     def _lookup_local(self, item, callback, itr, art_size):
@@ -269,6 +305,10 @@ class AlbumArtCache(GObject.GObject):
             return
 
         def do_callback(pixbuf):
+
+            # Lookup finished, decrease the counter
+            _pop_lookup_counter()
+
             if not pixbuf:
                 surface = DefaultIcon(self._scale).get(DefaultIcon.Type.music,
                                                        art_size)
@@ -298,6 +338,12 @@ class AlbumArtCache(GObject.GObject):
             do_callback(None)
             return
 
+        # When we reach here because it fails to retrive the artwork,
+        # well do a long round trip (either through _lookup_embedded or
+        # _lookup_remote) and call self.lookup() again. Thus, decrease
+        # global lookup counter.
+        _pop_lookup_counter()
+
         self._lookup_embedded(item, callback, itr, art_size)
 
     @log


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