7#include "collectionscheduler.h" 
    8#include "akonadiserver_debug.h" 
    9#include "storage/datastore.h" 
   10#include "storage/selectquerybuilder.h" 
   12#include "private/tristate_p.h" 
   18using namespace std::literals::chrono_literals;
 
   28class PauseableTimer : 
public QTimer
 
   38    void start(std::chrono::milliseconds 
interval)
 
   41        mPaused = QDateTime();
 
   48        start(std::chrono::milliseconds{
interval()});
 
   53        mStarted = QDateTime();
 
   54        mPaused = QDateTime();
 
   74        const auto remainder = std::chrono::milliseconds{
interval()} - std::chrono::seconds{mStarted.secsTo(mPaused)};
 
   75        start(qMax(std::chrono::milliseconds{0}, remainder));
 
   76        mPaused = QDateTime();
 
   83        return mPaused.isValid();
 
   94using namespace Akonadi::Server;
 
   97    : AkThread(threadName, priority, parent)
 
  101CollectionScheduler::~CollectionScheduler()
 
  106void CollectionScheduler::quit()
 
  109    mScheduler = 
nullptr;
 
  114void CollectionScheduler::inhibit(
bool inhibit)
 
  127int CollectionScheduler::minimumInterval()
 const 
  132CollectionScheduler::TimePoint CollectionScheduler::nextScheduledTime(qint64 collectionId)
 const 
  134    QMutexLocker locker(&mScheduleLock);
 
  135    const auto i = constFind(collectionId);
 
  136    if (i != mSchedule.cend()) {
 
  142std::chrono::milliseconds CollectionScheduler::currentTimerInterval()
 const 
  144    return std::chrono::milliseconds(mScheduler->isActive() ? mScheduler->interval() : 0);
 
  147void CollectionScheduler::setMinimumInterval(
int intervalMinutes)
 
  150    mMinInterval = intervalMinutes;
 
  153void CollectionScheduler::collectionAdded(qint64 collectionId)
 
  155    Collection collection = Collection::retrieveById(collectionId);
 
  157    if (shouldScheduleCollection(collection)) {
 
  160            [
this, collection]() {
 
  161                scheduleCollection(collection);
 
  167void CollectionScheduler::collectionChanged(qint64 collectionId)
 
  169    QMutexLocker locker(&mScheduleLock);
 
  170    const auto it = constFind(collectionId);
 
  171    if (it != mSchedule.cend()) {
 
  172        const Collection &oldCollection = it.value();
 
  173        Collection changed = Collection::retrieveById(collectionId);
 
  175        if (hasChanged(oldCollection, changed)) {
 
  176            if (shouldScheduleCollection(changed)) {
 
  182                        scheduleCollection(changed);
 
  188                collectionRemoved(collectionId);
 
  193        collectionAdded(collectionId);
 
  197void CollectionScheduler::collectionRemoved(qint64 collectionId)
 
  199    QMutexLocker locker(&mScheduleLock);
 
  200    auto it = find(collectionId);
 
  201    if (it != mSchedule.end()) {
 
  202        const bool reschedule = it == mSchedule.begin();
 
  213void CollectionScheduler::startScheduler()
 
  215    QMutexLocker locker(&mScheduleLock);
 
  217    if (mScheduler->isPaused()) {
 
  221    if (mSchedule.isEmpty()) {
 
  228    const auto next = mSchedule.constBegin().key();
 
  230    const auto delayUntilNext = std::chrono::duration_cast<std::chrono::milliseconds>(next - std::chrono::steady_clock::now());
 
  231    mScheduler->start(qMax(std::chrono::milliseconds{0}, delayUntilNext));
 
  235void CollectionScheduler::scheduleCollection(Collection collection, 
bool shouldStartScheduler)
 
  239    QMutexLocker locker(&mScheduleLock);
 
  240    auto i = find(collection.id());
 
  241    if (i != mSchedule.end()) {
 
  245    if (!shouldScheduleCollection(collection)) {
 
  249    const int expireMinutes = qMax(mMinInterval, collectionScheduleInterval(collection));
 
  250    TimePoint nextCheck(std::chrono::steady_clock::now() + std::chrono::minutes(expireMinutes));
 
  255    auto it = constLowerBound(nextCheck);
 
  256    if (it != mSchedule.cend() && it.key() - nextCheck < 1min) {
 
  257        nextCheck = it.key();
 
  261    } 
else if (it != mSchedule.cbegin()) {
 
  263        if (nextCheck - it.key() < 1min) {
 
  264            nextCheck = it.key();
 
  268    mSchedule.insert(nextCheck, collection);
 
  269    if (shouldStartScheduler && !mScheduler->isActive()) {
 
  275CollectionScheduler::ScheduleMap::const_iterator CollectionScheduler::constFind(qint64 collectionId)
 const 
  277    return std::find_if(mSchedule.cbegin(), mSchedule.cend(), [collectionId](
const Collection &c) {
 
  278        return c.id() == collectionId;
 
  282CollectionScheduler::ScheduleMap::iterator CollectionScheduler::find(qint64 collectionId)
 
  284    return std::find_if(mSchedule.begin(), mSchedule.end(), [collectionId](
const Collection &c) {
 
  285        return c.id() == collectionId;
 
  290CollectionScheduler::ScheduleMap::const_iterator CollectionScheduler::constLowerBound(TimePoint timestamp)
 const 
  292    return mSchedule.lowerBound(timestamp);
 
  296void CollectionScheduler::init()
 
  300    mScheduler = 
new PauseableTimer();
 
  301    mScheduler->setSingleShot(
true);
 
  306    SelectQueryBuilder<Collection> qb;
 
  308        qCWarning(AKONADISERVER_LOG) << 
"Failed to query initial collections for scheduler!";
 
  309        qCWarning(AKONADISERVER_LOG) << 
"Not a fatal error, no collections will be scheduled for sync or cache expiration!";
 
  313    for (
const Collection &collection : collections) {
 
  314        scheduleCollection(collection);
 
  321void CollectionScheduler::schedulerTimeout()
 
  323    QMutexLocker locker(&mScheduleLock);
 
  328    const auto timestamp = mSchedule.constBegin().key();
 
  329    const QList<Collection> collections = mSchedule.values(timestamp);
 
  330    mSchedule.
remove(timestamp);
 
  333    for (
const Collection &collection : collections) {
 
  334        collectionExpired(collection);
 
  335        scheduleCollection(collection, 
false);
 
  341#include "collectionscheduler.moc" 
  343#include "moc_collectionscheduler.cpp" 
QList< Collection > List
Describes a list of collections.
 
static DataStore * self()
Per thread singleton.
 
virtual void activeCachePolicy(Collection &col)
Determines the active cache policy for this Collection.
 
bool exec()
Executes the query, returns true on success.
 
QList< T > result()
Returns the result of this SELECT query.
 
Helper integration between Akonadi and Qt.
 
const QList< QKeySequence > & next()
 
QDateTime currentDateTimeUtc()
 
void remove(qsizetype i, qsizetype n)
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
QObject * parent() const const
 
bool isActive() const const