From f34e951c3f06de3c04b27c2553a5cab82e4b8880 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Mon, 4 Apr 2016 13:28:13 -0700 Subject: [PATCH] Make resource cache props thread-safe --- libraries/networking/src/ResourceCache.cpp | 32 ++++++++++++++++------ libraries/networking/src/ResourceCache.h | 31 +++++++++++++-------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 1f687593bb..2e2b89046b 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -38,6 +38,7 @@ ResourceCache::~ResourceCache() { void ResourceCache::refreshAll() { // Clear all unused resources so we don't have to reload them clearUnusedResource(); + resetResourceCounters(); // Refresh all remaining resources in use foreach (auto resource, _resources) { @@ -53,16 +54,24 @@ void ResourceCache::refresh(const QUrl& url) { resource->refresh(); } else { _resources.remove(url); + resetResourceCounters(); } } -const QVariantList ResourceCache::getResourceList() const { +QVariantList ResourceCache::getResourceList() { QVariantList list; - auto resources = _resources.uniqueKeys(); - list.reserve(resources.size()); - for (auto& resource : resources) { - list << resource; + if (QThread::currentThread() != thread()) { + // NOTE: invokeMethod does not allow a const QObject* + QMetaObject::invokeMethod(this, "getResourceList", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QVariantList, list)); + } else { + auto resources = _resources.uniqueKeys(); + list.reserve(resources.size()); + for (auto& resource : resources) { + list << resource; + } } + return list; } @@ -124,7 +133,7 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& void ResourceCache::setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize) { _unusedResourcesMaxSize = clamp(unusedResourcesMaxSize, MIN_UNUSED_MAX_SIZE, MAX_UNUSED_MAX_SIZE); reserveUnusedResource(0); - emit dirty(); + resetResourceCounters(); } void ResourceCache::addUnusedResource(const QSharedPointer& resource) { @@ -138,7 +147,8 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) resource->setLRUKey(++_lastLRUKey); _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); - emit dirty(); + + resetResourceCounters(); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { @@ -146,7 +156,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); } - emit dirty(); + resetResourceCounters(); } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { @@ -177,6 +187,12 @@ void ResourceCache::clearUnusedResource() { } } +void ResourceCache::resetResourceCounters() { + _numTotalResources = _resources.size(); + _numUnusedResources = _unusedResources.size(); + emit dirty(); +} + void ResourceCache::updateTotalSize(const qint64& oldSize, const qint64& newSize) { _totalResourcesSize += (newSize - oldSize); emit dirty(); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 3f930a1f11..933eb1a6d9 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -12,7 +12,9 @@ #ifndef hifi_ResourceCache_h #define hifi_ResourceCache_h +#include #include + #include #include #include @@ -29,6 +31,8 @@ #include "ResourceManager.h" +Q_DECLARE_METATYPE(size_t) + class QNetworkReply; class QTimer; @@ -79,20 +83,19 @@ private: /// Base class for resource caches. class ResourceCache : public QObject { Q_OBJECT - Q_PROPERTY(int numTotal READ getNumTotalResources NOTIFY dirty) - Q_PROPERTY(int numCached READ getNumCachedResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeTotal READ getSizeTotalResources NOTIFY dirty) - Q_PROPERTY(qint64 sizeCached READ getSizeCachedResources NOTIFY dirty) - Q_PROPERTY(QVariantList resources READ getResourceList NOTIFY dirty) + Q_PROPERTY(size_t numTotal READ getNumTotalResources NOTIFY dirty) + Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty) + Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty) + Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty) public: - int getNumTotalResources() const { return _resources.size(); } - qint64 getSizeTotalResources() const { return _totalResourcesSize; } + size_t getNumTotalResources() const { return _numTotalResources; } + size_t getSizeTotalResources() const { return _totalResourcesSize; } - int getNumCachedResources() const { return _unusedResources.size(); } - qint64 getSizeCachedResources() const { return _unusedResourcesSize; } + size_t getNumCachedResources() const { return _numUnusedResources; } + size_t getSizeCachedResources() const { return _unusedResourcesSize; } - const QVariantList getResourceList() const; + Q_INVOKABLE QVariantList getResourceList(); static void setRequestLimit(int limit); static int getRequestLimit() { return _requestLimit; } @@ -149,6 +152,7 @@ private: void reserveUnusedResource(qint64 resourceSize); void clearUnusedResource(); + void resetResourceCounters(); QHash> _resources; int _lastLRUKey = 0; @@ -160,8 +164,11 @@ private: QReadWriteLock _resourcesToBeGottenLock; QQueue _resourcesToBeGotten; - qint64 _totalResourcesSize { 0 }; - qint64 _unusedResourcesSize { 0 }; + std::atomic _numTotalResources { 0 }; + std::atomic _numUnusedResources { 0 }; + + std::atomic _totalResourcesSize { 0 }; + std::atomic _unusedResourcesSize { 0 }; qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; QMap> _unusedResources;