- 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
This commit is contained in:
Aaron J. Seigo 2007-09-13 20:34:17 +00:00
parent 0fc83b6e76
commit 6ffbc459ad
5 changed files with 88 additions and 26 deletions

View File

@ -46,16 +46,13 @@ const DataEngine::Data DataContainer::data() const
void DataContainer::setData(const QString& key, const QVariant& value) void DataContainer::setData(const QString& key, const QVariant& value)
{ {
if (value.isNull() || !value.isValid()) { if (value.isNull() || !value.isValid()) {
if (!d->data.contains(key)) {
return;
}
d->data.remove(key); d->data.remove(key);
} else { } else {
d->data[key] = value; d->data[key] = value;
} }
d->dirty = true; d->dirty = true;
d->updateTs = QTime::currentTime().msec();
} }
void DataContainer::clearData() void DataContainer::clearData()
@ -73,10 +70,35 @@ void DataContainer::checkForUpdate()
{ {
if (d->dirty) { if (d->dirty) {
emit updated(objectName(), d->data); emit updated(objectName(), d->data);
foreach (SignalRelay* relay, d->relays) {
relay->checkQueueing();
}
d->dirty = false; 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() void DataContainer::checkUsage()
{ {
if (d->relays.count() < 1 && 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 // the visualization was connected already, but not to a relay
// and it still doesn't want to connect to a relay, so we have // and it still doesn't want to connect to a relay, so we have
// nothing to do! // nothing to do!
kDebug() << " already connected, nothing to do"; //kDebug() << " already connected, nothing to do";
return; return;
} else { } else {
disconnect(this, SIGNAL(updated(QString,Plasma::DataEngine::Data)), disconnect(this, SIGNAL(updated(QString,Plasma::DataEngine::Data)),
@ -119,7 +141,7 @@ void DataContainer::connectVisualization(QObject* visualization, uint updateInte
if (!connected) { if (!connected) {
connect(visualization, SIGNAL(destroyed(QObject*)), connect(visualization, SIGNAL(destroyed(QObject*)),
this, SLOT(disconnectVisualization(QObject*)), Qt::QueuedConnection); this, SLOT(disconnectVisualization(QObject*)));//, Qt::QueuedConnection);
} }
d->relayObjects[visualization] = 0; d->relayObjects[visualization] = 0;

View File

@ -80,6 +80,16 @@ class PLASMA_EXPORT DataContainer : public QObject
**/ **/
void checkForUpdate(); 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: public Q_SLOTS:
/** /**
* Check if the DataContainer is still in use. * 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, * Emitted when the source, usually due to an internal timer firing,
* requests to be updated. * requests to be updated.
**/ **/
void requestUpdate(const QString& source); void requestUpdate(DataContainer *source);
private: private:
friend class SignalRelay; friend class SignalRelay;

View File

@ -30,7 +30,8 @@ class DataContainer::Private
{ {
public: public:
Private() Private()
: dirty(false) : updateTs(0),
dirty(false)
{} {}
QObject* signalRelay(const DataContainer* dc, QObject *visualization, QObject* signalRelay(const DataContainer* dc, QObject *visualization,
@ -39,6 +40,7 @@ public:
DataEngine::Data data; DataEngine::Data data;
QMap<QObject *, SignalRelay *> relayObjects; QMap<QObject *, SignalRelay *> relayObjects;
QMap<uint, SignalRelay *> relays; QMap<uint, SignalRelay *> relays;
int updateTs;
bool dirty : 1; bool dirty : 1;
}; };
@ -53,8 +55,10 @@ public:
d(data), d(data),
m_interval(ival), m_interval(ival),
m_align(align), 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); m_timerId = startTimer(m_interval);
if (m_align != Plasma::NoAlignment) { if (m_align != Plasma::NoAlignment) {
checkAlignment(); checkAlignment();
@ -92,12 +96,20 @@ public:
} }
} }
void checkQueueing() {
if (m_queued) {
emit updated(dc->objectName(), d->data);
m_queued = false;
}
}
DataContainer *dc; DataContainer *dc;
DataContainer::Private *d; DataContainer::Private *d;
uint m_interval; uint m_interval;
Plasma::IntervalAlignment m_align; Plasma::IntervalAlignment m_align;
int m_timerId; int m_timerId;
bool m_resetTimer; bool m_resetTimer;
bool m_queued;
signals: signals:
void updated(const QString&, const Plasma::DataEngine::Data&); void updated(const QString&, const Plasma::DataEngine::Data&);
@ -115,7 +127,12 @@ protected:
checkAlignment(); 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); emit updated(dc->objectName(), d->data);
event->accept(); event->accept();
} }

View File

@ -70,13 +70,13 @@ class DataEngine::Private
return 0; return 0;
} }
/* kDebug() << "DataEngine " << engine->objectName() /*kDebug() << "DataEngine " << engine->objectName()
<< ": could not find DataContainer " << sourceName << ": could not find DataContainer " << sourceName
<< ", creating" << endl;*/ << ", creating" << endl;*/
DataContainer* s = new DataContainer(engine); DataContainer* s = new DataContainer(engine);
s->setObjectName(sourceName); s->setObjectName(sourceName);
sources.insert(sourceName, s); 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) { if (limit > 0) {
trimQueue(); trimQueue();
@ -88,6 +88,7 @@ class DataEngine::Private
void connectSource(DataContainer* s, QObject* visualization, uint updateInterval, Plasma::IntervalAlignment align) void connectSource(DataContainer* s, QObject* visualization, uint updateInterval, Plasma::IntervalAlignment align)
{ {
//kDebug() << "connect source called with interval" << updateInterval;
if (updateInterval > 0) { if (updateInterval > 0) {
// never more frequently than allowed, never more than 20 times per second // never more frequently than allowed, never more than 20 times per second
uint min = qMax(50, minUpdateFreq); // for qMin below uint min = qMax(50, minUpdateFreq); // for qMin below
@ -106,26 +107,31 @@ class DataEngine::Private
DataContainer* requestSource(const QString& sourceName) DataContainer* requestSource(const QString& sourceName)
{ {
//kDebug() << "requesting source " << sourceName;
DataContainer* s = source(sourceName, false); DataContainer* s = source(sourceName, false);
if (!s) { if (!s) {
// we didn't find a data source, so give the engine an opportunity to make one // 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)) { if (engine->sourceRequested(sourceName)) {
s = source(sourceName, false); s = source(sourceName, false);
if (s) { if (s) {
// now we have a source; since it was created on demand, assume // now we have a source; since it was created on demand, assume
// it should be removed when not used // it should be removed when not used
connect(s, SIGNAL(unused(QString)), engine, SLOT(removeSource(QString))); connect(s, SIGNAL(unused(QString)), engine, SLOT(removeSource(QString)));
connect(s, SIGNAL(requestUpdate(QString)), engine, SLOT(internalUpdateSource(QString)));
} }
} }
} }
return s; return s;
} }
void trimQueue() void trimQueue()
{ {
while (sourceQueue.count() >= limit) { uint queueCount = sourceQueue.count();
while (queueCount >= limit) {
DataContainer* punted = sourceQueue.dequeue(); DataContainer* punted = sourceQueue.dequeue();
engine->removeSource(punted->objectName()); engine->removeSource(punted->objectName());
} }
@ -177,13 +183,13 @@ QStringList DataEngine::sources() const
void DataEngine::connectSource(const QString& source, QObject* visualization, void DataEngine::connectSource(const QString& source, QObject* visualization,
uint updateInterval, Plasma::IntervalAlignment intervalAlignment) const uint updateInterval, Plasma::IntervalAlignment intervalAlignment) const
{ {
//kDebug() << "connectSource" << source;
DataContainer* s = d->requestSource(source); DataContainer* s = d->requestSource(source);
if (!s) { if (s) {
return; d->connectSource(s, visualization, updateInterval, intervalAlignment);
//kDebug() << " ==> source connected";
} }
d->connectSource(s, visualization, updateInterval, intervalAlignment);
} }
void DataEngine::connectAllSources(QObject* visualization, uint updateInterval, 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); DataContainer* s = d->source(source, false);
if (!s) { if (s) {
return; s->disconnectVisualization(visualization);
} }
s->disconnectVisualization(visualization);
} }
DataContainer* DataEngine::containerForSource(const QString &source) DataContainer* DataEngine::containerForSource(const QString &source)
@ -228,9 +232,18 @@ void DataEngine::startInit()
init(); 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(); d->queueUpdate();
} }
} }
@ -251,7 +264,7 @@ bool DataEngine::sourceRequested(const QString &name)
bool DataEngine::updateSource(const QString& source) bool DataEngine::updateSource(const QString& source)
{ {
Q_UNUSED(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? return false; //TODO: should this be true to trigger, even needless, updates on every tick?
} }

View File

@ -382,7 +382,7 @@ class PLASMA_EXPORT DataEngine : public QObject
/** /**
* @internal * @internal
**/ **/
void internalUpdateSource(const QString& source); void internalUpdateSource(DataContainer* source);
private: private:
class Private; class Private;