• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

scheduler.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
00003                       Waldo Bastian <bastian@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "scheduler.h"
00021 
00022 #include "sessiondata.h"
00023 #include "slaveconfig.h"
00024 #include "authinfo.h"
00025 #include "slave.h"
00026 #include "connection.h"
00027 #include "job_p.h"
00028 
00029 #include <kdebug.h>
00030 #include <kglobal.h>
00031 #include <kprotocolmanager.h>
00032 #include <kprotocolinfo.h>
00033 #include <assert.h>
00034 #include <kdesu/client.h>
00035 
00036 #include <QtCore/QHash>
00037 #include <QtGui/QWidget>
00038 #include <QtDBus/QtDBus>
00039 
00040 // Slaves may be idle for MAX_SLAVE_IDLE time before they are being returned
00041 // to the system wide slave pool. (3 minutes)
00042 #define MAX_SLAVE_IDLE (3*60)
00043 
00044 using namespace KIO;
00045 
00046 #ifndef KDE_USE_FINAL // already defined in job.cpp
00047 static inline Slave *jobSlave(SimpleJob *job)
00048 {
00049     return SimpleJobPrivate::get(job)->m_slave;
00050 }
00051 #endif
00052 
00053 static inline int jobCommand(SimpleJob *job)
00054 {
00055     return SimpleJobPrivate::get(job)->m_command;
00056 }
00057 
00058 static inline void startJob(SimpleJob *job, Slave *slave)
00059 {
00060     SimpleJobPrivate::get(job)->start(slave);
00061 }
00062 
00063 typedef QList<Slave *> SlaveList;
00064 typedef QMap<Slave *, QList<SimpleJob *> * > CoSlaveMap;
00065 
00066 class KIO::SchedulerPrivate
00067 {
00068 public:
00069     class JobData;
00070     class ProtocolInfo;
00071     class ProtocolInfoDict : public QHash<QString, ProtocolInfo*>
00072     {
00073     public:
00074         ProtocolInfoDict() { }
00075 
00076         ProtocolInfo *get(const QString &protocol);
00077     };
00078 
00079     typedef QHash<KIO::SimpleJob*, JobData> ExtraJobData;
00080     typedef QList<SimpleJob *> JobList;
00081 
00082     SchedulerPrivate() :
00083         q(new Scheduler),
00084         busy( false ),
00085         slaveOnHold( 0 ),
00086         slaveConfig( SlaveConfig::self() ),
00087         sessionData( new SessionData ),
00088         checkOnHold( true ) // !! Always check with KLauncher for the first request
00089     {
00090         slaveTimer.setObjectName( "Scheduler::slaveTimer" );
00091         slaveTimer.setSingleShot( true );
00092         q->connect(&slaveTimer, SIGNAL(timeout()), SLOT(startStep()));
00093         coSlaveTimer.setObjectName( "Scheduler::coSlaveTimer" );
00094         coSlaveTimer.setSingleShot( true );
00095         q->connect(&coSlaveTimer, SIGNAL(timeout()), SLOT(slotScheduleCoSlave()));
00096         cleanupTimer.setObjectName( "Scheduler::cleanupTimer" );
00097         cleanupTimer.setSingleShot( true );
00098         q->connect(&cleanupTimer, SIGNAL(timeout()), SLOT(slotCleanIdleSlaves()));
00099     }
00100     ~SchedulerPrivate()
00101     {
00102         delete q; q = 0;
00103         qDeleteAll( protInfoDict );
00104         delete sessionData;
00105     }
00106     Scheduler *q;
00107 
00108     QTimer slaveTimer;
00109     QTimer coSlaveTimer;
00110     QTimer cleanupTimer;
00111     bool busy;
00112 
00113     ProtocolInfoDict protInfoDict;
00114     Slave *slaveOnHold;
00115     KUrl urlOnHold;
00116     JobList newJobs;
00117 
00118     CoSlaveMap coSlaves;
00119     ExtraJobData extraJobData;
00120     SlaveConfig *slaveConfig;
00121     SessionData *sessionData;
00122     bool checkOnHold;
00123     QMap<QObject *,WId> m_windowList;
00124 
00125     void doJob(SimpleJob *job);
00126     void scheduleJob(SimpleJob *job);
00127     void cancelJob(SimpleJob *job);
00128     void jobFinished(KIO::SimpleJob *job, KIO::Slave *slave);
00129     void scheduleCleanup();
00130     void putSlaveOnHold(KIO::SimpleJob *job, const KUrl &url);
00131     void removeSlaveOnHold();
00132     Slave *getConnectedSlave(const KUrl &url, const KIO::MetaData &metaData );
00133     bool assignJobToSlave(KIO::Slave *slave, KIO::SimpleJob *job);
00134     bool disconnectSlave(KIO::Slave *slave);
00135     void checkSlaveOnHold(bool b);
00136     void publishSlaveOnHold();
00137     void registerWindow(QWidget *wid);
00138 
00139     Slave *findIdleSlave(ProtocolInfo *protInfo, SimpleJob *job, bool &exact);
00140     Slave *createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KUrl &url);
00141 
00142     void debug_info();
00143 
00144     void setupSlave(KIO::Slave *slave, const KUrl &url, const QString &protocol, const QString &proxy , bool newSlave, const KIO::MetaData *config=0);
00145     bool startJobScheduled(ProtocolInfo *protInfo);
00146     bool startJobDirect();
00147 
00148     void slotSlaveDied(KIO::Slave *slave);
00149     void slotSlaveStatus(pid_t pid, const QByteArray &protocol,
00150                          const QString &host, bool connected);
00151 
00152     void slotReparseSlaveConfiguration(const QString &);
00153 
00154     void startStep();
00155     void slotCleanIdleSlaves();
00156     void slotSlaveConnected();
00157     void slotSlaveError(int error, const QString &errorMsg);
00158     void slotScheduleCoSlave();
00159     void slotUnregisterWindow(QObject *);
00160 };
00161 
00162 class KIO::SchedulerPrivate::ProtocolInfo
00163 {
00164 public:
00165     ProtocolInfo() : maxSlaves(1), skipCount(0)
00166     {
00167     }
00168 
00169     ~ProtocolInfo()
00170     {
00171         qDeleteAll(allSlaves());
00172     }
00173 
00174     // bad performance, but will change this later
00175     SlaveList allSlaves() const
00176     {
00177         SlaveList ret(activeSlaves);
00178         ret.append(idleSlaves);
00179         ret.append(coSlaves.keys());
00180         ret.append(coIdleSlaves);
00181         return ret;
00182     }
00183 
00184     QList<SimpleJob *> joblist;
00185     SlaveList activeSlaves;
00186     SlaveList idleSlaves;
00187     CoSlaveMap coSlaves;
00188     SlaveList coIdleSlaves;
00189     int maxSlaves;
00190     int skipCount;
00191     QString protocol;
00192 };
00193 
00194 KIO::SchedulerPrivate::ProtocolInfo *
00195 KIO::SchedulerPrivate::ProtocolInfoDict::get(const QString &protocol)
00196 {
00197     ProtocolInfo *info = value(protocol, 0);
00198     if (!info)
00199     {
00200         info = new ProtocolInfo;
00201         info->protocol = protocol;
00202         info->maxSlaves = KProtocolInfo::maxSlaves( protocol );
00203 
00204         insert(protocol, info);
00205     }
00206     return info;
00207 }
00208 
00209 K_GLOBAL_STATIC(SchedulerPrivate, schedulerPrivate)
00210 Scheduler* Scheduler::self()
00211 {
00212     return schedulerPrivate->q;
00213 }
00214 
00215 
00216 //
00217 // There are two kinds of protocol:
00218 // (1) The protocol of the url
00219 // (2) The actual protocol that the io-slave uses.
00220 //
00221 // These two often match, but not necessarily. Most notably, they don't
00222 // match when doing ftp via a proxy.
00223 // In that case (1) is ftp, but (2) is http.
00224 //
00225 // JobData::protocol stores (2) while Job::url().protocol() returns (1).
00226 // The ProtocolInfoDict is indexed with (2).
00227 //
00228 // We schedule slaves based on (2) but tell the slave about (1) via
00229 // Slave::setProtocol().
00230 
00231 class KIO::SchedulerPrivate::JobData
00232 {
00233 public:
00234     JobData() : checkOnHold(false) { }
00235 
00236 public:
00237     QString protocol;
00238     QString proxy;
00239     bool checkOnHold;
00240 };
00241 
00242 
00243 Scheduler::Scheduler()
00244     : QObject(), d(0)
00245 {
00246     setObjectName( "scheduler" );
00247 
00248     const QString dbusPath = "/KIO/Scheduler";
00249     const QString dbusInterface = "org.kde.KIO.Scheduler";
00250     QDBusConnection dbus = QDBusConnection::sessionBus();
00251     dbus.registerObject( "/KIO/Scheduler", this, QDBusConnection::ExportScriptableSlots |
00252                                                  QDBusConnection::ExportScriptableSignals );
00253     dbus.connect(QString(), dbusPath, dbusInterface, "reparseSlaveConfiguration",
00254                  this, SLOT(slotReparseSlaveConfiguration(QString)));
00255 }
00256 
00257 Scheduler::~Scheduler()
00258 {
00259 }
00260 
00261 void Scheduler::doJob(SimpleJob *job)
00262 {
00263     schedulerPrivate->doJob(job);
00264 }
00265 
00266 void Scheduler::scheduleJob(SimpleJob *job)
00267 {
00268     schedulerPrivate->scheduleJob(job);
00269 }
00270 
00271 void Scheduler::cancelJob(SimpleJob *job)
00272 {
00273     schedulerPrivate->cancelJob(job);
00274 }
00275 
00276 void Scheduler::jobFinished(KIO::SimpleJob *job, KIO::Slave *slave)
00277 {
00278     schedulerPrivate->jobFinished(job, slave);
00279 }
00280 
00281 void Scheduler::putSlaveOnHold(KIO::SimpleJob *job, const KUrl &url)
00282 {
00283     schedulerPrivate->putSlaveOnHold(job, url);
00284 }
00285 
00286 void Scheduler::removeSlaveOnHold()
00287 {
00288     schedulerPrivate->removeSlaveOnHold();
00289 }
00290 
00291 void Scheduler::publishSlaveOnHold()
00292 {
00293     schedulerPrivate->publishSlaveOnHold();
00294 }
00295 
00296 KIO::Slave *Scheduler::getConnectedSlave(const KUrl &url,
00297         const KIO::MetaData &config )
00298 {
00299     return schedulerPrivate->getConnectedSlave(url, config);
00300 }
00301 
00302 bool Scheduler::assignJobToSlave(KIO::Slave *slave, KIO::SimpleJob *job)
00303 {
00304     return schedulerPrivate->assignJobToSlave(slave, job);
00305 }
00306 
00307 bool Scheduler::disconnectSlave(KIO::Slave *slave)
00308 {
00309     return schedulerPrivate->disconnectSlave(slave);
00310 }
00311 
00312 void Scheduler::registerWindow(QWidget *wid)
00313 {
00314     schedulerPrivate->registerWindow(wid);
00315 }
00316 
00317 void Scheduler::unregisterWindow(QObject *wid)
00318 {
00319     schedulerPrivate->slotUnregisterWindow(wid);
00320 }
00321 
00322 bool Scheduler::connect( const char *signal, const QObject *receiver,
00323                          const char *member)
00324 {
00325     return QObject::connect(self(), signal, receiver, member);
00326 }
00327 
00328 bool Scheduler::connect( const QObject* sender, const char* signal,
00329                          const QObject* receiver, const char* member )
00330 {
00331     return QObject::connect(sender, signal, receiver, member);
00332 }
00333 
00334 bool Scheduler::disconnect( const QObject* sender, const char* signal,
00335                             const QObject* receiver, const char* member )
00336 {
00337     return QObject::disconnect(sender, signal, receiver, member);
00338 }
00339 
00340 bool Scheduler::connect( const QObject *sender, const char *signal,
00341                          const char *member )
00342 {
00343     return QObject::connect(sender, signal, member);
00344 }
00345 
00346 void Scheduler::checkSlaveOnHold(bool b)
00347 {
00348     schedulerPrivate->checkSlaveOnHold(b);
00349 }
00350 
00351 void Scheduler::emitReparseSlaveConfiguration()
00352 {
00353     self()->reparseSlaveConfiguration( QString() );
00354 }
00355 
00356 void
00357 SchedulerPrivate::debug_info()
00358 {
00359 }
00360 
00361 void SchedulerPrivate::slotReparseSlaveConfiguration(const QString &proto)
00362 {
00363     kDebug( 7006 ) << "reparseSlaveConfiguration( " << proto << " )";
00364     KProtocolManager::reparseConfiguration();
00365     slaveConfig->reset();
00366     sessionData->reset();
00367     NetRC::self()->reload();
00368 
00369     ProtocolInfoDict::ConstIterator it = proto.isEmpty() ? protInfoDict.constBegin() :
00370                                                            protInfoDict.constFind(proto);
00371     // not found?
00372     if (it == protInfoDict.constEnd()) {
00373         return;
00374     }
00375     ProtocolInfoDict::ConstIterator endIt = proto.isEmpty() ? protInfoDict.constEnd() :
00376                                                               it + 1;
00377     for (; it != endIt; ++it) {
00378         foreach(Slave *slave, (*it)->allSlaves()) {
00379             slave->send(CMD_REPARSECONFIGURATION);
00380             slave->resetHost();
00381         }
00382     }
00383 }
00384 
00385 void SchedulerPrivate::doJob(SimpleJob *job) {
00386     JobData jobData;
00387     jobData.protocol = KProtocolManager::slaveProtocol(job->url(), jobData.proxy);
00388 //    kDebug(7006) << "protocol=" << jobData->protocol;
00389     if (jobCommand(job) == CMD_GET)
00390     {
00391        jobData.checkOnHold = checkOnHold;
00392        checkOnHold = false;
00393     }
00394     extraJobData.insert(job, jobData);
00395     newJobs.append(job);
00396     slaveTimer.start(0);
00397 #ifndef NDEBUG
00398     if (newJobs.count() > 150)
00399         kDebug() << "WARNING - KIO::Scheduler got more than 150 jobs! This shows a misuse in your app (yes, a job is a QObject).";
00400 #endif
00401 }
00402 
00403 void SchedulerPrivate::scheduleJob(SimpleJob *job) {
00404     newJobs.removeOne(job);
00405     const JobData& jobData = extraJobData.value(job);
00406 
00407     QString protocol = jobData.protocol;
00408 //    kDebug(7006) << "protocol=" << protocol;
00409     ProtocolInfo *protInfo = protInfoDict.get(protocol);
00410     protInfo->joblist.append(job);
00411 
00412     slaveTimer.start(0);
00413 }
00414 
00415 void SchedulerPrivate::cancelJob(SimpleJob *job) {
00416     //    kDebug(7006) << "Scheduler: canceling job " << job;
00417     Slave *slave = jobSlave(job);
00418     if ( !slave  )
00419     {
00420         // was not yet running (don't call this on a finished job!)
00421         JobData jobData = extraJobData.value(job);
00422         newJobs.removeAll(job);
00423         ProtocolInfo *protInfo = protInfoDict.get(jobData.protocol);
00424         protInfo->joblist.removeAll(job);
00425 
00426         // Search all slaves to see if job is in the queue of a coSlave
00427         foreach(Slave* coSlave, protInfo->allSlaves())
00428         {
00429            JobList *list = protInfo->coSlaves.value(coSlave);
00430            if (list && list->removeAll(job)) {
00431                // Job was found and removed.
00432                // Fall through to kill the slave as well!
00433                slave = coSlave;
00434                break;
00435            }
00436         }
00437         if (!slave)
00438         {
00439            extraJobData.remove(job);
00440            return; // Job was not yet running and not in a coSlave queue.
00441         }
00442     }
00443     //kDebug(7006) << "Scheduler: killing slave " << slave->slave_pid();
00444     slave->kill();
00445     jobFinished( job, slave );
00446     slotSlaveDied(slave);
00447 }
00448 
00449 void SchedulerPrivate::startStep()
00450 {
00451     while (newJobs.count()) {
00452        (void) startJobDirect();
00453     }
00454 
00455     QHashIterator<QString, ProtocolInfo*> it(protInfoDict);
00456     while(it.hasNext()) {
00457        it.next();
00458        if (startJobScheduled(it.value())) return;
00459     }
00460 }
00461 
00462 void SchedulerPrivate::setupSlave(KIO::Slave *slave, const KUrl &url, const QString &protocol, const QString &proxy , bool newSlave, const KIO::MetaData *config)
00463 {
00464     QString host = url.host();
00465     int port = url.port();
00466     if ( port == -1 ) // no port is -1 in QUrl, but in kde3 we used 0 and the kioslaves assume that.
00467         port = 0;
00468     QString user = url.user();
00469     QString passwd = url.pass();
00470 
00471     if ((newSlave) ||
00472         (slave->host() != host) ||
00473         (slave->port() != port) ||
00474         (slave->user() != user) ||
00475         (slave->passwd() != passwd))
00476     {
00477         slaveConfig = SlaveConfig::self();
00478 
00479         MetaData configData = slaveConfig->configData(protocol, host);
00480         sessionData->configDataFor( configData, protocol, host );
00481 
00482         configData["UseProxy"] = proxy;
00483 
00484         QString autoLogin = configData["EnableAutoLogin"].toLower();
00485         if ( autoLogin == "true" )
00486         {
00487             NetRC::AutoLogin l;
00488             l.login = user;
00489             bool usern = (protocol == "ftp");
00490             if ( NetRC::self()->lookup( url, l, usern) )
00491             {
00492                 configData["autoLoginUser"] = l.login;
00493                 configData["autoLoginPass"] = l.password;
00494                 if ( usern )
00495                 {
00496                     QString macdef;
00497                     QMap<QString, QStringList>::ConstIterator it = l.macdef.constBegin();
00498                     for ( ; it != l.macdef.constEnd(); ++it )
00499                         macdef += it.key() + '\\' + it.value().join( "\\" ) + '\n';
00500                     configData["autoLoginMacro"] = macdef;
00501                 }
00502             }
00503         }
00504         if (config)
00505            configData += *config;
00506         slave->setConfig(configData);
00507         slave->setProtocol(url.protocol());
00508         slave->setHost(host, port, user, passwd);
00509     }
00510 }
00511 
00512 bool SchedulerPrivate::startJobScheduled(ProtocolInfo *protInfo)
00513 {
00514     if (protInfo->joblist.isEmpty())
00515        return false;
00516 
00517 //       kDebug(7006) << "Scheduling job";
00518     debug_info();
00519     bool newSlave = false;
00520 
00521     SimpleJob *job = 0;
00522     Slave *slave = 0;
00523 
00524     if (protInfo->skipCount > 2)
00525     {
00526        bool dummy;
00527        // Prevent starvation. We skip the first entry in the queue at most
00528        // 2 times in a row. The
00529        protInfo->skipCount = 0;
00530        job = protInfo->joblist.at(0);
00531        slave = findIdleSlave(protInfo, job, dummy );
00532     }
00533     else
00534     {
00535        bool exact=false;
00536        SimpleJob *firstJob = 0;
00537        Slave *firstSlave = 0;
00538        for(int i = 0; (i < protInfo->joblist.count()) && (i < 10); i++)
00539        {
00540           job = protInfo->joblist.at(i);
00541           slave = findIdleSlave(protInfo, job, exact);
00542           if (!firstSlave)
00543           {
00544              firstJob = job;
00545              firstSlave = slave;
00546           }
00547           if (!slave) break;
00548           if (exact) break;
00549        }
00550 
00551        if (!exact)
00552        {
00553          slave = firstSlave;
00554          job = firstJob;
00555        }
00556        if (job == firstJob)
00557          protInfo->skipCount = 0;
00558        else
00559          protInfo->skipCount++;
00560     }
00561 
00562     if (!slave)
00563     {
00564        if ( protInfo->maxSlaves > static_cast<int>(protInfo->activeSlaves.count()) )
00565        {
00566           newSlave = true;
00567           slave = createSlave(protInfo, job, job->url());
00568           if (!slave)
00569              slaveTimer.start(0);
00570        }
00571     }
00572 
00573     if (!slave)
00574     {
00575 //          kDebug(7006) << "No slaves available";
00576 //          kDebug(7006) << " -- active: " << protInfo->activeSlaves.count();
00577        return false;
00578     }
00579 
00580     protInfo->activeSlaves.append(slave);
00581     protInfo->idleSlaves.removeAll(slave);
00582     protInfo->joblist.removeOne(job);
00583 //        kDebug(7006) << "scheduler: job started " << job;
00584 
00585 
00586     SchedulerPrivate::JobData jobData = extraJobData.value(job);
00587     setupSlave(slave, job->url(), jobData.protocol, jobData.proxy, newSlave);
00588     startJob(job, slave);
00589 
00590     slaveTimer.start(0);
00591     return true;
00592 }
00593 
00594 bool SchedulerPrivate::startJobDirect()
00595 {
00596     debug_info();
00597     SimpleJob *job = newJobs.takeFirst();
00598     SchedulerPrivate::JobData jobData = extraJobData.value(job);
00599 
00600     QString protocol = jobData.protocol;
00601     ProtocolInfo *protInfo = protInfoDict.get(protocol);
00602 
00603     bool newSlave = false;
00604     bool dummy;
00605 
00606     // Look for matching slave
00607     Slave *slave = findIdleSlave(protInfo, job, dummy);
00608 
00609     if (!slave)
00610     {
00611        newSlave = true;
00612        slave = createSlave(protInfo, job, job->url());
00613     }
00614 
00615     if (!slave)
00616        return false;
00617 
00618     protInfo->activeSlaves.append(slave);
00619     protInfo->idleSlaves.removeAll(slave);
00620 //       kDebug(7006) << "scheduler: job started " << job;
00621 
00622     setupSlave(slave, job->url(), protocol, jobData.proxy, newSlave);
00623     startJob(job, slave);
00624     return true;
00625 }
00626 
00627 static Slave *searchIdleList(SlaveList &idleSlaves, const KUrl &url, const QString &protocol, bool &exact)
00628 {
00629     QString host = url.host();
00630     int port = url.port();
00631     if ( port == -1 ) // no port is -1 in QUrl, but in kde3 we used 0 and the kioslaves assume that.
00632         port = 0;
00633     QString user = url.user();
00634     exact = true;
00635 
00636     foreach( Slave *slave, idleSlaves )
00637     {
00638        if ((protocol == slave->slaveProtocol()) &&
00639            (host == slave->host()) &&
00640            (port == slave->port()) &&
00641            (user == slave->user()))
00642            return slave;
00643     }
00644 
00645     exact = false;
00646 
00647     // pick the first slave from the protocol's idle list: at least the protocol matches.
00648     if (!idleSlaves.isEmpty()) {
00649         Q_ASSERT(idleSlaves.first()->protocol() == protocol);
00650         return idleSlaves.first();
00651     }
00652     return 0;
00653 }
00654 
00655 Slave *SchedulerPrivate::findIdleSlave(ProtocolInfo *protInfo, SimpleJob *job, bool &exact)
00656 {
00657     Slave *slave = 0;
00658     JobData jobData = extraJobData.value(job);
00659 
00660     if (jobData.checkOnHold)
00661     {
00662        slave = Slave::holdSlave(jobData.protocol, job->url());
00663        if (slave)
00664           return slave;
00665     }
00666     if (slaveOnHold)
00667     {
00668        // Make sure that the job wants to do a GET or a POST, and with no offset
00669        bool bCanReuse = (jobCommand(job) == CMD_GET);
00670        KIO::TransferJob * tJob = qobject_cast<KIO::TransferJob *>(job);
00671        if ( tJob )
00672        {
00673           bCanReuse = (jobCommand(job) == CMD_GET || jobCommand(job) == CMD_SPECIAL);
00674           if ( bCanReuse )
00675           {
00676             KIO::MetaData outgoing = tJob->outgoingMetaData();
00677             QString resume = (!outgoing.contains("resume")) ? QString() : outgoing["resume"];
00678             kDebug(7006) << "Resume metadata is" << resume;
00679             bCanReuse = (resume.isEmpty() || resume == "0");
00680           }
00681        }
00682 //       kDebug(7006) << "bCanReuse = " << bCanReuse;
00683        if (bCanReuse)
00684        {
00685           if (job->url() == urlOnHold)
00686           {
00687              kDebug(7006) << "HOLD: Reusing held slave for" << urlOnHold;
00688              slave = slaveOnHold;
00689           }
00690           else
00691           {
00692              kDebug(7006) << "HOLD: Discarding held slave (" << urlOnHold << ")";
00693              slaveOnHold->kill();
00694           }
00695           slaveOnHold = 0;
00696           urlOnHold = KUrl();
00697        }
00698        if (slave)
00699           return slave;
00700     }
00701 
00702     return searchIdleList(protInfo->idleSlaves, job->url(), jobData.protocol, exact);
00703 }
00704 
00705 Slave *SchedulerPrivate::createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KUrl &url)
00706 {
00707    int error;
00708    QString errortext;
00709    Slave *slave = Slave::createSlave(protInfo->protocol, url, error, errortext);
00710    if (slave)
00711    {
00712       protInfo->idleSlaves.append(slave);
00713       q->connect(slave, SIGNAL(slaveDied(KIO::Slave *)),
00714                  SLOT(slotSlaveDied(KIO::Slave *)));
00715       q->connect(slave, SIGNAL(slaveStatus(pid_t,const QByteArray&,const QString &, bool)),
00716                  SLOT(slotSlaveStatus(pid_t,const QByteArray&, const QString &, bool)));
00717    }
00718    else
00719    {
00720       kError() << "couldn't create slave:" << errortext;
00721       if (job)
00722       {
00723          protInfo->joblist.removeAll(job);
00724          extraJobData.remove(job);
00725          job->slotError( error, errortext );
00726       }
00727    }
00728    return slave;
00729 }
00730 
00731 void SchedulerPrivate::slotSlaveStatus(pid_t, const QByteArray&, const QString &, bool)
00732 {
00733 }
00734 
00735 void SchedulerPrivate::jobFinished(SimpleJob *job, Slave *slave)
00736 {
00737     JobData jobData = extraJobData.take(job);
00738 
00739     ProtocolInfo *protInfo = protInfoDict.get(jobData.protocol);
00740     slave->disconnect(job);
00741     protInfo->activeSlaves.removeAll(slave);
00742     if (slave->isAlive())
00743     {
00744        JobList *list = protInfo->coSlaves.value(slave);
00745        if (list)
00746        {
00747           assert(slave->isConnected());
00748           assert(!protInfo->coIdleSlaves.contains(slave));
00749           protInfo->coIdleSlaves.append(slave);
00750           if (!list->isEmpty())
00751              coSlaveTimer.start(0);
00752           return;
00753        }
00754        else
00755        {
00756           assert(!slave->isConnected());
00757           protInfo->idleSlaves.append(slave);
00758           slave->setIdle();
00759           scheduleCleanup();
00760 //          slave->send( CMD_SLAVE_STATUS );
00761        }
00762     }
00763     if (protInfo->joblist.count())
00764     {
00765        slaveTimer.start(0);
00766     }
00767 }
00768 
00769 void SchedulerPrivate::slotSlaveDied(KIO::Slave *slave)
00770 {
00771     assert(!slave->isAlive());
00772     ProtocolInfo *protInfo = protInfoDict.get(slave->slaveProtocol());
00773     protInfo->activeSlaves.removeAll(slave);
00774     if (slave == slaveOnHold)
00775     {
00776        slaveOnHold = 0;
00777        urlOnHold = KUrl();
00778     }
00779     protInfo->idleSlaves.removeAll(slave);
00780 
00781     disconnectSlave(slave);
00782 
00783     slave->deref(); // Delete slave
00784 }
00785 
00786 void SchedulerPrivate::slotCleanIdleSlaves()
00787 {
00788     foreach (ProtocolInfo *protInfo, protInfoDict) {
00789         SlaveList::iterator it = protInfo->idleSlaves.begin();
00790         for( ; it != protInfo->idleSlaves.end(); )
00791         {
00792             Slave *slave = *it;
00793             if (slave->idleTime() >= MAX_SLAVE_IDLE)
00794             {
00795                 // kDebug(7006) << "Removing idle slave: " << slave->slaveProtocol() << " " << slave->host();
00796                 Slave *removeSlave = slave;
00797                 it = protInfo->idleSlaves.erase( it );
00798                 removeSlave->connection()->close();
00799                 removeSlave->deref();
00800             }
00801             else
00802             {
00803                 ++it;
00804             }
00805         }
00806     }
00807     scheduleCleanup();
00808 }
00809 
00810 void SchedulerPrivate::scheduleCleanup()
00811 {
00812     foreach (ProtocolInfo *protInfo, protInfoDict) {
00813         if (protInfo->idleSlaves.count() && !cleanupTimer.isActive()) {
00814             cleanupTimer.start(MAX_SLAVE_IDLE * 1000);
00815             break;
00816         }
00817     }
00818 }
00819 
00820 void SchedulerPrivate::putSlaveOnHold(KIO::SimpleJob *job, const KUrl &url)
00821 {
00822     Slave *slave = jobSlave(job);
00823     slave->disconnect(job);
00824 
00825     if (slaveOnHold)
00826     {
00827         slaveOnHold->kill();
00828     }
00829     slaveOnHold = slave;
00830     urlOnHold = url;
00831     slaveOnHold->suspend();
00832 }
00833 
00834 void SchedulerPrivate::publishSlaveOnHold()
00835 {
00836     if (!slaveOnHold)
00837        return;
00838 
00839     slaveOnHold->hold(urlOnHold);
00840 }
00841 
00842 void SchedulerPrivate::removeSlaveOnHold()
00843 {
00844     if (slaveOnHold)
00845     {
00846         slaveOnHold->kill();
00847     }
00848     slaveOnHold = 0;
00849     urlOnHold = KUrl();
00850 }
00851 
00852 Slave *
00853 SchedulerPrivate::getConnectedSlave(const KUrl &url, const KIO::MetaData &config )
00854 {
00855     QString proxy;
00856     QString protocol = KProtocolManager::slaveProtocol(url, proxy);
00857     ProtocolInfo *protInfo = protInfoDict.get(protocol);
00858     bool dummy;
00859     Slave *slave = searchIdleList(protInfo->idleSlaves, url, protocol, dummy);
00860     if (!slave)  {
00861        slave = createSlave(protInfo, 0, url);
00862     }
00863     if (!slave) {
00864        return 0; // Error
00865     }
00866     protInfo->idleSlaves.removeAll(slave);
00867 
00868     setupSlave(slave, url, protocol, proxy, true, &config);
00869 
00870     slave->send( CMD_CONNECT );
00871     q->connect(slave, SIGNAL(connected()),
00872                SLOT(slotSlaveConnected()));
00873     q->connect(slave, SIGNAL(error(int, const QString &)),
00874                SLOT(slotSlaveError(int, const QString &)));
00875 
00876     protInfo->coSlaves.insert(slave, new JobList);
00877 //    kDebug(7006) << "_getConnectedSlave( " << slave << ")";
00878     return slave;
00879 }
00880 
00881 void
00882 SchedulerPrivate::slotScheduleCoSlave()
00883 {
00884     slaveConfig = SlaveConfig::self();
00885     foreach (ProtocolInfo *protInfo, protInfoDict) {
00886         SlaveList::iterator it = protInfo->coIdleSlaves.begin();
00887         for( ; it != protInfo->coIdleSlaves.end(); )
00888         {
00889             Slave* slave = *it;
00890             JobList *list = protInfo->coSlaves.value(slave);
00891             assert(list);
00892             if (list && !list->isEmpty())
00893             {
00894                 SimpleJob *job = list->takeFirst();
00895                 it = protInfo->coIdleSlaves.erase( it );
00896                 //           kDebug(7006) << "scheduler: job started " << job;
00897 
00898                 KUrl url =job->url();
00899                 QString host = url.host();
00900                 int port = url.port();
00901                 if ( port == -1 ) // no port is -1 in QUrl, but in kde3 we used 0 and the kioslaves assume that.
00902                     port = 0;
00903 
00904                 if (slave->host() == "<reset>")
00905                 {
00906                     QString user = url.user();
00907                     QString passwd = url.pass();
00908 
00909                     MetaData configData = slaveConfig->configData(url.protocol(), url.host());
00910                     slave->setConfig(configData);
00911                     slave->setProtocol(url.protocol());
00912                     slave->setHost(host, port, user, passwd);
00913                 }
00914 
00915                 assert(slave->protocol() == url.protocol());
00916                 assert(slave->host() == host);
00917                 assert(slave->port() == port);
00918                 startJob(job, slave);
00919             } else {
00920                 ++it;
00921             }
00922         }
00923     }
00924 }
00925 
00926 void
00927 SchedulerPrivate::slotSlaveConnected()
00928 {
00929     Slave *slave = static_cast<Slave *>(q->sender());
00930 //    kDebug(7006) << "slotSlaveConnected( " << slave << ")";
00931     slave->setConnected(true);
00932     q->disconnect(slave, SIGNAL(connected()),
00933                   q, SLOT(slotSlaveConnected()));
00934     emit q->slaveConnected(slave);
00935     ProtocolInfo *protInfo = protInfoDict.get(slave->protocol());
00936     assert(!protInfo->coIdleSlaves.contains(slave));
00937     protInfo->coIdleSlaves.append(slave);
00938     coSlaveTimer.start(0);
00939 }
00940 
00941 void
00942 SchedulerPrivate::slotSlaveError(int errorNr, const QString &errorMsg)
00943 {
00944     Slave *slave = static_cast<Slave *>(q->sender());
00945     ProtocolInfo *protInfo = protInfoDict.get(slave->protocol());
00946     if (!slave->isConnected() || protInfo->coIdleSlaves.contains(slave))
00947     {
00948        // Only forward to application if slave is idle or still connecting.
00949        emit q->slaveError(slave, errorNr, errorMsg);
00950     }
00951 }
00952 
00953 bool
00954 SchedulerPrivate::assignJobToSlave(KIO::Slave *slave, SimpleJob *job)
00955 {
00956 //    kDebug(7006) << "_assignJobToSlave( " << job << ", " << slave << ")";
00957     QString dummy;
00958     if ((slave->slaveProtocol() != KProtocolManager::slaveProtocol( job->url(), dummy ))
00959         ||
00960         (!newJobs.removeAll(job)))
00961     {
00962         kDebug(7006) << "_assignJobToSlave(): ERROR, nonmatching or unknown job.";
00963         job->kill();
00964         return false;
00965     }
00966 
00967     ProtocolInfo *protInfo = protInfoDict.get(slave->protocol());
00968     JobList *list = protInfo->coSlaves.value(slave);
00969     assert(list);
00970     if (!list)
00971     {
00972         kDebug(7006) << "_assignJobToSlave(): ERROR, unknown slave.";
00973         job->kill();
00974         return false;
00975     }
00976 
00977     assert(!list->contains(job));
00978     list->append(job);
00979     coSlaveTimer.start(0); // Start job on timer event
00980 
00981     return true;
00982 }
00983 
00984 bool
00985 SchedulerPrivate::disconnectSlave(KIO::Slave *slave)
00986 {
00987 //    kDebug(7006) << "_disconnectSlave( " << slave << ")";
00988     ProtocolInfo *protInfo = protInfoDict.get(slave->protocol());   //### or slaveProtocol?
00989     CoSlaveMap::iterator coSlaveIt = protInfo->coSlaves.find( slave );
00990     if ( coSlaveIt != protInfo->coSlaves.end() ) {
00991         JobList *list = *coSlaveIt;
00992         protInfo->coSlaves.erase( coSlaveIt );
00993         if (list)
00994         {
00995             // Kill jobs still in queue.
00996             while(!list->isEmpty())
00997             {
00998                Job *job = list->takeFirst();
00999                job->kill();
01000             }
01001             delete list;
01002         }
01003     }
01004     protInfo->coIdleSlaves.removeAll(slave);
01005     assert(!protInfo->coIdleSlaves.contains(slave));
01006     QObject::disconnect(slave, SIGNAL(connected()),
01007                         q, SLOT(slotSlaveConnected()));
01008     QObject::disconnect(slave, SIGNAL(error(int, const QString &)),
01009                         q, SLOT(slotSlaveError(int, const QString &)));
01010     if (slave->isAlive())
01011     {
01012        protInfo->idleSlaves.append(slave);
01013        slave->send( CMD_DISCONNECT );
01014        slave->setIdle();
01015        slave->setConnected(false);
01016        scheduleCleanup();
01017     }
01018     return true;
01019 }
01020 
01021 void
01022 SchedulerPrivate::checkSlaveOnHold(bool b)
01023 {
01024     checkOnHold = b;
01025 }
01026 
01027 void
01028 SchedulerPrivate::registerWindow(QWidget *wid)
01029 {
01030    if (!wid)
01031       return;
01032 
01033    QWidget* window = wid->window();
01034 
01035    QObject *obj = static_cast<QObject *>(window);
01036    if (!m_windowList.contains(obj))
01037    {
01038       // We must store the window Id because by the time
01039       // the destroyed signal is emitted we can no longer
01040       // access QWidget::winId() (already destructed)
01041       WId windowId = window->winId();
01042       m_windowList.insert(obj, windowId);
01043       q->connect(window, SIGNAL(destroyed(QObject *)),
01044                  SLOT(slotUnregisterWindow(QObject*)));
01045       QDBusInterface("org.kde.kded", "/kded", "org.kde.kded").
01046           call(QDBus::NoBlock, "registerWindowId", qlonglong(windowId));
01047    }
01048 }
01049 
01050 void
01051 SchedulerPrivate::slotUnregisterWindow(QObject *obj)
01052 {
01053    if (!obj)
01054       return;
01055 
01056    QMap<QObject *, WId>::Iterator it = m_windowList.find(obj);
01057    if (it == m_windowList.end())
01058       return;
01059    WId windowId = it.value();
01060    q->disconnect(it.key(), SIGNAL(destroyed(QObject *)),
01061                  q, SLOT(slotUnregisterWindow(QObject*)));
01062    m_windowList.erase( it );
01063    QDBusInterface("org.kde.kded", "/kded", "org.kde.kded").
01064        call(QDBus::NoBlock, "unregisterWindowId", qlonglong(windowId));
01065 }
01066 
01067 #include "scheduler.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal