[Marble-commits] KDE/kdeedu/marble/src/plugins/runner/monav

Dennis Nienhüser earthwings at gentoo.org
Mon Aug 30 22:51:22 CEST 2010


SVN commit 1170138 by nienhueser:

Change to pipe mode to avoid the repeated costs for creating a QProcess and loading monav maps in the client. The plugin manages the QProcess now (instead of the runner), keeping it alive for 30 seconds after the last user activity (route request). Complicated routes are retrieved even faster now (e.g. 1000 km, 10 via points in 350 ms from RouteSkeleton to GeoDataDocument.)

 M  +71 -3     MonavPlugin.cpp  
 M  +10 -0     MonavPlugin.h  
 M  +29 -34    MonavRunner.cpp  
 M  +3 -1      MonavRunner.h  


--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavPlugin.cpp #1170137:1170138
@@ -10,28 +10,96 @@
 
 #include "MonavPlugin.h"
 #include "MonavRunner.h"
+#include "MarbleDirs.h"
+#include "MarbleDebug.h"
 
+#include <QtCore/QProcess>
+#include <QtCore/QDir>
+#include <QtCore/QMutexLocker>
+#include <QtCore/QTimer>
+
 namespace Marble
 {
 
-MonavPlugin::MonavPlugin( QObject *parent ) : RunnerPlugin( parent )
+class MonavPluginPrivate
 {
-    setCapabilities( Routing );
+public:
+    QProcess* m_monavProcess;
+
+    QDir m_mapDir;
+
+    QMutex m_processMutex;
+
+    QTimer m_shutdownTimer;
+
+    MonavPluginPrivate();
+};
+
+MonavPluginPrivate::MonavPluginPrivate() : m_monavProcess( 0 )
+{
+    m_shutdownTimer.setInterval( 30 * 1000 );
+    m_shutdownTimer.setSingleShot( true );
+}
+
+MonavPlugin::MonavPlugin( QObject *parent ) : RunnerPlugin( parent ), d( new MonavPluginPrivate )
+{
     setSupportedCelestialBodies( QStringList() << "earth" );
     setCanWorkOffline( true );
     setName( tr( "Monav" ) );
     setNameId( "monav" );
     setDescription( tr( "Retrieves routes from monav" ) );
     setGuiString( tr( "Monav Routing" ) );
+
+    // Check installation
+    d->m_mapDir = QDir( MarbleDirs::localPath() + "/maps/earth/monav/" );
+    bool haveMap = QFileInfo( d->m_mapDir, "Contraction Hierarchies" ).exists();
+    setCapabilities( haveMap ? Routing : None );
+
+    connect( &d->m_shutdownTimer, SIGNAL( timeout() ), this, SLOT( killProcess( ) ) );
 }
 
+MonavPlugin::~MonavPlugin()
+{
+    killProcess();
+    delete d;
+}
+
 MarbleAbstractRunner* MonavPlugin::newRunner() const
 {
-    return new MonavRunner;
+    QMutexLocker locker( &d->m_processMutex );
+    if ( !d->m_monavProcess ) {
+        d->m_monavProcess = new QProcess;
+        d->m_monavProcess->start( "monav", QStringList() << "--pipe" << d->m_mapDir.absolutePath() );
+
+        if ( !d->m_monavProcess->waitForStarted( 5000 ) )
+        {
+            mDebug() << "Couldn't start monav from the current PATH. Install it to retrieve routing results from monav.";
 }
+    }
 
+    d->m_shutdownTimer.start();
+    return new MonavRunner( d->m_monavProcess );
 }
 
+void MonavPlugin::killProcess()
+{
+    QMutexLocker locker( &d->m_processMutex );
+
+    if ( d->m_monavProcess ) {
+        QProcess* dying = d->m_monavProcess;
+        d->m_monavProcess = 0;
+        dying->closeWriteChannel();
+        if ( !dying->waitForFinished( 1000 ) ) {
+            dying->terminate();
+            if ( !dying->waitForFinished( 1000 ) ) {
+                mDebug() << "monav process did not terminate properly.";
+            }
+        }
+    }
+}
+
+}
+
 Q_EXPORT_PLUGIN2( MonavPlugin, Marble::MonavPlugin )
 
 #include "MonavPlugin.moc"
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavPlugin.h #1170137:1170138
@@ -16,6 +16,8 @@
 namespace Marble
 {
 
+class MonavPluginPrivate;
+
 class MonavPlugin : public RunnerPlugin
 {
     Q_OBJECT
@@ -24,7 +26,15 @@
 public:
     explicit MonavPlugin( QObject *parent = 0 );
 
+    ~MonavPlugin();
+
     virtual MarbleAbstractRunner* newRunner() const;
+
+private Q_SLOTS:
+    void killProcess();
+
+private:
+    MonavPluginPrivate* const d;
 };
 
 }
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavRunner.cpp #1170137:1170138
@@ -10,7 +10,6 @@
 
 #include "MonavRunner.h"
 
