[rkward-cvs] SF.net SVN: rkward:[3192] branches/2010_10_18_backend_restructuring_branch/ rkward
tfry at users.sourceforge.net
tfry at users.sourceforge.net
Wed Nov 17 19:14:00 UTC 2010
Revision: 3192
http://rkward.svn.sourceforge.net/rkward/?rev=3192&view=rev
Author: tfry
Date: 2010-11-17 19:14:00 +0000 (Wed, 17 Nov 2010)
Log Message:
-----------
Separate process backend is basically functional (but a lot of small stuff is still left to do).
Performance looks better than expected.
Hooray.
Modified Paths:
--------------
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp
branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h
branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp 2010-11-17 19:14:00 UTC (rev 3192)
@@ -131,6 +131,7 @@
RK_ASSERT (previous_command == 0);
RK_ASSERT (!all_current_commands.isEmpty ());
previous_command = all_current_commands.takeLast ();
+qDebug ("previous command: %d", previous_command->id ());
RCommandStack::currentStack ()->pop ();
}
@@ -328,7 +329,6 @@
issueCommand ("rk.set.output.html.file (\"" + RKSettingsModuleGeneral::filesPath () + "/rk_out.html\")\n", RCommand::App | RCommand::Sync, QString (), this, SET_RUNTIME_OPTS, chain);
closeChain (chain);
- RKRBackendProtocolFrontend::setRequestCompleted (request);
} else {
processRBackendRequest (request);
}
@@ -694,6 +694,8 @@
message += i18n ("\nIt will be shut down immediately. This means, you can not use any more functions that rely on the R backend. I.e. you can do hardly anything at all, not even save the workspace (but if you're lucky, R already did that). What you can do, however, is save any open command-files, the output, or copy data out of open data editors. Quit RKWard after that.\nSince this should never happen, please write a mail to rkward-devel at lists.sourceforge.net, and tell us, what you were trying to do, when this happened. Sorry!");
KMessageBox::error (0, message, i18n ("R engine has died"));
backend_dead = true;
+ } else {
+ RK_ASSERT (false);
}
RKRBackendProtocolFrontend::setRequestCompleted (request);
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.cpp 2010-11-17 19:14:00 UTC (rev 3192)
@@ -18,6 +18,8 @@
#include "rkfrontendtransmitter.h"
#include "rkrbackendprotocol_frontend.h"
+#include "../misc/rkcommonfunctions.h"
+#include "../settings/rksettingsmodulegeneral.h"
#include "kstandarddirs.h"
#include <QCoreApplication>
@@ -28,56 +30,62 @@
RKFrontendTransmitter::RKFrontendTransmitter () : QThread () {
RK_TRACE (RBACKEND);
- // start server
connection = 0;
- if (!server.listen ("rkward")) handleTransmitError ("failure to start frontend server: " + server.errorString ());
- connect (&server, SIGNAL (newConnection ()), this, SLOT (connectAndEnterLoop ()));
- // start backend
- QStringList args;
- args.append ("--debug-level " + QString::number (RK_Debug_Level));
- args.append ("--server-name " + server.fullServerName ());
- backend.setProcessChannelMode (QProcess::MergedChannels); // at least for now. Seems difficult to get interleaving right, without this.
- connect (&backend, SIGNAL (readyReadStandardOutput ()), this, SLOT (newProcessOutput ()));
- connect (&backend, SIGNAL (finished (int, QProcess::ExitStatus)), this, SLOT (backendExit (int, QProcess::ExitStatus)));
- backend.start (KStandardDirs::findExe ("rkward.rbackend", QCoreApplication::applicationDirPath ()), args, QIODevice::ReadOnly);
-
RK_ASSERT (_instance == 0);
_instance = this;
+
+ moveToThread (this);
+ start ();
}
RKFrontendTransmitter::~RKFrontendTransmitter () {
RK_TRACE (RBACKEND);
- RK_ASSERT (!server.isListening ());
+ RK_ASSERT (!server->isListening ());
delete connection;
}
void RKFrontendTransmitter::run () {
- RK_ASSERT (connection);
+ RK_TRACE (RBACKEND);
- connection->moveToThread (this);
- connect (connection, SIGNAL (stateChanged (QLocalSocket::LocalSocketState)), this, SLOT (connectionStateChanged (QLocalSocket::LocalSocketState)));
- connect (connection, SIGNAL (readyRead ()), this, SLOT (newConnectionData ()));
- backend.moveToThread (this);
+ // start server
+ server = new QLocalServer (this);
+ if (!server->listen ("rkward")) handleTransmitError ("failure to start frontend server: " + server->errorString ());
+ connect (server, SIGNAL (newConnection ()), this, SLOT (connectAndEnterLoop ()), Qt::QueuedConnection);
+ // start backend
+ backend = new QProcess (this);
+ QStringList args;
+ args.append ("--debug-level " + QString::number (RK_Debug_Level));
+ args.append ("--server-name " + server->fullServerName ());
+ args.append ("--data-dir " + RKSettingsModuleGeneral::filesPath ());
+ backend->setProcessChannelMode (QProcess::MergedChannels); // at least for now. Seems difficult to get interleaving right, without this.
+ connect (backend, SIGNAL (readyReadStandardOutput ()), this, SLOT (newProcessOutput ()));
+ connect (backend, SIGNAL (finished (int, QProcess::ExitStatus)), this, SLOT (backendExit (int, QProcess::ExitStatus)));
+ QString backend_executable = KStandardDirs::findExe ("rkward.rbackend", QCoreApplication::applicationDirPath () + "/rbackend");
+ if (backend_executable.isEmpty ()) backend_executable = KStandardDirs::findExe ("rkward.rbackend", QCoreApplication::applicationDirPath ());
+ RK_ASSERT (!backend_executable.isEmpty ());
+ backend->start (backend_executable, args, QIODevice::ReadOnly);
+
exec ();
}
void RKFrontendTransmitter::connectAndEnterLoop () {
RK_TRACE (RBACKEND);
- RK_ASSERT (server.hasPendingConnections ());
+ RK_ASSERT (server->hasPendingConnections ());
- connection = server.nextPendingConnection ();
- server.close ();
+ connection = server->nextPendingConnection ();
+ server->close ();
- start ();
+ connect (connection, SIGNAL (stateChanged (QLocalSocket::LocalSocketState)), this, SLOT (connectionStateChanged ()));
+ connect (connection, SIGNAL (readyRead ()), this, SLOT (newConnectionData ()));
}
void RKFrontendTransmitter::newProcessOutput () {
RK_TRACE (RBACKEND);
#warning TODO: fix interleaving
- QString output = QString::fromLocal8Bit (backend.readAll ());
+ QString output = QString::fromLocal8Bit (backend->readAll ());
handleOutput (output, output.size (), ROutput::Warning);
}
@@ -105,8 +113,20 @@
}
RBackendRequest *req = RKRBackendSerializer::unserialize (receive_buffer);
+ if (req->type == RBackendRequest::Output) {
+ ROutputList* list = req->output;
+ for (int i = 0; i < list->size (); ++i) {
+ ROutput *out = (*list)[i];
+ handleOutput (out->output, out->output.length (), out->type);
+ delete (out);
+ }
+ req->output = 0;
+ RK_ASSERT (req->synchronous);
+ writeRequest (req); // to tell the backend, that we are keeping up. This also deletes the request.
+ return;
+ }
RKRBackendEvent* event = new RKRBackendEvent (req);
- qApp->postEvent (RKRBackendProtocolFrontend::instance ()->parent (), event);
+ qApp->postEvent (RKRBackendProtocolFrontend::instance (), event);
}
void RKFrontendTransmitter::backendExit (int exitcode, QProcess::ExitStatus exitstatus) {
@@ -114,16 +134,16 @@
RBackendRequest* req = new RBackendRequest (false, RBackendRequest::BackendExit);
RKRBackendEvent* event = new RKRBackendEvent (req);
- qApp->postEvent (RKRBackendProtocolFrontend::instance ()->parent (), event);
+ qApp->postEvent (RKRBackendProtocolFrontend::instance (), event);
}
-void RKFrontendTransmitter::connectionStateChanged (QLocalSocket::LocalSocketState state) {
- if (state != QLocalSocket::UnconnectedState) return; // only interested in connection failure
+void RKFrontendTransmitter::connectionStateChanged () {
+ if (connection->state () != QLocalSocket::UnconnectedState) return; // only interested in connection failure
RK_TRACE (RBACKEND);
RBackendRequest* req = new RBackendRequest (false, RBackendRequest::BackendExit);
RKRBackendEvent* event = new RKRBackendEvent (req);
- qApp->postEvent (RKRBackendProtocolFrontend::instance ()->parent (), event);
+ qApp->postEvent (RKRBackendProtocolFrontend::instance (), event);
}
void RKFrontendTransmitter::writeRequest (RBackendRequest *request) {
@@ -132,6 +152,7 @@
QByteArray buffer = RKRBackendSerializer::serialize (*request);
connection->write (QString::number (buffer.length ()).toLocal8Bit () + "\n");
connection->write (buffer);
+ connection->flush ();
delete request;
}
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkfrontendtransmitter.h 2010-11-17 19:14:00 UTC (rev 3192)
@@ -50,13 +50,13 @@
void newProcessOutput ();
void newConnectionData ();
void backendExit (int exitcode, QProcess::ExitStatus exitstatus);
- void connectionStateChanged (QLocalSocket::LocalSocketState state);
+ void connectionStateChanged ();
private:
void handleTransmitError (const QString &message);
int current_request_length;
- QProcess backend;
- QLocalServer server;
+ QProcess* backend;
+ QLocalServer* server;
QLocalSocket* connection;
static RKFrontendTransmitter *_instance;
};
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackend.cpp 2010-11-17 19:14:00 UTC (rev 3192)
@@ -25,6 +25,7 @@
#include <qstring.h>
#include <QStringList>
#include <QThread>
+#include <QDir>
#include <qtextcodec.h>
#include <klocale.h>
@@ -368,7 +369,16 @@
RKRBackend::this_pointer->r_running = false; // To signify we have finished everything else and are now trying to create an emergency save (if applicable)
if (RKRBackend::this_pointer->killed == RKRBackend::EmergencySaveThenExit) {
- if (R_DirtyImage) R_SaveGlobalEnvToFile (RKCommonFunctions::getUseableRKWardSavefileName ("rkward_recover", ".RData").toLocal8Bit ());
+ QString filename;
+ QDir dir (RKRBackendProtocolBackend::dataDir ());
+ int i=0;
+ while (true) {
+ filename = "rkward_recover" + QString::number (i) + ".RData";
+ if (!dir.exists (filename)) break;
+ i++;
+ }
+
+ if (R_DirtyImage) R_SaveGlobalEnvToFile (filename.toLocal8Bit ());
}
RKRBackend::this_pointer->killed = RKRBackend::AlreadyDead; // just in case
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.cpp 2010-11-17 19:14:00 UTC (rev 3192)
@@ -88,8 +88,10 @@
RK_TRACE (RBACKEND);
RK_ASSERT (_instance == 0);
_instance = this;
+ connection = 0;
- connection.connectToServer (servername); // acutal connection will be done inside run()
+ moveToThread (this);
+ RKRBackendTransmitter::servername = servername;
};
~RKRBackendTransmitter () {
@@ -104,7 +106,10 @@
void run () {
RK_TRACE (RBACKEND);
- if (!connection.waitForConnected ()) handleTransmitError ("Could not connect: %s");
+ connection = new QLocalSocket (this);
+ connection->connectToServer (servername); // acutal connection will be done inside run()
+
+ if (!connection->waitForConnected ()) handleTransmitError ("Could not connect: %s");
#warning do handshake
while (1) {
flushOutput (false);
@@ -137,10 +142,10 @@
// send request
QByteArray buffer = RKRBackendSerializer::serialize (*request);
- connection.write (QString::number (buffer.length ()).toLocal8Bit () + "\n");
- connection.write (buffer);
- while (connection.bytesToWrite ()) {
- if (!connection.waitForBytesWritten ()) handleTransmitError ("Could not connect: %s");
+ connection->write (QString::number (buffer.length ()).toLocal8Bit () + "\n");
+ connection->write (buffer);
+ while (connection->bytesToWrite ()) {
+ if (!connection->waitForBytesWritten ()) handleTransmitError ("Could not connect: %s");
#warning, at this point we could check for an early reply to CommandOut requests
// currently, there is not as much concurrency between the processes as there could be. This is due to the fact, that the transmitter will always block until the result of the
// last command has been serialized and transmitted to the frontend. Instead, it could check for and fetch the next command, already (if available), to keep the backend going.
@@ -154,7 +159,6 @@
// NOTE: currently, in the backend, we *never* expect a read without a synchronous request
RBackendRequest* reply = RKRBackendSerializer::unserialize (fetchTransmission (true));
request->mergeReply (reply);
- RK_ASSERT (reply->done);
delete reply;
#warning Read up on whether volatile provides a good enough memory barrier at this point!
request->done = true; // must be the very last thing we do with the request!
@@ -164,32 +168,34 @@
@param block Block until a transmission was received.
@note @em If a transmission is available, this will always block until the transmission has been received in full. */
QByteArray fetchTransmission (bool block) {
+ RK_ASSERT (connection);
+
QByteArray receive_buffer;
int expected_length = 0;
bool got_header = false;
- bool have_data = false;
while (1) {
- have_data = have_data || connection.waitForReadyRead (1);
- if (!connection.isOpen ()) {
+ connection->waitForReadyRead (1);
+ if (!connection->isOpen ()) {
handleTransmitError ("Connection closed unexepctedly. Last error: %s");
return receive_buffer;
}
- if (!have_data) {
+ if (!connection->bytesAvailable ()) {
if (!block) return receive_buffer;
continue;
}
+
RK_TRACE (RBACKEND);
if (!got_header) {
- if (!connection.canReadLine ()) continue; // at this point we have received *something*, but not even a full header, yet.
+ if (!connection->canReadLine ()) continue; // at this point we have received *something*, but not even a full header, yet.
- QString line = QString::fromLocal8Bit (connection.readLine ());
+ QString line = QString::fromLocal8Bit (connection->readLine ());
bool ok;
expected_length = line.toInt (&ok);
if (!ok) handleTransmitError ("Protocol header error. Last connection error was: %s");
got_header = true;
}
- receive_buffer.append (connection.read (expected_length - receive_buffer.length ()));
+ receive_buffer.append (connection->read (expected_length - receive_buffer.length ()));
if (receive_buffer.length () >= expected_length) return receive_buffer;
}
}
@@ -205,14 +211,15 @@
}
void handleTransmitError (const char* message_template) {
- printf (message_template, qPrintable (connection.errorString ()));
+ printf (message_template, qPrintable (connection->errorString ()));
}
- QLocalSocket connection;
+ QLocalSocket* connection;
QList<RBackendRequest *> current_requests; // there *can* be multiple active requests (if the first ones are asynchronous)
QMutex request_mutex;
static RKRBackendTransmitter* _instance;
static RKRBackendTransmitter* instance () { return _instance; };
+ QString servername;
};
RKRBackendTransmitter* RKRBackendTransmitter::_instance = 0;
@@ -237,12 +244,16 @@
KGlobal::locale (); // to initialize it in the primary thread
QString servername;
+ QString data_dir;
QStringList args = app.arguments ();
for (int i = 1; i < args.count (); ++i) {
if (args[i].startsWith ("--debug-level")) {
- RK_Debug_Level = args.value (++i, QString ()).toInt ();
+ RK_Debug_Level = args[i].section (' ', 1).toInt ();
} else if (args[i].startsWith ("--server-name")) {
- servername = args.value (++i, QString ());
+ servername = args[i].section (' ', 1);
+ } else if (args[i].startsWith ("--data-dir")) {
+#warning What about paths with spaces?!
+ data_dir = args[i].section (' ', 1);
} else {
printf ("unkown argument %s", qPrintable (args[i]));
}
@@ -252,14 +263,14 @@
}
RKRBackendTransmitter transmitter (servername);
- RKRBackendProtocolBackend backend ();
+ RKRBackendProtocolBackend backend (data_dir);
transmitter.start ();
RKRBackend::this_pointer->run ();
}
#endif
RKRBackendProtocolBackend* RKRBackendProtocolBackend::_instance = 0;
-RKRBackendProtocolBackend::RKRBackendProtocolBackend () {
+RKRBackendProtocolBackend::RKRBackendProtocolBackend (const QString &storage_dir) {
RK_TRACE (RBACKEND);
_instance = this;
@@ -272,6 +283,7 @@
r_thread = QThread::currentThread (); // R thread == main thread
r_thread_id = QThread::currentThreadId ();
#endif
+ data_dir = storage_dir;
}
RKRBackendProtocolBackend::~RKRBackendProtocolBackend () {
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_backend.h 2010-11-17 19:14:00 UTC (rev 3192)
@@ -25,17 +25,19 @@
class RKRBackendProtocolBackend {
public:
static bool inRThread ();
+ static QString dataDir () { return _instance->data_dir; };
+
+ RKRBackendProtocolBackend (const QString &data_dir);
+ ~RKRBackendProtocolBackend ();
protected:
friend class RKRBackendProtocolFrontend;
friend class RKRBackend;
friend class RKRBackendThread;
- RKRBackendProtocolBackend ();
- ~RKRBackendProtocolBackend ();
-
void sendRequest (RBackendRequest *request);
static void msleep (int delay);
static void interruptProcessing ();
static RKRBackendProtocolBackend* instance () { return _instance; };
+ QString data_dir;
private:
static RKRBackendProtocolBackend* _instance;
QThread *r_thread;
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.cpp 2010-11-17 19:14:00 UTC (rev 3192)
@@ -79,8 +79,6 @@
}
ROutputList RKRBackendProtocolFrontend::flushOutput (bool force) {
- RK_TRACE (RBACKEND);
-
#ifdef RKWARD_THREADED
return (RKRBackend::this_pointer->flushOutput (force));
#else
@@ -96,7 +94,7 @@
RKRBackendProtocolBackend::interruptProcessing ();
#else
// kill (SIGUSR1, pid_of_it);
-#warning wont't work on windows!
+#warning will not work on windows!
#endif
}
@@ -107,11 +105,10 @@
RKRBackend::this_pointer->kill ();
#else
// kill (SIGUSR2, pid_of_it);
-#warning wont't work on windows!
+#warning will not work on windows!
#endif
}
-#ifdef RKWARD_THREADED
void RKRBackendProtocolFrontend::customEvent (QEvent *e) {
if (((int) e->type ()) == ((int) RKRBackendEvent::RKWardEvent)) {
RKRBackendEvent *ev = static_cast<RKRBackendEvent*> (e);
@@ -121,5 +118,4 @@
return;
}
}
-#endif
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rkrbackendprotocol_frontend.h 2010-11-17 19:14:00 UTC (rev 3192)
@@ -37,10 +37,9 @@
void setupBackend (QVariantMap backend_params);
static RKRBackendProtocolFrontend* instance () { return _instance; };
protected:
-#ifdef RKWARD_THREADED
/** needed to handle the QEvents, the R thread is sending (notifications on what's happening in the backend thread) */
void customEvent (QEvent *e);
-#else
+#ifndef RKWARD_THREADED
QThread* main_thread;
#endif
private:
Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp 2010-11-17 13:29:41 UTC (rev 3191)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rkward.cpp 2010-11-17 19:14:00 UTC (rev 3192)
@@ -156,14 +156,14 @@
RK_TRACE (APP);
// these would not be strictly necessary, as we're exiting the app, anyway.
- delete RControlWindow::getControl ();
- delete RKGlobals::rInterface ();
delete RObjectList::getObjectList ();
delete RObjectBrowser::mainBrowser ();
delete RKCommandLog::getLog ();
delete RKConsole::mainConsole ();
delete RKHelpSearchWindow::mainHelpSearch ();
delete RKGlobals::tracker ();
+ delete RKGlobals::rInterface ();
+ delete RControlWindow::getControl ();
}
void RKWardMainWindow::closeEvent (QCloseEvent *e) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the rkward-tracker
mailing list