]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/NavDataCache.cxx
Fix crash starting at heliport.
[flightgear.git] / src / Navaids / NavDataCache.cxx
index 6b102f2fbde6e0389699f1349f39bc62da214aa9..2010743cd74cf0cfd6731798aeac21d5e366f99d 100644 (file)
@@ -51,7 +51,7 @@
 #include <Main/globals.hxx>
 #include "markerbeacon.hxx"
 #include "navrecord.hxx"
-#include <Airports/simple.hxx>
+#include <Airports/airport.hxx>
 #include <Airports/runways.hxx>
 #include <ATC/CommStation.hxx>
 #include "fix.hxx"
@@ -60,6 +60,7 @@
 #include "PositionedOctree.hxx"
 #include <Airports/apt_loader.hxx>
 #include <Navaids/airways.hxx>
+#include "poidb.hxx"
 #include <Airports/parking.hxx>
 #include <Airports/gnnode.hxx>
 
@@ -71,8 +72,9 @@ using std::string;
 namespace {
 
 const int MAX_RETRIES = 10;
-const int SCHEMA_VERSION = 6;
-
+const int SCHEMA_VERSION = 8;
+const int CACHE_SIZE_KBYTES= 16000;
+    
 // 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
 // std::string, or the compiler may delete it, freeing the C-string storage,
@@ -205,12 +207,7 @@ public:
   
   ~NavDataCachePrivate()
   {
-    BOOST_FOREACH(sqlite3_stmt_ptr stmt, prepared) {
-      sqlite3_finalize(stmt);
-    }
-    prepared.clear();
-    
-    sqlite3_close(db);
+    close();
   }
   
   void init()
@@ -248,9 +245,23 @@ public:
       }
     }
     
+    // see http://www.sqlite.org/pragma.html#pragma_cache_size
+    // for the details, small cache would cause thrashing.
+    std::ostringstream q;
+    q << "PRAGMA cache_size=-" << CACHE_SIZE_KBYTES << ";";
+    runSQL(q.str());
     prepareQueries();
   }
   
+  void close()
+  {
+    BOOST_FOREACH(sqlite3_stmt_ptr stmt, prepared) {
+      sqlite3_finalize(stmt);
+    }
+    prepared.clear();
+    sqlite3_close(db);
+  }
+  
   void checkCacheFile()
   {
     SG_LOG(SG_NAVCACHE, SG_INFO, "running DB integrity check");
@@ -563,6 +574,8 @@ public:
                            " VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)");
     runwayLengthFtQuery = prepare("SELECT length_ft FROM runway WHERE rowid=?1");
     
+    removePOIQuery = prepare("DELETE FROM positioned WHERE type=?1 AND ident=?2");
+    
   // query statement    
     findClosestWithIdent = prepare("SELECT rowid FROM positioned WHERE ident=?1 "
                                    AND_TYPED " ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?4, ?5, ?6)");
@@ -714,13 +727,16 @@ public:
     if (ty == FGPositioned::TAXIWAY) {
       reset(loadRunwayStmt);
       return new FGTaxiway(rowId, id, pos, heading, lengthM, widthM, surface);
+    } else if (ty == FGPositioned::HELIPAD) {
+        reset(loadRunwayStmt);
+        return new FGHelipad(rowId, apt, id, pos, heading, lengthM, widthM, surface);
     } else {
       double displacedThreshold = sqlite3_column_double(loadRunwayStmt, 4);
       double stopway = sqlite3_column_double(loadRunwayStmt, 5);
       PositionedID reciprocal = sqlite3_column_int64(loadRunwayStmt, 6);
       PositionedID ils = sqlite3_column_int64(loadRunwayStmt, 7);
       FGRunway* r = new FGRunway(rowId, apt, id, pos, heading, lengthM, widthM,
-                          displacedThreshold, stopway, surface, false);
+                          displacedThreshold, stopway, surface);
       
       if (reciprocal > 0) {
         r->setReciprocalRunway(reciprocal);
@@ -908,6 +924,14 @@ public:
     
     deferredOctreeUpdates.clear();
   }
+    
+  void removePositionedWithIdent(FGPositioned::Type ty, const std::string& aIdent)
+  {
+    sqlite3_bind_int(removePOIQuery, 1, ty);
+    sqlite_bind_stdstring(removePOIQuery, 2, aIdent);
+    execUpdate(removePOIQuery);
+    reset(removePOIQuery);
+  }
   
   NavDataCache* outer;
   sqlite3* db;
