]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/NavDataCache.cxx
Bug #927 - flightplan XML loading.
[flightgear.git] / src / Navaids / NavDataCache.cxx
index 24de0fbd3fda5429fb882cae48e35085af7322fa..05e8c011eec4cd204a65474f44d50f1beef72727 100644 (file)
 
 using std::string;
 
-#define SG_NAVCACHE SG_GENERAL
+#define SG_NAVCACHE SG_NAVAID
 //#define LAZY_OCTREE_UPDATES 1
 
 namespace {
 
-const int SCHEMA_VERSION = 5;
+const int SCHEMA_VERSION = 6;
 
 // 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
@@ -163,7 +163,7 @@ public:
     SGTimeStamp st;
     st.stamp();
     _cache->doRebuild();
-    SG_LOG(SG_GENERAL, SG_INFO, "cache rebuild took:" << st.elapsedMSec() << "msec");
+    SG_LOG(SG_NAVCACHE, SG_INFO, "cache rebuild took:" << st.elapsedMSec() << "msec");
     
     SGGuard<SGMutex> g(_lock);
     _isFinished = true;
@@ -232,8 +232,8 @@ public:
     }
     
     readPropertyQuery = prepare("SELECT value FROM properties WHERE key=?");
-    writePropertyQuery = prepare("INSERT OR REPLACE INTO properties "
-                                 "(key, value) VALUES (?,?)");
+    writePropertyQuery = prepare("INSERT INTO properties (key, value) VALUES (?,?)");
+    clearProperty = prepare("DELETE FROM properties WHERE key=?1");
     
     if (didCreate) {
       writeIntProperty("schema-version", SCHEMA_VERSION);
@@ -334,15 +334,32 @@ public:
     return stepSelect(stmt);
   }
   
