diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 4643633cf0..9611e2ec65 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -20,6 +20,7 @@ #include "NetworkAccessManager.h" #include "NetworkLogging.h" +#include "NodeList.h" #include "ResourceCache.h" @@ -27,21 +28,63 @@ (((x) > (max)) ? (max) :\ (x))) -ResourceCache::ResourceCache(QObject* parent) : - QObject(parent) { +ResourceCache::ResourceCache(QObject* parent) : QObject(parent) { + auto& domainHandler = DependencyManager::get()->getDomainHandler(); + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, + this, &ResourceCache::clearATPAssets, Qt::DirectConnection); } ResourceCache::~ResourceCache() { clearUnusedResource(); } +void ResourceCache::clearATPAssets() { + { + QWriteLocker locker(&_resourcesLock); + for (auto& url : _resources.keys()) { + // If this is an ATP resource + if (url.scheme() == URL_SCHEME_ATP) { + + // Remove it from the resource hash + auto resource = _resources.take(url); + if (auto strongRef = resource.lock()) { + // Make sure the resource won't reinsert itself + strongRef->setCache(nullptr); + } + } + } + } + { + QWriteLocker locker(&_unusedResourcesLock); + for (auto& resource : _unusedResources.values()) { + if (resource->getURL().scheme() == URL_SCHEME_ATP) { + _unusedResources.remove(resource->getLRUKey()); + } + } + } + { + QWriteLocker locker(&_resourcesToBeGottenLock); + for (auto& url : _resourcesToBeGotten) { + if (url.scheme() == URL_SCHEME_ATP) { + _resourcesToBeGotten.removeAll(url); + } + } + } + + +} + void ResourceCache::refreshAll() { // Clear all unused resources so we don't have to reload them clearUnusedResource(); resetResourceCounters(); - + + _resourcesLock.lockForRead(); + auto resourcesCopy = _resources; + _resourcesLock.unlock(); + // Refresh all remaining resources in use - foreach (QSharedPointer resource, _resources) { + foreach (QSharedPointer resource, resourcesCopy) { if (resource) { resource->refresh(); } @@ -49,10 +92,16 @@ void ResourceCache::refreshAll() { } void ResourceCache::refresh(const QUrl& url) { - QSharedPointer resource = _resources.value(url); - if (!resource.isNull()) { + QSharedPointer resource; + { + QReadLocker locker(&_resourcesLock); + resource = _resources.value(url).lock(); + } + + if (resource) { resource->refresh(); } else { + QWriteLocker locker(&_resourcesLock); _resources.remove(url); resetResourceCounters(); } @@ -103,8 +152,12 @@ void ResourceCache::checkAsynchronousGets() { QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& fallback, bool delayLoad, void* extra) { - QSharedPointer resource = _resources.value(url); - if (!resource.isNull()) { + QSharedPointer resource; + { + QReadLocker locker(&_resourcesLock); + resource = _resources.value(url).lock(); + } + if (resource) { removeUnusedResource(resource); return resource; } @@ -123,7 +176,10 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& getResource(fallback, QUrl(), true) : QSharedPointer(), delayLoad, extra); resource->setSelf(resource); resource->setCache(this); - _resources.insert(url, resource); + { + QWriteLocker locker(&_resourcesLock); + _resources.insert(url, resource); + } removeUnusedResource(resource); resource->ensureLoading(); @@ -150,13 +206,16 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) reserveUnusedResource(resource->getBytes()); resource->setLRUKey(++_lastLRUKey); - _unusedResources.insert(resource->getLRUKey(), resource); _unusedResourcesSize += resource->getBytes(); resetResourceCounters(); + + QWriteLocker locker(&_unusedResourcesLock); + _unusedResources.insert(resource->getLRUKey(), resource); } void ResourceCache::removeUnusedResource(const QSharedPointer& resource) { + QWriteLocker locker(&_unusedResourcesLock); if (_unusedResources.contains(resource->getLRUKey())) { _unusedResources.remove(resource->getLRUKey()); _unusedResourcesSize -= resource->getBytes(); @@ -165,6 +224,7 @@ void ResourceCache::removeUnusedResource(const QSharedPointer& resourc } void ResourceCache::reserveUnusedResource(qint64 resourceSize) { + QWriteLocker locker(&_unusedResourcesLock); while (!_unusedResources.empty() && _unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) { // unload the oldest resource @@ -184,6 +244,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { void ResourceCache::clearUnusedResource() { // the unused resources may themselves reference resources that will be added to the unused // list on destruction, so keep clearing until there are no references left + QWriteLocker locker(&_unusedResourcesLock); while (!_unusedResources.isEmpty()) { foreach (const QSharedPointer& resource, _unusedResources) { resource->setCache(nullptr); @@ -450,6 +511,7 @@ void Resource::setSize(const qint64& bytes) { } void Resource::reinsert() { + QWriteLocker locker(&_cache->_resourcesLock); _cache->_resources.insert(_url, _self); } diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index ad9ba10a7c..aea1e91099 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -123,6 +123,9 @@ public slots: protected slots: void updateTotalSize(const qint64& oldSize, const qint64& newSize); +private slots: + void clearATPAssets(); + protected: /// Loads a resource from the specified URL. /// \param fallback a fallback URL to load if the desired one is unavailable @@ -151,6 +154,7 @@ private: void clearUnusedResource(); void resetResourceCounters(); + QReadWriteLock _resourcesLock { QReadWriteLock::Recursive }; QHash> _resources; int _lastLRUKey = 0; @@ -158,7 +162,7 @@ private: static int _requestsActive; void getResourceAsynchronously(const QUrl& url); - QReadWriteLock _resourcesToBeGottenLock; + QReadWriteLock _resourcesToBeGottenLock { QReadWriteLock::Recursive }; QQueue _resourcesToBeGotten; std::atomic _numTotalResources { 0 }; @@ -168,6 +172,7 @@ private: std::atomic _unusedResourcesSize { 0 }; qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; + QReadWriteLock _unusedResourcesLock { QReadWriteLock::Recursive }; QMap> _unusedResources; };