@@ -926,7 +950,7 @@ public:
   bool transactionAborted;
   sqlite3_stmt_ptr beginTransactionStmt, commitTransactionStmt, rollbackTransactionStmt;
   
-  SGPath aptDatPath, metarDatPath, navDatPath, fixDatPath,
+  SGPath aptDatPath, metarDatPath, navDatPath, fixDatPath, poiDatPath,
   carrierDatPath, airwayDatPath;
   
   sqlite3_stmt_ptr readPropertyQuery, writePropertyQuery,
@@ -939,6 +963,7 @@ public:
   insertCommStation, insertNavaid;
   sqlite3_stmt_ptr setAirportMetar, setRunwayReciprocal, setRunwayILS,
     setAirportPos, updateRunwayThreshold, updateILS;
+  sqlite3_stmt_ptr removePOIQuery;
   
   sqlite3_stmt_ptr findClosestWithIdent;
 // octree (spatial index) related queries
@@ -1010,6 +1035,7 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
       return new AirportTower(rowid, aptId, ident, pos);
       
     case FGPositioned::RUNWAY:
+    case FGPositioned::HELIPAD:
     case FGPositioned::TAXIWAY:
       return loadRunway(rowid, ty, ident, pos, aptId);
       
@@ -1042,8 +1068,12 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
       return new FGFix(rowid, ident, pos);
       
     case FGPositioned::WAYPOINT:
+    case FGPositioned::COUNTRY:
+    case FGPositioned::CITY:
+    case FGPositioned::TOWN:
+    case FGPositioned::VILLAGE:
     {
-      FGPositioned* wpt = new FGPositioned(rowid, FGPositioned::WAYPOINT, ident, pos);
+        FGPositioned* wpt = new FGPositioned(rowid, ty, ident, pos);
       return wpt;
     }
       
