1
0
Fork 0

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.
This commit is contained in:
James Turner 2021-06-04 16:58:02 +01:00
parent ef07f26023
commit 7935d5d97c
6 changed files with 91 additions and 73 deletions

View file

@ -218,21 +218,9 @@ private:
if (m_abandoned) if (m_abandoned)
return; 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 flightgear::PolyLine::bulkAddToSpatialIndex(m_parsedLines.begin(), m_parsedLines.end());
// the database for too long. (Which triggers SQLITE_BUSY)
const int lineInsertBatchSize = 100U;
unsigned int numToAdd = std::min<unsigned int>(100U, static_cast<unsigned int>(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 deleteLater(); // commit suicide
} else {
m_lineInsertCount += lineInsertBatchSize;
QTimer::singleShot(50, this, SLOT(onFinished()));
}
} }
void loadNaturalEarthFile(const std::string& aFileName, void loadNaturalEarthFile(const std::string& aFileName,
@ -245,7 +233,6 @@ private:
if (!path.exists()) if (!path.exists())
return; // silently fail for now return; // silently fail for now
flightgear::PolyLineList lines;
flightgear::SHPParser::parsePolyLines(path, aType, m_parsedLines, areClosed); flightgear::SHPParser::parsePolyLines(path, aType, m_parsedLines, areClosed);
} }

View file

@ -796,7 +796,7 @@ public:
sqlite3_bind_double(insertPositionedQuery, 7, pos.getElevationM()); sqlite3_bind_double(insertPositionedQuery, 7, pos.getElevationM());
if (spatialIndex) { if (spatialIndex) {
Octree::Leaf* octreeLeaf = Octree::global_spatialOctree->findLeafForPos(cartPos); Octree::Leaf* octreeLeaf = Octree::globalPersistentOctree()->findLeafForPos(cartPos);
assert(intersects(octreeLeaf->bbox(), cartPos)); assert(intersects(octreeLeaf->bbox(), cartPos));
sqlite3_bind_int64(insertPositionedQuery, 8, octreeLeaf->guid()); sqlite3_bind_int64(insertPositionedQuery, 8, octreeLeaf->guid());
} else { } else {
@ -1292,11 +1292,6 @@ NavDataCache::NavDataCache()
} }
} // of retry loop } // 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<double>(-earthExtent, earthExtent), 1);
// Update d->aptDatFilesInfo, d->metarDatPath, d->navDatPath, etc. // Update d->aptDatFilesInfo, d->metarDatPath, d->navDatPath, etc.
updateListsOfDatFiles(); 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 // structures alone. This is fine providing items do no move very far, since
// all the spatial searches ultimately use the items' real cartesian position, // all the spatial searches ultimately use the items' real cartesian position,
// which was updated above. // 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_int64(d->setAirportPos, 5, octreeLeaf->guid());
sqlite3_bind_double(d->setAirportPos, 6, cartPos.x()); sqlite3_bind_double(d->setAirportPos, 6, cartPos.x());

View file

