Skip to content

Commit

Permalink
FS|libcore: Clarified waiting behavior when populating file system
Browse files Browse the repository at this point in the history
  • Loading branch information
skyjake committed Oct 23, 2017
1 parent 075471b commit bde41ea
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 23 deletions.
5 changes: 3 additions & 2 deletions doomsday/sdk/libcore/include/de/filesys/filesystem.h
Expand Up @@ -145,9 +145,10 @@ class DENG2_PUBLIC FileSystem : public System
Folder const &root() const;

/**
* Refresh the file system. Populates all folders with files from the feeds.
* Refresh the file system asynchronously. Populates all folders with files from
* the feeds.
*/
void refresh();
void refreshAsync();

enum FolderCreationBehavior {
DontInheritFeeds = 0, ///< Subfolder will not have any feeds created for them.
Expand Down
19 changes: 18 additions & 1 deletion doomsday/sdk/libcore/include/de/filesys/folder.h
Expand Up @@ -28,6 +28,7 @@

namespace de {

struct AsyncTask;
class Feed;

/**
Expand Down Expand Up @@ -360,7 +361,23 @@ class DENG2_PUBLIC Folder : public File
Node const *tryGetChild(String const &name) const;

public:
static void waitForPopulation();
enum WaitBehavior {
OnlyInBackground,
BlockingMainThread,
};
static void waitForPopulation(WaitBehavior waitBehavior = OnlyInBackground);

/**
* When all folder population tasks are finished, performs a callback in the main
* thread. Does not block the main thread. If nothing is currently being populated,
* the callback is called immediately before the method returns.
*
* @param func Callback to be called in the main thread.
*
* @return Task handle. Can be ignored or added to an AsyncScope.
*/
static AsyncTask *afterPopulation(std::function<void ()> func);

static bool isPopulatingAsync();

private:
Expand Down
5 changes: 2 additions & 3 deletions doomsday/sdk/libcore/src/core/app.cpp
Expand Up @@ -268,9 +268,8 @@ DENG2_PIMPL(App)
// Metadata for files.
metaBank.reset(new MetadataBank);

// Populate the file system.
fs.refresh();
Folder::waitForPopulation();
// Populate the file system (blocking).
fs.root().populate(Folder::PopulateFullTree);

// Ensure known subfolders exist:
// - /home/configs is used by de::Profiles.
Expand Down
2 changes: 1 addition & 1 deletion doomsday/sdk/libcore/src/data/bank.cpp
Expand Up @@ -572,7 +572,7 @@ DENG2_PIMPL(Bank)

if (Folder *folder = serialCache->folder())
{
Folder::waitForPopulation();
Folder::waitForPopulation(Folder::BlockingMainThread);
folder->destroyAllFilesRecursively();
}
}
Expand Down
21 changes: 6 additions & 15 deletions doomsday/sdk/libcore/src/filesys/filesystem.cpp
Expand Up @@ -87,23 +87,14 @@ void FileSystem::addInterpreter(filesys::IInterpreter const &interpreter)
d->interpreters.prepend(&interpreter);
}

void FileSystem::refresh()
void FileSystem::refreshAsync()
{
if (Folder::isPopulatingAsync())
// We may need to wait until a previous population is complete.
Folder::afterPopulation([this] ()
{
qDebug() << "FileSystem has to wait for previous population to finish...";
}

// Wait for a previous refresh to finish.
Folder::waitForPopulation();

LOG_AS("FS::refresh");

//Time startedAt;
d->root->populate(Folder::PopulateAsyncFullTree);

/*LOGDEV_RES_VERBOSE("Completed in %.2f seconds") << startedAt.since();
printIndex();*/
LOG_AS("FS::refresh");
d->root->populate(Folder::PopulateAsyncFullTree);
});
}

Folder &FileSystem::makeFolder(String const &path, FolderCreationBehaviors behavior)
Expand Down
28 changes: 27 additions & 1 deletion doomsday/sdk/libcore/src/filesys/folder.cpp
Expand Up @@ -19,6 +19,8 @@

#include "de/Folder"

#include "de/App"
#include "de/Async"
#include "de/DirectoryFeed"
#include "de/FS"
#include "de/Feed"
Expand Down Expand Up @@ -507,11 +509,35 @@ filesys::Node const *Folder::tryGetChild(String const &name) const
return nullptr;
}

void Folder::waitForPopulation()
void Folder::waitForPopulation(WaitBehavior waitBehavior)
{
if (waitBehavior == OnlyInBackground && App::inMainThread())
{
DENG2_ASSERT(!App::inMainThread());
throw Error("Folder::waitForPopulation", "Not allowed to block the main thread");
}
internal::populateTasks.waitForDone();
}

AsyncTask *Folder::afterPopulation(std::function<void ()> func)
{
if (!isPopulatingAsync())
{
func();
return nullptr;
}

return async([] ()
{
waitForPopulation();
return 0;
},
[func] (int)
{
func();
});
}

bool Folder::isPopulatingAsync()
{
return !internal::populateTasks.isDone();
Expand Down

0 comments on commit bde41ea

Please sign in to comment.