00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00041
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 )
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
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
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
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
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
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
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
00417 Slave *slave = jobSlave(job);
00418 if ( !slave )
00419 {
00420
00421 JobData jobData = extraJobData.value(job);
00422 newJobs.removeAll(job);
00423 ProtocolInfo *protInfo = protInfoDict.get(jobData.protocol);
00424 protInfo->joblist.removeAll(job);
00425
00426
00427 foreach(Slave* coSlave, protInfo->allSlaves())
00428 {
00429 JobList *list = protInfo->coSlaves.value(coSlave);
00430 if (list && list->removeAll(job)) {
00431
00432
00433 slave = coSlave;
00434 break;
00435 }
00436 }
00437 if (!slave)
00438 {
00439 extraJobData.remove(job);
00440 return;
00441 }
00442 }
00443
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 )
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
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
00528
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
00576
00577 return false;
00578 }
00579
00580 protInfo->activeSlaves.append(slave);
00581 protInfo->idleSlaves.removeAll(slave);
00582 protInfo->joblist.removeOne(job);
00583
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
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
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 )
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
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
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
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
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();
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
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;
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
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
00897
00898 KUrl url =job->url();
00899 QString host = url.host();
00900 int port = url.port();
00901 if ( port == -1 )
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
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
00949 emit q->slaveError(slave, errorNr, errorMsg);
00950 }
00951 }
00952
00953 bool
00954 SchedulerPrivate::assignJobToSlave(KIO::Slave *slave, SimpleJob *job)
00955 {
00956
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);
00980
00981 return true;
00982 }
00983
00984 bool
00985 SchedulerPrivate::disconnectSlave(KIO::Slave *slave)
00986 {
00987
00988 ProtocolInfo *protInfo = protInfoDict.get(slave->protocol());
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
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
01039
01040
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"