From 071dbda4b719beb8521f23830089bef74299ff97 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Thu, 4 Feb 2016 18:28:01 +0000 Subject: [PATCH] refs #581 Store a TTL value in the data cache revision file, skip loading a cached value if its timestamp is too old. --- src/blackmisc/datacache.cpp | 18 +++++++++++++++++- src/blackmisc/datacache.h | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/blackmisc/datacache.cpp b/src/blackmisc/datacache.cpp index 606a70f13..e81d8a20b 100644 --- a/src/blackmisc/datacache.cpp +++ b/src/blackmisc/datacache.cpp @@ -99,6 +99,11 @@ namespace BlackMisc } } + void CDataCache::setTimeToLive(const QString &key, int ttl) + { + QTimer::singleShot(0, &m_serializer, [this, key, ttl] { m_revision.setTimeToLive(key, ttl); }); + } + QString lockFileError(const QLockFile &lock) { switch (lock.error()) @@ -250,10 +255,13 @@ namespace BlackMisc } m_uuid = uuid; + auto timesToLive = fromJson(json.value("ttl").toObject()); auto newTimestamps = fromJson(json.value("timestamps").toObject()); for (auto it = newTimestamps.cbegin(); it != newTimestamps.cend(); ++it) { - if (timestamps.value(it.key(), 0) < it.value()) + auto current = timestamps.value(it.key(), 0); + auto ttl = timesToLive.value(it.key(), -1); + if (current < it.value() && (ttl < 0 || QDateTime::currentMSecsSinceEpoch() < it.value() + ttl)) { m_timestamps.insert(it.key(), it.value()); } @@ -302,6 +310,7 @@ namespace BlackMisc QJsonObject json; json.insert("uuid", m_uuid.toString()); json.insert("timestamps", toJson(timestamps)); + json.insert("ttl", toJson(m_timesToLive)); revisionFile.write(QJsonDocument(json).toJson()); } @@ -368,6 +377,13 @@ namespace BlackMisc return std::move(m_promises); // move into the return value, so m_promises becomes empty } + void CDataCacheRevision::setTimeToLive(const QString &key, int ttl) + { + Q_ASSERT(! m_updateInProgress); + + m_timesToLive.insert(key, ttl); + } + QJsonObject CDataCacheRevision::toJson(const QMap ×tamps) { QJsonObject result; diff --git a/src/blackmisc/datacache.h b/src/blackmisc/datacache.h index 56bfb3636..a3ae2521a 100644 --- a/src/blackmisc/datacache.h +++ b/src/blackmisc/datacache.h @@ -72,6 +72,9 @@ namespace BlackMisc //! Returns (by move) the container of promises to load values. std::vector>> loadedValuePromises(); + //! Set TTL value that will be written to the revision file. + void setTimeToLive(const QString &key, int ttl); + private: mutable QMutex m_mutex { QMutex::Recursive }; bool m_updateInProgress = false; @@ -81,6 +84,7 @@ namespace BlackMisc QLockFile m_lockFile { m_basename + "/.lock" }; QUuid m_uuid; QMap m_timestamps; + QMap m_timesToLive; std::vector>> m_promises; static QJsonObject toJson(const QMap ×tamps); @@ -149,6 +153,9 @@ namespace BlackMisc //! Method used for implementing CData::syncLoad. std::future syncLoad(QObject *pageOwner, const QString &key); + //! Method used for implementing TTL. + void setTimeToLive(const QString &key, int ttl); + private: CDataCache(); @@ -183,7 +190,9 @@ namespace BlackMisc CData(T *owner, NotifySlot slot = nullptr) : CData::CCached(CDataCache::instance(), Trait::key(), Trait::isValid, Trait::defaultValue(), owner, slot), m_owner(owner) - {} + { + if (Trait::timeToLive() >= 0) { CDataCache::instance()->setTimeToLive(Trait::key(), Trait::timeToLive()); } + } //! Reset the data to its default value. void setDefault() { this->set(Trait::defaultValue()); } @@ -191,6 +200,9 @@ namespace BlackMisc //! Return the file that is used for persistence for this value. QString getFilename() const { return CDataCache::filenameForKey(this->getKey()); } + //! True if the current timestamp is older than the TTL (time to live). + bool isStale() const { return this->getTimestamp() + Trait::timeToLive() > QDateTime::currentMSecsSinceEpoch(); } + //! Return a future providing the value. If the value is still loading, the future will wait for it. //! If the value is not present, the variant is null. Bypasses async get and inhibits notification slot. std::future syncLoad() { return CDataCache::instance()->syncLoad(m_owner, this->getKey()); } @@ -222,6 +234,10 @@ namespace BlackMisc //! Default implementation returns a default-constructed value. static const T &defaultValue() { static const T def {}; return def; } + //! Number of milliseconds after which cached value becomes stale. + //! Default is -1 which means value never becomes stale. + static int timeToLive() { return -1; } + //! Deleted default constructor. CDataTrait() = delete;