Skip to content

Commit

Permalink
IconCache: Add pending state to avoid duplicate downloads in some cases
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Jun 18, 2023
1 parent cb59267 commit 2bf2f74
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 8 deletions.
25 changes: 22 additions & 3 deletions Common/UI/IconCache.cpp
Expand Up @@ -33,12 +33,10 @@ void IconCache::SaveToFile(FILE *file) {
DiskCacheHeader header;
header.magic = ICON_CACHE_MAGIC;
header.version = ICON_CACHE_VERSION;
header.entryCount = 0; // (uint32_t)cache_.size();
header.entryCount = (uint32_t)cache_.size();

fwrite(&header, 1, sizeof(header), file);

return;

for (auto &iter : cache_) {
DiskCacheEntry entryHeader;
entryHeader.keyLen = (uint32_t)iter.first.size();
Expand Down Expand Up @@ -142,6 +140,23 @@ bool IconCache::Contains(const std::string &key) {
return cache_.find(key) != cache_.end();
}

bool IconCache::MarkPending(const std::string &key) {
std::unique_lock<std::mutex> lock(lock_);
if (cache_.find(key) != cache_.end()) {
return false;
}
if (pending_.find(key) != pending_.end()) {
return false;
}
pending_.insert(key);
return true;
}

void IconCache::Cancel(const std::string &key) {
std::unique_lock<std::mutex> lock(lock_);
pending_.erase(key);
}

bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::string &&data) {
std::unique_lock<std::mutex> lock(lock_);

Expand All @@ -159,6 +174,8 @@ bool IconCache::InsertIcon(const std::string &key, IconFormat format, std::strin
return false;
}

pending_.erase(key);

double now = time_now_d();
cache_.emplace(key, Entry{ std::move(data), format, nullptr, now, now, false });
return true;
Expand Down Expand Up @@ -238,5 +255,7 @@ IconCacheStats IconCache::GetStats() {
stats.dataSize += iter.second.data.size();
}

stats.pending = pending_.size();

return stats;
}
7 changes: 6 additions & 1 deletion Common/UI/IconCache.h
@@ -1,6 +1,7 @@
#pragma once

#include <map>
#include <set>
#include <string>
#include <cstdio>
#include <mutex>
Expand All @@ -23,14 +24,17 @@ class Texture;
struct IconCacheStats {
size_t cachedCount;
size_t textureCount; // number of cached images that are "live" textures
size_t pending;
size_t dataSize;
};

class IconCache {
public:
Draw::Texture *BindIconTexture(UIContext *context, const std::string &key);

// It's okay to call this from any thread.
// It's okay to call these from any thread.
bool MarkPending(const std::string &key); // returns false if already pending or loaded
void Cancel(const std::string &key);
bool InsertIcon(const std::string &key, IconFormat format, std::string &&pngData);
bool GetDimensions(const std::string &key, int *width, int *height);
bool Contains(const std::string &key);
Expand All @@ -56,6 +60,7 @@ class IconCache {
void Decimate();

std::map<std::string, Entry> cache_;
std::set<std::string> pending_;

std::mutex lock_;
};
Expand Down
12 changes: 8 additions & 4 deletions UI/Store.cpp
Expand Up @@ -56,12 +56,16 @@ class HttpImageFileView : public UI::View {
HttpImageFileView(http::Downloader *downloader, const std::string &path, UI::ImageSizeMode sizeMode = UI::IS_DEFAULT, bool useIconCache = true, UI::LayoutParams *layoutParams = nullptr)
: UI::View(layoutParams), path_(path), sizeMode_(sizeMode), downloader_(downloader), useIconCache_(useIconCache) {

if (useIconCache && !g_iconCache.Contains(path_)) {
if (useIconCache && g_iconCache.MarkPending(path_)) {
const char *acceptMime = "image/png, image/jpeg, image/*; q=0.9, */*; q=0.8";
downloader_->StartDownloadWithCallback(path_, Path(), [&](http::Download &download) {
std::string data;
download.buffer().TakeAll(&data);
g_iconCache.InsertIcon(path_, IconFormat::PNG, std::move(data));
if (download.ResultCode() == 200) {
std::string data;
download.buffer().TakeAll(&data);
g_iconCache.InsertIcon(path_, IconFormat::PNG, std::move(data));
} else {
g_iconCache.Cancel(path_);
}
}, acceptMime);
}
}
Expand Down

0 comments on commit 2bf2f74

Please sign in to comment.