From 7935d5d97c9a45102d85d10dfb1c14ef0bd2aa6f Mon Sep 17 00:00:00 2001 From: James Turner Date: Fri, 4 Jun 2021 16:58:02 +0100 Subject: [PATCH] NavData poly-lines: split out from main Octree Use a transient index for the poly-lines. This avoids NavCache disk contention when multiple copies of FG race after the rebuild completes. Should reduce locking errors early in startup. --- src/GUI/QtLauncher.cxx | 17 +------- src/Navaids/NavDataCache.cxx | 13 ++---- src/Navaids/PolyLine.cxx | 6 +-- src/Navaids/PolyLine.hxx | 1 - src/Navaids/PositionedOctree.cxx | 70 ++++++++++++++++++++++++-------- src/Navaids/PositionedOctree.hxx | 57 ++++++++++++++------------ 6 files changed, 91 insertions(+), 73 deletions(-) diff --git a/src/GUI/QtLauncher.cxx b/src/GUI/QtLauncher.cxx index aff0e7b8f..69d5a8283 100644 --- a/src/GUI/QtLauncher.cxx +++ b/src/GUI/QtLauncher.cxx @@ -218,21 +218,9 @@ private: if (m_abandoned) return; - flightgear::PolyLineList::const_iterator begin = m_parsedLines.begin() + m_lineInsertCount; - // add lines in batches of 100; this is a tradeoff to ensure we don't lock - // the database for too long. (Which triggers SQLITE_BUSY) - const int lineInsertBatchSize = 100U; - unsigned int numToAdd = std::min(100U, static_cast(m_parsedLines.size()) - m_lineInsertCount); - flightgear::PolyLineList::const_iterator end = begin + numToAdd; - flightgear::PolyLine::bulkAddToSpatialIndex(begin, end); - - if (end == m_parsedLines.end()) { - deleteLater(); // commit suicide - } else { - m_lineInsertCount += lineInsertBatchSize; - QTimer::singleShot(50, this, SLOT(onFinished())); - } + flightgear::PolyLine::bulkAddToSpatialIndex(m_parsedLines.begin(), m_parsedLines.end()); + deleteLater(); // commit suicide } void loadNaturalEarthFile(const std::string& aFileName, @@ -245,7 +233,6 @@ private: if (!path.exists()) return; // silently fail for now - flightgear::PolyLineList lines; flightgear::SHPParser::parsePolyLines(path, aType, m_parsedLines, areClosed); } diff --git a/src/Navaids/NavDataCache.cxx b/src/Navaids/NavDataCache.cxx index be039718b..d86dac6a1 100755 --- a/src/Navaids/NavDataCache.cxx +++ b/src/Navaids/NavDataCache.cxx @@ -796,9 +796,9 @@ public: sqlite3_bind_double(insertPositionedQuery, 7, pos.getElevationM()); if (spatialIndex) { - Octree::Leaf* octreeLeaf = Octree::global_spatialOctree->findLeafForPos(cartPos); - assert(intersects(octreeLeaf->bbox(), cartPos)); - sqlite3_bind_int64(insertPositionedQuery, 8, octreeLeaf->guid()); + Octree::Leaf* octreeLeaf = Octree::globalPersistentOctree()->findLeafForPos(cartPos); + assert(intersects(octreeLeaf->bbox(), cartPos)); + sqlite3_bind_int64(insertPositionedQuery, 8, octreeLeaf->guid()); } else { sqlite3_bind_null(insertPositionedQuery, 8); } @@ -1292,11 +1292,6 @@ NavDataCache::NavDataCache() } } // of retry loop - double RADIUS_EARTH_M = 7000 * 1000.0; // 7000km is plenty - SGVec3d earthExtent(RADIUS_EARTH_M, RADIUS_EARTH_M, RADIUS_EARTH_M); - Octree::global_spatialOctree = - new Octree::Branch(SGBox(-earthExtent, earthExtent), 1); - // Update d->aptDatFilesInfo, d->metarDatPath, d->navDatPath, etc. updateListsOfDatFiles(); } @@ -1995,7 +1990,7 @@ void NavDataCache::updatePosition(PositionedID item, const SGGeod &pos) // 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); + Octree::Leaf* octreeLeaf = Octree::globalPersistentOctree()->findLeafForPos(cartPos); sqlite3_bind_int64(d->setAirportPos, 5, octreeLeaf->guid()); sqlite3_bind_double(d->setAirportPos, 6, cartPos.x()); diff --git a/src/Navaids/PolyLine.cxx b/src/Navaids/PolyLine.cxx index d7fe0229a..3333b1831 100644 --- a/src/Navaids/PolyLine.cxx +++ b/src/Navaids/PolyLine.cxx @@ -103,17 +103,15 @@ PolyLineRef PolyLine::create(PolyLine::Type aTy, const SGGeodVec &aRawPoints) void PolyLine::bulkAddToSpatialIndex(PolyLineList::const_iterator begin, PolyLineList::const_iterator end) { - NavDataCache::Transaction txn( NavDataCache::instance()); flightgear::PolyLineList::const_iterator it; for (it=begin; it != end; ++it) { (*it)->addToSpatialIndex(); } - txn.commit(); } void PolyLine::addToSpatialIndex() const { - Octree::Node* node = Octree::global_spatialOctree->findNodeForBox(cartesianBox()); + Octree::Node* node = Octree::globalTransientOctree()->findNodeForBox(cartesianBox()); node->addPolyLine(const_cast(this)); } @@ -155,7 +153,7 @@ PolyLineList PolyLine::linesNearPos(const SGGeod& aPos, double aRangeNm, const T SGVec3d cart = SGVec3d::fromGeod(aPos); double cutoffM = aRangeNm * SG_NM_TO_METER; Octree::FindLinesDeque deque; - deque.push_back(Octree::global_spatialOctree); + deque.push_back(Octree::globalTransientOctree()); while (!deque.empty()) { Octree::Node* nd = deque.front(); diff --git a/src/Navaids/PolyLine.hxx b/src/Navaids/PolyLine.hxx index 0a33acf9d..b3403f154 100644 --- a/src/Navaids/PolyLine.hxx +++ b/src/Navaids/PolyLine.hxx @@ -38,7 +38,6 @@ typedef std::vector SGGeodVec; class PolyLine; typedef SGSharedPtr PolyLineRef; - typedef std::vector PolyLineList; /** diff --git a/src/Navaids/PositionedOctree.cxx b/src/Navaids/PositionedOctree.cxx index 180e8e756..0ac365e0b 100644 --- a/src/Navaids/PositionedOctree.cxx +++ b/src/Navaids/PositionedOctree.cxx @@ -21,9 +21,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include "config.h" #include "PositionedOctree.hxx" #include "positioned.hxx" @@ -37,14 +35,48 @@ #include #include +#include "PolyLine.hxx" + namespace flightgear { namespace Octree { -Node* global_spatialOctree = NULL; +std::unique_ptr global_spatialOctree; +std::unique_ptr global_transientOctree; +double RADIUS_EARTH_M = 7000 * 1000.0; // 7000km is plenty + +Node* globalTransientOctree() +{ + if (!global_transientOctree) { + SGVec3d earthExtent(RADIUS_EARTH_M, RADIUS_EARTH_M, RADIUS_EARTH_M); + global_transientOctree.reset(new Octree::Branch(SGBox(-earthExtent, earthExtent), 1, false)); + } + + return global_transientOctree.get(); +} + +Node* globalPersistentOctree() +{ + if (!global_spatialOctree) { + SGVec3d earthExtent(RADIUS_EARTH_M, RADIUS_EARTH_M, RADIUS_EARTH_M); + global_spatialOctree.reset(new Octree::Branch(SGBox(-earthExtent, earthExtent), 1, true)); + } + + return global_spatialOctree.get(); +} + +Node::Node(const SGBoxd& aBox, int64_t aIdent, bool persistent) : _ident(aIdent), + _persistent(persistent), + _box(aBox) +{ +} + +Node::~Node() +{ +} void Node::addPolyLine(const PolyLineRef& aLine) { @@ -66,9 +98,8 @@ Node *Node::findNodeForBox(const SGBoxd&) const return const_cast(this); } -Leaf::Leaf(const SGBoxd& aBox, int64_t aIdent) : - Node(aBox, aIdent), - childrenLoaded(false) +Leaf::Leaf(const SGBoxd& aBox, int64_t aIdent, bool persistent) : Node(aBox, aIdent, persistent), + childrenLoaded(false) { } @@ -136,9 +167,8 @@ void Leaf::loadChildren() /////////////////////////////////////////////////////////////////////////////// -Branch::Branch(const SGBoxd& aBox, int64_t aIdent) : - Node(aBox, aIdent), - childrenLoaded(false) +Branch::Branch(const SGBoxd& aBox, int64_t aIdent, bool persistent) : Node(aBox, aIdent, persistent), + childrenLoaded(false) { memset(children, 0, sizeof(Node*) * 8); } @@ -249,18 +279,18 @@ Node* Branch::childAtIndex(int childIndex) const if (d2 < LEAF_SIZE_SQR) { // REVIEW: Memory Leak - 480 bytes in 3 blocks are still reachable - child = new Leaf(cb, childIdent); + child = new Leaf(cb, childIdent, _persistent); } else { // REVIEW: Memory Leak - 9,152 bytes in 52 blocks are still reachable - child = new Branch(cb, childIdent); + child = new Branch(cb, childIdent, _persistent); } children[childIndex] = child; - if (childrenLoaded) { - // childrenLoad is done, so we're defining a new node - add it to the - // cache too. - NavDataCache::instance()->defineOctreeNode(const_cast(this), child); + if (_persistent && childrenLoaded) { + // childrenLoad is done, so we're defining a new node - add it to the + // cache too. + NavDataCache::instance()->defineOctreeNode(const_cast(this), child); } } @@ -273,6 +303,10 @@ void Branch::loadChildren() const return; } + if (!_persistent) { + childrenLoaded = true; + } + int childrenMask = NavDataCache::instance()->getOctreeBranchChildren(guid()); for (int i=0; i<8; ++i) { if ((1 << i) & childrenMask) { @@ -302,7 +336,7 @@ bool findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPosit aResults.clear(); FindNearestPQueue pq; FindNearestResults results; - pq.push(Ordered(global_spatialOctree, 0)); + pq.push(Ordered(globalPersistentOctree(), 0)); double cut = aCutoffM; SGTimeStamp tm; @@ -343,7 +377,7 @@ bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filte aResults.clear(); FindNearestPQueue pq; FindNearestResults results; - pq.push(Ordered(global_spatialOctree, 0)); + pq.push(Ordered(globalPersistentOctree(), 0)); double rng = aRangeM; SGTimeStamp tm; diff --git a/src/Navaids/PositionedOctree.hxx b/src/Navaids/PositionedOctree.hxx index 09ad331d3..7b3b2f674 100644 --- a/src/Navaids/PositionedOctree.hxx +++ b/src/Navaids/PositionedOctree.hxx @@ -37,11 +37,16 @@ #include #include -#include namespace flightgear { +// forward decls +class PolyLine; +typedef SGSharedPtr PolyLineRef; +typedef std::vector PolyLineList; + + namespace Octree { @@ -117,7 +122,9 @@ namespace Octree // we're always grabbing all the lines in an area typedef std::deque FindLinesDeque; - extern Node* global_spatialOctree; + Node* globalPersistentOctree(); + + Node* globalTransientOctree(); class Leaf; @@ -156,34 +163,32 @@ namespace Octree virtual Node* findNodeForBox(const SGBoxd& box) const; - virtual ~Node() {} + virtual ~Node(); void addPolyLine(const PolyLineRef&); protected: - Node(const SGBoxd &aBox, int64_t aIdent) : - _ident(aIdent), - _box(aBox) - { - } + Node(const SGBoxd& aBox, int64_t aIdent, bool persistent); - const int64_t _ident; - const SGBoxd _box; - PolyLineList lines; + const int64_t _ident; + const bool _persistent = false; + const SGBoxd _box; + + PolyLineList lines; }; class Leaf : public Node { public: - Leaf(const SGBoxd& aBox, int64_t aIdent); + Leaf(const SGBoxd& aBox, int64_t aIdent, bool persistent); - virtual void visit(const SGVec3d& aPos, double aCutoff, - FGPositioned::Filter* aFilter, - FindNearestResults& aResults, FindNearestPQueue&); + virtual void visit(const SGVec3d& aPos, double aCutoff, + FGPositioned::Filter* aFilter, + FindNearestResults& aResults, FindNearestPQueue&); - virtual Leaf* findLeafForPos(const SGVec3d&) const - { - return const_cast(this); + virtual Leaf* findLeafForPos(const SGVec3d&) const + { + return const_cast(this); } void insertChild(FGPositioned::Type ty, PositionedID id); @@ -200,16 +205,16 @@ namespace Octree class Branch : public Node { public: - Branch(const SGBoxd& aBox, int64_t aIdent); + Branch(const SGBoxd& aBox, int64_t aIdent, bool persistent); - virtual void visit(const SGVec3d& aPos, double aCutoff, - FGPositioned::Filter*, - FindNearestResults&, FindNearestPQueue& aQ); + virtual void visit(const SGVec3d& aPos, double aCutoff, + FGPositioned::Filter*, + FindNearestResults&, FindNearestPQueue& aQ); - virtual Leaf* findLeafForPos(const SGVec3d& aPos) const - { - loadChildren(); - return childForPos(aPos)->findLeafForPos(aPos); + virtual Leaf* findLeafForPos(const SGVec3d& aPos) const + { + loadChildren(); + return childForPos(aPos)->findLeafForPos(aPos); } int childMask() const;