/**
* 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;
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
#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"
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
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;
};
//////////////////////////////////////////////////////////////////////
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");
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);
AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
private:
NavDataCache();
-
+
+ friend class RebuildThread;
+ void doRebuild();
+
class NavDataCachePrivate;
std::auto_ptr<NavDataCachePrivate> d;
};