diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | src/resources/resource.cpp | 12 | ||||
-rw-r--r-- | src/resources/resource.h | 6 | ||||
-rw-r--r-- | src/resources/resourcemanager.cpp | 79 | ||||
-rw-r--r-- | src/resources/resourcemanager.h | 14 |
5 files changed, 90 insertions, 24 deletions
@@ -182,6 +182,9 @@ 2007-11-16 Guillaume Melquiond <guillaume.melquiond@gmail.com> + * src/resources/resourcemanager.h, src/resources/resource.h, + src/resources/resourcemanager.cpp, src/resources/resource.cpp: Delayed + resource deletion by 30 seconds. * src/resources/image.cpp: Sped up recoloring of transparent pixels. 2007-11-16 Eugenio Favalli <elvenprogrammer@gmail.com> diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp index 07f31b8f..8f21f5d2 100644 --- a/src/resources/resource.cpp +++ b/src/resources/resource.cpp @@ -21,10 +21,10 @@ * $Id$ */ -#include "resource.h" - #include <cassert> +#include "resource.h" + #include "resourcemanager.h" Resource::~Resource() @@ -45,10 +45,10 @@ Resource::decRef() mRefCount--; - if (mRefCount == 0) { - // Make sure resource manager won't refer to deleted resource + if (mRefCount == 0) + { + // Warn the manager that this resource is no longer used. ResourceManager *resman = ResourceManager::getInstance(); - resman->release(mIdPath); - delete this; + resman->release(this); } } diff --git a/src/resources/resource.h b/src/resources/resource.h index 7c39f176..5b9a5eb8 100644 --- a/src/resources/resource.h +++ b/src/resources/resource.h @@ -24,6 +24,7 @@ #ifndef _TMW_RESOURCE_H #define _TMW_RESOURCE_H +#include <ctime> #include <string> /** @@ -69,8 +70,9 @@ class Resource ~Resource(); private: - unsigned int mRefCount; /**< Reference count */ - std::string mIdPath; /**< Path identifying this resource */ + std::string mIdPath; /**< Path identifying this resource. */ + time_t mTimeStamp; /**< Time at which the resource was orphaned. */ + unsigned mRefCount; /**< Reference count. */ }; #endif diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 658915d2..fb9da9d7 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -21,13 +21,15 @@ * $Id$ */ -#include "resourcemanager.h" - #include <cassert> #include <sstream> +#include <sys/time.h> + #include <physfs.h> #include <SDL_image.h> +#include "resourcemanager.h" + #include "dye.h" #include "image.h" #include "music.h" @@ -41,12 +43,15 @@ ResourceManager *ResourceManager::instance = NULL; ResourceManager::ResourceManager() + : mOldestOrphan(0) { logger->log("Initializing resource manager..."); } ResourceManager::~ResourceManager() { + mResources.insert(mOrphanedResources.begin(), mOrphanedResources.end()); + // Release any remaining spritedefs first because they depend on image sets ResourceIterator iter = mResources.begin(); while (iter != mResources.end()) @@ -82,10 +87,11 @@ ResourceManager::~ResourceManager() } // Release remaining resources, logging the number of dangling references. - while (!mResources.empty()) + iter = mResources.begin(); + while (iter != mResources.end()) { - cleanUp(mResources.begin()->second); - mResources.erase(mResources.begin()); + cleanUp(iter->second); + ++iter; } } @@ -100,6 +106,38 @@ ResourceManager::cleanUp(Resource *res) delete res; } +void ResourceManager::cleanOrphans() +{ + timeval tv; + gettimeofday(&tv, NULL); + // Delete orphaned resources after 30 seconds. + time_t oldest = tv.tv_sec, threshold = oldest - 30; + + if (mOrphanedResources.empty() || mOldestOrphan >= threshold) return; + + ResourceIterator iter = mOrphanedResources.begin(); + while (iter != mOrphanedResources.end()) + { + Resource *res = iter->second; + time_t t = res->mTimeStamp; + if (t >= threshold) + { + if (t < oldest) oldest = t; + ++iter; + } + else + { + logger->log("ResourceManager::release(%s)", res->mIdPath.c_str()); + delete res; + ResourceIterator toErase = iter; + ++iter; + mOrphanedResources.erase(toErase); + } + } + + mOldestOrphan = oldest; +} + bool ResourceManager::setWriteDir(const std::string &path) { @@ -166,13 +204,22 @@ Resource *ResourceManager::get(std::string const &idPath, generator fun, void *d { // Check if the id exists, and return the value if it does. ResourceIterator resIter = mResources.find(idPath); - if (resIter != mResources.end()) { resIter->second->incRef(); return resIter->second; } + resIter = mOrphanedResources.find(idPath); + if (resIter != mOrphanedResources.end()) + { + Resource *res = resIter->second; + mResources.insert(*resIter); + mOrphanedResources.erase(resIter); + res->incRef(); + return res; + } + Resource *resource = fun(data); if (resource) @@ -180,6 +227,7 @@ Resource *ResourceManager::get(std::string const &idPath, generator fun, void *d resource->incRef(); resource->mIdPath = idPath; mResources[idPath] = resource; + cleanOrphans(); } // Returns NULL if the object could not be created. @@ -298,17 +346,22 @@ SpriteDef *ResourceManager::getSprite return static_cast<SpriteDef*>(get(ss.str(), SpriteDefLoader::load, &l)); } -void -ResourceManager::release(const std::string &idPath) +void ResourceManager::release(Resource *res) { - logger->log("ResourceManager::release(%s)", idPath.c_str()); - - ResourceIterator resIter = mResources.find(idPath); + ResourceIterator resIter = mResources.find(res->mIdPath); // The resource has to exist - assert(resIter != mResources.end() && resIter->second); + assert(resIter != mResources.end() && resIter->second == res); + + timeval tv; + gettimeofday(&tv, NULL); + time_t timestamp = tv.tv_sec; + + res->mTimeStamp = timestamp; + if (mOrphanedResources.empty()) mOldestOrphan = timestamp; - mResources.erase(idPath); + mOrphanedResources.insert(*resIter); + mResources.erase(resIter); } ResourceManager* diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index 1adb8446..abfd629a 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -24,6 +24,7 @@ #ifndef _TMW_RESOURCE_MANAGER_H #define _TMW_RESOURCE_MANAGER_H +#include <ctime> #include <map> #include <string> #include <vector> @@ -41,7 +42,11 @@ struct SDL_Surface; */ class ResourceManager { + + friend class Resource; + public: + typedef Resource *(*loader)(void *, unsigned); typedef Resource *(*generator)(void *); @@ -156,10 +161,9 @@ class ResourceManager SpriteDef *getSprite(std::string const &path, int variant = 0); /** - * Releases a resource, removing it from the set of loaded resources. + * Releases a resource, placing it in the set of orphaned resources. */ - void - release(const std::string &idPath); + void release(Resource *); /** * Allocates data into a buffer pointer for raw data loading. The @@ -207,10 +211,14 @@ class ResourceManager static void cleanUp(Resource *resource); + void cleanOrphans(); + static ResourceManager *instance; typedef std::map<std::string, Resource*> Resources; typedef Resources::iterator ResourceIterator; Resources mResources; + Resources mOrphanedResources; + time_t mOldestOrphan; }; #endif |