-#include "MarbleDebug.h"
 #include "MarbleDirs.h"
 #include "routing/RouteSkeleton.h"
 #include "GeoDataDocument.h"
@@ -23,39 +22,44 @@
 class MonavRunnerPrivate
 {
 public:
-    QDir m_mapDir;
+    QProcess* m_monavProcess;
 
-    GeoDataLineString* retrieveWaypoints( const QStringList &params ) const;
+    MonavRunnerPrivate( QProcess* monav );
 
+    GeoDataLineString* retrieveWaypoints( const QString &params );
+
     GeoDataDocument* createDocument( GeoDataLineString* routeWaypoints ) const;
 
     GeoDataLineString* parseMonavOutput( const QByteArray &content ) const;
 };
 
-GeoDataLineString* MonavRunnerPrivate::retrieveWaypoints( const QStringList &params ) const
+MonavRunnerPrivate::MonavRunnerPrivate( QProcess* monav ) :
+        m_monavProcess( monav )
 {
-    QStringList monavParams;
-    monavParams << params << m_mapDir.absolutePath();
-    QProcess monavProcess;
-    monavProcess.start( "monav", monavParams );
-
-    if ( !monavProcess.waitForStarted( 5000 ) )
-    {
-        mDebug() << "Couldn't start monav from the current PATH. Install it to retrieve routing results from monav.";
-        return 0;
+    // nothing to do
     }
 
-    if ( monavProcess.waitForFinished( 60 * 1000 ) )
+GeoDataLineString* MonavRunnerPrivate::retrieveWaypoints( const QString &params )
     {
-        return parseMonavOutput( monavProcess.readAllStandardOutput() );
+    Q_ASSERT( m_monavProcess );
+    m_monavProcess->write( params.toAscii() );
+    QByteArray data;
+    for ( int i=1; i<15; ++i ) {
+        if ( m_monavProcess->bytesAvailable() ) {
+            data += m_monavProcess->readAllStandardOutput();
+            bool haveRoute = data.endsWith("\n\n");
+            if ( haveRoute ) {
+                return parseMonavOutput( data );
     }
-    else
-    {
-        mDebug() << "Couldn't stop monav";
-        return 0;
+        } else {
+            ++i;
+            usleep( 1000 * pow( 2, i ) );
     }
 }
 
+    return 0;
+}
+
 GeoDataLineString* MonavRunnerPrivate::parseMonavOutput( const QByteArray &content ) const
 {
     GeoDataLineString* routeWaypoints = new GeoDataLineString;
@@ -101,12 +105,10 @@
     return result;
 }
 
-MonavRunner::MonavRunner( QObject *parent ) :
+MonavRunner::MonavRunner( QProcess* monav, QObject *parent ) :
         MarbleAbstractRunner( parent ),
-        d( new MonavRunnerPrivate )
+        d( new MonavRunnerPrivate( monav ) )
 {
-    // Check installation
-    d->m_mapDir = QDir( MarbleDirs::localPath() + "/maps/earth/monav/" );
 }
 
 MonavRunner::~MonavRunner()
@@ -121,23 +123,16 @@
 
 void MonavRunner::retrieveRoute( RouteSkeleton *route )
 {
-    if ( ! QFileInfo( d->m_mapDir, "Contraction Hierarchies" ).exists() )
-    {
-        emit routeCalculated( 0 );
-        return;
-    }
-
-    QStringList params;
-
+    QString params;
     for ( int i = 0; i < route->size(); ++i )
     {
         double lon = route->at( i ).longitude( GeoDataCoordinates::Degree );
         double lat = route->at( i ).latitude( GeoDataCoordinates::Degree );
-        params << QString( "--lat%1=%2" ).arg( i + 1 ).arg( lat, 0, 'f', 8 );
-        params << QString( "--lon%1=%2" ).arg( i + 1 ).arg( lon, 0, 'f', 8 );
+        params += QString( " --lat%1=%2" ).arg( i + 1 ).arg( lat, 0, 'f', 8 );
+        params += QString( " --lon%1=%2" ).arg( i + 1 ).arg( lon, 0, 'f', 8 );
     }
-    GeoDataLineString* wayPoints = d->retrieveWaypoints( params );
 
+    GeoDataLineString* wayPoints = d->retrieveWaypoints( params.trimmed() + "\n" );
     GeoDataDocument* result = d->createDocument( wayPoints );
     emit routeCalculated( result );
 }
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavRunner.h #1170137:1170138
@@ -14,6 +14,8 @@
 #include "MarbleAbstractRunner.h"
 #include "routing/RouteSkeleton.h"
 
+class QProcess;
+
 namespace Marble
 {
 
@@ -23,7 +25,7 @@
 {
     Q_OBJECT
 public:
-    explicit MonavRunner( QObject *parent = 0 );
+    explicit MonavRunner( QProcess* monav, QObject *parent = 0 );
 
     ~MonavRunner();
 


More information about the Marble-commits mailing list