+  static const int MAX_RETRIES = 10;
+  
   bool stepSelect(sqlite3_stmt_ptr stmt)
   {
-    int result = sqlite3_step(stmt);
-    if (result == SQLITE_ROW) {
-      return true; // at least one result row
-    }
+    int retries = 0;
+    int result;
+    while (retries < MAX_RETRIES) {
+      result = sqlite3_step(stmt);
+      if (result == SQLITE_ROW) {
+        return true; // at least one result row
+      }
+      
+      if (result == SQLITE_DONE) {
+        return false; // no result rows
+      }
+      
+      if (result != SQLITE_LOCKED) {
+        break;
+      }
+      
+      ++retries;
+    } // of retry loop for DB locked
     
-    if (result == SQLITE_DONE) {
-      return false; // no result rows
+    if (retries >= MAX_RETRIES) {
+      SG_LOG(SG_NAVCACHE, SG_ALERT, "exceeded maximum number of SQLITE_LOCKED retries");
+      return false;
     }
     
     string errMsg;
@@ -490,7 +507,6 @@ public:
   
   void prepareQueries()
   {
-    clearProperty = prepare("DELETE FROM properties WHERE key=?1");
     writePropertyMulti = prepare("INSERT INTO properties (key, value) VALUES(?1,?2)");
     
 #define POSITIONED_COLS "rowid, type, ident, name, airport, lon, lat, elev_m, octree_node"
@@ -651,6 +667,10 @@ public:
   
   void writeIntProperty(const string& key, int value)
   {
+    reset(clearProperty);
+    sqlite_bind_stdstring(clearProperty, 1, key);
+    execUpdate(clearProperty);
+    
     sqlite_bind_stdstring(writePropertyQuery, 1, key);
     sqlite3_bind_int(writePropertyQuery, 2, value);
     execSelect(writePropertyQuery);
@@ -1096,11 +1116,17 @@ bool NavDataCache::isRebuildRequired()
       isCachedFileModified(d->fixDatPath) ||
       isCachedFileModified(d->airwayDatPath))
   {
-    SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: rebuild required");
+    SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: main cache rebuild required");
     return true;
   }
 
-  SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: no rebuild required");
+  string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");  
+  if (readStringProperty("scenery_paths") != sceneryPaths) {
+    SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: scenery paths changed, main cache rebuild required");
+    return true;
+  }
+    
+  SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: no main cache rebuild required");
   return false;
 }
   
@@ -1131,6 +1157,10 @@ void NavDataCache::doRebuild()
     d->runSQL("DELETE FROM octree");
     d->runSQL("DELETE FROM airway");
     d->runSQL("DELETE FROM airway_edge");
+    d->runSQL("DELETE FROM taxi_node");
+    d->runSQL("DELETE FROM parking");
+    d->runSQL("DELETE FROM groundnet_edge");
+    d->runSQL("DELETE FROM stat_cache");
     
   // initialise the root octree node
     d->runSQL("INSERT INTO octree (rowid, children) VALUES (1, 0)");
@@ -1165,6 +1195,9 @@ void NavDataCache::doRebuild()
     
     d->flushDeferredOctreeUpdates();
     
+    string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
+    writeStringProperty("scenery_paths", sceneryPaths);
+    
     d->runSQL("COMMIT");
   } catch (sg_exception& e) {
     SG_LOG(SG_NAVCACHE, SG_ALERT, "caught exception rebuilding navCache:" << e.what());
@@ -1217,6 +1250,10 @@ void NavDataCache::writeIntProperty(const string& key, int value)
 
 void NavDataCache::writeStringProperty(const string& key, const string& value)
 {
+  d->reset(d->clearProperty);
+  sqlite_bind_stdstring(d->clearProperty, 1, key);
+  d->execUpdate(d->clearProperty);
+
   d->reset(d->writePropertyQuery);
   sqlite_bind_stdstring(d->writePropertyQuery, 1, key);
   sqlite_bind_stdstring(d->writePropertyQuery, 2, value);
@@ -1225,6 +1262,10 @@ void NavDataCache::writeStringProperty(const string& key, const string& value)
 
 void NavDataCache::writeDoubleProperty(const string& key, const double& value)
 {
+  d->reset(d->clearProperty);
+  sqlite_bind_stdstring(d->clearProperty, 1, key);
+  d->execUpdate(d->clearProperty);
+  
   d->reset(d->writePropertyQuery);
   sqlite_bind_stdstring(d->writePropertyQuery, 1, key);
   sqlite3_bind_double(d->writePropertyQuery, 2, value);
@@ -1267,8 +1308,25 @@ bool NavDataCache::isCachedFileModified(const SGPath& path) const
   sqlite_bind_temp_stdstring(d->statCacheCheck, 1, path.str());
   if (d->execSelect(d->statCacheCheck)) {
     time_t modtime = sqlite3_column_int64(d->statCacheCheck, 0);
-    return (modtime != path.modTime());
+    time_t delta = std::labs(modtime - path.modTime());
+    if (delta != 0)
+    {
+      SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: rebuild required for " << path << ". Timestamps: " << modtime << " != " << path.modTime());
+      if (delta < 30)
+      {
+          // File system time stamp has slightly changed. It's unlikely that the user has managed to change a file, start fgfs,
+          // and then changed file again within x seconds - so it's suspicious...
+          SG_LOG(SG_NAVCACHE, SG_ALERT, "NavCache: suspicious file timestamp change. Please report this to FlightGear. "
+                  << "Delta: " << delta << ", Timestamps: " << modtime << ", " << path.modTime() << ", path: " << path);
+      }
+    }
+    else
+    {
+      SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: no rebuild required for " << path);
+    }
+    return (delta != 0);
   } else {
+    SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: initial build required for " << path);
     return true;
   }
 }
@@ -1338,7 +1396,7 @@ PositionedID NavDataCache::insertAirport(FGPositioned::Type ty, const string& id
 void NavDataCache::updatePosition(PositionedID item, const SGGeod &pos)
 {
   if (d->cache.find(item) != d->cache.end()) {
-    SG_LOG(SG_GENERAL, SG_DEBUG, "updating position of an item in the cache");
+    SG_LOG(SG_NAVCACHE, SG_DEBUG, "updating position of an item in the cache");
     d->cache[item]->modifyPosition(pos);
   }
   
@@ -1350,6 +1408,14 @@ void NavDataCache::updatePosition(PositionedID item, const SGGeod &pos)
   sqlite3_bind_double(d->setAirportPos, 3, pos.getLatitudeDeg());
   sqlite3_bind_double(d->setAirportPos, 4, pos.getElevationM());
   
+// bug 905; the octree leaf may change here, but the leaf may already be
+// loaded, and caching its children. (Either the old or new leaf!). Worse,
+// we may be called here as a result of loading one of those leaf's children.
+// instead of dealing with all those possibilites, such as modifying
+// the in-memory leaf's STL child container, we simply leave the runtime
+// structures alone. This is fine providing items do no move very far, since
+// all the spatial searches ultimately use the items' real cartesian position,
+// which was updated above.
   Octree::Leaf* octreeLeaf = Octree::global_spatialOctree->findLeafForPos(cartPos);
   sqlite3_bind_int64(d->setAirportPos, 5, octreeLeaf->guid());
   
@@ -1973,5 +2039,28 @@ PositionedIDVec NavDataCache::findAirportParking(PositionedID airport, const std
   return d->selectIds(d->findAirportParking);
 }
 
+void NavDataCache::dropGroundnetFor(PositionedID aAirport)
+{
+  sqlite3_stmt_ptr q = d->prepare("DELETE FROM parking WHERE rowid IN (SELECT rowid FROM positioned WHERE type=?1 AND airport=?2)");
+  sqlite3_bind_int(q, 1, FGPositioned::PARKING);
+  sqlite3_bind_int64(q, 2, aAirport);
+  d->execUpdate(q);
+  
+  q = d->prepare("DELETE FROM taxi_node WHERE rowid IN (SELECT rowid FROM positioned WHERE type=?1 AND airport=?2)");
+  sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
+  sqlite3_bind_int64(q, 2, aAirport);
+  d->execUpdate(q);
+  
+  q = d->prepare("DELETE FROM positioned WHERE (type=?1 OR type=?2) AND airport=?3");
+  sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
+  sqlite3_bind_int(q, 2, FGPositioned::PARKING);
+  sqlite3_bind_int64(q, 3, aAirport);
+  d->execUpdate(q);
+  
+  q = d->prepare("DELETE FROM groundnet_edge WHERE airport=?1");
+  sqlite3_bind_int64(q, 1, aAirport);
+  d->execUpdate(q);
+}
+  
 } // of namespace flightgear