ported from UXP: Issue #2928 - Improve imgLoader cache queue handling. (c5cc9805)

This commit is contained in:
2026-02-07 22:12:17 +08:00
parent d5277bcad6
commit daa9648aaa
2 changed files with 52 additions and 17 deletions
+50 -16
View File
@@ -942,12 +942,38 @@ using namespace std;
void
imgCacheQueue::Remove(imgCacheEntry* entry)
{
auto it = find(mQueue.begin(), mQueue.end(), entry);
if (it != mQueue.end()) {
mSize -= (*it)->GetDataSize();
mQueue.erase(it);
MarkDirty();
uint64_t index = mQueue.IndexOf(entry);
if (index == queueContainer::NoIndex) {
return;
}
mSize -= mQueue[index]->GetDataSize();
// If the queue is clean and this is the first entry,
// then we can efficiently remove the entry without
// dirtying the sort order.
if (!IsDirty() && index == 0) {
std::pop_heap(mQueue.begin(), mQueue.end(),
imgLoader::CompareCacheEntries);
mQueue.RemoveElementAt(mQueue.Length() - 1);
return;
}
// Remove from the middle of the list. This potentially
// breaks the binary heap sort order.
mQueue.RemoveElementAt(index);
// If we only have one entry or the queue is empty, though,
// then the sort order is still effectively good.
// Simply refresh the list to clear the dirty flag.
if (mQueue.Length() <= 1) {
Refresh();
return;
}
// Otherwise we must mark the queue dirty and potentially
// trigger an expensive sort later.
MarkDirty();
}
void
@@ -956,23 +982,26 @@ imgCacheQueue::Push(imgCacheEntry* entry)
mSize += entry->GetDataSize();
RefPtr<imgCacheEntry> refptr(entry);
mQueue.push_back(refptr);
MarkDirty();
mQueue.AppendElement(Move(refptr));
// If we're not dirty already, then we can efficiently add this to the binary heap immediately.
if (!IsDirty()) {
std::push_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
}
}
already_AddRefed<imgCacheEntry>
imgCacheQueue::Pop()
{
if (mQueue.empty()) {
if (mQueue.IsEmpty()) {
return nullptr;
}
if (IsDirty()) {
Refresh();
}
RefPtr<imgCacheEntry> entry = mQueue[0];
std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
mQueue.pop_back();
RefPtr<imgCacheEntry> entry = Move(mQueue.LastElement());
mQueue.RemoveElementAt(mQueue.Length() - 1);
mSize -= entry->GetDataSize();
return entry.forget();
@@ -981,6 +1010,7 @@ imgCacheQueue::Pop()
void
imgCacheQueue::Refresh()
{
// Re-heap the list. This is an O(3 * n) operation and best avoided if possible.
std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
mDirty = false;
}
@@ -1000,7 +1030,7 @@ imgCacheQueue::IsDirty()
uint32_t
imgCacheQueue::GetNumElements() const
{
return mQueue.size();
return mQueue.Length();
}
bool
@@ -1560,7 +1590,11 @@ void
imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */)
{
imgCacheQueue& queue = GetCacheQueue(aForChrome);
queue.MarkDirty();
// We only need to dirty the queue if there is any sorting taking place.
// Empty or single-entry lists can't become dirty.
if (queue.GetNumElements() > 1) {
queue.MarkDirty();
}
queue.UpdateSize(aSizeDiff);
}
@@ -1970,13 +2004,13 @@ imgLoader::EvictEntries(imgCacheQueue& aQueueToClear)
// We have to make a temporary, since RemoveFromCache removes the element
// from the queue, invalidating iterators.
nsTArray<RefPtr<imgCacheEntry> > entries(aQueueToClear.GetNumElements());
for (imgCacheQueue::const_iterator i = aQueueToClear.begin();
i != aQueueToClear.end(); ++i) {
for (auto i = aQueueToClear.begin(); i != aQueueToClear.end(); ++i) {
entries.AppendElement(*i);
}
for (uint32_t i = 0; i < entries.Length(); ++i) {
if (!RemoveFromCache(entries[i])) {
// Iterate in reverse order to minimize array copying.
for (auto& entry : entries) {
if (!RemoveFromCache(entry)) {
return NS_ERROR_FAILURE;
}
}
+2 -1
View File
@@ -177,7 +177,8 @@ public:
uint32_t GetSize() const;
void UpdateSize(int32_t diff);
uint32_t GetNumElements() const;
typedef std::vector<RefPtr<imgCacheEntry> > queueContainer;
bool Contains(imgCacheEntry* aEntry) const;
typedef nsTArray<RefPtr<imgCacheEntry> > queueContainer;
typedef queueContainer::iterator iterator;
typedef queueContainer::const_iterator const_iterator;