#include <msp/time/utils.h>
#include "resourcemanager.h"
#include "resources.h"
-#include "resourcewatcher.h"
+#include "resourceobserver.h"
using namespace std;
ResourceManager::ResourceManager():
policy(LOAD_ON_DEMAND),
async_loads(true),
+ total_data_size(0),
size_limit(0),
frame(0),
min_retain_frames(30),
void ResourceManager::add_resource(Resource &r)
{
+ MutexLock lock(map_mutex);
insert_unique(resources, &r, ManagedResource(r));
}
-void *ResourceManager::get_data_for_resource(const Resource &r)
+const ResourceManager::ManagedResource &ResourceManager::get_managed_resource(const Resource &r) const
{
- return &get_item(resources, &r);
+ MutexLock lock(map_mutex);
+ return get_item(resources, &r);
+}
+
+ResourceManager::ManagedResource &ResourceManager::get_managed_resource(const Resource &r)
+{
+ MutexLock lock(map_mutex);
+ return get_item(resources, &r);
}
void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
void ResourceManager::set_resource_location(Resource &r, const ResourceLocation &l)
{
- ManagedResource &managed = get_item(resources, &r);
- managed.location = l;
+ {
+ MutexLock lock(map_mutex);
+ ManagedResource &managed = get_item(resources, &r);
+ managed.location = l;
+ }
if(policy==LOAD_IMMEDIATELY)
load_resource(r);
const ResourceManager::ResourceLocation *ResourceManager::get_resource_location(const Resource &r) const
{
- const ManagedResource &managed = get_item(resources, &r);
+ const ManagedResource &managed = get_managed_resource(r);
return managed.location.collection ? &managed.location : 0;
}
void ResourceManager::load_resource(Resource &r)
{
- ManagedResource &managed = get_item(resources, &r);
+ ManagedResource &managed = get_managed_resource(r);
if(!managed.location.collection)
throw runtime_error("no location");
if(async_loads)
{
managed.state = ManagedResource::LOAD_QUEUED;
- queue.push_back(&managed);
+ LoadQueue::iterator i;
+ for(i=queue.begin(); (i!=queue.end() && (*i)->load_priority>=managed.load_priority); ++i) ;
+ queue.insert(i, &managed);
}
else
{
managed.start_loading();
while(!managed.loader->process()) ;
managed.finish_loading(true);
+ total_data_size += managed.data_size;
}
}
void ResourceManager::remove_resource(Resource &r)
{
- ManagedResource &managed = get_item(resources, &r);
+ ManagedResource &managed = get_managed_resource(r);
ManagedResource::State state = managed.state;
if(state==ManagedResource::LOAD_QUEUED)
{
}
else if(state>ManagedResource::LOAD_QUEUED && state<ManagedResource::LOADED)
thread.remove_resource(managed);
+
+ for(vector<ResourceObserver *>::const_iterator i=managed.observers.begin(); i!=managed.observers.end(); ++i)
+ (*i)->resource_removed(r);
+
+ MutexLock lock(map_mutex);
remove_existing(resources, &r);
}
-void ResourceManager::watch_resource(const Resource &r, ResourceWatcher &w)
+void ResourceManager::observe_resource(const Resource &r, ResourceObserver &w)
{
- get_item(resources, &r).add_watcher(w);
+ get_managed_resource(r).add_observer(w);
}
-void ResourceManager::unwatch_resource(const Resource &r, ResourceWatcher &w)
+void ResourceManager::unobserve_resource(const Resource &r, ResourceObserver &w)
{
- get_item(resources, &r).remove_watcher(w);
+ get_managed_resource(r).remove_observer(w);
}
void ResourceManager::tick()
bool do_unload = (frame>=next_unload);
if(thread.sync())
+ {
+ total_data_size += thread.get_and_reset_loaded_data_size();
do_unload = true;
+ }
if(thread.needs_work() && !queue.empty())
dispatch_work();
if(do_unload)
{
+ MutexLock lock(map_mutex);
if(max_retain_frames && frame>=next_unload)
{
unload_by_age();
{
queue.sort(age_order);
- if(queue.front()->last_used+10<frame)
+ if(queue.front()->last_used+min_retain_frames<frame)
{
for(LoadQueue::iterator i=queue.begin(); i!=queue.end(); ++i)
(*i)->state = ManagedResource::NOT_LOADED;
for(ResourceMap::iterator i=resources.begin(); i!=resources.end(); ++i)
if(i->second.state==ManagedResource::LOADED && i->second.last_used<unload_limit)
+ {
i->second.unload();
+ total_data_size -= i->second.data_size;
+ }
}
void ResourceManager::unload_by_size()
{
unsigned unload_limit = frame-min_retain_frames;
- while(get_total_data_size()>size_limit)
+ while(total_data_size>size_limit)
{
ManagedResource *best = 0;
UInt64 best_impact = 0;
break;
best->unload();
+ total_data_size -= best->data_size;
}
}
-UInt64 ResourceManager::get_total_data_size() const
-{
- UInt64 total = 0;
- for(ResourceMap::const_iterator i=resources.begin(); i!=resources.end(); ++i)
- if(i->second.state==ManagedResource::LOADED)
- total += i->second.data_size;
- return total;
-}
-
bool ResourceManager::age_order(ManagedResource *mr1, ManagedResource *mr2)
{
return mr1->last_used>mr2->last_used;
ResourceManager::ManagedResource::ManagedResource(Resource &r):
resource(&r),
+ load_priority(r.get_load_priority()),
io(0),
loader(0),
state(NOT_LOADED),
state = LOADED;
data_size = resource->get_data_size();
- for(vector<ResourceWatcher *>::const_iterator i=watchers.begin(); i!=watchers.end(); ++i)
+ for(vector<ResourceObserver *>::const_iterator i=observers.begin(); i!=observers.end(); ++i)
(*i)->resource_loaded(*resource);
}
else
resource->unload();
state = NOT_LOADED;
- for(vector<ResourceWatcher *>::const_iterator i=watchers.begin(); i!=watchers.end(); ++i)
+ for(vector<ResourceObserver *>::const_iterator i=observers.begin(); i!=observers.end(); ++i)
(*i)->resource_unloaded(*resource);
}
-void ResourceManager::ManagedResource::add_watcher(ResourceWatcher &w)
+void ResourceManager::ManagedResource::add_observer(ResourceObserver &w)
{
- if(find(watchers.begin(), watchers.end(), &w)==watchers.end())
- watchers.push_back(&w);
+ if(find(observers.begin(), observers.end(), &w)==observers.end())
+ observers.push_back(&w);
}
-void ResourceManager::ManagedResource::remove_watcher(ResourceWatcher &w)
+void ResourceManager::ManagedResource::remove_observer(ResourceObserver &w)
{
- vector<ResourceWatcher *>::iterator end = remove(watchers.begin(), watchers.end(), &w);
- if(end!=watchers.end())
- watchers.erase(end, watchers.end());
+ vector<ResourceObserver *>::iterator end = remove(observers.begin(), observers.end(), &w);
+ if(end!=observers.end())
+ observers.erase(end, observers.end());
}
ResourceManager::LoadingThread::LoadingThread():
+ Thread("ResourceManager"),
sem(1),
capacity(2),
size(0),
+ loaded_data_size(0),
done(false)
{
launch();
}
}
-ResourceManager::ManagedResource *ResourceManager::LoadingThread::front(LoadQueue &queue)
+ResourceManager::ManagedResource *ResourceManager::LoadingThread::front(LoadQueue &que)
{
MutexLock lock(queue_mutex);
- if(queue.empty())
+ if(que.empty())
return 0;
- return queue.front();
+ return que.front();
}
void ResourceManager::LoadingThread::add_resource(ManagedResource &r)
Time::sleep(Time::msec);
r.finish_loading();
+ if(r.state==ManagedResource::LOADED)
+ {
+ MutexLock lock(data_size_mutex);
+ loaded_data_size += r.data_size;
+ }
}
bool ResourceManager::LoadingThread::try_remove_resource(ManagedResource &r)
{
i = find(sync_queue.begin(), sync_queue.end(), &r);
if(i!=sync_queue.end())
+ {
sync_queue.erase(i);
+ --size;
+ }
}
else if(i==async_queue.begin())
return false;
else
+ {
async_queue.erase(i);
+ --size;
+ }
return true;
}
if(managed->state==ManagedResource::LOAD_ERROR || managed->process(true))
{
managed->finish_loading();
+ if(managed->state==ManagedResource::LOADED)
+ {
+ MutexLock lock(data_size_mutex);
+ loaded_data_size += managed->data_size;
+ }
any_finished = true;
--size;
return any_finished;
}
+UInt64 ResourceManager::LoadingThread::get_and_reset_loaded_data_size()
+{
+ MutexLock lock(data_size_mutex);
+ UInt64 result = loaded_data_size;
+ loaded_data_size = 0;
+ return result;
+}
+
void ResourceManager::LoadingThread::terminate()
{
done = true;