mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-20 04:25:42 +08:00
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:
@@ -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)
|
QString lockFileError(const QLockFile &lock)
|
||||||
{
|
{
|
||||||
switch (lock.error())
|
switch (lock.error())
|
||||||
@@ -250,10 +255,13 @@ namespace BlackMisc
|
|||||||
}
|
}
|
||||||
m_uuid = uuid;
|
m_uuid = uuid;
|
||||||
|
|
||||||
|
auto timesToLive = fromJson(json.value("ttl").toObject());
|
||||||
auto newTimestamps = fromJson(json.value("timestamps").toObject());
|
auto newTimestamps = fromJson(json.value("timestamps").toObject());
|
||||||
for (auto it = newTimestamps.cbegin(); it != newTimestamps.cend(); ++it)
|
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());
|
m_timestamps.insert(it.key(), it.value());
|
||||||
}
|
}
|
||||||
@@ -302,6 +310,7 @@ namespace BlackMisc
|
|||||||
QJsonObject json;
|
QJsonObject json;
|
||||||
json.insert("uuid", m_uuid.toString());
|
json.insert("uuid", m_uuid.toString());
|
||||||
json.insert("timestamps", toJson(timestamps));
|
json.insert("timestamps", toJson(timestamps));
|
||||||
|
json.insert("ttl", toJson(m_timesToLive));
|
||||||
revisionFile.write(QJsonDocument(json).toJson());
|
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
|
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> ×tamps)
|
QJsonObject CDataCacheRevision::toJson(const QMap<QString, qint64> ×tamps)
|
||||||
{
|
{
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ namespace BlackMisc
|
|||||||
//! Returns (by move) the container of promises to load values.
|
//! Returns (by move) the container of promises to load values.
|
||||||
std::vector<std::tuple<QObject *, QString, std::promise<CVariant>>> loadedValuePromises();
|
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:
|
private:
|
||||||
mutable QMutex m_mutex { QMutex::Recursive };
|
mutable QMutex m_mutex { QMutex::Recursive };
|
||||||
bool m_updateInProgress = false;
|
bool m_updateInProgress = false;
|
||||||
@@ -81,6 +84,7 @@ namespace BlackMisc
|
|||||||
QLockFile m_lockFile { m_basename + "/.lock" };
|
QLockFile m_lockFile { m_basename + "/.lock" };
|
||||||
QUuid m_uuid;
|
QUuid m_uuid;
|
||||||
QMap<QString, qint64> m_timestamps;
|
QMap<QString, qint64> m_timestamps;
|
||||||
|
QMap<QString, qint64> m_timesToLive;
|
||||||
std::vector<std::tuple<QObject *, QString, std::promise<CVariant>>> m_promises;
|
std::vector<std::tuple<QObject *, QString, std::promise<CVariant>>> m_promises;
|
||||||
|
|
||||||
static QJsonObject toJson(const QMap<QString, qint64> ×tamps);
|
static QJsonObject toJson(const QMap<QString, qint64> ×tamps);
|
||||||
@@ -149,6 +153,9 @@ namespace BlackMisc
|
|||||||
//! Method used for implementing CData::syncLoad.
|
//! Method used for implementing CData::syncLoad.
|
||||||
std::future<CVariant> syncLoad(QObject *pageOwner, const QString &key);
|
std::future<CVariant> syncLoad(QObject *pageOwner, const QString &key);
|
||||||
|
|
||||||
|
//! Method used for implementing TTL.
|
||||||
|
void setTimeToLive(const QString &key, int ttl);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CDataCache();
|
CDataCache();
|
||||||
|
|
||||||
@@ -183,7 +190,9 @@ namespace BlackMisc
|
|||||||
CData(T *owner, NotifySlot<T> slot = nullptr) :
|
CData(T *owner, NotifySlot<T> slot = nullptr) :
|
||||||
CData::CCached(CDataCache::instance(), Trait::key(), Trait::isValid, Trait::defaultValue(), owner, slot),
|
CData::CCached(CDataCache::instance(), Trait::key(), Trait::isValid, Trait::defaultValue(), owner, slot),
|
||||||
m_owner(owner)
|
m_owner(owner)
|
||||||
{}
|
{
|
||||||
|
if (Trait::timeToLive() >= 0) { CDataCache::instance()->setTimeToLive(Trait::key(), Trait::timeToLive()); }
|
||||||
|
}
|
||||||
|
|
||||||
//! Reset the data to its default value.
|
//! Reset the data to its default value.
|
||||||
void setDefault() { this->set(Trait::defaultValue()); }
|
void setDefault() { this->set(Trait::defaultValue()); }
|
||||||
@@ -191,6 +200,9 @@ namespace BlackMisc
|
|||||||
//! Return the file that is used for persistence for this value.
|
//! Return the file that is used for persistence for this value.
|
||||||
QString getFilename() const { return CDataCache::filenameForKey(this->getKey()); }
|
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.
|
//! 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.
|
//! 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()); }
|
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.
|
//! Default implementation returns a default-constructed value.
|
||||||
static const T &defaultValue() { static const T def {}; return def; }
|
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.
|
//! Deleted default constructor.
|
||||||
CDataTrait() = delete;
|
CDataTrait() = delete;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user