Skip to content
  • knuxify's avatar
    1214c043
    backends: file: rework file cover handling · 1214c043
    knuxify authored
    This is another pretty huge optimization, both memory-wise (in theory -
    I haven't compared...), but especially speed-wise.
    
    To explain this change, let's talk about Ear Tag's previous handling
    of covers.
    
    Historically, Ear Tag supported only front covers, and they were loaded
    from a path. The reason for that is that we were using a Gtk.Image and
    loading an image from, well, the path. It occured to me later that this
    was extremely inefficient - every time we selected a file, we'd have to
    reload the cover from the disk, causing massive lag. So I optimized it to
    create two pixbufs - a 48x48 thumbnail and a 196x196 image for the button -
    and keep them in a helper cover class, then use them for showing covers.
    
    Still, though, the system had a couple of flaws:
    
    - It still assumed that there was an actual *file* with the cover, meaning
      that covers extracted from metadata had to be saved as tempfiles.
    
    - Based on this assumption, the diffing algorithm (used to determine whether
      to show a placeholder or the cover when selecting multiple files) was
      implemented byrunning a file comparison. This meant that we were doing
      blocking IO operations every time a comparison was done, which was... a lot.
    
    - Every time the cover was loaded, new pixbufs were created, even if the cover
      was bit-for-bit identical with one from another file (as is often the case
      with albums).
    
    The new implementation resolves to change all of this.
    
    - All cover data is now stored in-memory. This means no more tempfiles for loaded
      covers, and no IO operations (past the initial load in the case of covers opened
      from files)!
    
    - A new diffing algorithm was introduced, using xxhash's XXH3 hash to calculate
      the hash of the data. Compared to more conventional algorithms like SHA256,
      XXH3 algorithm is super fast and specifically done for file comparisons
      (where the priority isn't being cryptographically secure, so some computational
      load can be dropped - citation needed, I'm not a cryptographer).
    
    - Moreover, since we now have a hash of the data, we use it to cache cover objects
      and return an existing object if we detect that the image is bit-for-bit identical.
      Cover data gets freed once all references to the cover object are freed. Thus, we
      don't waste memory on repeated pixbufs \o/
    
    - The cover object also stores some metadata about the image (...rather, currently
      just the mimetype), which backend implementations can use for their own purposes.
    
    - As a nice bonus, cover loading is now done fully asynchronously, even from
      files! This fixes some of the stutter that happened at startup.
    1214c043
    backends: file: rework file cover handling
    knuxify authored
    This is another pretty huge optimization, both memory-wise (in theory -
    I haven't compared...), but especially speed-wise.
    
    To explain this change, let's talk about Ear Tag's previous handling
    of covers.
    
    Historically, Ear Tag supported only front covers, and they were loaded
    from a path. The reason for that is that we were using a Gtk.Image and
    loading an image from, well, the path. It occured to me later that this
    was extremely inefficient - every time we selected a file, we'd have to
    reload the cover from the disk, causing massive lag. So I optimized it to
    create two pixbufs - a 48x48 thumbnail and a 196x196 image for the button -
    and keep them in a helper cover class, then use them for showing covers.
    
    Still, though, the system had a couple of flaws:
    
    - It still assumed that there was an actual *file* with the cover, meaning
      that covers extracted from metadata had to be saved as tempfiles.
    
    - Based on this assumption, the diffing algorithm (used to determine whether
      to show a placeholder or the cover when selecting multiple files) was
      implemented byrunning a file comparison. This meant that we were doing
      blocking IO operations every time a comparison was done, which was... a lot.
    
    - Every time the cover was loaded, new pixbufs were created, even if the cover
      was bit-for-bit identical with one from another file (as is often the case
      with albums).
    
    The new implementation resolves to change all of this.
    
    - All cover data is now stored in-memory. This means no more tempfiles for loaded
      covers, and no IO operations (past the initial load in the case of covers opened
      from files)!
    
    - A new diffing algorithm was introduced, using xxhash's XXH3 hash to calculate
      the hash of the data. Compared to more conventional algorithms like SHA256,
      XXH3 algorithm is super fast and specifically done for file comparisons
      (where the priority isn't being cryptographically secure, so some computational
      load can be dropped - citation needed, I'm not a cryptographer).
    
    - Moreover, since we now have a hash of the data, we use it to cache cover objects
      and return an existing object if we detect that the image is bit-for-bit identical.
      Cover data gets freed once all references to the cover object are freed. Thus, we
      don't waste memory on repeated pixbufs \o/
    
    - The cover object also stores some metadata about the image (...rather, currently
      just the mimetype), which backend implementations can use for their own purposes.
    
    - As a nice bonus, cover loading is now done fully asynchronously, even from
      files! This fixes some of the stutter that happened at startup.
Loading