From 937b00af46cd74d0e2b9ec4eac9b3888bda791f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 30 Sep 2026 11:29:43 -0600 Subject: [PATCH] IconCache: Expire saved icons after 24 hours Icons were kept in icon.cache indefinitely, so one that changes on the server (a RetroAchievements user avatar, keyed by username) never refreshed. The insertion timestamp was process-relative, so it couldn't be compared across sessions. Store wall-clock time, and skip entries older than a day when loading. Bumps the cache version. Co-Authored-By: Claude Opus 5.5 (1M context) --- Common/UI/IconCache.cpp | 12 ++++++++---- Common/UI/IconCache.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Common/UI/IconCache.cpp b/Common/UI/IconCache.cpp index 467e3504cf..83a339423e 100644 --- a/Common/UI/IconCache.cpp +++ b/Common/UI/IconCache.cpp @@ -9,7 +9,8 @@ #include "Common/GPU/thin3d.h" #include "Common/File/FileUtil.h" -#define ICON_CACHE_VERSION 1 +// 2: insertedTimestamp became wall-clock time. +#define ICON_CACHE_VERSION 2 #define MK_FOURCC(str) (str[0] | ((uint8_t)str[1] << 8) | ((uint8_t)str[2] << 16) | ((uint8_t)str[3] << 24)) #define MAX_RUNTIME_CACHE_SIZE (1024 * 1024 * 4) @@ -17,6 +18,8 @@ // Seconds before MarkPending accepts a key whose download failed. constexpr double FAILED_RETRY_DELAY = 30.0; +// Seconds a saved icon is kept across sessions, so that ones that change (user avatars) get refreshed. +constexpr double MAX_SAVED_ICON_AGE = 24 * 60 * 60.0; // Seconds before BindIconTexture tries again to create a texture that failed. constexpr double UPLOAD_RETRY_DELAY = 5.0; @@ -91,6 +94,7 @@ bool IconCache::LoadFromFile(FILE *file) { } double now = time_now_d(); + double nowUnix = time_now_unix_utc(); for (uint32_t i = 0; i < header.entryCount; i++) { DiskCacheEntry entryHeader{}; @@ -110,8 +114,8 @@ bool IconCache::LoadFromFile(FILE *file) { break; } - // Check if we already have the entry somehow. - if (cache_.find(key) != cache_.end()) { + // Skip it if we already have the entry somehow, or it's too old. + if (cache_.find(key) != cache_.end() || nowUnix - entryHeader.insertedTimestamp > MAX_SAVED_ICON_AGE) { // Seek past the data and go to the next entry. File::Fseek(file, entryHeader.dataLen, SEEK_CUR); continue; @@ -319,7 +323,7 @@ bool IconCache::InsertIcon(std::string_view key, IconFormat format, std::string } double now = time_now_d(); - Entry entry{ std::move(data), format, nullptr, now, now }; + Entry entry{ std::move(data), format, nullptr, time_now_unix_utc(), now }; PeekIconSize(entry.data, entry.format, &entry.width, &entry.height); cache_.emplace(key, std::move(entry)); return true; diff --git a/Common/UI/IconCache.h b/Common/UI/IconCache.h index 45eee95f54..c3f690b689 100644 --- a/Common/UI/IconCache.h +++ b/Common/UI/IconCache.h @@ -60,7 +60,7 @@ private: std::string data; IconFormat format; Draw::Texture *texture; - double insertedTimeStamp; + double insertedTimeStamp; // Wall-clock (time_now_unix_utc), since it's saved. double usedTimeStamp; double uploadFailedTime; // When CreateTexture last failed, or 0. int width; // From the image header, 0 if unknown.