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:
parent
ae6218ff10
commit
a10638c6b4
4 changed files with 91 additions and 15 deletions
|
@ -450,17 +450,23 @@ bool fgInitConfig ( int argc, char **argv )
|
||||||
/**
|
/**
|
||||||
* Initialize vor/ndb/ils/fix list management and query systems (as
|
* Initialize vor/ndb/ils/fix list management and query systems (as
|
||||||
* well as simple airport db list)
|
* 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
|
bool
|
||||||
fgInitNav ()
|
fgInitNav ()
|
||||||
{
|
{
|
||||||
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
|
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
|
||||||
if (cache->isRebuildRequired()) {
|
static bool doingRebuild = false;
|
||||||
SGTimeStamp st;
|
if (doingRebuild || cache->isRebuildRequired()) {
|
||||||
st.stamp();
|
doingRebuild = true;
|
||||||
cache->rebuild();
|
bool finished = cache->rebuild();
|
||||||
|
if (!finished) {
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "rebuilding NavDataCache took:" << st.elapsedMSec());
|
// sleep to give the rebuild thread more time
|
||||||
|
SGTimeStamp::sleepForMSec(50);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FGTACANList *channellist = new FGTACANList;
|
FGTACANList *channellist = new FGTACANList;
|
||||||
|
|
|
@ -189,10 +189,14 @@ static void fgIdleFunction ( void ) {
|
||||||
fgSplashProgress("loading-nav-data");
|
fgSplashProgress("loading-nav-data");
|
||||||
|
|
||||||
} else if ( idle_state == 3 ) {
|
} else if ( idle_state == 3 ) {
|
||||||
idle_state++;
|
|
||||||
fgInitNav();
|
|
||||||
|
|
||||||
|
bool done = fgInitNav();
|
||||||
|
if (done) {
|
||||||
|
++idle_state;
|
||||||
fgSplashProgress("init-scenery");
|
fgSplashProgress("init-scenery");
|
||||||
|
} else {
|
||||||
|
fgSplashProgress("loading-nav-data");
|
||||||
|
}
|
||||||
|
|
||||||
} else if ( idle_state == 4 ) {
|
} else if ( idle_state == 4 ) {
|
||||||
idle_state+=2;
|
idle_state+=2;
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
#include <simgear/bucket/newbucket.hxx>
|
#include <simgear/bucket/newbucket.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
|
#include <simgear/threads/SGThread.hxx>
|
||||||
|
#include <simgear/threads/SGGuard.hxx>
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include "markerbeacon.hxx"
|
#include "markerbeacon.hxx"
|
||||||
|
@ -131,6 +133,47 @@ static string cleanRunwayNo(const string& aRwyNo)
|
||||||
namespace flightgear
|
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;
|
typedef std::map<PositionedID, FGPositionedRef> PositionedCache;
|
||||||
|
|
||||||
class AirportTower : public FGPositioned
|
class AirportTower : public FGPositioned
|
||||||
|
@ -785,6 +828,10 @@ public:
|
||||||
StmtVec prepared;
|
StmtVec prepared;
|
||||||
|
|
||||||
std::set<Octree::Branch*> deferredOctreeUpdates;
|
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;
|
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 {
|
try {
|
||||||
d->runSQL("BEGIN");
|
d->runSQL("BEGIN");
|
||||||
|
|
|
@ -65,9 +65,10 @@ public:
|
||||||
bool isRebuildRequired();
|
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;
|
bool isCachedFileModified(const SGPath& path) const;
|
||||||
void stampCacheFile(const SGPath& path);
|
void stampCacheFile(const SGPath& path);
|
||||||
|
@ -181,6 +182,9 @@ public:
|
||||||
private:
|
private:
|
||||||
NavDataCache();
|
NavDataCache();
|
||||||
|
|
||||||
|
friend class RebuildThread;
|
||||||
|
void doRebuild();
|
||||||
|
|
||||||
class NavDataCachePrivate;
|
class NavDataCachePrivate;
|
||||||
std::auto_ptr<NavDataCachePrivate> d;
|
std::auto_ptr<NavDataCachePrivate> d;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue