From 2c81f2af73609f6379dd0e7fbcf901fbc90d20d6 Mon Sep 17 00:00:00 2001 From: Evan Paterakis Date: Sun, 26 May 2024 05:48:59 +0300 Subject: [PATCH] feat: abstract cache --- src/Services/Cache/Abstract.vala | 90 ++++++++++++++++++++++++++++++++ src/Services/Cache/meson.build | 3 ++ src/Services/Helpers/Image.vala | 14 +++++ src/Services/meson.build | 1 + 4 files changed, 108 insertions(+) create mode 100644 src/Services/Cache/Abstract.vala create mode 100644 src/Services/Cache/meson.build diff --git a/src/Services/Cache/Abstract.vala b/src/Services/Cache/Abstract.vala new file mode 100644 index 000000000..64aef96ce --- /dev/null +++ b/src/Services/Cache/Abstract.vala @@ -0,0 +1,90 @@ +public class Tuba.Cache.Abstract : Object { + public const string DATA_MIN_REF_COUNT = "refs"; + + protected Gee.Map items; + + private uint timeout_source = -1; + private int _maintenance_secs = 5; + public int maintenance_secs { + get { + return _maintenance_secs; + } + + set { + _maintenance_secs = value; + if (timeout_source != -1) + GLib.Source.remove (timeout_source); + setup_maintenance (); + } + } + + public uint size { + get { return items.size; } + } + + construct { + items = new Gee.HashMap (); + + setup_maintenance (); + } + + private void setup_maintenance () { + timeout_source = Timeout.add_seconds (_maintenance_secs, maintenance_func, Priority.LOW); + } + + bool maintenance_func () { + if (size > 0) { + uint cleared = 0; + var iter = items.map_iterator (); + + while (iter.has_next ()) { + iter.next (); + var obj = iter.get_value (); + if (obj == null) continue; + + var min_ref_count = obj.get_data (DATA_MIN_REF_COUNT); + // debug (@"[Cache] Key \"$(iter.get_key ())\": $(obj.ref_count)/$(min_ref_count)"); + if (obj.ref_count < min_ref_count) { + cleared++; + debug (@"[Cache] Freeing: $(iter.get_key ())"); + iter.unset (); + obj.dispose (); + } + } + + if (cleared > 0) + debug (@"[Cache] Freed $cleared items from cache. Size: $size"); + } + + return Source.CONTINUE; + } + + public Object? lookup (string key) { + return items.@get (key); + } + + public virtual string get_key (string id) { + return id; + } + + public bool contains (string id) { + return items.has_key (get_key (id)); + } + + public string insert (string id, owned Object obj) { + var key = get_key (id); + debug (@"[Cache] Inserting: $key"); + items.@set (key, (owned) obj); + + var nobj = items.@get (key); + nobj.set_data (DATA_MIN_REF_COUNT, nobj.ref_count); + + return key; + } + + public void nuke () { + debug ("[Cache] Clearing"); + items.clear (); + } + +} diff --git a/src/Services/Cache/meson.build b/src/Services/Cache/meson.build new file mode 100644 index 000000000..4f5d48021 --- /dev/null +++ b/src/Services/Cache/meson.build @@ -0,0 +1,3 @@ +sources += files( + 'Abstract.vala', +) diff --git a/src/Services/Helpers/Image.vala b/src/Services/Helpers/Image.vala index 3db81f1b5..91512d5e5 100644 --- a/src/Services/Helpers/Image.vala +++ b/src/Services/Helpers/Image.vala @@ -15,6 +15,7 @@ public class Tuba.Helper.Image { private static Soup.Session session; private static Soup.Cache cache; + private static Cache.Abstract abstract_cache; public static void clear_cache () { new Helper.Image (); @@ -28,6 +29,7 @@ public class Tuba.Helper.Image { } static construct { + abstract_cache = new Cache.Abstract (); cache = new Soup.Cache ( GLib.Path.build_path (GLib.Path.DIR_SEPARATOR_S, Tuba.cache_path, "soup", "media"), Soup.CacheType.SINGLE_USER @@ -68,6 +70,14 @@ public class Tuba.Helper.Image { if (url == null || url == "") return; new Helper.Image (); bool has_loaded = false; + + var key = abstract_cache.get_key (url); + if (abstract_cache.contains (key)) { + has_loaded = true; + cb (abstract_cache.lookup (key) as Gdk.Paintable); + return; + } + cb (null); if (blurhash != null) { @@ -82,6 +92,10 @@ public class Tuba.Helper.Image { fetch_paintable.begin (url, (obj, res) => { var result = fetch_paintable.end (res); has_loaded = true; + + if (result != null) + abstract_cache.insert (url, result); + cb (result); }); } diff --git a/src/Services/meson.build b/src/Services/meson.build index fb21f2bc0..b46bf941f 100644 --- a/src/Services/meson.build +++ b/src/Services/meson.build @@ -3,5 +3,6 @@ sources += files( ) subdir('Accounts') +subdir('Cache') subdir('Helpers') subdir('Network')