Skip to content

Commit

Permalink
libcore|Bank: Added new priority level, isLoaded() method, iterate()
Browse files Browse the repository at this point in the history
The ImmediatelyInCurrentThread priority causes the operation to be
performed immediately in the current thread even if the bank uses a
background thread.

One can now special importance also when unloading items. By default,
unloading occurs after any queued tasks.
  • Loading branch information
skyjake committed Aug 9, 2014
1 parent b3460c7 commit 56f8d90
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 21 deletions.
34 changes: 28 additions & 6 deletions doomsday/libcore/include/de/data/bank.h
Expand Up @@ -21,6 +21,7 @@

#include <QObject>
#include <set>
#include <functional>

#include "../libcore.h"
#include "../DotPath"
Expand Down Expand Up @@ -125,8 +126,9 @@ class DENG2_PUBLIC Bank

enum Importance
{
Immediately, ///< Request handled before any queued tasks.
AfterQueued ///< Request handled after any queued tasks.
ImmediatelyInCurrentThread, ///< Request handled in this thread synchronously.
BeforeQueued, ///< Request handled before any queued tasks.
AfterQueued ///< Request handled after any queued tasks.
};

enum { Unlimited = -1 };
Expand Down Expand Up @@ -259,6 +261,13 @@ class DENG2_PUBLIC Bank
*/
bool has(DotPath const &path) const;

/**
* Iterates through the entire contents of the bank.
*
* @param func Function that gets called with the path of each item.
*/
void iterate(std::function<void (DotPath const &)> func) const;

/**
* Collects a list of the paths of all items in the bank.
*
Expand All @@ -279,15 +288,15 @@ class DENG2_PUBLIC Bank
* @param path Identifier of the data.
* @param importance When/how to carry out the load request (with BackgroundThread).
*/
void load(DotPath const &path, Importance importance = Immediately);
void load(DotPath const &path, Importance importance = BeforeQueued);

void loadAll();

/**
* Returns the data of an item.
*
* If the item is presently not in memory, it will first be loaded (using
* Immediately; blocks until complete). The data is automatically
* BeforeQueued; blocks until complete). The data is automatically
* marked as used at the current time, so it will not leave the memory
* cache level until sometime in the future.
*
Expand All @@ -301,6 +310,15 @@ class DENG2_PUBLIC Bank
*/
IData &data(DotPath const &path) const;

/**
* Determines if an item is currently loaded (InMemory).
*
* @param path Identifier of the item.
*
* @return @c true if the item is in memory, @c false otherwise.
*/
bool isLoaded(DotPath const &path) const;

/**
* Moves a data item to a lower cache level. When using BackgroundThread,
* this is an asynchronous operation. audienceForLevelChanged is notified
Expand All @@ -309,15 +327,19 @@ class DENG2_PUBLIC Bank
* @param path Identifier of the data.
* @param toLevel Destination level for the data.
*/
void unload(DotPath const &path, CacheLevel toLevel = InHotStorage);
void unload(DotPath const &path, CacheLevel toLevel = InHotStorage,
Importance importance = AfterQueued);

/**
* Moves all data items to a lower cache level.
* Moves all data items to a lower cache level. Jobs are done with AfterQueued
* importance.
*
* @param maxLevel Maximum cache level for all items.
*/
void unloadAll(CacheLevel maxLevel = InColdStorage);

void unloadAll(Importance importance, CacheLevel maxLevel = InColdStorage);