@ -103,17 +103,15 @@ PolyLineRef PolyLine::create(PolyLine::Type aTy, const SGGeodVec &aRawPoints)
void PolyLine::bulkAddToSpatialIndex(PolyLineList::const_iterator begin, void PolyLine::bulkAddToSpatialIndex(PolyLineList::const_iterator begin,
PolyLineList::const_iterator end) PolyLineList::const_iterator end)
{ {
NavDataCache::Transaction txn( NavDataCache::instance());
flightgear::PolyLineList::const_iterator it; flightgear::PolyLineList::const_iterator it;
for (it=begin; it != end; ++it) { for (it=begin; it != end; ++it) {
(*it)->addToSpatialIndex(); (*it)->addToSpatialIndex();
} }
txn.commit();
} }
void PolyLine::addToSpatialIndex() const void PolyLine::addToSpatialIndex() const
{ {
Octree::Node* node = Octree::global_spatialOctree->findNodeForBox(cartesianBox()); Octree::Node* node = Octree::globalTransientOctree()->findNodeForBox(cartesianBox());
node->addPolyLine(const_cast<PolyLine*>(this)); node->addPolyLine(const_cast<PolyLine*>(this));
} }
@ -155,7 +153,7 @@ PolyLineList PolyLine::linesNearPos(const SGGeod& aPos, double aRangeNm, const T
SGVec3d cart = SGVec3d::fromGeod(aPos); SGVec3d cart = SGVec3d::fromGeod(aPos);
double cutoffM = aRangeNm * SG_NM_TO_METER; double cutoffM = aRangeNm * SG_NM_TO_METER;
Octree::FindLinesDeque deque; Octree::FindLinesDeque deque;
deque.push_back(Octree::global_spatialOctree); deque.push_back(Octree::globalTransientOctree());
while (!deque.empty()) { while (!deque.empty()) {
Octree::Node* nd = deque.front(); Octree::Node* nd = deque.front();

View file

@ -38,7 +38,6 @@ typedef std::vector<SGGeod> SGGeodVec;
class PolyLine; class PolyLine;
typedef SGSharedPtr<PolyLine> PolyLineRef; typedef SGSharedPtr<PolyLine> PolyLineRef;
typedef std::vector<PolyLineRef> PolyLineList; typedef std::vector<PolyLineRef> PolyLineList;
/** /**

View file

@ -21,9 +21,7 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H #include "config.h"
# include "config.h"
#endif
#include "PositionedOctree.hxx" #include "PositionedOctree.hxx"
#include "positioned.hxx" #include "positioned.hxx"
@ -37,14 +35,48 @@
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/timing/timestamp.hxx> #include <simgear/timing/timestamp.hxx>
#include "PolyLine.hxx"
namespace flightgear namespace flightgear
{ {
namespace Octree namespace Octree
{ {
Node* global_spatialOctree = NULL; std::unique_ptr<Node> global_spatialOctree;
std::unique_ptr<Node> 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<double>(-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<double>(-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) void Node::addPolyLine(const PolyLineRef& aLine)
{ {
@ -66,8 +98,7 @@ Node *Node::findNodeForBox(const SGBoxd&) const
return const_cast<Node*>(this); return const_cast<Node*>(this);
} }
Leaf::Leaf(const SGBoxd& aBox, int64_t aIdent) : Leaf::Leaf(const SGBoxd& aBox, int64_t aIdent, bool persistent) : Node(aBox, aIdent, persistent),
Node(aBox, aIdent),
childrenLoaded(false) childrenLoaded(false)
{ {
} }
@ -136,8 +167,7 @@ void Leaf::loadChildren()
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
Branch::Branch(const SGBoxd& aBox, int64_t aIdent) : Branch::Branch(const SGBoxd& aBox, int64_t aIdent, bool persistent) : Node(aBox, aIdent, persistent),
Node(aBox, aIdent),
childrenLoaded(false) childrenLoaded(false)
{ {
memset(children, 0, sizeof(Node*) * 8); memset(children, 0, sizeof(Node*) * 8);
@ -249,15 +279,15 @@ Node* Branch::childAtIndex(int childIndex) const
if (d2 < LEAF_SIZE_SQR) { if (d2 < LEAF_SIZE_SQR) {
// REVIEW: Memory Leak - 480 bytes in 3 blocks are still reachable // REVIEW: Memory Leak - 480 bytes in 3 blocks are still reachable
child = new Leaf(cb, childIdent); child = new Leaf(cb, childIdent, _persistent);
} else { } else {
// REVIEW: Memory Leak - 9,152 bytes in 52 blocks are still reachable // 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; children[childIndex] = child;
if (childrenLoaded) { if (_persistent && childrenLoaded) {
// childrenLoad is done, so we're defining a new node - add it to the // childrenLoad is done, so we're defining a new node - add it to the
// cache too. // cache too.
NavDataCache::instance()->defineOctreeNode(const_cast<Branch*>(this), child); NavDataCache::instance()->defineOctreeNode(const_cast<Branch*>(this), child);
@ -273,6 +303,10 @@ void Branch::loadChildren() const
return; return;
} }
if (!_persistent) {
childrenLoaded = true;
}
int childrenMask = NavDataCache::instance()->getOctreeBranchChildren(guid()); int childrenMask = NavDataCache::instance()->getOctreeBranchChildren(guid());
for (int i=0; i<8; ++i) { for (int i=0; i<8; ++i) {
if ((1 << i) & childrenMask) { if ((1 << i) & childrenMask) {
@ -302,7 +336,7 @@ bool findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPosit
aResults.clear(); aResults.clear();
FindNearestPQueue pq; FindNearestPQueue pq;
FindNearestResults results; FindNearestResults results;
pq.push(Ordered<Node*>(global_spatialOctree, 0)); pq.push(Ordered<Node*>(globalPersistentOctree(), 0));
double cut = aCutoffM; double cut = aCutoffM;
SGTimeStamp tm; SGTimeStamp tm;
@ -343,7 +377,7 @@ bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filte
aResults.clear(); aResults.clear();
FindNearestPQueue pq; FindNearestPQueue pq;
FindNearestResults results; FindNearestResults results;
pq.push(Ordered<Node*>(global_spatialOctree, 0)); pq.push(Ordered<Node*>(globalPersistentOctree(), 0));
double rng = aRangeM; double rng = aRangeM;
SGTimeStamp tm; SGTimeStamp tm;

View file

@ -37,11 +37,16 @@
#include <Navaids/positioned.hxx> #include <Navaids/positioned.hxx>
#include <Navaids/NavDataCache.hxx> #include <Navaids/NavDataCache.hxx>
#include <Navaids/PolyLine.hxx>
namespace flightgear namespace flightgear
{ {
// forward decls
class PolyLine;
typedef SGSharedPtr<PolyLine> PolyLineRef;
typedef std::vector<PolyLineRef> PolyLineList;
namespace Octree namespace Octree
{ {
@ -117,7 +122,9 @@ namespace Octree
// we're always grabbing all the lines in an area // we're always grabbing all the lines in an area
typedef std::deque<Node*> FindLinesDeque; typedef std::deque<Node*> FindLinesDeque;
extern Node* global_spatialOctree; Node* globalPersistentOctree();
Node* globalTransientOctree();
class Leaf; class Leaf;
@ -156,17 +163,15 @@ namespace Octree
virtual Node* findNodeForBox(const SGBoxd& box) const; virtual Node* findNodeForBox(const SGBoxd& box) const;
virtual ~Node() {} virtual ~Node();
void addPolyLine(const PolyLineRef&); void addPolyLine(const PolyLineRef&);
protected: protected:
Node(const SGBoxd &aBox, int64_t aIdent) : Node(const SGBoxd& aBox, int64_t aIdent, bool persistent);
_ident(aIdent),
_box(aBox)
{
}
const int64_t _ident; const int64_t _ident;
const bool _persistent = false;
const SGBoxd _box; const SGBoxd _box;
PolyLineList lines; PolyLineList lines;
@ -175,7 +180,7 @@ namespace Octree
class Leaf : public Node class Leaf : public Node
{ {
public: 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, virtual void visit(const SGVec3d& aPos, double aCutoff,
FGPositioned::Filter* aFilter, FGPositioned::Filter* aFilter,
@ -200,7 +205,7 @@ namespace Octree
class Branch : public Node class Branch : public Node
{ {
public: 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, virtual void visit(const SGVec3d& aPos, double aCutoff,
FGPositioned::Filter*, FGPositioned::Filter*,