From 6ffbc459ad19cf86638ea968a7d3d4b943368a54 Mon Sep 17 00:00:00 2001 From: "Aaron J. Seigo" Date: Thu, 13 Sep 2007 20:34:17 +0000 Subject: [PATCH] - when an intervalled visualization triggers an update, but the update is async, we queue up to trigger updated when the data _actually_ arrives. - timestamp sources on update so we don't over update them due to multiple visualizations hammering on it. improves our tick situation even more. svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=712188 --- datacontainer.cpp | 34 ++++++++++++++++++++++++++++------ datacontainer.h | 12 +++++++++++- datacontainer_p.h | 23 ++++++++++++++++++++--- dataengine.cpp | 43 ++++++++++++++++++++++++++++--------------- dataengine.h | 2 +- 5 files changed, 88 insertions(+), 26 deletions(-) diff --git a/datacontainer.cpp b/datacontainer.cpp index a48648a7d..749cdc8d1 100644 --- a/datacontainer.cpp +++ b/datacontainer.cpp @@ -46,16 +46,13 @@ const DataEngine::Data DataContainer::data() const void DataContainer::setData(const QString& key, const QVariant& value) { if (value.isNull() || !value.isValid()) { - if (!d->data.contains(key)) { - return; - } - d->data.remove(key); } else { d->data[key] = value; } d->dirty = true; + d->updateTs = QTime::currentTime().msec(); } void DataContainer::clearData() @@ -73,10 +70,35 @@ void DataContainer::checkForUpdate() { if (d->dirty) { emit updated(objectName(), d->data); + + foreach (SignalRelay* relay, d->relays) { + relay->checkQueueing(); + } + d->dirty = false; } } +uint DataContainer::timeSinceLastUpdate() const +{ + int msec = QTime::currentTime().msec(); + if (msec < d->updateTs) { + // we wrapped over midnight here, so return the current + // msec's plus the number of msec left in the previous day. + // 86400000 is the # of msec in a day + // + // yes, we assume we don't wrap more than one day here. + return msec + (86400000 - d->updateTs); + } + + return msec - d->updateTs; +} + +bool DataContainer::hasUpdates() const +{ + return d->dirty; +} + void DataContainer::checkUsage() { if (d->relays.count() < 1 && @@ -109,7 +131,7 @@ void DataContainer::connectVisualization(QObject* visualization, uint updateInte // the visualization was connected already, but not to a relay // and it still doesn't want to connect to a relay, so we have // nothing to do! - kDebug() << " already connected, nothing to do"; + //kDebug() << " already connected, nothing to do"; return; } else { disconnect(this, SIGNAL(updated(QString,Plasma::DataEngine::Data)), @@ -119,7 +141,7 @@ void DataContainer::connectVisualization(QObject* visualization, uint updateInte if (!connected) { connect(visualization, SIGNAL(destroyed(QObject*)), - this, SLOT(disconnectVisualization(QObject*)), Qt::QueuedConnection); + this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection); } d->relayObjects[visualization] = 0; diff --git a/datacontainer.h b/datacontainer.h index 8bc51b159..1aebead3d 100644 --- a/datacontainer.h +++ b/datacontainer.h @@ -80,6 +80,16 @@ class PLASMA_EXPORT DataContainer : public QObject **/ void checkForUpdate(); + /** + * Returns how long ago, in msecs, that the data in this container was last updated + **/ + uint timeSinceLastUpdate() const; + + /** + * @internal + **/ + bool hasUpdates() const; + public Q_SLOTS: /** * Check if the DataContainer is still in use. @@ -118,7 +128,7 @@ class PLASMA_EXPORT DataContainer : public QObject * Emitted when the source, usually due to an internal timer firing, * requests to be updated. **/ - void requestUpdate(const QString& source); + void requestUpdate(DataContainer *source); private: friend class SignalRelay; diff --git a/datacontainer_p.h b/datacontainer_p.h index 006242f68..46a3a2d88 100644 --- a/datacontainer_p.h +++ b/datacontainer_p.h @@ -30,7 +30,8 @@ class DataContainer::Private { public: Private() - : dirty(false) + : updateTs(0), + dirty(false) {} QObject* signalRelay(const DataContainer* dc, QObject *visualization, @@ -39,6 +40,7 @@ public: DataEngine::Data data; QMap relayObjects; QMap relays; + int updateTs; bool dirty : 1; }; @@ -53,8 +55,10 @@ public: d(data), m_interval(ival), m_align(align), - m_resetTimer(false) + m_resetTimer(false), + m_queued(false) { + //kDebug() << "signal relay with time of" << m_timerId << "being set up"; m_timerId = startTimer(m_interval); if (m_align != Plasma::NoAlignment) { checkAlignment(); @@ -92,12 +96,20 @@ public: } } + void checkQueueing() { + if (m_queued) { + emit updated(dc->objectName(), d->data); + m_queued = false; + } + } + DataContainer *dc; DataContainer::Private *d; uint m_interval; Plasma::IntervalAlignment m_align; int m_timerId; bool m_resetTimer; + bool m_queued; signals: void updated(const QString&, const Plasma::DataEngine::Data&); @@ -115,7 +127,12 @@ protected: checkAlignment(); } - emit dc->requestUpdate(dc->objectName()); + emit dc->requestUpdate(dc); + if (!dc->hasUpdates()) { + // the source wasn't actually updated; so let's put ourselves in the queue + // so we get an updated() when the data does arrive + m_queued = true; + } emit updated(dc->objectName(), d->data); event->accept(); } diff --git a/dataengine.cpp b/dataengine.cpp index 4a9a54fa4..e7893b526 100644 --- a/dataengine.cpp +++ b/dataengine.cpp @@ -70,13 +70,13 @@ class DataEngine::Private return 0; } -/* kDebug() << "DataEngine " << engine->objectName() + /*kDebug() << "DataEngine " << engine->objectName() << ": could not find DataContainer " << sourceName << ", creating" << endl;*/ DataContainer* s = new DataContainer(engine); s->setObjectName(sourceName); sources.insert(sourceName, s); - connect(s, SIGNAL(requestUpdate(QString)), engine, SLOT(internalUpdateSource(QString))); + connect(s, SIGNAL(requestUpdate(DataContainer*)), engine, SLOT(internalUpdateSource(DataContainer*))); if (limit > 0) { trimQueue(); @@ -88,6 +88,7 @@ class DataEngine::Private void connectSource(DataContainer* s, QObject* visualization, uint updateInterval, Plasma::IntervalAlignment align) { + //kDebug() << "connect source called with interval" << updateInterval; if (updateInterval > 0) { // never more frequently than allowed, never more than 20 times per second uint min = qMax(50, minUpdateFreq); // for qMin below @@ -106,26 +107,31 @@ class DataEngine::Private DataContainer* requestSource(const QString& sourceName) { + //kDebug() << "requesting source " << sourceName; DataContainer* s = source(sourceName, false); if (!s) { // we didn't find a data source, so give the engine an opportunity to make one + /*kDebug() << "DataEngine " << engine->objectName() + << ": could not find DataContainer " << sourceName + << " will create on request" << endl;*/ if (engine->sourceRequested(sourceName)) { s = source(sourceName, false); if (s) { // now we have a source; since it was created on demand, assume // it should be removed when not used connect(s, SIGNAL(unused(QString)), engine, SLOT(removeSource(QString))); - connect(s, SIGNAL(requestUpdate(QString)), engine, SLOT(internalUpdateSource(QString))); } } } + return s; } void trimQueue() { - while (sourceQueue.count() >= limit) { + uint queueCount = sourceQueue.count(); + while (queueCount >= limit) { DataContainer* punted = sourceQueue.dequeue(); engine->removeSource(punted->objectName()); } @@ -177,13 +183,13 @@ QStringList DataEngine::sources() const void DataEngine::connectSource(const QString& source, QObject* visualization, uint updateInterval, Plasma::IntervalAlignment intervalAlignment) const { + //kDebug() << "connectSource" << source; DataContainer* s = d->requestSource(source); - if (!s) { - return; + if (s) { + d->connectSource(s, visualization, updateInterval, intervalAlignment); + //kDebug() << " ==> source connected"; } - - d->connectSource(s, visualization, updateInterval, intervalAlignment); } void DataEngine::connectAllSources(QObject* visualization, uint updateInterval, @@ -198,11 +204,9 @@ void DataEngine::disconnectSource(const QString& source, QObject* visualization) { DataContainer* s = d->source(source, false); - if (!s) { - return; + if (s) { + s->disconnectVisualization(visualization); } - - s->disconnectVisualization(visualization); } DataContainer* DataEngine::containerForSource(const QString &source) @@ -228,9 +232,18 @@ void DataEngine::startInit() init(); } -void DataEngine::internalUpdateSource(const QString& source) +void DataEngine::internalUpdateSource(DataContainer* source) { - if (updateSource(source)) { + if (d->minUpdateFreq > 0 && + source->timeSinceLastUpdate() < d->minUpdateFreq) { + // skip updating this source; it's been too soon + //TODO: should we queue an update in this case? return to this + // once we see the results in real world usage + //kDebug() << "internal update source is delaying" << source->timeSinceLastUpdate() << d->minUpdateFreq; + return; + } + + if (updateSource(source->objectName())) { d->queueUpdate(); } } @@ -251,7 +264,7 @@ bool DataEngine::sourceRequested(const QString &name) bool DataEngine::updateSource(const QString& source) { Q_UNUSED(source); - kDebug() << "updateSource source" << endl; + //kDebug() << "updateSource source" << endl; return false; //TODO: should this be true to trigger, even needless, updates on every tick? } diff --git a/dataengine.h b/dataengine.h index f8be7501a..e6122c211 100644 --- a/dataengine.h +++ b/dataengine.h @@ -382,7 +382,7 @@ class PLASMA_EXPORT DataEngine : public QObject /** * @internal **/ - void internalUpdateSource(const QString& source); + void internalUpdateSource(DataContainer* source); private: class Private;