Estimator lazy refresh

.. Refresh model estimates when rides added, deleted, saved.

.. Lazy refresh will cancel any pending or running threads and
   trigger a new one in 15 secs time.

.. This strategy allows us to call a lazy refresh even when importing
   large number of rides, since the start will be delayed and cancelled
   by the next ride added etc.

.. The thread stop() function is also called by the destructor to stop
   when the user exits and avoiding delay/SEGV on exit.
This commit is contained in:
Mark Liversedge
2018-04-01 14:46:30 +01:00
parent 6e6db666c5
commit f8af6334fb
5 changed files with 73 additions and 3 deletions

View File

@@ -287,6 +287,9 @@ RideCache::addRide(QString name, bool dosignal, bool select, bool useTempActivit
// notify everyone to select the one we were already on
context->notifyRideSelected(prior);
}
// model estimates (lazy refresh)
estimator->refresh();
}
void
@@ -376,6 +379,9 @@ RideCache::removeCurrentRide()
// now select another ride
context->notifyRideSelected(select);
// model estimates (lazy refresh)
estimator->refresh();
}
// NOTE:

View File

@@ -132,6 +132,7 @@ class RideCache : public QObject
protected:
friend class ::Athlete;
friend class ::MainWindow; // save dialog
friend class ::RideCacheBackgroundRefresh;
Context *context;

View File

@@ -19,6 +19,7 @@
#include "Tab.h"
#include "Athlete.h"
#include "RideCache.h"
#include "Estimator.h"
#include "GcRideFile.h"
#include "JsonRideFile.h"
#include "RideItem.h"
@@ -197,6 +198,9 @@ MainWindow::saveSilent(Context *context, RideItem *rideItem)
// mark clean as we have now saved the data
rideItem->ride()->emitSaved();
// model estimates (lazy refresh)
context->athlete->rideCache->estimator->refresh();
}

View File

@@ -99,10 +99,51 @@ class RollingBests {
Estimator::Estimator(Context *context) : context(context)
{
// used to flag when we need to stop
abort = false;
// lazy start signal
connect(&singleshot, SIGNAL(timeout()), this, SLOT(calculate()));
// when thread finishes we can let everyone know estimates are updated
connect(this, SIGNAL(finished()), context, SLOT(notifyEstimatesRefreshed()));
}
void
Estimator::stop()
{
if (isRunning()) {
// we could use requestInterruption but would mean we need QT > 5.2
// and there isn't much value in that.
abort = true;
// now wait for the thread to stop
while(isRunning() && abort == true) msleep(50);
}
}
// terminate thread before closing
Estimator::~Estimator()
{
stop();
}
// refresh
void
Estimator::refresh()
{
printd("Lazy start triggered.\n");
stop(); // stop any running threads
singleshot.stop(); // stop any pending threads
// 15 secs delay before calculate() is triggered
singleshot.setSingleShot(true);
singleshot.setInterval(15000);
singleshot.start();
}
// setup and run, if not already running
void
Estimator::calculate()
@@ -184,6 +225,13 @@ Estimator::run()
QDate date = from;
while (date < to) {
// check if we've been asked to stop
if (abort == true) {
printd("Model estimator aborted.\n");
abort = false;
return;
}
QDate begin = date;
QDate end = date.addDays(6);

View File

@@ -38,13 +38,22 @@ class Estimator : public QThread {
public:
Estimator(Context *);
// sets up and kicks off thread
void calculate();
~Estimator();
// perform calculation in thread
void run();
// halt the thread
void stop();
// cancel any pending/running and kick off with 15 sec delay
void refresh();
public slots:
// setup and run estimators
void calculate();
protected:
friend class ::Athlete;
@@ -53,7 +62,9 @@ class Estimator : public QThread {
QMutex lock;
QList<PDEstimate> estimates;
QVector<RideItem*> rides; // worklist
QTimer singleshot;
bool abort;
};
#endif