- 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)
{
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;

View File

@ -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;

View File

@ -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<QObject *, SignalRelay *> relayObjects;
QMap<uint, SignalRelay *> 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();
}

View File

@ -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";
}
}
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);
}
}
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?
}

View File

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