1
0
Fork 0

Use a helper thread to rebuild the navcache.

Avoid the application becoming unresponsive during nav-cache rebuilds. We still have to wait for the rebuild, but perform it on a helper thread so the main GUI thread stays responsive and hence doesn't trigger a beach-ball / 'not responding' alert. Also ensures there's some feedback (the spinner) during the rebuild operation, so users don't think we've hung.
This commit is contained in:
James Turner 2012-09-25 17:24:12 +01:00
parent ae6218ff10
commit a10638c6b4
4 changed files with 91 additions and 15 deletions

View file

@ -450,17 +450,23 @@ bool fgInitConfig ( int argc, char **argv )
/**
* Initialize vor/ndb/ils/fix list management and query systems (as
* well as simple airport db list)
* This is called multiple times in the case of a cache rebuild,
* to allow length caching to take place in the background, without
* blocking the main/UI thread.
*/
bool
fgInitNav ()
{
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
if (cache->isRebuildRequired()) {
SGTimeStamp st;
st.stamp();
cache->rebuild();
SG_LOG(SG_GENERAL, SG_INFO, "rebuilding NavDataCache took:" << st.elapsedMSec());
static bool doingRebuild = false;
if (doingRebuild || cache->isRebuildRequired()) {
doingRebuild = true;
bool finished = cache->rebuild();
if (!finished) {
// sleep to give the rebuild thread more time
SGTimeStamp::sleepForMSec(50);
return false;
}
}
FGTACANList *channellist = new FGTACANList;

View file

@ -189,11 +189,15 @@ static void fgIdleFunction ( void ) {
fgSplashProgress("loading-nav-data");
} else if ( idle_state == 3 ) {
idle_state++;
fgInitNav();
fgSplashProgress("init-scenery");
bool done = fgInitNav();
if (done) {
++idle_state;
fgSplashProgress("init-scenery");
} else {
fgSplashProgress("loading-nav-data");
}
} else if ( idle_state == 4 ) {
idle_state+=2;
// based on the requested presets, calculate the true starting

View file

@ -45,6 +45,8 @@
#include <simgear/bucket/newbucket.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include <Main/globals.hxx>
#include "markerbeacon.hxx"
@ -131,6 +133,47 @@ static string cleanRunwayNo(const string& aRwyNo)
namespace flightgear
{
/**
* Thread encapsulating a cache rebuild. This is not used to parallelise
* the rebuild - we must still wait until completion before doing other
* startup, since many things rely on a complete cache. The thread is used
* so we don't block the main event loop for an unacceptable duration,
* which causes 'not responding' / spinning beachballs on Windows & Mac
*/
class RebuildThread : public SGThread
{
public:
RebuildThread(NavDataCache* cache) :
_cache(cache),
_isFinished(false)
{
}
bool isFinished() const
{
SGGuard<SGMutex> g(_lock);
return _isFinished;
}
virtual void run()
{
SGTimeStamp st;
st.stamp();
_cache->doRebuild();
SG_LOG(SG_GENERAL, SG_INFO, "cache rebuild took:" << st.elapsedMSec() << "msec");
SGGuard<SGMutex> g(_lock);
_isFinished = true;
}
private:
NavDataCache* _cache;
mutable SGMutex _lock;
bool _isFinished;
};
////////////////////////////////////////////////////////////////////////////
typedef std::map<PositionedID, FGPositionedRef> PositionedCache;
class AirportTower : public FGPositioned
@ -785,6 +828,10 @@ public:
StmtVec prepared;
std::set<Octree::Branch*> deferredOctreeUpdates;
// if we're performing a rebuild, the thread that is doing the work.
// otherwise, NULL
std::auto_ptr<RebuildThread> rebuilder;
};
//////////////////////////////////////////////////////////////////////
@ -946,7 +993,22 @@ bool NavDataCache::isRebuildRequired()
return false;
}
void NavDataCache::rebuild()
bool NavDataCache::rebuild()
{
if (!d->rebuilder.get()) {
d->rebuilder.reset(new RebuildThread(this));
d->rebuilder->start();
}
// poll the rebuild thread
bool fin = d->rebuilder->isFinished();
if (fin) {
d->rebuilder.reset(); // all done!
}
return fin;
}
void NavDataCache::doRebuild()
{
try {
d->runSQL("BEGIN");

View file

@ -65,9 +65,10 @@ public:
bool isRebuildRequired();
/**
* run the cache rebuild
* run the cache rebuild - returns true if rebuild is complete,
* otherwise keep going.
*/
void rebuild();
bool rebuild();
bool isCachedFileModified(const SGPath& path) const;
void stampCacheFile(const SGPath& path);
@ -180,7 +181,10 @@ public:
AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
private:
NavDataCache();
friend class RebuildThread;
void doRebuild();
class NavDataCachePrivate;
std::auto_ptr<NavDataCachePrivate> d;
};