/**
* Removes an item's cached data from all cache levels.
*
Expand Down
2 changes: 1 addition & 1 deletion doomsday/libcore/include/de/data/pathtree.h
Expand Up @@ -69,7 +69,7 @@ class DENG2_PUBLIC PathTree : public Lockable
class Node; // forward declaration

typedef QMultiHash<Path::hash_type, Node *> Nodes;
typedef QList<String> FoundPaths;
typedef StringList FoundPaths;

/**
* Leaves and branches are stored in separate hashes.
Expand Down
47 changes: 33 additions & 14 deletions doomsday/libcore/src/data/bank.cpp
Expand Up @@ -124,8 +124,8 @@ DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via mai
typedef internal::Cache<Data> Cache;

Bank *bank; ///< Bank that owns the data.
std::auto_ptr<IData> data; ///< Non-NULL for in-memory items.
std::auto_ptr<ISource> source; ///< Always required.
std::unique_ptr<IData> data; ///< Non-NULL for in-memory items.
std::unique_ptr<ISource> source;///< Always required.
IByteArray *serial; ///< Serialized representation (if one is present; not owned).
Cache *cache; ///< Current cache for the data (never NULL).
Time accessedAt;
Expand Down Expand Up @@ -581,7 +581,7 @@ DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via mai

void beginJob(Job *job, Importance importance)
{
if(!isThreaded())
if(!isThreaded() || importance == ImmediatelyInCurrentThread)
{
// Execute the job immediately.
QScopedPointer<Job> j(job);
Expand Down Expand Up @@ -656,13 +656,13 @@ DENG2_OBSERVES(Loop, Iteration) // notifications from other threads sent via mai
beginJob(new Job(self, Job::Load, path), importance);
}

void unload(Path const &path, CacheLevel toLevel)
void unload(Path const &path, CacheLevel toLevel, Importance importance)
{
if(toLevel < InMemory)
{
Job::Task const task = (toLevel == InHotStorage && serialCache?
Job::Serialize : Job::Unload);
beginJob(new Job(self, task, path), Immediately);
beginJob(new Job(self, task, path), importance);
}
}

Expand Down Expand Up @@ -812,13 +812,20 @@ bool Bank::has(DotPath const &path) const
dint Bank::allItems(Names &names) const
{
names.clear();
iterate([&names] (DotPath const &path) {
names.insert(path.toString());
});
return dint(names.size());
}

void Bank::iterate(std::function<void (DotPath const &)> func) const
{
PathTree::FoundPaths paths;
d->items.findAllPaths(paths, PathTree::NoBranch);
DENG2_FOR_EACH(PathTree::FoundPaths, i, paths)
d->items.findAllPaths(paths, PathTree::NoBranch, '.');
foreach(String const &path, paths)
{
names.insert(Path(*i).withSeparators('.'));
func(path);
}
return dint(names.size());
}

PathTree const &Bank::index() const
Expand Down Expand Up @@ -865,7 +872,7 @@ Bank::IData &Bank::data(DotPath const &path) const
LOG_RES_XVERBOSE("Loading \"%s\"...") << path;

Time requestedAt;
d->load(path, Immediately);
d->load(path, BeforeQueued);
item.wait();

TimeDelta const waitTime = requestedAt.since();
Expand All @@ -886,26 +893,38 @@ Bank::IData &Bank::data(DotPath const &path) const
return *item.data;
}

void Bank::unload(DotPath const &path, CacheLevel toLevel)
bool Bank::isLoaded(DotPath const &path) const
{
d->unload(path, toLevel);
Instance::Data &item = d->items.find(path, PathTree::MatchFull | PathTree::NoBranch);
DENG2_GUARD(item);
return bool(item.data);
}

void Bank::unload(DotPath const &path, CacheLevel toLevel, Importance importance)
{
d->unload(path, toLevel, importance);
}

void Bank::unloadAll(CacheLevel maxLevel)
{
return unloadAll(AfterQueued, maxLevel);
}

void Bank::unloadAll(Importance importance, CacheLevel maxLevel)
{
if(maxLevel >= InMemory) return;

Names names;
allItems(names);
DENG2_FOR_EACH(Names, i, names)
{
unload(*i, maxLevel);
unload(*i, maxLevel, importance);
}
}

void Bank::clearFromCache(DotPath const &path)
{
d->unload(path, InColdStorage);
d->unload(path, InColdStorage, AfterQueued);
}

void Bank::purge()
Expand Down

0 comments on commit 56f8d90

Please sign in to comment.