]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/NavDataCache.cxx
Run the filters for comm/navaids as required.
[flightgear.git] / src / Navaids / NavDataCache.cxx
index 3506d64fe13d86f80f979bc502e3e1d89c714eb2..bcc82a2609c7e7a44a62599ec2707f8fa79a00a9 100644 (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"
@@ -66,7 +68,7 @@ using std::string;
 
 namespace {
 
-const int SCHEMA_VERSION = 3;
+const int SCHEMA_VERSION = 4;
 
 // bind a std::string to a sqlite statement. The std::string must live the
 // entire duration of the statement execution - do not pass a temporary
@@ -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
@@ -423,7 +466,7 @@ public:
   void prepareQueries()
   {
     clearProperty = prepare("DELETE FROM properties WHERE key=?1");
-    writePropertyMulti = prepare("INSERT INTO properties (key, value) VALUES(?,?)");
+    writePropertyMulti = prepare("INSERT INTO properties (key, value) VALUES(?1,?2)");
     
 #define POSITIONED_COLS "rowid, type, ident, name, airport, lon, lat, elev_m, octree_node"
 #define AND_TYPED "AND type>=?2 AND type <=?3"
@@ -603,7 +646,7 @@ public:
     int range = sqlite3_column_int(loadCommStation, 0);
     int freqKhz = sqlite3_column_int(loadCommStation, 1);
     
-    CommStation* c = new CommStation(rowId, id, ty, pos, freqKhz, range);
+    CommStation* c = new CommStation(rowId, name, ty, pos, freqKhz, range);
     c->setAirport(airport);
     return c;
   }
@@ -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;
 };
 
   //////////////////////////////////////////////////////////////////////
@@ -882,10 +929,10 @@ NavDataCache::NavDataCache()
     // reached this point with no exception, success
       break;
     } catch (sg_exception& e) {
-      SG_LOG(SG_NAVCACHE, SG_WARN, "NavCache: init failed:" << e.what()
+      SG_LOG(SG_NAVCACHE, t == 0 ? SG_WARN : SG_ALERT, "NavCache: init failed:" << e.what()
              << " (attempt " << t << ")");
-      homePath.remove();
       d.reset();
+      homePath.remove();
     }
   } // of retry loop
     
@@ -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");
@@ -1064,7 +1126,7 @@ string_list NavDataCache::readStringListProperty(const string& key)
   sqlite_bind_stdstring(d->readPropertyQuery, 1, key);
   string_list result;
   while (d->stepSelect(d->readPropertyQuery)) {
-    result.push_back((char*) sqlite3_column_text(d->readPropertyQuery, 1));
+    result.push_back((char*) sqlite3_column_text(d->readPropertyQuery, 0));
   }
   
   return result;
@@ -1076,9 +1138,9 @@ void NavDataCache::writeStringListProperty(const string& key, const string_list&
   sqlite_bind_stdstring(d->clearProperty, 1, key);
   d->execUpdate(d->clearProperty);
   
-  sqlite_bind_stdstring(d->writePropertyMulti, 1, key);
   BOOST_FOREACH(string value, values) {
     d->reset(d->writePropertyMulti);
+    sqlite_bind_stdstring(d->writePropertyMulti, 1, key);
     sqlite_bind_stdstring(d->writePropertyMulti, 2, value);
     d->execInsert(d->writePropertyMulti);
   }
@@ -1468,11 +1530,16 @@ NavDataCache::findCommByFreq(int freqKhz, const SGGeod& aPos, FGPositioned::Filt
   sqlite3_bind_double(d->findCommByFreq, 5, cartPos.y());
   sqlite3_bind_double(d->findCommByFreq, 6, cartPos.z());
   
-  if (!d->execSelect(d->findCommByFreq)) {
-    return NULL;
+  while (d->execSelect(d->findCommByFreq)) {
+    FGPositioned* p = loadById(sqlite3_column_int64(d->findCommByFreq, 0));
+    if (aFilter && !aFilter->pass(p)) {
+      continue;
+    }
+    
+    return p;
   }
   
-  return loadById(sqlite3_column_int64(d->findCommByFreq, 0));
+  return NULL;
 }
   
 PositionedIDVec