refs #581 Store a TTL value in the data cache revision file, skip loading a cached value if its timestamp is too old.

This commit is contained in:
Mathew Sutcliffe
2016-02-04 18:28:01 +00:00
parent e0607eb83c
commit 071dbda4b7
2 changed files with 34 additions and 2 deletions

View File

@@ -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<QString, qint64> &timestamps)
{
QJsonObject result;

View File

@@ -72,6 +72,9 @@ namespace BlackMisc
//! Returns (by move) the container of promises to load values.
std::vector<std::tuple<QObject *, QString, std::promise<CVariant>>> 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<QString, qint64> m_timestamps;
QMap<QString, qint64> m_timesToLive;
std::vector<std::tuple<QObject *, QString, std::promise<CVariant>>> m_promises;
static QJsonObject toJson(const QMap<QString, qint64> &timestamps);
@@ -149,6 +153,9 @@ namespace BlackMisc
//! Method used for implementing CData::syncLoad.
std::future<CVariant> 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<T> 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<CVariant> 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;