@@ -1075,7 +1105,16 @@ NavDataCache::NavDataCache()
 {
   const int MAX_TRIES = 3;
   SGPath homePath(globals->get_fg_home());
-  homePath.append("navdata.cache");
+  
+  std::ostringstream os;
+  string_list versionParts = simgear::strutils::split(VERSION, ".");
+  if (versionParts.size() < 2) {
+    os << "navdata.cache";
+  } else {
+    os << "navdata_" << versionParts[0] << "_" << versionParts[1] << ".cache";
+  }
+    
+  homePath.append(os.str());
   
   for (int t=0; t < MAX_TRIES; ++t) {
     try {
@@ -1108,6 +1147,9 @@ NavDataCache::NavDataCache()
 
   d->fixDatPath = SGPath(globals->get_fg_root());
   d->fixDatPath.append("Navaids/fix.dat.gz");
+
+  d->poiDatPath = SGPath(globals->get_fg_root());
+  d->poiDatPath.append("Navaids/poi.dat.gz");
   
   d->carrierDatPath = SGPath(globals->get_fg_root());
   d->carrierDatPath.append("Navaids/carrier_nav.dat.gz");
@@ -1139,6 +1181,7 @@ bool NavDataCache::isRebuildRequired()
       isCachedFileModified(d->metarDatPath) ||
       isCachedFileModified(d->navDatPath) ||
       isCachedFileModified(d->fixDatPath) ||
+      isCachedFileModified(d->poiDatPath) ||
       isCachedFileModified(d->airwayDatPath))
   {
     SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: main cache rebuild required");
@@ -1173,20 +1216,11 @@ bool NavDataCache::rebuild()
 void NavDataCache::doRebuild()
 {
   try {
-    Transaction txn(this);
-    d->runSQL("DELETE FROM positioned");
-    d->runSQL("DELETE FROM airport");
-    d->runSQL("DELETE FROM runway");
-    d->runSQL("DELETE FROM navaid");
-    d->runSQL("DELETE FROM comm");
-    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");
+    d->close(); // completely close the sqlite object
+    d->path.remove(); // remove the file on disk
+    d->init(); // star again from scratch
     
+    Transaction txn(this);
   // initialise the root octree node
     d->runSQL("INSERT INTO octree (rowid, children) VALUES (1, 0)");
     
@@ -1209,6 +1243,11 @@ void NavDataCache::doRebuild()
     navDBInit(d->navDatPath);
     stampCacheFile(d->navDatPath);
     SG_LOG(SG_NAVCACHE, SG_INFO, "nav.dat load took:" << st.elapsedMSec());
+
+    st.stamp();
+    poiDBInit(d->poiDatPath);
+    stampCacheFile(d->poiDatPath);
+    SG_LOG(SG_NAVCACHE, SG_INFO, "poi.dat load took:" << st.elapsedMSec());
     
     loadCarrierNav(d->carrierDatPath);
     stampCacheFile(d->carrierDatPath);
@@ -1515,7 +1554,7 @@ NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident,
 {
   // only runways are spatially indexed; don't bother indexing taxiways
   // or pavements
-  bool spatialIndex = (ty == FGPositioned::RUNWAY);
+  bool spatialIndex = ( ty == FGPositioned::RUNWAY || ty == FGPositioned::HELIPAD);
   
   sqlite3_int64 rowId = d->insertPositioned(ty, cleanRunwayNo(ident), "", pos, apt,
                                             spatialIndex);
@@ -1547,6 +1586,12 @@ void NavDataCache::setRunwayILS(PositionedID runway, PositionedID ils)
   sqlite3_bind_int64(d->setRunwayILS, 1, runway);
   sqlite3_bind_int64(d->setRunwayILS, 2, ils);
   d->execUpdate(d->setRunwayILS);
+    
+  // and the in-memory one
+  if (d->cache.find(runway) != d->cache.end()) {
+    FGRunway* instance = (FGRunway*) d->cache[runway].ptr();
+    instance->setILS(ils);
+  }
 }
   
 void NavDataCache::updateRunwayThreshold(PositionedID runwayID, const SGGeod &aThreshold,
@@ -1559,14 +1604,9 @@ void NavDataCache::updateRunwayThreshold(PositionedID runwayID, const SGGeod &aT
   sqlite3_bind_double(d->updateRunwayThreshold, 3, aDisplacedThreshold);
   sqlite3_bind_double(d->updateRunwayThreshold, 4, aStopway);
   d->execUpdate(d->updateRunwayThreshold);
-      
-// compute the new runway center, based on the threshold lat/lon and length,
-  double offsetFt = (0.5 * d->runwayLengthFt(runwayID));
-  SGGeod newCenter= SGGeodesy::direct(aThreshold, aHeading, offsetFt * SG_FEET_TO_METER);
-  newCenter.setElevationM(aThreshold.getElevationM());
-  
-// now update the positional data
-  updatePosition(runwayID, newCenter);
+
+  // now update the positional data
+  updatePosition(runwayID, aThreshold);
 }
   
 PositionedID
@@ -1614,11 +1654,17 @@ PositionedID NavDataCache::insertFix(const std::string& ident, const SGGeod& aPo
   return d->insertPositioned(FGPositioned::FIX, ident, string(), aPos, 0, true);
 }
 
-PositionedID NavDataCache::createUserWaypoint(const std::string& ident, const SGGeod& aPos)
+PositionedID NavDataCache::createPOI(FGPositioned::Type ty, const std::string& ident, const SGGeod& aPos)
 {
-  return d->insertPositioned(FGPositioned::WAYPOINT, ident, string(), aPos, 0,
+  return d->insertPositioned(ty, ident, string(), aPos, 0,
                              true /* spatial index */);
 }
+    
+void NavDataCache::removePOI(FGPositioned::Type ty, const std::string& aIdent)
+{
+  d->removePositionedWithIdent(ty, aIdent);
+  // should remove from the live cache too?
+}
   
 void NavDataCache::setAirportMetar(const string& icao, bool hasMetar)
 {
@@ -2115,9 +2161,10 @@ void NavDataCache::dropGroundnetFor(PositionedID aAirport)
   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)");
+  q = d->prepare("DELETE FROM taxi_node WHERE rowid IN (SELECT rowid FROM positioned WHERE (type=?1 OR type=?2) AND airport=?3)");
   sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
-  sqlite3_bind_int64(q, 2, aAirport);
+  sqlite3_bind_int(q, 2, FGPositioned::PARKING);
+  sqlite3_bind_int64(q, 3, aAirport);
   d->execUpdate(q);
   
   q = d->prepare("DELETE FROM positioned WHERE (type=?1 OR type=?2) AND airport=?3");