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:
parent
ef07f26023
commit
7935d5d97c
6 changed files with 91 additions and 73 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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*,
|
||||||
|
|
Loading…
Add table
Reference in a new issue